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