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