• 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_list.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_api/js_api_list.h"
22 #include "ecmascript/js_api/js_api_list_iterator.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/object_factory.h"
25 #include "ecmascript/tagged_array-inl.h"
26 #include "ecmascript/tagged_list.h"
27 
28 namespace panda::ecmascript::containers {
ListConstructor(EcmaRuntimeCallInfo * argv)29 JSTaggedValue ContainersList::ListConstructor(EcmaRuntimeCallInfo *argv)
30 {
31     ASSERT(argv != nullptr);
32     JSThread *thread = argv->GetThread();
33     BUILTINS_API_TRACE(thread, List, Constructor);
34     [[maybe_unused]] EcmaHandleScope handleScope(thread);
35     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
36     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
37     if (newTarget->IsUndefined()) {
38         JSTaggedValue error =
39             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
40                                           "The List's constructor cannot be directly invoked");
41         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
42     }
43     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
44     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
45     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
46     JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
47 
48     JSTaggedValue singleList = TaggedSingleList::Create(thread);
49     list->SetSingleList(thread, singleList);
50 
51     return list.GetTaggedValue();
52 }
53 
Add(EcmaRuntimeCallInfo * argv)54 JSTaggedValue ContainersList::Add(EcmaRuntimeCallInfo *argv)
55 {
56     ASSERT(argv != nullptr);
57     JSThread *thread = argv->GetThread();
58     BUILTINS_API_TRACE(thread, List, Add);
59     [[maybe_unused]] EcmaHandleScope handleScope(thread);
60     JSHandle<JSTaggedValue> self = GetThis(argv);
61     if (!self->IsJSAPIList()) {
62         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
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     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
73     JSAPIList::Add(thread, jSAPIList, value);
74     return JSTaggedValue::True();
75 }
76 
Insert(EcmaRuntimeCallInfo * argv)77 JSTaggedValue ContainersList::Insert(EcmaRuntimeCallInfo *argv)
78 {
79     ASSERT(argv != nullptr);
80     JSThread *thread = argv->GetThread();
81     BUILTINS_API_TRACE(thread, List, Insert);
82     [[maybe_unused]] EcmaHandleScope handleScope(thread);
83     JSHandle<JSTaggedValue> self = GetThis(argv);
84     if (!self->IsJSAPIList()) {
85         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
86             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
87         } else {
88             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
89                                                                 "The insert method cannot be bound");
90             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
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.GetTaggedValue());
97         CString errorMsg =
98             "The type of \"index\" must be number. 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     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
103     JSAPIList::Insert(thread, jSAPIList, value, index->GetInt());
104     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
105     return JSTaggedValue::True();
106 }
107 
GetFirst(EcmaRuntimeCallInfo * argv)108 JSTaggedValue ContainersList::GetFirst(EcmaRuntimeCallInfo *argv)
109 {
110     ASSERT(argv != nullptr);
111     JSThread *thread = argv->GetThread();
112     BUILTINS_API_TRACE(thread, List, GetFirst);
113     [[maybe_unused]] EcmaHandleScope handleScope(thread);
114     JSHandle<JSTaggedValue> self = GetThis(argv);
115     if (!self->IsJSAPIList()) {
116         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
117             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
118         } else {
119             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
120                                                                 "The getFirst method cannot be bound");
121             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
122         }
123     }
124     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
125     return jSAPIList->GetFirst();
126 }
127 
GetLast(EcmaRuntimeCallInfo * argv)128 JSTaggedValue ContainersList::GetLast(EcmaRuntimeCallInfo *argv)
129 {
130     ASSERT(argv != nullptr);
131     JSThread *thread = argv->GetThread();
132     BUILTINS_API_TRACE(thread, List, GetLast);
133     [[maybe_unused]] EcmaHandleScope handleScope(thread);
134     JSHandle<JSTaggedValue> self = GetThis(argv);
135     if (!self->IsJSAPIList()) {
136         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
137             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
138         } else {
139             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
140                                                                 "The getLast method cannot be bound");
141             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
142         }
143     }
144     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
145     return jSAPIList->GetLast();
146 }
147 
Has(EcmaRuntimeCallInfo * argv)148 JSTaggedValue ContainersList::Has(EcmaRuntimeCallInfo *argv)
149 {
150     ASSERT(argv != nullptr);
151     JSThread *thread = argv->GetThread();
152     BUILTINS_API_TRACE(thread, List, Has);
153     [[maybe_unused]] EcmaHandleScope handleScope(thread);
154     JSHandle<JSTaggedValue> self = GetThis(argv);
155     if (!self->IsJSAPIList()) {
156         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
157             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
158         } else {
159             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
160                                                                 "The has method cannot be bound");
161             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
162         }
163     }
164     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
165     JSHandle<JSTaggedValue> element= GetCallArg(argv, 0);
166     return GetTaggedBoolean(jSAPIList->Has(element.GetTaggedValue()));
167 }
168 
IsEmpty(EcmaRuntimeCallInfo * argv)169 JSTaggedValue ContainersList::IsEmpty(EcmaRuntimeCallInfo *argv)
170 {
171     ASSERT(argv != nullptr);
172     JSThread *thread = argv->GetThread();
173     BUILTINS_API_TRACE(thread, List, IsEmpty);
174     [[maybe_unused]] EcmaHandleScope handleScope(thread);
175     JSHandle<JSTaggedValue> self = GetThis(argv);
176     if (!self->IsJSAPIList()) {
177         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
178             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
179         } else {
180             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
181                                                                 "The isEmpty method cannot be bound");
182             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
183         }
184     }
185     JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
186     return GetTaggedBoolean(jSAPIList->IsEmpty());
187 }
188 
Get(EcmaRuntimeCallInfo * argv)189 JSTaggedValue ContainersList::Get(EcmaRuntimeCallInfo *argv)
190 {
191     ASSERT(argv != nullptr);
192     JSThread *thread = argv->GetThread();
193     BUILTINS_API_TRACE(thread, List, Get);
194     [[maybe_unused]] EcmaHandleScope handleScope(thread);
195     JSHandle<JSTaggedValue> self = GetThis(argv);
196     if (!self->IsJSAPIList()) {
197         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
198             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
199         } else {
200             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
201                                                                 "The get method cannot be bound");
202             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
203         }
204     }
205     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
206     JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
207     if (!index->IsInteger()) {
208         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
209         CString errorMsg =
210             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
211         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
212         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
213     }
214     return jsAPIList->Get(index->GetInt());
215 }
216 
GetIndexOf(EcmaRuntimeCallInfo * argv)217 JSTaggedValue ContainersList::GetIndexOf(EcmaRuntimeCallInfo *argv)
218 {
219     ASSERT(argv != nullptr);
220     JSThread *thread = argv->GetThread();
221     BUILTINS_API_TRACE(thread, List, GetIndexOf);
222     [[maybe_unused]] EcmaHandleScope handleScope(thread);
223     JSHandle<JSTaggedValue> self = GetThis(argv);
224     if (!self->IsJSAPIList()) {
225         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
226             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
227         } else {
228             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
229                                                                 "The getIndexOf method cannot be bound");
230             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
231         }
232     }
233     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
234     JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
235     return jsAPIList->GetIndexOf(element.GetTaggedValue());
236 }
237 
GetLastIndexOf(EcmaRuntimeCallInfo * argv)238 JSTaggedValue ContainersList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
239 {
240     ASSERT(argv != nullptr);
241     JSThread *thread = argv->GetThread();
242     BUILTINS_API_TRACE(thread, List, GetLastIndexOf);
243     [[maybe_unused]] EcmaHandleScope handleScope(thread);
244     JSHandle<JSTaggedValue> self = GetThis(argv);
245     if (!self->IsJSAPIList()) {
246         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
247             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
248         } else {
249             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
250                                                                 "The getLastIndexOf method cannot be bound");
251             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
252         }
253     }
254     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
255     JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
256     return jsAPIList->GetLastIndexOf(element.GetTaggedValue());
257 }
258 
Set(EcmaRuntimeCallInfo * argv)259 JSTaggedValue ContainersList::Set(EcmaRuntimeCallInfo *argv)
260 {
261     ASSERT(argv != nullptr);
262     JSThread *thread = argv->GetThread();
263     BUILTINS_API_TRACE(thread, List, Set);
264     [[maybe_unused]] EcmaHandleScope handleScope(thread);
265     JSHandle<JSTaggedValue> self = GetThis(argv);
266     if (!self->IsJSAPIList()) {
267         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
268             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
269         } else {
270             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
271                                                                 "The set method cannot be bound");
272             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
273         }
274     }
275     JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
276     JSHandle<JSTaggedValue> element = GetCallArg(argv, 1);
277     if (!index->IsInteger()) {
278         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
279         CString errorMsg =
280             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
281         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
282         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
283     }
284     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
285     JSTaggedValue oldValue = JSAPIList::Set(thread, jsAPIList, index->GetInt(), element);
286     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
287     return oldValue;
288 }
289 
ForEach(EcmaRuntimeCallInfo * argv)290 JSTaggedValue ContainersList::ForEach(EcmaRuntimeCallInfo *argv)
291 {
292     ASSERT(argv != nullptr);
293     JSThread *thread = argv->GetThread();
294     BUILTINS_API_TRACE(thread, List, ForEach);
295     [[maybe_unused]] EcmaHandleScope handleScope(thread);
296     // get and check List object
297     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
298     if (!thisHandle->IsJSAPIList()) {
299         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
300             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
301         } else {
302             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
303                                                                 "The forEach method cannot be bound");
304             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
305         }
306     }
307 
308     // get and check callback function
309     JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0));
310     if (!callbackFnHandle->IsCallable()) {
311         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
312         CString errorMsg =
313             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
314         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
315         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
316     }
317 
318     // If thisArgHandle was supplied, let T be thisArgHandle; else let T be undefined.
319     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
320     JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
321     JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
322     int length = list->Length();
323 
324     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
325     int index = 0;
326     const uint32_t argsLength = 3; // 3: «kValue, k, O»
327     int valueNode = TaggedSingleList::ELEMENTS_START_INDEX;
328     while (index < length) {
329         valueNode = singleList->GetNextDataIndex(valueNode);
330         JSTaggedValue value = singleList->GetElement(valueNode);
331         EcmaRuntimeCallInfo *info =
332             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
333         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
334         info->SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue());
335         JSTaggedValue funcResult = JSFunction::Call(info);
336         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
337         index++;
338     }
339     return JSTaggedValue::Undefined();
340 }
341 
Clear(EcmaRuntimeCallInfo * argv)342 JSTaggedValue ContainersList::Clear(EcmaRuntimeCallInfo *argv)
343 {
344     ASSERT(argv != nullptr);
345     JSThread *thread = argv->GetThread();
346     BUILTINS_API_TRACE(thread, List, Clear);
347     [[maybe_unused]] EcmaHandleScope handleScope(thread);
348     JSHandle<JSTaggedValue> self = GetThis(argv);
349     if (!self->IsJSAPIList()) {
350         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
351             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
352         } else {
353             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
354                                                                 "The clear method cannot be bound");
355             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
356         }
357     }
358     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
359     jsAPIList->Clear(thread);
360     return JSTaggedValue::Undefined();
361 }
362 
RemoveByIndex(EcmaRuntimeCallInfo * argv)363 JSTaggedValue ContainersList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
364 {
365     ASSERT(argv != nullptr);
366     JSThread *thread = argv->GetThread();
367     BUILTINS_API_TRACE(thread, List, RemoveByIndex);
368     [[maybe_unused]] EcmaHandleScope handleScope(thread);
369     JSHandle<JSTaggedValue> self = GetThis(argv);
370     if (!self->IsJSAPIList()) {
371         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
372             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
373         } else {
374             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
375                                                                 "The removeByIndex method cannot be bound");
376             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
377         }
378     }
379     JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
380     if (!index->IsInteger()) {
381         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
382         CString errorMsg =
383             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
384         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
385         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
386     }
387     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
388     JSTaggedValue result = JSAPIList::RemoveByIndex(thread, jsAPIList, index->GetInt());
389     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
390     return result;
391 }
392 
Remove(EcmaRuntimeCallInfo * argv)393 JSTaggedValue ContainersList::Remove(EcmaRuntimeCallInfo *argv)
394 {
395     ASSERT(argv != nullptr);
396     JSThread *thread = argv->GetThread();
397     BUILTINS_API_TRACE(thread, List, Remove);
398     [[maybe_unused]] EcmaHandleScope handleScope(thread);
399     JSHandle<JSTaggedValue> self = GetThis(argv);
400     if (!self->IsJSAPIList()) {
401         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
402             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
403         } else {
404             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
405                                                                 "The remove method cannot be bound");
406             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
407         }
408     }
409     JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
410     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
411     return jsAPIList->Remove(thread, element.GetTaggedValue());
412 }
413 
ReplaceAllElements(EcmaRuntimeCallInfo * argv)414 JSTaggedValue ContainersList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
415 {
416     ASSERT(argv != nullptr);
417     JSThread *thread = argv->GetThread();
418     BUILTINS_API_TRACE(thread, List, ReplaceAllElements);
419     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
420     if (!thisHandle->IsJSAPIList()) {
421         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
422             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
423         } else {
424             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
425                                                                 "The replaceAllElements method cannot be bound");
426             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
427         }
428     }
429     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
430     if (!callbackFnHandle->IsCallable()) {
431         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
432         CString errorMsg =
433             "The type of \"callbackfn\" must be callable. 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     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
438     return JSAPIList::ReplaceAllElements(thread, thisHandle, callbackFnHandle, thisArgHandle);
439 }
440 
Equal(EcmaRuntimeCallInfo * argv)441 JSTaggedValue ContainersList::Equal(EcmaRuntimeCallInfo *argv)
442 {
443     ASSERT(argv != nullptr);
444     JSThread *thread = argv->GetThread();
445     BUILTINS_API_TRACE(thread, List, Equal);
446     [[maybe_unused]] EcmaHandleScope handleScope(thread);
447     JSHandle<JSTaggedValue> self = GetThis(argv);
448     if (!self->IsJSAPIList()) {
449         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
450             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
451         } else {
452             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
453                                                                 "The equal method cannot be bound");
454             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
455         }
456     }
457     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
458     JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
459     if (!obj->IsJSAPIList()) {
460         if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPIList()) {
461             obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
462         } else {
463             return JSTaggedValue::False();
464         }
465     }
466     JSHandle<JSAPIList> handleObj = JSHandle<JSAPIList>::Cast(obj);
467     return jsAPIList->Equal(thread, handleObj);
468 }
469 
Sort(EcmaRuntimeCallInfo * argv)470 JSTaggedValue ContainersList::Sort(EcmaRuntimeCallInfo *argv)
471 {
472     ASSERT(argv != nullptr);
473     JSThread *thread = argv->GetThread();
474     BUILTINS_API_TRACE(thread, List, Sort);
475     [[maybe_unused]] EcmaHandleScope handleScope(thread);
476     JSHandle<JSTaggedValue> self = GetThis(argv);
477     if (!self->IsJSAPIList()) {
478         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
479             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
480         } else {
481             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
482                                                                 "The sort method cannot be bound");
483             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
484         }
485     }
486     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
487     if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
488         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
489         CString errorMsg =
490             "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
491         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
492         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
493     }
494     return JSAPIList::Sort(thread, self, callbackFnHandle);
495 }
496 
GetIteratorObj(EcmaRuntimeCallInfo * argv)497 JSTaggedValue ContainersList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
498 {
499     ASSERT(argv != nullptr);
500     JSThread *thread = argv->GetThread();
501     BUILTINS_API_TRACE(thread, List, GetIteratorObj);
502     [[maybe_unused]] EcmaHandleScope handleScope(thread);
503     JSHandle<JSTaggedValue> self = GetThis(argv);
504     JSHandle<JSTaggedValue> iter = JSAPIListIterator::CreateListIterator(thread, self);
505     return iter.GetTaggedValue();
506 }
507 
ConvertToArray(EcmaRuntimeCallInfo * argv)508 JSTaggedValue ContainersList::ConvertToArray(EcmaRuntimeCallInfo *argv)
509 {
510     ASSERT(argv != nullptr);
511     JSThread *thread = argv->GetThread();
512     BUILTINS_API_TRACE(thread, List, ConvertToArray);
513     [[maybe_unused]] EcmaHandleScope handleScope(thread);
514     JSHandle<JSTaggedValue> self = GetThis(argv);
515     if (!self->IsJSAPIList()) {
516         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
517             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
518         } else {
519             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
520                                                                 "The convertToArray method cannot be bound");
521             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
522         }
523     }
524     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
525     return JSAPIList::ConvertToArray(thread, jsAPIList);
526 }
527 
GetSubList(EcmaRuntimeCallInfo * argv)528 JSTaggedValue ContainersList::GetSubList(EcmaRuntimeCallInfo *argv)
529 {
530     ASSERT(argv != nullptr);
531     JSThread *thread = argv->GetThread();
532     BUILTINS_API_TRACE(thread, List, GetSubList);
533     [[maybe_unused]] EcmaHandleScope handleScope(thread);
534     JSHandle<JSTaggedValue> self = GetThis(argv);
535     if (!self->IsJSAPIList()) {
536         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
537             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
538         } else {
539             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
540                                                                 "The getSubList method cannot be bound");
541             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
542         }
543     }
544     JSHandle<JSTaggedValue> fromIndex= GetCallArg(argv, 0);
545 
546     if (!fromIndex->IsInteger()) {
547         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, fromIndex.GetTaggedValue());
548         CString errorMsg =
549             "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
550         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
551         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
552     }
553 
554     JSHandle<JSTaggedValue> toIndex = GetCallArg(argv, 1);
555 
556     if (!toIndex->IsInteger()) {
557         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, toIndex.GetTaggedValue());
558         CString errorMsg =
559             "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
560         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
561         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
562     }
563 
564     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
565     JSTaggedValue newList = JSAPIList::GetSubList(thread, jsAPIList, fromIndex->GetInt(), toIndex->GetInt());
566     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
567     return newList;
568 }
569 
Length(EcmaRuntimeCallInfo * argv)570 JSTaggedValue ContainersList::Length(EcmaRuntimeCallInfo *argv)
571 {
572     ASSERT(argv != nullptr);
573     JSThread *thread = argv->GetThread();
574     BUILTINS_API_TRACE(thread, List, Length);
575     [[maybe_unused]] EcmaHandleScope handleScope(thread);
576     JSHandle<JSTaggedValue> self = GetThis(argv);
577     if (!self->IsJSAPIList()) {
578         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
579             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
580         } else {
581             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
582                                                                 "The length method cannot be bound");
583             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
584         }
585     }
586     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
587     return JSTaggedValue(jsAPIList->Length());
588 }
589 }  // namespace panda::ecmascript::containers
590