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