1/*
2 * Copyright (c) 2022-2024 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/js_api/js_api_plain_array.h"
17
18#include "ecmascript/containers/containers_errors.h"
19#include "ecmascript/interpreter/interpreter.h"
20#include "ecmascript/js_function.h"
21#include <codecvt>
22
23namespace panda::ecmascript {
24using ContainerError = containers::ContainerError;
25using ErrorFlag = containers::ErrorFlag;
26void JSAPIPlainArray::Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key,
27                          JSHandle<JSTaggedValue> value)
28{
29    JSHandle<TaggedArray> keyArray(thread, obj->GetKeys());
30    JSHandle<TaggedArray> valueArray(thread, obj->GetValues());
31    uint32_t size = obj->GetLength();
32    int32_t index = obj->BinarySearch(*keyArray, 0, size, key.GetTaggedValue().GetNumber());
33    if (index >= 0) {
34        keyArray->Set(thread, index, key);
35        valueArray->Set(thread, index, value);
36        return;
37    }
38    index ^= 0xFFFFFFFF;
39    if (index < static_cast<int32_t>(size)) {
40        obj->AdjustArray(thread, *keyArray, index, size, true);
41        obj->AdjustArray(thread, *valueArray, index, size, true);
42    }
43    uint32_t capacity = valueArray->GetLength();
44    if (size + 1 >= capacity) {
45        uint32_t newCapacity = capacity << 1U;
46        keyArray =
47            thread->GetEcmaVM()->GetFactory()->CopyArray(keyArray, capacity, newCapacity);
48        valueArray =
49            thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
50        obj->SetKeys(thread, keyArray);
51        obj->SetValues(thread, valueArray);
52    }
53    keyArray->Set(thread, index, key);
54    valueArray->Set(thread, index, value);
55    size++;
56    obj->SetLength(size);
57}
58
59JSHandle<TaggedArray> JSAPIPlainArray::CreateSlot(const JSThread *thread, const uint32_t capacity)
60{
61    ASSERT_PRINT(capacity > 0, "size must be a non-negative integer");
62    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
63    JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity, JSTaggedValue::Hole());
64    return taggedArray;
65}
66
67bool JSAPIPlainArray::AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize)
68{
69    uint32_t size = GetLength();
70    TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
71    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
72    AdjustPrimitiveArray(keys, index + forwardSize, index);
73    AdjustArray(thread, values, index + forwardSize, index, false);
74    size = size - static_cast<uint32_t>(forwardSize);
75    SetLength(size);
76    return true;
77}
78
79void JSAPIPlainArray::AdjustPrimitiveArray(TaggedArray *srcArray, int32_t fromIndex, int32_t toIndex)
80{
81    uint32_t size = GetLength();
82    auto srcPtr = reinterpret_cast<JSTaggedType *>(
83                            ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
84    auto dstPtr = reinterpret_cast<JSTaggedType *>(
85                            ToUintPtr(srcArray->GetData()) + toIndex * JSTaggedValue::TaggedTypeSize());
86    // move Array element from srcPtr to dstPtr
87    for (uint32_t count = size - fromIndex; count > 0; --count) {
88        *dstPtr = *srcPtr;
89        ++srcPtr;
90        ++dstPtr;
91    }
92    for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
93        *dstPtr = JSTaggedValue::Hole().GetRawData();
94        ++dstPtr;
95    }
96}
97
98void JSAPIPlainArray::AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex,
99                                  int32_t toIndex, bool direction)
100{
101    uint32_t size = GetLength();
102    ASSERT(size > 0);
103    uint32_t idx = size - 1;
104    if (direction) {
105        while (fromIndex < toIndex) {
106            JSTaggedValue value = srcArray->Get(idx);
107            srcArray->Set(thread, idx + 1, value);
108            idx--;
109            fromIndex++;
110        }
111    } else {
112        if (srcArray->IsGeneralNewAndNotMarking(thread)) {
113            AdjustPrimitiveArray(srcArray, fromIndex, toIndex);
114        } else {
115            auto srcPtr = reinterpret_cast<JSTaggedType *>(
116                                    ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
117            uint32_t dstIndex = toIndex;
118            for (uint32_t count = size - fromIndex; count > 0; --count) {
119                srcArray->Set(thread, dstIndex, JSTaggedValue(*srcPtr));
120                ++srcPtr;
121                ++dstIndex;
122            }
123            for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
124                srcArray->Set(thread, dstIndex, JSTaggedValue::Hole());
125                ++dstIndex;
126            }
127        }
128    }
129}
130
131int32_t JSAPIPlainArray::BinarySearch(TaggedArray *array, int32_t fromIndex, int32_t toIndex, int32_t key)
132{
133    int32_t low = fromIndex;
134    int32_t high = toIndex - 1;
135    while (low <= high) {
136        int32_t mid = static_cast<int32_t>(static_cast<uint32_t>(low + high) >> 1U);
137        int32_t midVal = static_cast<int32_t>(array->Get(mid).GetNumber());
138        if (midVal < key) {
139            low = mid + 1;
140        } else {
141            if (midVal <= key) {
142                return mid;
143            }
144            high = mid - 1;
145        }
146    }
147    return -(low + 1);
148}
149
150void JSAPIPlainArray::Clear(JSThread *thread)
151{
152    TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
153    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
154    uint32_t size = GetLength();
155    for (uint32_t index = 0; index < size; index++) {
156        keys->Set(thread, index, JSTaggedValue::Hole());
157        values->Set(thread, index, JSTaggedValue::Hole());
158    }
159    SetLength(0);
160}
161
162JSTaggedValue JSAPIPlainArray::RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize)
163{
164    int32_t size = static_cast<int32_t>(GetLength());
165    if (size <= 0) {
166        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
167        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
168    }
169    if (index < 0 || index >= size) {
170        std::ostringstream oss;
171        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
172            << ". Received value is: " << index;
173        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
174        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
175    }
176    if (batchSize < 1) {
177        std::ostringstream oss;
178        oss << "The value of \"size\" is out of range. It must be > 0" << ". Received value is: " << batchSize;
179        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
180        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
181    }
182    int32_t safeSize = (size - (index + batchSize)) < 0 ? size - index : batchSize;
183    AdjustForward(thread, index, safeSize);
184    return JSTaggedValue(safeSize);
185}
186
187JSTaggedValue JSAPIPlainArray::Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
188                                   const uint32_t index, JSTaggedValue value)
189{
190    JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
191    JSHandle<JSTaggedValue> valueHandle(thread, value);
192    JSAPIPlainArray::Add(thread, obj, key, valueHandle);
193    return JSTaggedValue::Undefined();
194}
195
196bool JSAPIPlainArray::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
197                                     const JSHandle<JSTaggedValue> &key)
198{
199    TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
200    uint32_t size = obj->GetLength();
201    if (size == 0) {
202        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
203        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
204    }
205    int32_t index = obj->BinarySearch(keyArray, 0, size, key.GetTaggedValue().GetInt());
206    if (index < 0 || index >= static_cast<int32_t>(size)) {
207        ASSERT(size > 0);
208        std::ostringstream oss;
209        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
210            << ". Received value is: " << index;
211        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
212        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
213    }
214
215    obj->Get(key.GetTaggedValue());
216    return true;
217}
218
219OperationResult JSAPIPlainArray::GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
220                                             const JSHandle<JSTaggedValue> &key)
221{
222    TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
223    uint32_t size = obj->GetLength();
224    if (size == 0) {
225        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
226        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
227                                                                        JSTaggedValue::Exception(),
228                                                                        PropertyMetaData(false)));
229    }
230    JSHandle<JSTaggedValue> indexKey = key;
231    if (indexKey->IsDouble()) {
232        // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
233        // For integer which is greater than INT32_MAX, it will remain TaggedDouble
234        indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
235    }
236    if (!indexKey->IsInt()) {
237        CString errorMsg = "The type of \"index\" must be small integer.";
238        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
239        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
240                                         OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
241    }
242
243    int keyVal = indexKey->GetInt();
244    int32_t index = obj->BinarySearch(keyArray, 0, size, keyVal);
245    if (index < 0 || index >= static_cast<int32_t>(size)) {
246        std::ostringstream oss;
247        ASSERT(size > 0);
248        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
249            << ". Received value is: " << index;
250        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
251        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
252                                                                        JSTaggedValue::Exception(),
253                                                                        PropertyMetaData(false)));
254    }
255
256    return OperationResult(thread, obj->Get(JSTaggedValue(index)), PropertyMetaData(false));
257}
258
259bool JSAPIPlainArray::SetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
260                                  const JSHandle<JSTaggedValue> &key,
261                                  const JSHandle<JSTaggedValue> &value)
262{
263    TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
264    uint32_t size = obj->GetLength();
265    JSHandle<JSTaggedValue> indexKey = key;
266    if (indexKey->IsDouble()) {
267        // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
268        // For integer which is greater than INT32_MAX, it will remain TaggedDouble
269        indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
270    }
271    if (!indexKey->IsInt()) {
272        return false;
273    }
274    int32_t index = obj->BinarySearch(keyArray, 0, size, indexKey->GetInt());
275    if (index < 0 || index >= static_cast<int32_t>(size)) {
276        return false;
277    }
278
279    obj->Set(thread, obj, index, value.GetTaggedValue());
280    return true;
281}
282
283JSHandle<JSAPIPlainArray> JSAPIPlainArray::Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj)
284{
285    JSHandle<TaggedArray> srckeys(thread, obj->GetKeys());
286    JSHandle<TaggedArray> srcvalues(thread, obj->GetValues());
287    auto factory = thread->GetEcmaVM()->GetFactory();
288    JSHandle<JSAPIPlainArray> newPlainArray = factory->NewJSAPIPlainArray(0);
289
290    uint32_t length = obj->GetLength();
291    newPlainArray->SetLength(length);
292    JSHandle<TaggedArray> srcKeyArray(thread, obj->GetKeys());
293    JSHandle<TaggedArray> srcValueArray(thread, obj->GetValues());
294
295    JSHandle<TaggedArray> dstKeyArray = factory->NewAndCopyTaggedArray(srcKeyArray, length, length);
296    JSHandle<TaggedArray> dstValueArray = factory->NewAndCopyTaggedArray(srcValueArray, length, length);
297
298    newPlainArray->SetKeys(thread, dstKeyArray);
299    newPlainArray->SetValues(thread, dstValueArray);
300    return newPlainArray;
301}
302
303bool JSAPIPlainArray::Has(const int32_t key)
304{
305    uint32_t size = GetLength();
306    TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
307    int32_t index = BinarySearch(keyArray, 0, size, key);
308    if (index < 0) {
309        return false;
310    }
311    return true;
312}
313
314JSTaggedValue JSAPIPlainArray::Get(const JSTaggedValue key)
315{
316    uint32_t size = GetLength();
317    TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
318    int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
319    if (index < 0) {
320        return JSTaggedValue::Undefined();
321    }
322    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
323    return values->Get(index);
324}
325
326JSHandle<JSTaggedValue> JSAPIPlainArray::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
327                                                        IterationKind kind)
328{
329    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
330    JSHandle<JSTaggedValue> iter =
331        JSHandle<JSTaggedValue>::Cast(factory->NewJSAPIPlainArrayIterator(obj, kind));
332    return iter;
333}
334
335JSTaggedValue JSAPIPlainArray::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
336                                       const JSHandle<JSTaggedValue> &callbackFn,
337                                       const JSHandle<JSTaggedValue> &thisArg)
338{
339    JSAPIPlainArray *plainarray = JSAPIPlainArray::Cast(thisHandle->GetTaggedObject());
340    uint32_t length = plainarray->GetLength();
341    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
342    JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys());
343    JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues());
344    for (uint32_t k = 0; k < length; k++) {
345        JSTaggedValue kValue = valueArray->Get(k);
346        JSTaggedValue key = keyArray->Get(k);
347        EcmaRuntimeCallInfo *info =
348            EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3);  // 3: three args
349        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
350        info->SetCallArg(kValue, key, thisHandle.GetTaggedValue());
351        JSTaggedValue funcResult = JSFunction::Call(info);
352        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
353    }
354    return JSTaggedValue::Undefined();
355}
356
357JSTaggedValue JSAPIPlainArray::ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray)
358{
359    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
360    std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
361    std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
362
363    uint32_t length = plainarray->GetLength();
364    std::u16string concatStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
365    std::u16string concatStrNew = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
366    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
367    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
368    for (uint32_t k = 0; k < length; k++) {
369        std::u16string valueStr;
370        valueHandle.Update(plainarray->GetValueAt(thread, k));
371        if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
372            JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
373            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374            valueStr = EcmaStringAccessor(valueStringHandle).ToU16String();
375        }
376
377        std::u16string nextStr;
378        keyHandle.Update(plainarray->GetKeyAt(k));
379        if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
380            JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
381            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
382            nextStr = EcmaStringAccessor(keyStringHandle).ToU16String();
383        }
384
385        nextStr.append(colonStr);
386        nextStr.append(valueStr);
387        if (k > 0) {
388            concatStr.append(sepStr);
389            concatStr.append(nextStr);
390            continue;
391        }
392        concatStr.append(nextStr);
393    }
394
395    char16_t *char16tData = concatStr.data();
396    auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
397    uint32_t u16strSize = concatStr.size();
398    return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
399}
400
401JSTaggedValue JSAPIPlainArray::GetIndexOfKey(int32_t key)
402{
403    uint32_t size = GetLength();
404    TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
405    int32_t index = BinarySearch(keyArray, 0, size, key);
406    if (index < 0) {
407        return JSTaggedValue(-1);
408    }
409    return JSTaggedValue(index);
410}
411
412JSTaggedValue JSAPIPlainArray::TryFastGetIndexOfValue(TaggedArray *values, JSTaggedValue value)
413{
414    uint32_t size = GetLength();
415    for (uint32_t i = 0; i < size; ++i) {
416        JSTaggedValue currVal = values->Get(i);
417        if (currVal.IsInt() && (currVal == value)) {
418            return JSTaggedValue(i);
419        }
420    }
421    return JSTaggedValue(-1);
422}
423
424JSTaggedValue JSAPIPlainArray::GetIndexOfValue(JSTaggedValue value)
425{
426    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
427    if (value.IsInt()) {
428        return TryFastGetIndexOfValue(values, value);
429    } else {
430        uint32_t size = GetLength();
431        for (uint32_t i = 0; i < size; ++i) {
432            if (JSTaggedValue::SameValue(values->Get(i), value)) {
433                return JSTaggedValue(i);
434            }
435        }
436    }
437    return JSTaggedValue(-1);
438}
439
440bool JSAPIPlainArray::IsEmpty()
441{
442    uint32_t length = GetLength();
443    return length == 0;
444}
445
446JSTaggedValue JSAPIPlainArray::GetKeyAt(int32_t index)
447{
448    uint32_t size = GetLength();
449    TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
450    if (index < 0 || index >= static_cast<int32_t>(size)) {
451        return JSTaggedValue::Undefined();
452    }
453    return keyArray->Get(index);
454}
455
456JSTaggedValue JSAPIPlainArray::GetValueAt(JSThread *thread, int32_t index)
457{
458    uint32_t size = GetLength();
459    if (size == 0) {
460        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
461        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
462    }
463    if (index < 0 || index >= static_cast<int32_t>(size)) {
464        ASSERT(size > 0);
465        std::ostringstream oss;
466        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
467            << ". Received value is: " << index;
468        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
469        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
470    }
471    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
472    return values->Get(index);
473}
474
475JSTaggedValue JSAPIPlainArray::Remove(JSThread *thread, JSTaggedValue key)
476{
477    uint32_t size = GetLength();
478    TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
479    int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
480    if (index < 0 || index >= static_cast<int32_t>(size)) {
481        return JSTaggedValue::Undefined();
482    }
483    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
484    JSTaggedValue value = values->Get(index);
485    AdjustForward(thread, index, 1); // 1 means the length of array
486    return value;
487}
488
489JSTaggedValue JSAPIPlainArray::RemoveAt(JSThread *thread, JSTaggedValue index)
490{
491    uint32_t size = GetLength();
492    int32_t seat = index.GetNumber();
493    if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
494        return JSTaggedValue::Undefined();
495    }
496    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
497    JSTaggedValue value = values->Get(seat);
498    AdjustForward(thread, seat, 1);
499    return value;
500}
501
502bool JSAPIPlainArray::SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value)
503{
504    uint32_t size = GetLength();
505    if (size == 0) {
506        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
507        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
508    }
509    int32_t seat = index.GetNumber();
510    if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
511        std::ostringstream oss;
512        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
513            << ". Received value is: " << seat;
514        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
515        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
516    }
517    TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
518    values->Set(thread, seat, value);
519    return true;
520}
521} // namespace panda::ecmascript
522