1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/containers/containers_arraylist.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/base/array_helper.h"
20 #include "ecmascript/js_api/js_api_arraylist.h"
21 #include "ecmascript/js_array.h"
22 #include "ecmascript/tagged_array-inl.h"
23
24 namespace panda::ecmascript::containers {
ArrayListConstructor(EcmaRuntimeCallInfo * argv)25 JSTaggedValue ContainersArrayList::ArrayListConstructor(EcmaRuntimeCallInfo *argv)
26 {
27 ASSERT(argv);
28 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Constructor);
29 JSThread *thread = argv->GetThread();
30 [[maybe_unused]] EcmaHandleScope handleScope(thread);
31 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33 if (newTarget->IsUndefined()) {
34 JSTaggedValue error =
35 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
36 "The ArrayList's constructor cannot be directly invoked.");
37 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
38 }
39 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
40 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
41 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42 JSHandle<TaggedArray> newTaggedArray = factory->NewTaggedArray(JSAPIArrayList::DEFAULT_CAPACITY_LENGTH);
43 obj->SetElements(thread, newTaggedArray);
44 return obj.GetTaggedValue();
45 }
46
Add(EcmaRuntimeCallInfo * argv)47 JSTaggedValue ContainersArrayList::Add(EcmaRuntimeCallInfo *argv)
48 {
49 ASSERT(argv);
50 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Add);
51 JSThread *thread = argv->GetThread();
52 [[maybe_unused]] EcmaHandleScope handleScope(thread);
53 JSHandle<JSTaggedValue> self = GetThis(argv);
54
55 if (!self->IsJSAPIArrayList()) {
56 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
57 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
58 } else {
59 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
60 "The add method cannot be bound");
61 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
62 }
63 }
64
65 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
66 return GetTaggedBoolean(JSAPIArrayList::Add(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
67 }
68
Insert(EcmaRuntimeCallInfo * argv)69 JSTaggedValue ContainersArrayList::Insert(EcmaRuntimeCallInfo *argv)
70 {
71 ASSERT(argv);
72 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Insert);
73 JSThread *thread = argv->GetThread();
74 [[maybe_unused]] EcmaHandleScope handleScope(thread);
75 JSHandle<JSTaggedValue> self = GetThis(argv);
76
77 if (!self->IsJSAPIArrayList()) {
78 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
79 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
80 } else {
81 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
82 "The insert method cannot be bound");
83 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
84 }
85 }
86
87 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
88 JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
89 if (index->IsDouble()) {
90 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
91 // For integer which is greater than INT32_MAX, it will remain TaggedDouble
92 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
93 }
94 if (!index->IsInt()) {
95 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
96 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
97 CString errorMsg =
98 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
99 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
100 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
101 }
102 JSAPIArrayList::Insert(thread, JSHandle<JSAPIArrayList>::Cast(self), value, JSTaggedValue::ToUint32(thread, index));
103 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
104
105 return JSTaggedValue::Undefined();
106 }
107
Clear(EcmaRuntimeCallInfo * argv)108 JSTaggedValue ContainersArrayList::Clear(EcmaRuntimeCallInfo *argv)
109 {
110 ASSERT(argv);
111 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clear);
112 JSThread *thread = argv->GetThread();
113 [[maybe_unused]] EcmaHandleScope handleScope(thread);
114 JSHandle<JSTaggedValue> self = GetThis(argv);
115
116 if (!self->IsJSAPIArrayList()) {
117 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
118 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
119 } else {
120 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
121 "The clear method cannot be bound");
122 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
123 }
124 }
125
126 JSAPIArrayList::Clear(thread, JSHandle<JSAPIArrayList>::Cast(self));
127
128 return JSTaggedValue::True();
129 }
130
Clone(EcmaRuntimeCallInfo * argv)131 JSTaggedValue ContainersArrayList::Clone(EcmaRuntimeCallInfo *argv)
132 {
133 ASSERT(argv);
134 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clone);
135 JSThread *thread = argv->GetThread();
136 [[maybe_unused]] EcmaHandleScope handleScope(thread);
137 JSHandle<JSTaggedValue> self = GetThis(argv);
138
139 if (!self->IsJSAPIArrayList()) {
140 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
141 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
142 } else {
143 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
144 "The clone method cannot be bound");
145 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
146 }
147 }
148
149 JSHandle<JSAPIArrayList> newArrayList = JSAPIArrayList::Clone(thread, JSHandle<JSAPIArrayList>::Cast(self));
150
151 return newArrayList.GetTaggedValue();
152 }
153
Has(EcmaRuntimeCallInfo * argv)154 JSTaggedValue ContainersArrayList::Has(EcmaRuntimeCallInfo *argv)
155 {
156 ASSERT(argv);
157 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Has);
158 JSThread *thread = argv->GetThread();
159 [[maybe_unused]] EcmaHandleScope handleScope(thread);
160 JSHandle<JSTaggedValue> self = GetThis(argv);
161
162 if (!self->IsJSAPIArrayList()) {
163 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
164 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
165 } else {
166 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
167 "The has method cannot be bound");
168 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
169 }
170 }
171
172 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
173 bool isHas = JSHandle<JSAPIArrayList>::Cast(self)->Has(value.GetTaggedValue());
174
175 return GetTaggedBoolean(isHas);
176 }
177
GetCapacity(EcmaRuntimeCallInfo * argv)178 JSTaggedValue ContainersArrayList::GetCapacity(EcmaRuntimeCallInfo *argv)
179 {
180 ASSERT(argv);
181
182 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetCapacity);
183 JSThread *thread = argv->GetThread();
184
185 JSHandle<JSTaggedValue> self = GetThis(argv);
186 if (!self->IsJSAPIArrayList()) {
187 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
188 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
189 } else {
190 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
191 "The getCapacity method cannot be bound");
192 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
193 }
194 }
195
196 uint32_t capacity = JSAPIArrayList::GetCapacity(thread, JSHandle<JSAPIArrayList>::Cast(self));
197
198 return JSTaggedValue(capacity);
199 }
200
IncreaseCapacityTo(EcmaRuntimeCallInfo * argv)201 JSTaggedValue ContainersArrayList::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
202 {
203 ASSERT(argv);
204 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IncreaseCapacityTo);
205 JSThread *thread = argv->GetThread();
206 [[maybe_unused]] EcmaHandleScope handleScope(thread);
207 JSHandle<JSTaggedValue> self = GetThis(argv);
208
209 if (!self->IsJSAPIArrayList()) {
210 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
211 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
212 } else {
213 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
214 "The increaseCapacityTo method cannot be bound");
215 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
216 }
217 }
218
219 JSHandle<JSTaggedValue> newCapacity = GetCallArg(argv, 0);
220 if (!newCapacity->IsInteger()) {
221 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, newCapacity);
222 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
223 CString errorMsg =
224 "The type of \"newCapacity\" must be number. Received value is: " + ConvertToString(*result);
225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227 }
228
229 JSAPIArrayList::IncreaseCapacityTo(thread, JSHandle<JSAPIArrayList>::Cast(self),
230 JSTaggedValue::ToUint32(thread, newCapacity));
231
232 return JSTaggedValue::True();
233 }
234
TrimToCurrentLength(EcmaRuntimeCallInfo * argv)235 JSTaggedValue ContainersArrayList::TrimToCurrentLength(EcmaRuntimeCallInfo *argv)
236 {
237 ASSERT(argv);
238 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, TrimToCurrentLength);
239 JSThread *thread = argv->GetThread();
240 [[maybe_unused]] EcmaHandleScope handleScope(thread);
241 JSHandle<JSTaggedValue> self = GetThis(argv);
242
243 if (!self->IsJSAPIArrayList()) {
244 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
245 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
246 } else {
247 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
248 "The trimToCurrentLength method cannot be bound");
249 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
250 }
251 }
252
253 JSAPIArrayList::TrimToCurrentLength(thread, JSHandle<JSAPIArrayList>::Cast(self));
254
255 return JSTaggedValue::True();
256 }
257
Get(EcmaRuntimeCallInfo * argv)258 JSTaggedValue ContainersArrayList::Get(EcmaRuntimeCallInfo *argv)
259 {
260 ASSERT(argv);
261 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Get);
262 JSThread *thread = argv->GetThread();
263 [[maybe_unused]] EcmaHandleScope handleScope(thread);
264 JSHandle<JSTaggedValue> self = GetThis(argv);
265
266 if (!self->IsJSAPIArrayList()) {
267 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
268 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
269 } else {
270 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
271 "The get method cannot be bound");
272 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
273 }
274 }
275
276 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
277
278 JSTaggedValue element = JSHandle<JSAPIArrayList>::Cast(self)->Get(thread, JSTaggedValue::ToUint32(thread, value));
279
280 return element;
281 }
282
GetIndexOf(EcmaRuntimeCallInfo * argv)283 JSTaggedValue ContainersArrayList::GetIndexOf(EcmaRuntimeCallInfo *argv)
284 {
285 ASSERT(argv);
286 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIndexOf);
287 JSThread *thread = argv->GetThread();
288 [[maybe_unused]] EcmaHandleScope handleScope(thread);
289 JSHandle<JSTaggedValue> self = GetThis(argv);
290
291 if (!self->IsJSAPIArrayList()) {
292 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
293 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
294 } else {
295 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
296 "The getIndexOf method cannot be bound");
297 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
298 }
299 }
300
301 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
302
303 return JSTaggedValue(JSAPIArrayList::GetIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
304 }
305
IsEmpty(EcmaRuntimeCallInfo * argv)306 JSTaggedValue ContainersArrayList::IsEmpty(EcmaRuntimeCallInfo *argv)
307 {
308 ASSERT(argv);
309 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IsEmpty);
310 JSThread *thread = argv->GetThread();
311 [[maybe_unused]] EcmaHandleScope handleScope(thread);
312 JSHandle<JSTaggedValue> self = GetThis(argv);
313
314 if (!self->IsJSAPIArrayList()) {
315 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
316 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
317 } else {
318 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
319 "The isEmpty method cannot be bound");
320 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
321 }
322 }
323
324 return JSTaggedValue(JSAPIArrayList::IsEmpty(JSHandle<JSAPIArrayList>::Cast(self)));
325 }
326
GetLastIndexOf(EcmaRuntimeCallInfo * argv)327 JSTaggedValue ContainersArrayList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
328 {
329 ASSERT(argv);
330 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetLastIndexOf);
331 JSThread *thread = argv->GetThread();
332 [[maybe_unused]] EcmaHandleScope handleScope(thread);
333 JSHandle<JSTaggedValue> self = GetThis(argv);
334
335 if (!self->IsJSAPIArrayList()) {
336 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
337 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
338 } else {
339 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
340 "The getLastIndexOf method cannot be bound");
341 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
342 }
343 }
344
345 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
346
347 return JSTaggedValue(JSAPIArrayList::GetLastIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
348 }
349
RemoveByIndex(EcmaRuntimeCallInfo * argv)350 JSTaggedValue ContainersArrayList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
351 {
352 ASSERT(argv);
353 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByIndex);
354 JSThread *thread = argv->GetThread();
355 [[maybe_unused]] EcmaHandleScope handleScope(thread);
356 JSHandle<JSTaggedValue> self = GetThis(argv);
357
358 if (!self->IsJSAPIArrayList()) {
359 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
360 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
361 } else {
362 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
363 "The removeByIndex method cannot be bound");
364 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
365 }
366 }
367
368 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
369 if (value->IsDouble()) {
370 value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
371 }
372 if (!value->IsInt()) {
373 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
374 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
375 CString errorMsg =
376 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
377 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
378 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
379 }
380
381 JSTaggedValue result =
382 JSAPIArrayList::RemoveByIndex(thread,
383 JSHandle<JSAPIArrayList>::Cast(self), JSTaggedValue::ToUint32(thread, value));
384
385 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
386 return result;
387 }
388
Remove(EcmaRuntimeCallInfo * argv)389 JSTaggedValue ContainersArrayList::Remove(EcmaRuntimeCallInfo *argv)
390 {
391 ASSERT(argv);
392 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Remove);
393 JSThread *thread = argv->GetThread();
394 [[maybe_unused]] EcmaHandleScope handleScope(thread);
395 JSHandle<JSTaggedValue> self = GetThis(argv);
396
397 if (!self->IsJSAPIArrayList()) {
398 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
399 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
400 } else {
401 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
402 "The remove method cannot be bound");
403 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
404 }
405 }
406
407 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
408
409 bool isRemove = JSAPIArrayList::Remove(thread, JSHandle<JSAPIArrayList>::Cast(self), value);
410 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
411
412 return GetTaggedBoolean(isRemove);
413 }
414
RemoveByRange(EcmaRuntimeCallInfo * argv)415 JSTaggedValue ContainersArrayList::RemoveByRange(EcmaRuntimeCallInfo *argv)
416 {
417 ASSERT(argv);
418 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByRange);
419 JSThread *thread = argv->GetThread();
420 [[maybe_unused]] EcmaHandleScope handleScope(thread);
421 JSHandle<JSTaggedValue> self = GetThis(argv);
422
423 if (!self->IsJSAPIArrayList()) {
424 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
425 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
426 } else {
427 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
428 "The removeByRange method cannot be bound");
429 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
430 }
431 }
432
433 JSHandle<JSTaggedValue> startIndex = GetCallArg(argv, 0);
434 JSHandle<JSTaggedValue> endIndex = GetCallArg(argv, 1);
435 if (!startIndex->IsInteger()) {
436 std::ostringstream oss;
437 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, startIndex);
438 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
439 CString errorMsg =
440 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
441 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
442 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
443 }
444 if (!endIndex->IsInteger()) {
445 std::ostringstream oss;
446 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, endIndex);
447 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
448 CString errorMsg =
449 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
450 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
451 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
452 }
453 JSTaggedValue result =
454 JSAPIArrayList::RemoveByRange(thread, JSHandle<JSAPIArrayList>::Cast(self), startIndex, endIndex);
455
456 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
457 return result;
458 }
459
ReplaceAllElements(EcmaRuntimeCallInfo * argv)460 JSTaggedValue ContainersArrayList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
461 {
462 ASSERT(argv);
463 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ReplaceAllElements);
464 JSThread *thread = argv->GetThread();
465 [[maybe_unused]] EcmaHandleScope handleScope(thread);
466 JSHandle<JSTaggedValue> self = GetThis(argv);
467
468 if (!self->IsJSAPIArrayList()) {
469 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
470 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
471 } else {
472 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
473 "The replaceAllElements method cannot be bound");
474 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
475 }
476 }
477
478 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
479 if (!callbackFnHandle->IsCallable()) {
480 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
481 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
482 CString errorMsg =
483 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
484 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
485 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
486 }
487 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
488
489 return JSAPIArrayList::ReplaceAllElements(thread, self, callbackFnHandle, thisArgHandle);
490 }
491
Set(EcmaRuntimeCallInfo * argv)492 JSTaggedValue ContainersArrayList::Set(EcmaRuntimeCallInfo *argv)
493 {
494 ASSERT(argv);
495 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Set);
496 JSThread *thread = argv->GetThread();
497 [[maybe_unused]] EcmaHandleScope handleScope(thread);
498 JSHandle<JSTaggedValue> self = GetThis(argv);
499
500 if (!self->IsJSAPIArrayList()) {
501 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
502 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
503 } else {
504 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
505 "The set method cannot be bound");
506 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
507 }
508 }
509
510 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
511 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
512 JSHandle<JSAPIArrayList>::Cast(self)->Set(thread, JSTaggedValue::ToUint32(thread, index), value.GetTaggedValue());
513
514 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
515 return JSTaggedValue::Undefined();
516 }
517
SubArrayList(EcmaRuntimeCallInfo * argv)518 JSTaggedValue ContainersArrayList::SubArrayList(EcmaRuntimeCallInfo *argv)
519 {
520 ASSERT(argv);
521 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, SubArrayList);
522 JSThread *thread = argv->GetThread();
523 [[maybe_unused]] EcmaHandleScope handleScope(thread);
524 JSHandle<JSTaggedValue> self = GetThis(argv);
525
526 if (!self->IsJSAPIArrayList()) {
527 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
528 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
529 } else {
530 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
531 "The subArrayList method cannot be bound");
532 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
533 }
534 }
535 JSHandle<JSTaggedValue> value1 = GetCallArg(argv, 0);
536 JSHandle<JSTaggedValue> value2 = GetCallArg(argv, 1);
537 if (!value1->IsInteger()) {
538 std::ostringstream oss;
539 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value1);
540 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
541 CString errorMsg =
542 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
543 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
544 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
545 }
546 if (!value2->IsInteger()) {
547 std::ostringstream oss;
548 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value2);
549 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
550 CString errorMsg =
551 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
552 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
553 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
554 }
555 JSTaggedValue newArrayList =
556 JSAPIArrayList::SubArrayList(thread, JSHandle<JSAPIArrayList>::Cast(self), value1, value2);
557
558 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
559 return newArrayList;
560 }
561
Sort(EcmaRuntimeCallInfo * argv)562 JSTaggedValue ContainersArrayList::Sort(EcmaRuntimeCallInfo *argv)
563 {
564 ASSERT(argv);
565 BUILTINS_API_TRACE(argv->GetThread(), Array, Sort);
566 JSThread *thread = argv->GetThread();
567 [[maybe_unused]] EcmaHandleScope handleScope(thread);
568 JSHandle<JSTaggedValue> self = GetThis(argv);
569 if (!self->IsJSAPIArrayList()) {
570 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
571 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
572 } else {
573 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
574 "The sort method cannot be bound");
575 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
576 }
577 }
578 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
579 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable() && !callbackFnHandle->IsNull()) {
580 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
581 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
582 CString errorMsg =
583 "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
584 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
585 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
586 }
587 auto obj = JSHandle<JSAPIArrayList>::Cast(self);
588 uint32_t length = JSHandle<JSAPIArrayList>::Cast(self)->GetLength().GetArrayLength();
589 JSHandle<TaggedArray> elements = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length);
590 elements->Copy(thread, 0, 0, TaggedArray::Cast(obj->GetElements()), length);
591 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
592 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
593 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
594 for (uint32_t i = 1; i < length; i++) {
595 uint32_t beginIndex = 0;
596 uint32_t endIndex = i;
597 presentValue.Update(elements->Get(i));
598 while (beginIndex < endIndex) {
599 uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
600 middleValue.Update(elements->Get(middleIndex));
601 double compareResult = base::ArrayHelper::SortCompare(thread, callbackFnHandle,
602 middleValue, presentValue);
603 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
604 if (compareResult > 0) {
605 endIndex = middleIndex;
606 } else {
607 beginIndex = middleIndex + 1;
608 }
609 }
610 if (endIndex >= 0 && endIndex < i) {
611 for (uint32_t j = i; j > endIndex; j--) {
612 previousValue.Update(elements->Get(j - 1));
613 elements->Set(thread, j, previousValue.GetTaggedValue());
614 }
615 elements->Set(thread, endIndex, presentValue.GetTaggedValue());
616 }
617 }
618 obj->SetElements(thread, elements);
619 obj->SetLength(thread, JSTaggedValue(elements->GetLength()));
620 return JSTaggedValue::Undefined();
621 }
622
GetSize(EcmaRuntimeCallInfo * argv)623 JSTaggedValue ContainersArrayList::GetSize(EcmaRuntimeCallInfo *argv)
624 {
625 ASSERT(argv);
626 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetSize);
627 JSThread *thread = argv->GetThread();
628 [[maybe_unused]] EcmaHandleScope handleScope(thread);
629 JSHandle<JSTaggedValue> self = GetThis(argv);
630
631 if (!self->IsJSAPIArrayList()) {
632 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
633 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
634 } else {
635 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
636 "The getLength method cannot be bound");
637 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
638 }
639 }
640
641 return JSTaggedValue(JSHandle<JSAPIArrayList>::Cast(self)->GetSize());
642 }
643
ConvertToArray(EcmaRuntimeCallInfo * argv)644 JSTaggedValue ContainersArrayList::ConvertToArray(EcmaRuntimeCallInfo *argv)
645 {
646 ASSERT(argv);
647 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ConvertToArray);
648 JSThread *thread = argv->GetThread();
649 [[maybe_unused]] EcmaHandleScope handleScope(thread);
650 JSHandle<JSTaggedValue> self = GetThis(argv);
651
652 if (!self->IsJSAPIArrayList()) {
653 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
654 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
655 } else {
656 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
657 "The convertToArray method cannot be bound");
658 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
659 }
660 }
661
662 JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(self);
663 auto factory = thread->GetEcmaVM()->GetFactory();
664 JSHandle<JSArray> array = factory->NewJSArray();
665
666 uint32_t length = arrayList->GetLength().GetArrayLength();
667 array->SetArrayLength(thread, length);
668
669 JSHandle<TaggedArray> srcElements(thread, arrayList->GetElements());
670 JSHandle<TaggedArray> dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length);
671 array->SetElements(thread, dstElements);
672 return array.GetTaggedValue();
673 }
674
ForEach(EcmaRuntimeCallInfo * argv)675 JSTaggedValue ContainersArrayList::ForEach(EcmaRuntimeCallInfo *argv)
676 {
677 ASSERT(argv);
678 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ForEach);
679 JSThread *thread = argv->GetThread();
680 [[maybe_unused]] EcmaHandleScope handleScope(thread);
681 JSHandle<JSTaggedValue> self = GetThis(argv);
682
683 if (!self->IsJSAPIArrayList()) {
684 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
685 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
686 } else {
687 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
688 "The forEach method cannot be bound");
689 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
690 }
691 }
692
693 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
694 if (!callbackFnHandle->IsCallable()) {
695 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
696 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
697 CString errorMsg =
698 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
699 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
700 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
701 }
702
703 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
704
705 return JSAPIArrayList::ForEach(thread, self, callbackFnHandle, thisArgHandle);
706 }
707
GetIteratorObj(EcmaRuntimeCallInfo * argv)708 JSTaggedValue ContainersArrayList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
709 {
710 ASSERT(argv);
711 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIteratorObj);
712 JSThread *thread = argv->GetThread();
713 [[maybe_unused]] EcmaHandleScope handleScope(thread);
714
715 JSHandle<JSTaggedValue> self = GetThis(argv);
716
717 if (!self->IsJSAPIArrayList()) {
718 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
719 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
720 } else {
721 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
722 "The Symbol.iterator method cannot be bound");
723 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
724 }
725 }
726
727 JSTaggedValue values = JSAPIArrayList::GetIteratorObj(thread, JSHandle<JSAPIArrayList>::Cast(self));
728
729 return values;
730 }
731 } // namespace panda::ecmascript::containers
732