• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_stable_array.h"
17 
18 #include "ecmascript/base/array_helper.h"
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/base/typed_array_helper-inl.h"
21 #include "ecmascript/builtins/builtins_arraybuffer.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
25 #include "ecmascript/js_array.h"
26 #include "ecmascript/js_tagged_value-inl.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tagged_array.h"
29 
30 namespace panda::ecmascript {
31 using TypedArrayHelper = base::TypedArrayHelper;
32 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
33 
Push(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)34 JSTaggedValue JSStableArray::Push(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
35 {
36     JSThread *thread = argv->GetThread();
37     uint32_t argc = argv->GetArgsNumber();
38     uint32_t oldLength = receiver->GetArrayLength();
39     uint32_t newLength = argc + oldLength;
40 
41     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
42     if (newLength > elements->GetLength()) {
43         elements = *JSObject::GrowElementsCapacity(thread, JSHandle<JSObject>::Cast(receiver), newLength);
44     }
45 
46     for (uint32_t k = 0; k < argc; k++) {
47         JSHandle<JSTaggedValue> value = argv->GetCallArg(k);
48         elements->Set(thread, oldLength + k, value.GetTaggedValue());
49     }
50     receiver->SetArrayLength(thread, newLength);
51 
52     return JSTaggedValue(newLength);
53 }
54 
Pop(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)55 JSTaggedValue JSStableArray::Pop(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
56 {
57     JSThread *thread = argv->GetThread();
58     uint32_t length = receiver->GetArrayLength();
59     if (length == 0) {
60         return JSTaggedValue::Undefined();
61     }
62 
63     JSArray::CheckAndCopyArray(thread, receiver);
64     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
65     uint32_t capacity = elements->GetLength();
66     uint32_t index = length - 1;
67     auto result = JSTaggedValue::Hole();
68     if (index < capacity) {
69         result = elements->Get(index);
70     }
71     if (!result.IsHole()) {
72         if (TaggedArray::ShouldTrim(capacity, index)) {
73             elements->Trim(thread, index);
74         } else {
75             elements->Set(thread, index, JSTaggedValue::Hole());
76         }
77     }
78     receiver->SetArrayLength(thread, index);
79     return result.IsHole() ? JSTaggedValue::Undefined() : result;
80 }
81 
Splice(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv,uint32_t start,uint32_t insertCount,uint32_t actualDeleteCount)82 JSTaggedValue JSStableArray::Splice(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv,
83                                     uint32_t start, uint32_t insertCount, uint32_t actualDeleteCount)
84 {
85     JSThread *thread = argv->GetThread();
86     uint32_t len = receiver->GetArrayLength();
87     uint32_t argc = argv->GetArgsNumber();
88 
89     JSHandle<JSObject> thisObjHandle(receiver);
90     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(actualDeleteCount));
91     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
92     JSHandle<JSObject> newArrayHandle(thread, newArray);
93 
94     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
95     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
96     TaggedArray *srcElements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
97     JSMutableHandle<TaggedArray> srcElementsHandle(thread, srcElements);
98     if (newArray.IsStableJSArray(thread)) {
99         TaggedArray *destElements = TaggedArray::Cast(newArrayHandle->GetElements().GetTaggedObject());
100         if (actualDeleteCount > destElements->GetLength()) {
101             destElements = *JSObject::GrowElementsCapacity(thread, newArrayHandle, actualDeleteCount);
102         }
103 
104         for (uint32_t idx = 0; idx < actualDeleteCount; idx++) {
105             if ((start + idx) >= srcElementsHandle->GetLength()) {
106                 destElements->Set(thread, idx, JSTaggedValue::Hole());
107             } else {
108                 destElements->Set(thread, idx, srcElementsHandle->Get(start + idx));
109             }
110         }
111         JSHandle<JSArray>::Cast(newArrayHandle)->SetArrayLength(thread, actualDeleteCount);
112     } else {
113         JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
114         JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
115         uint32_t k = 0;
116         while (k < actualDeleteCount) {
117             uint32_t from = start + k;
118             fromKey.Update(JSTaggedValue(from));
119             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
120             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
121             if (exists) {
122                 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
123                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
124                 toKey.Update(JSTaggedValue(k));
125                 if (newArrayHandle->IsJSProxy()) {
126                     toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue());
127                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
128                 }
129                 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue);
130                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
131             }
132             k++;
133         }
134 
135         JSHandle<JSTaggedValue> deleteCount(thread, JSTaggedValue(actualDeleteCount));
136         JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, deleteCount,
137                                    true);
138         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
139     }
140     uint32_t oldCapacity = srcElementsHandle->GetLength();
141     uint32_t newCapacity = len - actualDeleteCount + insertCount;
142     if (newCapacity > oldCapacity) {
143         srcElementsHandle.Update(JSObject::GrowElementsCapacity(thread, thisObjHandle, newCapacity));
144     }
145     if (insertCount < actualDeleteCount) {
146         JSArray::CheckAndCopyArray(thread, receiver);
147         srcElementsHandle.Update(receiver->GetElements());
148         for (uint32_t idx = start; idx < len - actualDeleteCount; idx++) {
149             auto element = JSTaggedValue::Hole();
150             if ((idx + actualDeleteCount) < srcElementsHandle->GetLength()) {
151                 element = srcElementsHandle->Get(idx + actualDeleteCount);
152             }
153             element = element.IsHole() ? JSTaggedValue::Undefined() : element;
154             if ((idx + insertCount) < srcElementsHandle->GetLength()) {
155                 srcElementsHandle->Set(thread, idx + insertCount, element);
156             }
157         }
158 
159         if ((oldCapacity > newCapacity) && TaggedArray::ShouldTrim(oldCapacity, newCapacity)) {
160             srcElementsHandle->Trim(thread, newCapacity);
161         } else {
162             for (uint32_t idx = newCapacity; idx < len; idx++) {
163                 if (idx < srcElementsHandle->GetLength()) {
164                     srcElementsHandle->Set(thread, idx, JSTaggedValue::Hole());
165                 }
166             }
167         }
168     } else {
169         for (uint32_t idx = len - actualDeleteCount; idx > start; idx--) {
170             auto element = srcElementsHandle->Get(idx + actualDeleteCount - 1);
171             element = element.IsHole() ? JSTaggedValue::Undefined() : element;
172             srcElementsHandle->Set(thread, idx + insertCount - 1, element);
173         }
174     }
175 
176     for (uint32_t i = 2, idx = start; i < argc; i++, idx++) {
177         srcElementsHandle->Set(thread, idx, argv->GetCallArg(i));
178     }
179 
180     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newCapacity));
181     JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true);
182     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
183     return newArrayHandle.GetTaggedValue();
184 }
185 
Shift(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)186 JSTaggedValue JSStableArray::Shift(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
187 {
188     JSThread *thread = argv->GetThread();
189     uint32_t length = receiver->GetArrayLength();
190     if (length == 0) {
191         return JSTaggedValue::Undefined();
192     }
193     JSArray::CheckAndCopyArray(thread, receiver);
194     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
195     auto result = elements->Get(0);
196     for (uint32_t k = 1; k < length; k++) {
197         auto kValue = elements->Get(k);
198         if (kValue.IsHole()) {
199             elements->Set(thread, k - 1, JSTaggedValue::Undefined());
200         } else {
201             elements->Set(thread, k - 1, kValue);
202         }
203     }
204     uint32_t capacity = elements->GetLength();
205     uint32_t index = length - 1;
206     if (TaggedArray::ShouldTrim(capacity, index)) {
207         elements->Trim(thread, index);
208     } else {
209         elements->Set(thread, index, JSTaggedValue::Hole());
210     }
211     receiver->SetArrayLength(thread, index);
212     return result.IsHole() ? JSTaggedValue::Undefined() : result;
213 }
214 
Join(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)215 JSTaggedValue JSStableArray::Join(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
216 {
217     JSThread *thread = argv->GetThread();
218     uint32_t length = receiver->GetArrayLength();
219     JSHandle<JSTaggedValue> sepHandle = base::BuiltinsBase::GetCallArg(argv, 0);
220     int sep = ',';
221     uint32_t sepLength = 1;
222     JSHandle<EcmaString> sepStringHandle;
223     auto context = thread->GetCurrentEcmaContext();
224     JSHandle<JSTaggedValue> receiverValue = JSHandle<JSTaggedValue>::Cast(receiver);
225     if (!sepHandle->IsUndefined()) {
226         if (sepHandle->IsString()) {
227             sepStringHandle = JSHandle<EcmaString>::Cast(sepHandle);
228         } else {
229             sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
230             RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
231         }
232         if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) {
233             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
234             sep = EcmaStringAccessor(sepStringHandle).Get(0);
235         } else if (EcmaStringAccessor(sepStringHandle).GetLength() == 0) {
236             sep = JSStableArray::SeparatorFlag::MINUS_TWO;
237             sepLength = 0;
238         } else {
239             sep = JSStableArray::SeparatorFlag::MINUS_ONE;
240             sepLength = EcmaStringAccessor(sepStringHandle).GetLength();
241         }
242     }
243     if (length == 0) {
244         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
245         context->JoinStackPopFastPath(receiverValue);
246         return globalConst->GetEmptyString();
247     }
248     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
249     size_t allocateLength = 0;
250     bool isOneByte = (sep != JSStableArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8();
251     CVector<JSHandle<EcmaString>> vec;
252     JSMutableHandle<JSTaggedValue> elementHandle(thread, JSTaggedValue::Undefined());
253     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
254     uint32_t elementsLength = elements->GetLength();
255     uint32_t len = elementsLength > length ? length : elementsLength;
256     if (elementsLength == 0 && length != 0) {
257         len = length;
258     }
259     for (uint32_t k = 0; k < len; k++) {
260         JSTaggedValue element = JSTaggedValue::Undefined();
261         if (k < elementsLength) {
262             element = elements->Get(k);
263         }
264         if (!element.IsUndefinedOrNull() && !element.IsHole()) {
265             if (!element.IsString()) {
266                 elementHandle.Update(element);
267                 JSHandle<EcmaString> strElement = JSTaggedValue::ToString(thread, elementHandle);
268                 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
269                 element = strElement.GetTaggedValue();
270                 elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
271             }
272             auto nextStr = EcmaString::Cast(element.GetTaggedObject());
273             JSHandle<EcmaString> nextStrHandle(thread, nextStr);
274             vec.push_back(nextStrHandle);
275             isOneByte = EcmaStringAccessor(nextStr).IsUtf8() ? isOneByte : false;
276             allocateLength += EcmaStringAccessor(nextStr).GetLength();
277         } else {
278             vec.push_back(JSHandle<EcmaString>(globalConst->GetHandledEmptyString()));
279         }
280     }
281     if (len > 0) {
282         allocateLength += sepLength * (len - 1);
283     }
284     auto newString = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), allocateLength, isOneByte);
285     int current = 0;
286     DISALLOW_GARBAGE_COLLECTION;
287     for (uint32_t k = 0; k < len; k++) {
288         if (k > 0) {
289             if (sep >= 0) {
290                 EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
291             } else if (sep != JSStableArray::SeparatorFlag::MINUS_TWO) {
292                 EcmaStringAccessor::ReadData(newString, *sepStringHandle, current,
293                     allocateLength - static_cast<uint32_t>(current), sepLength);
294             }
295             current += static_cast<int>(sepLength);
296         }
297         JSHandle<EcmaString> nextStr = vec[k];
298         int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
299         EcmaStringAccessor::ReadData(newString, *nextStr, current,
300             allocateLength - static_cast<uint32_t>(current), nextLength);
301         current += nextLength;
302     }
303     ASSERT_PRINT(
304         isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
305     context->JoinStackPopFastPath(receiverValue);
306     return JSTaggedValue(newString);
307 }
308 
HandleFindIndexOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)309 JSTaggedValue JSStableArray::HandleFindIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
310                                                      JSHandle<JSTaggedValue> callbackFnHandle,
311                                                      JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
312 {
313     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
314     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
315     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
316     JSTaggedValue callResult = base::BuiltinsBase::GetTaggedBoolean(false);
317     const int32_t argsLength = 3; // 3: ?kValue, k, O?
318     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
319     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
320     while (k < len) {
321         // Elements of thisObjHandle may change.
322         array.Update(thisObjHandle->GetElements());
323         kValue.Update(array->Get(k));
324         EcmaRuntimeCallInfo *info =
325             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
326         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
327         info->SetCallArg(kValue.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
328         callResult = JSFunction::Call(info);
329         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, callResult);
330         if (callResult.ToBoolean()) {
331             return callResult;
332         }
333         if (array->GetLength() < len) {
334             len = array->GetLength();
335         }
336         if (base::ArrayHelper::GetArrayLength(thread, thisObjVal) > static_cast<int64_t>(len)) {
337             array.Update(thisObjHandle->GetElements());
338         }
339         k++;
340         if (!thisObjVal->IsStableJSArray(thread)) {
341             return callResult;
342         }
343     }
344     return callResult;
345 }
346 
HandleFindLastIndexOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,int64_t & k)347 JSTaggedValue JSStableArray::HandleFindLastIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
348                                                          JSHandle<JSTaggedValue> callbackFnHandle,
349                                                          JSHandle<JSTaggedValue> thisArgHandle, int64_t &k)
350 {
351     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
352     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
353     JSTaggedValue callResult = base::BuiltinsBase::GetTaggedBoolean(false);
354     const int32_t argsLength = 3; // 3: ?kValue, k, O?
355     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
356     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
357     while (k >= 0) {
358         // Elements of thisObjHandle may change.
359         array.Update(thisObjHandle->GetElements());
360         kValue.Update(array->Get(k));
361         EcmaRuntimeCallInfo *info =
362             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
363         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
364         info->SetCallArg(kValue.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
365         callResult = JSFunction::Call(info);
366         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, callResult);
367         if (callResult.ToBoolean()) {
368             return callResult;
369         }
370         k--;
371         if (base::ArrayHelper::GetArrayLength(thread, thisObjVal) - 1 < k) {
372             return callResult;
373         }
374         if (!thisObjVal->IsStableJSArray(thread)) {
375             return callResult;
376         }
377     }
378     return callResult;
379 }
380 
HandleEveryOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)381 JSTaggedValue JSStableArray::HandleEveryOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
382                                                  JSHandle<JSTaggedValue> callbackFnHandle,
383                                                  JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
384 {
385     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
386     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
387     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
388     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
389     const int32_t argsLength = 3; // 3: ?kValue, k, O?
390     JSTaggedValue callResult = base::BuiltinsBase::GetTaggedBoolean(true);
391     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
392     while (k < len) {
393         // Elements of thisObjHandle may change.
394         array.Update(thisObjHandle->GetElements());
395         kValue.Update(array->Get(k));
396         if (!kValue.GetTaggedValue().IsHole()) {
397             EcmaRuntimeCallInfo *info =
398                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
399             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
400             info->SetCallArg(kValue.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
401             callResult = JSFunction::Call(info);
402             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
403             if (array->GetLength() < len) {
404                 len = array->GetLength();
405             }
406         } else if (JSTaggedValue::HasProperty(thread, thisObjVal, k)) {
407             JSHandle<JSTaggedValue> kValue1 = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
408             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
409             EcmaRuntimeCallInfo *info =
410                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
411             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
412             info->SetCallArg(kValue1.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
413             callResult = JSFunction::Call(info);
414             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
415         }
416         if (!callResult.ToBoolean()) {
417             return base::BuiltinsBase::GetTaggedBoolean(false);
418         }
419         k++;
420         if (!thisObjVal->IsStableJSArray(thread)) {
421             return base::BuiltinsBase::GetTaggedBoolean(true);
422         }
423     }
424     return base::BuiltinsBase::GetTaggedBoolean(true);
425 }
426 
HandleforEachOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)427 JSTaggedValue JSStableArray::HandleforEachOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
428                                                    JSHandle<JSTaggedValue> callbackFnHandle,
429                                                    JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
430 {
431     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
432     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
433     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
434     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
435     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
436     const int32_t argsLength = 3; // 3: ?kValue, k, O?
437     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
438     if (array->GetLength() <= k) {
439         return base::BuiltinsBase::GetTaggedBoolean(false);
440     }
441     while (k < len) {
442         // Elements of thisObjHandle may change.
443         array.Update(thisObjHandle->GetElements());
444         kValue.Update(array->Get(k));
445         if (!kValue.GetTaggedValue().IsHole()) {
446             key.Update(JSTaggedValue(k));
447             EcmaRuntimeCallInfo *info =
448                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
449             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
450             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
451             JSTaggedValue funcResult = JSFunction::Call(info);
452             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
453             if (array->GetLength() < len) {
454                 len = array->GetLength();
455             }
456         } else if (JSTaggedValue::HasProperty(thread, thisObjVal, k)) {
457             key.Update(JSTaggedValue(k));
458             JSHandle<JSTaggedValue> kValue1 = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
459             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
460             EcmaRuntimeCallInfo *info =
461                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
462             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
463             info->SetCallArg(kValue1.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
464             JSTaggedValue funcResult = JSFunction::Call(info);
465             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
466         }
467         k++;
468         if (!thisObjVal->IsStableJSArray(thread)) {
469             break;
470         }
471     }
472     return base::BuiltinsBase::GetTaggedBoolean(true);
473 }
474 
IndexOf(JSThread * thread,JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> searchElement,uint32_t from,uint32_t len)475 JSTaggedValue JSStableArray::IndexOf(JSThread *thread, JSHandle<JSTaggedValue> receiver,
476                                      JSHandle<JSTaggedValue> searchElement, uint32_t from, uint32_t len)
477 {
478     JSHandle<TaggedArray> elements(thread, JSHandle<JSObject>::Cast(receiver)->GetElements());
479     while (from < len) {
480         JSTaggedValue value = JSTaggedValue::Hole();
481         if (elements->GetLength() > from) {
482             value = elements->Get(from);
483         }
484         if (!value.IsUndefined() && !value.IsHole()) {
485             if (JSTaggedValue::StrictEqual(searchElement.GetTaggedValue(), value)) {
486                 return JSTaggedValue(from);
487             }
488         } else {
489             bool exist = JSTaggedValue::HasProperty(thread, receiver, from);
490             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
491             if (exist) {
492                 JSHandle<JSTaggedValue> kValueHandle = JSArray::FastGetPropertyByValue(thread, receiver, from);
493                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
494                 if (JSTaggedValue::StrictEqual(thread, searchElement, kValueHandle)) {
495                     return JSTaggedValue(from);
496                 }
497             }
498         }
499         from++;
500     }
501     return JSTaggedValue(-1);
502 }
503 
Filter(JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,EcmaRuntimeCallInfo * argv,uint32_t & k,uint32_t & toIndex)504 JSTaggedValue JSStableArray::Filter(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle,
505                                     EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t &toIndex)
506 {
507     JSThread *thread = argv->GetThread();
508     JSHandle<JSTaggedValue> callbackFnHandle = base::BuiltinsBase::GetCallArg(argv, 0);
509     JSHandle<JSTaggedValue> thisArgHandle = base::BuiltinsBase::GetCallArg(argv, 1);
510     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
511     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
512     JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined());
513     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
514     const int32_t argsLength = 3; // 3: ?kValue, k, O?
515     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
516     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
517     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
518     while (k < len) {
519         // Elements of thisObjHandle may change.
520         array.Update(thisObjHandle->GetElements());
521         kValue.Update(array->Get(k));
522         if (!kValue.GetTaggedValue().IsHole()) {
523             key.Update(JSTaggedValue(k));
524             EcmaRuntimeCallInfo *info =
525                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
526             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
527             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
528             JSTaggedValue callResult = JSFunction::Call(info);
529             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
530             if (array->GetLength() < len) {
531                 len = array->GetLength();
532             }
533             bool boolResult = callResult.ToBoolean();
534             if (boolResult) {
535                 toIndexHandle.Update(JSTaggedValue(toIndex));
536                 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toIndexHandle, kValue);
537                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
538                 toIndex++;
539             }
540         }
541         k++;
542         if (!thisObjVal->IsStableJSArray(thread)) {
543             break;
544         }
545     }
546     return base::BuiltinsBase::GetTaggedDouble(true);
547 }
548 
Map(JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,EcmaRuntimeCallInfo * argv,uint32_t & k,uint32_t len)549 JSTaggedValue JSStableArray::Map(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle,
550                                  EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t len)
551 {
552     JSThread *thread = argv->GetThread();
553     JSHandle<JSTaggedValue> callbackFnHandle = base::BuiltinsBase::GetCallArg(argv, 0);
554     JSHandle<JSTaggedValue> thisArgHandle = base::BuiltinsBase::GetCallArg(argv, 1);
555     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
556     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
557     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
558     JSMutableHandle<JSTaggedValue> mapResultHandle(thread, JSTaggedValue::Undefined());
559     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
560     const int32_t argsLength = 3; // 3: ?kValue, k, O?
561     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
562     while (k < len) {
563         // Elements of thisObjHandle may change.
564         array.Update(thisObjHandle->GetElements());
565         kValue.Update(array->Get(k));
566         if (!kValue.GetTaggedValue().IsHole()) {
567             key.Update(JSTaggedValue(k));
568             EcmaRuntimeCallInfo *info =
569                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
570             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
571             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
572             JSTaggedValue mapResult = JSFunction::Call(info);
573             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
574             mapResultHandle.Update(mapResult);
575             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle);
576             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
577             if (array->GetLength() < len) {
578                 len = array->GetLength();
579             }
580         }
581         k++;
582         if (!thisObjVal->IsStableJSArray(thread)) {
583             break;
584         }
585     }
586     return base::BuiltinsBase::GetTaggedDouble(true);
587 }
588 
Reverse(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> thisHandle,int64_t & lower,uint32_t len)589 JSTaggedValue JSStableArray::Reverse(JSThread *thread, JSHandle<JSObject> thisObjHandle,
590                                      JSHandle<JSTaggedValue> thisHandle, int64_t &lower, uint32_t len)
591 {
592     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
593     if (thisObjHandle->IsJSArray()) {
594         JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(thisObjHandle));
595     }
596     JSHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
597     JSMutableHandle<JSTaggedValue> lowerP(thread, JSTaggedValue::Undefined());
598     JSMutableHandle<JSTaggedValue> upperP(thread, JSTaggedValue::Undefined());
599     JSMutableHandle<JSTaggedValue> lowerValueHandle(thread, JSTaggedValue::Undefined());
600     JSMutableHandle<JSTaggedValue> upperValueHandle(thread, JSTaggedValue::Undefined());
601     int64_t middle = std::floor(len / 2);
602     while (lower != middle) {
603         if (array->GetLength() != len) {
604             break;
605         }
606         int64_t upper = static_cast<int64_t>(len) - lower - 1;
607         lowerP.Update(JSTaggedValue(lower));
608         upperP.Update(JSTaggedValue(upper));
609         bool lowerExists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, lowerP));
610         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
611         if (lowerExists) {
612             lowerValueHandle.Update(array->Get(lower));
613         }
614         bool upperExists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, upperP));
615         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
616         if (upperExists) {
617             upperValueHandle.Update(array->Get(upper));
618         }
619         if (lowerExists && upperExists) {
620             array->Set(thread, lower, upperValueHandle.GetTaggedValue());
621             array->Set(thread, upper, lowerValueHandle.GetTaggedValue());
622         } else if (upperExists) {
623             array->Set(thread, lower, upperValueHandle.GetTaggedValue());
624             JSTaggedValue::SetProperty(thread, thisObjVal, lowerP, upperValueHandle, true);
625             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
626             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, upperP);
627             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
628         } else if (lowerExists) {
629             array->Set(thread, upper, lowerValueHandle.GetTaggedValue());
630             JSTaggedValue::SetProperty(thread, thisObjVal, upperP, lowerValueHandle, true);
631             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
632             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, lowerP);
633             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
634         }
635         lower++;
636     }
637     return base::BuiltinsBase::GetTaggedDouble(true);
638 }
639 
Concat(JSThread * thread,JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,int64_t & k,int64_t & n)640 JSTaggedValue JSStableArray::Concat(JSThread *thread, JSHandle<JSObject> newArrayHandle,
641                                     JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &n)
642 {
643     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
644     int64_t thisLen = base::ArrayHelper::GetArrayLength(thread, thisObjVal);
645     JSHandle<TaggedArray> arrayFrom(thread, thisObjHandle->GetElements());
646     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
647     while (k < thisLen) {
648         if (arrayFrom->GetLength() != thisLen) {
649             break;
650         }
651         toKey.Update(JSTaggedValue(n));
652         JSTaggedValue kValue = arrayFrom->Get(k);
653         if (!kValue.IsHole()) {
654             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, JSHandle<JSTaggedValue>(thread, kValue));
655             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
656         }
657         n++;
658         k++;
659     }
660     return base::BuiltinsBase::GetTaggedDouble(true);
661 }
662 
FastCopyFromArrayToTypedArray(JSThread * thread,JSHandle<JSTypedArray> & targetArray,DataViewType targetType,uint32_t targetOffset,uint32_t srcLength,JSHandle<TaggedArray> & elements)663 JSTaggedValue JSStableArray::FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle<JSTypedArray> &targetArray,
664                                                            DataViewType targetType, uint32_t targetOffset,
665                                                            uint32_t srcLength, JSHandle<TaggedArray> &elements)
666 {
667     JSHandle<JSTaggedValue> targetBuffer(thread, targetArray->GetViewedArrayBufferOrByteArray());
668     // If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
669     if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
670         THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
671                                     JSTaggedValue::Exception());
672     }
673     uint32_t targetLength = targetArray->GetArrayLength();
674     uint32_t targetByteOffset = targetArray->GetByteOffset();
675     uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType);
676     if (srcLength + static_cast<uint64_t>(targetOffset) > targetLength) {
677         THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of length and targetOffset is greater than targetLength.",
678                                      JSTaggedValue::Exception());
679     }
680     uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset * targetElementSize + targetByteOffset);
681     JSMutableHandle<JSTaggedValue> elem(thread, JSTaggedValue::Hole());
682     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
683     ContentType contentType = targetArray->GetContentType();
684     uint32_t elemLen = elements->GetLength();
685     for (uint32_t i = 0; i < srcLength; i++) {
686         if (i < elemLen) {
687             elem.Update(elements->Get(i));
688         } else {
689             elem.Update(JSTaggedValue::Hole());
690         }
691         if (contentType == ContentType::BigInt) {
692             kValue.Update(JSTaggedValue::ToBigInt(thread, elem));
693         } else {
694             kValue.Update(JSTaggedValue::ToNumber(thread, elem));
695         }
696         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
697         BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
698                                               targetType, kValue, true);
699         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
700         targetByteIndex += targetElementSize;
701     }
702     return JSTaggedValue::Undefined();
703 }
704 
At(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)705 JSTaggedValue JSStableArray::At(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
706 {
707     JSThread *thread = argv->GetThread();
708     uint32_t thisLen = receiver->GetArrayLength();
709     if (thisLen == 0) {
710         return JSTaggedValue::Undefined();
711     }
712     JSTaggedNumber index = JSTaggedValue::ToInteger(thread, base::BuiltinsBase::GetCallArg(argv, 0));
713     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
714     int64_t relativeIndex = index.GetNumber();
715     int64_t k = 0;
716     if (relativeIndex >= 0) {
717         k = relativeIndex;
718     } else {
719         k = static_cast<int64_t>(thisLen) + relativeIndex;
720     }
721     if (k < 0 || k >= thisLen) {
722         return JSTaggedValue::Undefined();
723     }
724 
725     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
726     auto result = JSTaggedValue::Hole();
727     result = elements->Get(k);
728     return result.IsHole() ? JSTaggedValue::Undefined() : result;
729 }
730 
With(JSThread * thread,JSHandle<JSArray> receiver,int64_t insertCount,int64_t index,JSHandle<JSTaggedValue> value)731 JSTaggedValue JSStableArray::With(JSThread *thread, JSHandle<JSArray> receiver,
732                                   int64_t insertCount, int64_t index, JSHandle<JSTaggedValue> value)
733 {
734     JSHandle<JSObject> thisObjHandle(receiver);
735     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle,
736                                                          JSTaggedNumber(static_cast<uint32_t>(insertCount)));
737     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
738     JSHandle<JSObject> newArrayHandle(thread, newArray);
739 
740     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
741     TaggedArray *srcElements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
742     JSMutableHandle<TaggedArray> srcElementsHandle(thread, srcElements);
743     TaggedArray *destElements = TaggedArray::Cast(newArrayHandle->GetElements().GetTaggedObject());
744 
745     if (insertCount > destElements->GetLength()) {
746         destElements = *JSObject::GrowElementsCapacity(thread, newArrayHandle, insertCount);
747     }
748 
749     for (uint32_t idx = 0; idx < insertCount; idx++) {
750         if (idx == index) {
751             destElements->Set(thread, idx, value.GetTaggedValue());
752         } else {
753             auto kValue = srcElementsHandle->Get(idx);
754             if (kValue.IsHole()) {
755                 destElements->Set(thread, idx, JSTaggedValue::Undefined());
756             } else {
757                 destElements->Set(thread, idx, kValue);
758             }
759         }
760     }
761     JSHandle<JSArray>::Cast(newArrayHandle)->SetArrayLength(thread, insertCount);
762 
763     return newArrayHandle.GetTaggedValue();
764 }
765 
ToSpliced(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv,int64_t argc,int64_t actualStart,int64_t actualSkipCount,int64_t insertCount)766 JSTaggedValue JSStableArray::ToSpliced(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv,
767                                        int64_t argc, int64_t actualStart, int64_t actualSkipCount, int64_t insertCount)
768 {
769     JSThread *thread = argv->GetThread();
770 
771     JSHandle<JSObject> thisObjHandle(receiver);
772     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle,
773                                                          JSTaggedNumber(static_cast<uint32_t>(insertCount)));
774     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
775     JSHandle<JSObject> newArrayHandle(thread, newArray);
776 
777     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
778     TaggedArray *srcElements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
779     JSMutableHandle<TaggedArray> srcElementsHandle(thread, srcElements);
780     TaggedArray *destElements = TaggedArray::Cast(newArrayHandle->GetElements().GetTaggedObject());
781 
782     if (insertCount > destElements->GetLength()) {
783         destElements = *JSObject::GrowElementsCapacity(thread, newArrayHandle, insertCount);
784     }
785 
786     uint32_t i = 0, r = actualStart + actualSkipCount;
787 
788     for (uint32_t idx = 0; idx < actualStart; idx++, i++) {
789         auto kValue = srcElementsHandle->Get(idx);
790         if (kValue.IsHole()) {
791             destElements->Set(thread, i, JSTaggedValue::Undefined());
792         } else {
793             destElements->Set(thread, i, kValue);
794         }
795     }
796 
797     for (uint32_t pos = 2; pos < argc; ++pos) { // 2:2 means there two arguments before the insert items.
798         auto element = base::BuiltinsBase::GetCallArg(argv, pos);
799         destElements->Set(thread, i, element.GetTaggedValue());
800         ++i;
801     }
802 
803     while (i < insertCount) {
804         auto kValue = srcElementsHandle->Get(r);
805         if (kValue.IsHole()) {
806             destElements->Set(thread, i, JSTaggedValue::Undefined());
807         } else {
808             destElements->Set(thread, i, kValue);
809         }
810         ++i;
811         ++r;
812     }
813 
814     JSHandle<JSArray>::Cast(newArrayHandle)->SetArrayLength(thread, insertCount);
815 
816     return newArrayHandle.GetTaggedValue();
817 }
818 
ToReversed(JSThread * thread,JSHandle<JSArray> receiver,int64_t insertCount)819 JSTaggedValue JSStableArray::ToReversed(JSThread *thread, JSHandle<JSArray> receiver,
820                                         int64_t insertCount)
821 {
822     JSHandle<JSObject> thisObjHandle(receiver);
823     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle,
824                                                          JSTaggedNumber(static_cast<uint32_t>(insertCount)));
825     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
826     JSHandle<JSObject> newArrayHandle(thread, newArray);
827 
828     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
829     TaggedArray *srcElements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
830     JSMutableHandle<TaggedArray> srcElementsHandle(thread, srcElements);
831     TaggedArray *destElements = TaggedArray::Cast(newArrayHandle->GetElements().GetTaggedObject());
832 
833     if (insertCount > destElements->GetLength()) {
834         destElements = *JSObject::GrowElementsCapacity(thread, newArrayHandle, insertCount);
835     }
836 
837     for (uint32_t idx = 0; idx < insertCount; idx++) {
838         auto kValue = srcElementsHandle->Get(idx);
839         if (kValue.IsHole()) {
840             destElements->Set(thread, insertCount - idx - 1, JSTaggedValue::Undefined());
841         } else {
842             destElements->Set(thread, insertCount - idx - 1, kValue);
843         }
844     }
845     JSHandle<JSArray>::Cast(newArrayHandle)->SetArrayLength(thread, insertCount);
846 
847     return newArrayHandle.GetTaggedValue();
848 }
849 
Reduce(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSMutableHandle<JSTaggedValue> accumulator,int64_t & k,int64_t & len)850 JSTaggedValue JSStableArray::Reduce(JSThread *thread, JSHandle<JSObject> thisObjHandle,
851                                     JSHandle<JSTaggedValue> callbackFnHandle,
852                                     JSMutableHandle<JSTaggedValue> accumulator, int64_t &k, int64_t &len)
853 {
854     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
855     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
856     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
857     JSTaggedValue callResult = JSTaggedValue::Undefined();
858     while (k < len) {
859         array.Update(thisObjHandle->GetElements());
860         JSTaggedValue kValue(array->Get(k));
861         if (!kValue.IsHole()) {
862             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
863             const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
864             EcmaRuntimeCallInfo *info =
865                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, undefined, undefined, argsLength);
866             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
867             info->SetCallArg(accumulator.GetTaggedValue(), kValue, JSTaggedValue(k),
868                              thisObjVal.GetTaggedValue());
869             callResult = JSFunction::Call(info);
870             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
871             if (array->GetLength() < len) {
872                 len = array->GetLength();
873             }
874             accumulator.Update(callResult);
875         }
876         k++;
877         if (!thisObjVal->IsStableJSArray(thread)) {
878             break;
879         }
880     }
881     return base::BuiltinsBase::GetTaggedDouble(true);
882 }
883 }  // namespace panda::ecmascript
884