• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)26 void 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 
CreateSlot(const JSThread * thread,const uint32_t capacity)59 JSHandle<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 
AdjustForward(JSThread * thread,int32_t index,int32_t forwardSize)67 bool 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 
AdjustPrimitiveArray(TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex)79 void 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 
AdjustArray(JSThread * thread,TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex,bool direction)98 void 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->IsYoungAndNotMarking(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 
BinarySearch(TaggedArray * array,int32_t fromIndex,int32_t toIndex,int32_t key)131 int32_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 
Clear(JSThread * thread)150 void 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 
RemoveRangeFrom(JSThread * thread,int32_t index,int32_t batchSize)162 JSTaggedValue 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 
Set(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const uint32_t index,JSTaggedValue value)187 JSTaggedValue 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 
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)196 bool 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 
GetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)219 OperationResult 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 
SetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)259 bool 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 
Clone(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj)283 JSHandle<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 
Has(const int32_t key)303 bool 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 
Get(const JSTaggedValue key)314 JSTaggedValue 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 
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,IterationKind kind)326 JSHandle<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 
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)335 JSTaggedValue 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 
ToString(JSThread * thread,const JSHandle<JSAPIPlainArray> & plainarray)357 JSTaggedValue 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 
GetIndexOfKey(int32_t key)401 JSTaggedValue 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 
TryFastGetIndexOfValue(TaggedArray * values,JSTaggedValue value)412 JSTaggedValue 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 
GetIndexOfValue(JSTaggedValue value)424 JSTaggedValue 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 
IsEmpty()440 bool JSAPIPlainArray::IsEmpty()
441 {
442     uint32_t length = GetLength();
443     return length == 0;
444 }
445 
GetKeyAt(int32_t index)446 JSTaggedValue 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 
GetValueAt(JSThread * thread,int32_t index)456 JSTaggedValue 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 
Remove(JSThread * thread,JSTaggedValue key)475 JSTaggedValue 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 
RemoveAt(JSThread * thread,JSTaggedValue index)489 JSTaggedValue 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 
SetValueAt(JSThread * thread,JSTaggedValue index,JSTaggedValue value)502 bool 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