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/js_api/js_api_arraylist.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_function.h"
22
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)26 bool JSAPIArrayList::Add(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
27 const JSHandle<JSTaggedValue> &value)
28 {
29 uint32_t length = arrayList->GetLength().GetArrayLength();
30 JSHandle<TaggedArray> elements = GrowCapacity(thread, arrayList, length + 1);
31
32 ASSERT(!elements->IsDictionaryMode());
33 elements->Set(thread, length, value);
34 arrayList->SetLength(thread, JSTaggedValue(++length));
35 return true;
36 }
37
Insert(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value,const int & index)38 void JSAPIArrayList::Insert(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
39 const JSHandle<JSTaggedValue> &value, const int &index)
40 {
41 int length = arrayList->GetLength().GetInt();
42 if (index < 0 || index > length) {
43 std::ostringstream oss;
44 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << length
45 << ". Received value is: " << index;
46 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
47 THROW_NEW_ERROR_AND_RETURN(thread, error);
48 }
49 JSHandle<TaggedArray> elements = GrowCapacity(thread, arrayList, length + 1);
50 ASSERT(!elements->IsDictionaryMode());
51 for (int i = length - 1; i >= index; --i) {
52 elements->Set(thread, i + 1, elements->Get(i));
53 }
54 elements->Set(thread, index, value);
55 arrayList->SetLength(thread, JSTaggedValue(++length));
56 }
57
Clear(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList)58 void JSAPIArrayList::Clear(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList)
59 {
60 if (!arrayList.IsEmpty()) {
61 int length = arrayList->GetLength().GetInt();
62 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
63 ASSERT(!elements->IsDictionaryMode());
64 for (int i = 0; i < length; ++i) {
65 elements->Set(thread, i, JSTaggedValue::Hole());
66 }
67 arrayList->SetLength(thread, JSTaggedValue(0));
68 }
69 }
70
Clone(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)71 JSHandle<JSAPIArrayList> JSAPIArrayList::Clone(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
72 {
73 JSHandle<TaggedArray> srcElements(thread, obj->GetElements());
74 ASSERT(!srcElements->IsDictionaryMode());
75
76 uint32_t length = obj->GetSize();
77 auto factory = thread->GetEcmaVM()->GetFactory();
78 JSHandle<JSAPIArrayList> newArrayList = factory->NewJSAPIArrayList(0);
79 newArrayList->SetLength(thread, JSTaggedValue(length));
80
81 JSHandle<TaggedArray> dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length);
82 newArrayList->SetElements(thread, dstElements);
83 return newArrayList;
84 }
85
GetCapacity(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)86 uint32_t JSAPIArrayList::GetCapacity(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
87 {
88 JSHandle<TaggedArray> elements(thread, obj->GetElements());
89 ASSERT(!elements->IsDictionaryMode());
90 uint32_t capacity = elements->GetLength();
91 return capacity;
92 }
93
IncreaseCapacityTo(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,int capacity)94 void JSAPIArrayList::IncreaseCapacityTo(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
95 int capacity)
96 {
97 JSHandle<TaggedArray> elementData(thread, arrayList->GetElements());
98 ASSERT(!elementData->IsDictionaryMode());
99 int length = arrayList->GetLength().GetInt();
100 int oldElementLength = static_cast<int>(elementData->GetLength());
101 if (oldElementLength != capacity && length < capacity) {
102 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
103 JSHandle<TaggedArray> newElements = factory->NewAndCopyTaggedArray(elementData,
104 static_cast<uint32_t>(capacity), static_cast<uint32_t>(length));
105 arrayList->SetElements(thread, newElements);
106 }
107 }
108
TrimToCurrentLength(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList)109 void JSAPIArrayList::TrimToCurrentLength(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList)
110 {
111 uint32_t length = arrayList->GetLength().GetArrayLength();
112 uint32_t capacity = JSAPIArrayList::GetCapacity(thread, arrayList);
113 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
114 ASSERT(!elements->IsDictionaryMode());
115 if (capacity > length) {
116 elements->Trim(thread, length);
117 }
118 }
119
Get(JSThread * thread,const uint32_t index)120 JSTaggedValue JSAPIArrayList::Get(JSThread *thread, const uint32_t index)
121 {
122 if (GetLength().GetArrayLength() == 0) {
123 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
124 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
125 }
126 if (index >= GetLength().GetArrayLength()) {
127 ASSERT(GetLength().GetArrayLength() > 0);
128 std::ostringstream oss;
129 oss << "The value of \"index\" is out of range. It must be >= 0 && <= "
130 << (GetLength().GetArrayLength() - 1) << ". Received value is: " << index;
131 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
132 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
133 }
134
135 TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
136 return elements->Get(index);
137 }
138
IsEmpty(const JSHandle<JSAPIArrayList> & arrayList)139 bool JSAPIArrayList::IsEmpty(const JSHandle<JSAPIArrayList> &arrayList)
140 {
141 return arrayList->GetSize() == 0;
142 }
143
GetIndexOf(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)144 int JSAPIArrayList::GetIndexOf(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
145 const JSHandle<JSTaggedValue> &value)
146 {
147 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
148 ASSERT(!elements->IsDictionaryMode());
149 uint32_t length = arrayList->GetLength().GetArrayLength();
150 JSTaggedValue targetValue = value.GetTaggedValue();
151 for (uint32_t i = 0; i < length; ++i) {
152 if (JSTaggedValue::StrictEqual(targetValue, elements->Get(i))) {
153 return i;
154 }
155 }
156 return -1;
157 }
158
GetLastIndexOf(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)159 int JSAPIArrayList::GetLastIndexOf(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
160 const JSHandle<JSTaggedValue> &value)
161 {
162 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
163 ASSERT(!elements->IsDictionaryMode());
164 JSTaggedValue targetValue = value.GetTaggedValue();
165 int length = arrayList->GetLength().GetInt();
166 for (int i = length - 1; i >= 0; --i) {
167 if (JSTaggedValue::StrictEqual(targetValue, elements->Get(i))) {
168 return i;
169 }
170 }
171 return -1;
172 }
173
RemoveByIndex(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,int index)174 JSTaggedValue JSAPIArrayList::RemoveByIndex(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList, int index)
175 {
176 int length = arrayList->GetLength().GetInt();
177 if (length <= 0) {
178 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
179 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
180 }
181 if (index < 0 || index >= length) {
182 std::ostringstream oss;
183 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
184 << ". Received value is: " << index;
185 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
186 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
187 }
188
189 TaggedArray *resElements = TaggedArray::Cast(arrayList->GetElements().GetTaggedObject());
190 JSTaggedValue oldValue = resElements->Get(index);
191
192 if (index >= 0) {
193 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
194 ASSERT(!elements->IsDictionaryMode());
195 TaggedArray::RemoveElementByIndex(thread, elements, index, length);
196 arrayList->SetLength(thread, JSTaggedValue(length - 1));
197 }
198
199 return oldValue;
200 }
201
Remove(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)202 bool JSAPIArrayList::Remove(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
203 const JSHandle<JSTaggedValue> &value)
204 {
205 int index = GetIndexOf(thread, arrayList, value);
206 uint32_t length = arrayList->GetSize();
207 if (index >= 0) {
208 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
209 ASSERT(!elements->IsDictionaryMode());
210 TaggedArray::RemoveElementByIndex(thread, elements, index, length);
211 arrayList->SetLength(thread, JSTaggedValue(length - 1));
212 return true;
213 }
214 return false;
215 }
216
RemoveByRange(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value1,const JSHandle<JSTaggedValue> & value2)217 JSTaggedValue JSAPIArrayList::RemoveByRange(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
218 const JSHandle<JSTaggedValue> &value1,
219 const JSHandle<JSTaggedValue> &value2)
220 {
221 int32_t startIndex = JSTaggedValue::ToInt32(thread, value1);
222 int32_t endIndex = JSTaggedValue::ToInt32(thread, value2);
223 int32_t length = arrayList->GetLength().GetInt();
224 if (length <= 0) {
225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227 }
228 int32_t size = length > endIndex ? endIndex : length;
229 if (startIndex < 0 || startIndex >= size) {
230 std::ostringstream oss;
231 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
232 << ". Received value is: " << startIndex;
233 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
234 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
235 }
236 if (endIndex <= startIndex || endIndex < 0 || endIndex > length) {
237 std::ostringstream oss;
238 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
239 << ". Received value is: " << endIndex;
240 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
241 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
242 }
243
244 int32_t toIndex = endIndex >= length ? length : endIndex;
245
246 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
247 ASSERT(!elements->IsDictionaryMode());
248 int32_t numMoved = length - toIndex;
249
250 for (int32_t i = 0; i < numMoved; i++) {
251 elements->Set(thread, startIndex + i, elements->Get(static_cast<uint32_t>(endIndex + i)));
252 }
253 int32_t newLength = length - (endIndex - startIndex);
254 arrayList->SetLength(thread, JSTaggedValue(newLength));
255 elements->Trim(thread, newLength);
256 return JSTaggedValue::Undefined();
257 }
258
ReplaceAllElements(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)259 JSTaggedValue JSAPIArrayList::ReplaceAllElements(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
260 const JSHandle<JSTaggedValue> &callbackFn,
261 const JSHandle<JSTaggedValue> &thisArg)
262 {
263 JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(thisHandle);
264 uint32_t length = arrayList->GetSize();
265 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
266 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
267 const int32_t argsLength = 3;
268 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
269 for (uint32_t k = 0; k < length; k++) {
270 kValue.Update(arrayList->Get(thread, k));
271 key.Update(JSTaggedValue(k));
272 EcmaRuntimeCallInfo *info =
273 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, argsLength);
274 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
275 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
276 JSTaggedValue funcResult = JSFunction::Call(info);
277 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
278
279 arrayList->Set(thread, k, funcResult);
280 }
281
282 return JSTaggedValue::Undefined();
283 }
284
Set(JSThread * thread,const uint32_t index,JSTaggedValue value)285 JSTaggedValue JSAPIArrayList::Set(JSThread *thread, const uint32_t index, JSTaggedValue value)
286 {
287 if (GetLength().GetArrayLength() == 0) {
288 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
289 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
290 }
291 if (index >= GetLength().GetArrayLength()) {
292 ASSERT(GetLength().GetArrayLength() > 0);
293 std::ostringstream oss;
294 oss << "The value of \"index\" is out of range. It must be >= 0 && <= "
295 << (GetLength().GetArrayLength() - 1) << ". Received value is: " << index;
296 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
297 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
298 }
299
300 TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
301 elements->Set(thread, index, value);
302 return JSTaggedValue::Undefined();
303 }
304
SubArrayList(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value1,const JSHandle<JSTaggedValue> & value2)305 JSTaggedValue JSAPIArrayList::SubArrayList(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
306 const JSHandle<JSTaggedValue> &value1,
307 const JSHandle<JSTaggedValue> &value2)
308 {
309 int length = arrayList->GetLength().GetInt();
310 int fromIndex = JSTaggedValue::ToInt32(thread, value1);
311 int toIndex = JSTaggedValue::ToInt32(thread, value2);
312 int32_t size = length > toIndex ? toIndex : length;
313 if (length <= 0) {
314 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
315 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
316 }
317 if (fromIndex < 0 || fromIndex >= size) {
318 std::ostringstream oss;
319 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
320 << ". Received value is: " << fromIndex;
321 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
322 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
323 }
324 if (toIndex <= fromIndex || toIndex < 0 || toIndex > length) {
325 std::ostringstream oss;
326 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
327 << ". Received value is: " << toIndex;
328 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
329 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
330 }
331
332 int endIndex = toIndex >= length - 1 ? length - 1 : toIndex;
333 int newLength = toIndex == length ? length - fromIndex : endIndex - fromIndex;
334 JSHandle<JSAPIArrayList> subArrayList = thread->GetEcmaVM()->GetFactory()->NewJSAPIArrayList(newLength);
335 if (newLength == 0) {
336 return subArrayList.GetTaggedValue();
337 }
338 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
339 ASSERT(!elements->IsDictionaryMode());
340 subArrayList->SetLength(thread, JSTaggedValue(newLength));
341
342 for (int i = 0; i < newLength; i++) {
343 subArrayList->Set(thread, i, elements->Get(fromIndex + i));
344 }
345
346 return subArrayList.GetTaggedValue();
347 }
348
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)349 JSTaggedValue JSAPIArrayList::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
350 const JSHandle<JSTaggedValue> &callbackFn,
351 const JSHandle<JSTaggedValue> &thisArg)
352 {
353 JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(thisHandle);
354 uint32_t length = arrayList->GetSize();
355 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
356 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
357 const int32_t argsLength = 3;
358 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
359 for (uint32_t k = 0; k < length; k++) {
360 kValue.Update(arrayList->Get(thread, k));
361 key.Update(JSTaggedValue(k));
362 EcmaRuntimeCallInfo *info =
363 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, argsLength);
364 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
365 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
366 JSTaggedValue funcResult = JSFunction::Call(info);
367 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
368 if (length != arrayList->GetSize()) {
369 length = arrayList->GetSize();
370 }
371 }
372
373 return JSTaggedValue::Undefined();
374 }
375
GrowCapacity(const JSThread * thread,const JSHandle<JSAPIArrayList> & obj,uint32_t capacity)376 JSHandle<TaggedArray> JSAPIArrayList::GrowCapacity(const JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
377 uint32_t capacity)
378 {
379 JSHandle<TaggedArray> oldElements(thread, obj->GetElements());
380 ASSERT(!oldElements->IsDictionaryMode());
381 uint32_t oldCapacity = oldElements->GetLength();
382 if (capacity < oldCapacity) {
383 return oldElements;
384 }
385 uint32_t newCapacity = ComputeCapacity(capacity);
386 JSHandle<TaggedArray> newElements =
387 thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, oldCapacity, newCapacity);
388
389 obj->SetElements(thread, newElements);
390 return newElements;
391 }
392
Has(const JSTaggedValue value) const393 bool JSAPIArrayList::Has(const JSTaggedValue value) const
394 {
395 TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
396 uint32_t length = GetSize();
397 if (length == 0) {
398 return false;
399 }
400
401 for (uint32_t i = 0; i < length; i++) {
402 if (JSTaggedValue::SameValue(elements->Get(i), value)) {
403 return true;
404 }
405 }
406 return false;
407 }
408
OwnKeys(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)409 JSHandle<TaggedArray> JSAPIArrayList::OwnKeys(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
410 {
411 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
412 }
413
OwnEnumKeys(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)414 JSHandle<TaggedArray> JSAPIArrayList::OwnEnumKeys(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
415 {
416 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
417 }
418
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key)419 bool JSAPIArrayList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
420 const JSHandle<JSTaggedValue> &key)
421 {
422 uint32_t index = 0;
423 if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
424 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
425 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
426 CString errorMsg =
427 "The type of \"index\" can not obtain attributes of no-number type. Received value is: "
428 + ConvertToString(*result);
429 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
430 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
431 }
432
433 uint32_t length = obj->GetLength().GetArrayLength();
434 if (length == 0) {
435 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
436 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
437 }
438 if (index >= length) {
439 ASSERT(length > 0);
440 std::ostringstream oss;
441 oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
442 << ". Received value is: " << index;
443 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
444 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
445 }
446
447 obj->Get(thread, index);
448 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
449 return true;
450 }
451
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)452 JSTaggedValue JSAPIArrayList::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
453 {
454 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
455 JSHandle<JSAPIArrayListIterator> iter(factory->NewJSAPIArrayListIterator(obj));
456
457 return iter.GetTaggedValue();
458 }
459
GetProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key)460 OperationResult JSAPIArrayList::GetProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
461 const JSHandle<JSTaggedValue> &key)
462 {
463 int length = obj->GetLength().GetInt();
464 JSHandle<JSTaggedValue> indexKey = key;
465 if (indexKey->IsDouble()) {
466 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
467 // For integer which is greater than INT32_MAX, it will remain TaggedDouble
468 indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
469 }
470 if (!indexKey->IsInt()) {
471 CString errorMsg = "The type of \"index\" must be small integer.";
472 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
473 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
474 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
475 }
476
477 int index = indexKey->GetInt();
478 if (index < 0 || index >= length) {
479 std::ostringstream oss;
480 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
481 << ". Received value is: " << index;
482 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
483 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
484 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
485 }
486
487 return OperationResult(thread, obj->Get(thread, index), PropertyMetaData(false));
488 }
489
SetProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)490 bool JSAPIArrayList::SetProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
491 const JSHandle<JSTaggedValue> &key,
492 const JSHandle<JSTaggedValue> &value)
493 {
494 int length = obj->GetLength().GetInt();
495 int index = static_cast<int>(key->GetNumber());
496 if (index < 0 || index >= length) {
497 return false;
498 }
499
500 obj->Set(thread, index, value.GetTaggedValue());
501 return true;
502 }
503 } // namespace panda::ecmascript
504