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