• 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_plainarray.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/js_api/js_api_plain_array.h"
20 #include "ecmascript/js_iterator.h"
21 
22 namespace panda::ecmascript::containers {
PlainArrayConstructor(EcmaRuntimeCallInfo * argv)23 JSTaggedValue ContainersPlainArray::PlainArrayConstructor(EcmaRuntimeCallInfo *argv)
24 {
25     ASSERT(argv != nullptr);
26     JSThread *thread = argv->GetThread();
27     BUILTINS_API_TRACE(thread, PlainArray, Constructor);
28     [[maybe_unused]] EcmaHandleScope handleScope(thread);
29     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
30     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
31     if (newTarget->IsUndefined()) {
32         JSTaggedValue error =
33             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
34                                           "The PlainArray's constructor cannot be directly invoked");
35         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
36     }
37     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
38     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
39     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
40     JSHandle<JSAPIPlainArray> plainArray = JSHandle<JSAPIPlainArray>::Cast(obj);
41     JSHandle<TaggedArray> keys =
42         JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
43     JSHandle<TaggedArray> values =
44         JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
45     plainArray->SetKeys(thread, keys);
46     plainArray->SetValues(thread, values);
47     return obj.GetTaggedValue();
48 }
49 
Add(EcmaRuntimeCallInfo * argv)50 JSTaggedValue ContainersPlainArray::Add(EcmaRuntimeCallInfo *argv)
51 {
52     ASSERT(argv != nullptr);
53     JSThread *thread = argv->GetThread();
54     BUILTINS_API_TRACE(thread, PlainArray, Add);
55     [[maybe_unused]] EcmaHandleScope handleScope(thread);
56     JSHandle<JSTaggedValue> self = GetThis(argv);
57     if (!self->IsJSAPIPlainArray()) {
58         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
59             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
60         } else {
61             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
62                                                                 "The add method cannot be bound");
63             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
64         }
65     }
66     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
67     JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
68     if (key->IsDouble()) {
69         key = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(key->GetDouble()));
70     }
71     if (!key->IsInt()) {
72         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
73         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
74         CString errorMsg =
75             "The type of \"key\" must be small integer. Received value is: " + ConvertToString(*result);
76         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
77         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
78     }
79     JSAPIPlainArray::Add(thread, JSHandle<JSAPIPlainArray>::Cast(self), key, value);
80     return JSTaggedValue::Undefined();
81 }
82 
Clear(EcmaRuntimeCallInfo * argv)83 JSTaggedValue ContainersPlainArray::Clear(EcmaRuntimeCallInfo *argv)
84 {
85     ASSERT(argv != nullptr);
86     JSThread *thread = argv->GetThread();
87     BUILTINS_API_TRACE(thread, PlainArray, Clear);
88     [[maybe_unused]] EcmaHandleScope handleScope(thread);
89     JSHandle<JSTaggedValue> self = GetThis(argv);
90     if (!self->IsJSAPIPlainArray()) {
91         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
92             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
93         } else {
94             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
95                                                                 "The clear method cannot be bound");
96             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
97         }
98     }
99     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
100     array->Clear(thread);
101     return JSTaggedValue::Undefined();
102 }
103 
Clone(EcmaRuntimeCallInfo * argv)104 JSTaggedValue ContainersPlainArray::Clone(EcmaRuntimeCallInfo *argv)
105 {
106     ASSERT(argv != nullptr);
107     JSThread *thread = argv->GetThread();
108     BUILTINS_API_TRACE(thread, PlainArray, Clone);
109     [[maybe_unused]] EcmaHandleScope handleScope(thread);
110     JSHandle<JSTaggedValue> self = GetThis(argv);
111     if (!self->IsJSAPIPlainArray()) {
112         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
113             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
114         } else {
115             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
116                                                                 "The clone method cannot be bound");
117             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
118         }
119     }
120     JSHandle<JSAPIPlainArray> newPlainArray =
121         JSAPIPlainArray::Clone(thread, JSHandle<JSAPIPlainArray>::Cast(self));
122     return newPlainArray.GetTaggedValue();
123 }
124 
Has(EcmaRuntimeCallInfo * argv)125 JSTaggedValue ContainersPlainArray::Has(EcmaRuntimeCallInfo *argv)
126 {
127     ASSERT(argv != nullptr);
128     JSThread *thread = argv->GetThread();
129     BUILTINS_API_TRACE(thread, PlainArray, Has);
130     [[maybe_unused]] EcmaHandleScope handleScope(thread);
131     JSHandle<JSTaggedValue> self = GetThis(argv);
132     if (!self->IsJSAPIPlainArray()) {
133         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
134             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
135         } else {
136             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
137                                                                 "The has method cannot be bound");
138             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
139         }
140     }
141     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
142     if (value->IsDouble()) {
143         value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
144     }
145     if (!value->IsInt()) {
146         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
147         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
148         CString errorMsg =
149             "The type of \"key\" must be small integer. Received value is: " + ConvertToString(*result);
150         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
151         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
152     }
153     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
154     int32_t key = value->GetNumber();
155     bool result = array->Has(key);
156     return JSTaggedValue(result);
157 }
158 
Get(EcmaRuntimeCallInfo * argv)159 JSTaggedValue ContainersPlainArray::Get(EcmaRuntimeCallInfo *argv)
160 {
161     ASSERT(argv != nullptr);
162     JSThread *thread = argv->GetThread();
163     BUILTINS_API_TRACE(thread, PlainArray, Get);
164     [[maybe_unused]] EcmaHandleScope handleScope(thread);
165     JSHandle<JSTaggedValue> self = GetThis(argv);
166     if (!self->IsJSAPIPlainArray()) {
167         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
168             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
169         } else {
170             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
171                                                                 "The get method cannot be bound");
172             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
173         }
174     }
175     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
176     if (key->IsDouble()) {
177         key = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(key->GetDouble()));
178     }
179     if (!key->IsInt()) {
180         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
181         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
182         CString errorMsg =
183             "The type of \"key\" must be small integer. Received value is: " + ConvertToString(*result);
184         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
185         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
186     }
187     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
188     JSTaggedValue value = array->Get(key.GetTaggedValue());
189 
190     return value;
191 }
192 
GetIteratorObj(EcmaRuntimeCallInfo * argv)193 JSTaggedValue ContainersPlainArray::GetIteratorObj(EcmaRuntimeCallInfo *argv)
194 {
195     ASSERT(argv != nullptr);
196     JSThread *thread = argv->GetThread();
197     BUILTINS_API_TRACE(thread, PlainArray, GetIteratorObj);
198     [[maybe_unused]] EcmaHandleScope handleScope(thread);
199     JSHandle<JSTaggedValue> self = GetThis(argv);
200     if (!self->IsJSAPIPlainArray()) {
201         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
202             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
203         } else {
204             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
205                                                                 "The Symbol.iterator method cannot be bound");
206             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
207         }
208     }
209     JSHandle<JSTaggedValue> iter =
210         JSAPIPlainArray::GetIteratorObj(thread, JSHandle<JSAPIPlainArray>::Cast(self), IterationKind::KEY_AND_VALUE);
211     return iter.GetTaggedValue();
212 }
213 
ForEach(EcmaRuntimeCallInfo * argv)214 JSTaggedValue ContainersPlainArray::ForEach(EcmaRuntimeCallInfo *argv)
215 {
216     ASSERT(argv != nullptr);
217     JSThread *thread = argv->GetThread();
218     BUILTINS_API_TRACE(thread, PlainArray, ForEach);
219     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
220     if (!thisHandle->IsJSAPIPlainArray()) {
221         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIPlainArray()) {
222             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
223         } else {
224             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
225                                                                 "The forEach method cannot be bound");
226             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227         }
228     }
229     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
230     if (!callbackFnHandle->IsCallable()) {
231         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
232         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
233         CString errorMsg =
234             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
235         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
236         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
237     }
238     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
239     return JSAPIPlainArray::ForEach(thread, thisHandle, callbackFnHandle, thisArgHandle);
240 }
241 
ToString(EcmaRuntimeCallInfo * argv)242 JSTaggedValue ContainersPlainArray::ToString(EcmaRuntimeCallInfo *argv)
243 {
244     ASSERT(argv != nullptr);
245     JSThread *thread = argv->GetThread();
246     BUILTINS_API_TRACE(thread, PlainArray, ToString);
247     JSHandle<JSTaggedValue> self = GetThis(argv);
248     if (!self->IsJSAPIPlainArray()) {
249         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
250             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
251         } else {
252             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
253                                                                 "The toString method cannot be bound");
254             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
255         }
256     }
257     JSTaggedValue value = JSAPIPlainArray::ToString(thread, JSHandle<JSAPIPlainArray>::Cast(self));
258     return value;
259 }
260 
GetIndexOfKey(EcmaRuntimeCallInfo * argv)261 JSTaggedValue ContainersPlainArray::GetIndexOfKey(EcmaRuntimeCallInfo *argv)
262 {
263     ASSERT(argv != nullptr);
264     JSThread *thread = argv->GetThread();
265     BUILTINS_API_TRACE(thread, PlainArray, GetIndexOfKey);
266     JSHandle<JSTaggedValue> self = GetThis(argv);
267     if (!self->IsJSAPIPlainArray()) {
268         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
269             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
270         } else {
271             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
272                                                                 "The getIndexOfKey method cannot be bound");
273             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
274         }
275     }
276     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
277     if (value->IsDouble()) {
278         value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
279     }
280     if (!value->IsInt()) {
281         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
282         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
283         CString errorMsg =
284             "The type of \"key\" must be small integer. Received value is: " + ConvertToString(*result);
285         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
286         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
287     }
288     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
289     int32_t key = value->GetNumber();
290     JSTaggedValue result = array->GetIndexOfKey(key);
291     return result;
292 }
293 
GetIndexOfValue(EcmaRuntimeCallInfo * argv)294 JSTaggedValue ContainersPlainArray::GetIndexOfValue(EcmaRuntimeCallInfo *argv)
295 {
296     ASSERT(argv != nullptr);
297     JSThread *thread = argv->GetThread();
298     BUILTINS_API_TRACE(thread, PlainArray, GetIndexOfValue);
299     JSHandle<JSTaggedValue> self = GetThis(argv);
300     if (!self->IsJSAPIPlainArray()) {
301         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
302             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
303         } else {
304             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
305                                                                 "The getIndexOfValue method cannot be bound");
306             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
307         }
308     }
309     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
310     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
311     JSTaggedValue jsValue = array->GetIndexOfValue(value.GetTaggedValue());
312     return jsValue;
313 }
314 
IsEmpty(EcmaRuntimeCallInfo * argv)315 JSTaggedValue ContainersPlainArray::IsEmpty(EcmaRuntimeCallInfo *argv)
316 {
317     ASSERT(argv != nullptr);
318     JSThread *thread = argv->GetThread();
319     BUILTINS_API_TRACE(thread, PlainArray, IsEmpty);
320     JSHandle<JSTaggedValue> self = GetThis(argv);
321     if (!self->IsJSAPIPlainArray()) {
322         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
323             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
324         } else {
325             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
326                                                                 "The isEmpty method cannot be bound");
327             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
328         }
329     }
330     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
331     bool ret = array->IsEmpty();
332     return JSTaggedValue(ret);
333 }
334 
GetKeyAt(EcmaRuntimeCallInfo * argv)335 JSTaggedValue ContainersPlainArray::GetKeyAt(EcmaRuntimeCallInfo *argv)
336 {
337     ASSERT(argv != nullptr);
338     JSThread *thread = argv->GetThread();
339     BUILTINS_API_TRACE(thread, PlainArray, GetKeyAt);
340     JSHandle<JSTaggedValue> self = GetThis(argv);
341     if (!self->IsJSAPIPlainArray()) {
342         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
343             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
344         } else {
345             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
346                                                                 "The getKeyAt method cannot be bound");
347             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
348         }
349     }
350     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
351     if (value->IsDouble()) {
352         value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
353     }
354     if (!value->IsInt()) {
355         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
356         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
357         CString errorMsg =
358             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
359         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
360         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
361     }
362     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
363     int32_t index = value->GetNumber();
364     JSTaggedValue result = array->GetKeyAt(index);
365     return result;
366 }
367 
Remove(EcmaRuntimeCallInfo * argv)368 JSTaggedValue ContainersPlainArray::Remove(EcmaRuntimeCallInfo *argv)
369 {
370     ASSERT(argv != nullptr);
371     JSThread *thread = argv->GetThread();
372     BUILTINS_API_TRACE(thread, PlainArray, Remove);
373     JSHandle<JSTaggedValue> self = GetThis(argv);
374     if (!self->IsJSAPIPlainArray()) {
375         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
376             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
377         } else {
378             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
379                                                                 "The remove method cannot be bound");
380             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
381         }
382     }
383     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
384     if (key->IsDouble()) {
385         key = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(key->GetDouble()));
386     }
387     if (!key->IsInt()) {
388         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
389         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
390         CString errorMsg =
391             "The type of \"key\" must be small integer. Received value is: " + ConvertToString(*result);
392         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
393         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
394     }
395     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
396     JSTaggedValue value = array->Remove(thread, key.GetTaggedValue());
397     return value;
398 }
399 
RemoveAt(EcmaRuntimeCallInfo * argv)400 JSTaggedValue ContainersPlainArray::RemoveAt(EcmaRuntimeCallInfo *argv)
401 {
402     ASSERT(argv != nullptr);
403     JSThread *thread = argv->GetThread();
404     BUILTINS_API_TRACE(thread, PlainArray, RemoveAt);
405     JSHandle<JSTaggedValue> self = GetThis(argv);
406     if (!self->IsJSAPIPlainArray()) {
407         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
408             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
409         } else {
410             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
411                                                                 "The removeAt method cannot be bound");
412             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
413         }
414     }
415     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
416     if (index->IsDouble()) {
417         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
418     }
419     if (!index->IsInt()) {
420         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
421         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
422         CString errorMsg =
423             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
424         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
425         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
426     }
427     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
428     JSTaggedValue value = array->RemoveAt(thread, index.GetTaggedValue());
429     return value;
430 }
431 
RemoveRangeFrom(EcmaRuntimeCallInfo * argv)432 JSTaggedValue ContainersPlainArray::RemoveRangeFrom(EcmaRuntimeCallInfo *argv)
433 {
434     ASSERT(argv != nullptr);
435     JSThread *thread = argv->GetThread();
436     BUILTINS_API_TRACE(thread, PlainArray, RemoveRangeFrom);
437     JSHandle<JSTaggedValue> self = GetThis(argv);
438     if (!self->IsJSAPIPlainArray()) {
439         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
440             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
441         } else {
442             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
443                                                                 "The removeRangeFrom method cannot be bound");
444             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
445         }
446     }
447     JSHandle<JSTaggedValue> valueIndex(GetCallArg(argv, 0));
448     JSHandle<JSTaggedValue> valueSize(GetCallArg(argv, 1));
449     if (valueIndex->IsDouble()) {
450         valueIndex = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(valueIndex->GetDouble()));
451     }
452     if (valueSize->IsDouble()) {
453         valueSize = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(valueSize->GetDouble()));
454     }
455     if (!valueIndex->IsInt()) {
456         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, valueIndex.GetTaggedValue());
457         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
458         CString errorMsg =
459             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
460         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
461         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
462     }
463     if (!valueSize->IsInt()) {
464         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, valueSize.GetTaggedValue());
465         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
466         CString errorMsg =
467             "The type of \"size\" must be small integer. Received value is: " + ConvertToString(*result);
468         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
469         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
470     }
471     int32_t index = valueIndex->GetNumber();
472     int32_t size = valueSize->GetNumber();
473     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
474     JSTaggedValue value = array->RemoveRangeFrom(thread, index, size);
475     return value;
476 }
477 
SetValueAt(EcmaRuntimeCallInfo * argv)478 JSTaggedValue ContainersPlainArray::SetValueAt(EcmaRuntimeCallInfo *argv)
479 {
480     ASSERT(argv != nullptr);
481     JSThread *thread = argv->GetThread();
482     BUILTINS_API_TRACE(thread, PlainArray, SetValueAt);
483     [[maybe_unused]] EcmaHandleScope handleScope(thread);
484     JSHandle<JSTaggedValue> self = GetThis(argv);
485     if (!self->IsJSAPIPlainArray()) {
486         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
487             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
488         } else {
489             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
490                                                                 "The setValueAt method cannot be bound");
491             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
492         }
493     }
494     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
495     JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
496     if (index->IsDouble()) {
497         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
498     }
499     if (!index->IsInt()) {
500         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
501         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
502         CString errorMsg =
503             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
504         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
505         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
506     }
507     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
508     array->SetValueAt(thread, index.GetTaggedValue(), value.GetTaggedValue());
509     return JSTaggedValue::Undefined();
510 }
511 
GetValueAt(EcmaRuntimeCallInfo * argv)512 JSTaggedValue ContainersPlainArray::GetValueAt(EcmaRuntimeCallInfo *argv)
513 {
514     ASSERT(argv != nullptr);
515     JSThread *thread = argv->GetThread();
516     BUILTINS_API_TRACE(thread, PlainArray, GetValueAt);
517     [[maybe_unused]] EcmaHandleScope handleScope(thread);
518     JSHandle<JSTaggedValue> self = GetThis(argv);
519     if (!self->IsJSAPIPlainArray()) {
520         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
521             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
522         } else {
523             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
524                                                                 "The getValueAt method cannot be bound");
525             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
526         }
527     }
528     JSHandle<JSTaggedValue> idx(GetCallArg(argv, 0));
529     if (idx->IsDouble()) {
530         idx = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(idx->GetDouble()));
531     }
532     if (!idx->IsInt()) {
533         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, idx.GetTaggedValue());
534         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
535         CString errorMsg =
536             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
537         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
538         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
539     }
540     JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
541     int32_t index = idx->GetNumber();
542     JSTaggedValue value = array->GetValueAt(thread, index);
543     return value;
544 }
545 
GetSize(EcmaRuntimeCallInfo * argv)546 JSTaggedValue ContainersPlainArray::GetSize(EcmaRuntimeCallInfo *argv)
547 {
548     ASSERT(argv != nullptr);
549     JSThread *thread = argv->GetThread();
550     BUILTINS_API_TRACE(thread, PlainArray, GetSize);
551     JSHandle<JSTaggedValue> self = GetThis(argv);
552     if (!self->IsJSAPIPlainArray()) {
553         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIPlainArray()) {
554             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
555         } else {
556             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
557                                                                 "The getLength method cannot be bound");
558             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
559         }
560     }
561     uint32_t length = JSHandle<JSAPIPlainArray>::Cast(self)->GetSize();
562     return JSTaggedValue(length);
563 }
564 } // namespace panda::ecmascript::containers
565