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