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
22namespace panda::ecmascript::containers {
23JSTaggedValue 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
50JSTaggedValue 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
83JSTaggedValue 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
104JSTaggedValue 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
125JSTaggedValue 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
159JSTaggedValue 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
193JSTaggedValue 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
214JSTaggedValue 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
242JSTaggedValue 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
261JSTaggedValue 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
294JSTaggedValue 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
315JSTaggedValue 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
335JSTaggedValue 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
368JSTaggedValue 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
400JSTaggedValue 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
432JSTaggedValue 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
478JSTaggedValue 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
512JSTaggedValue 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
546JSTaggedValue 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