• 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 = elements->Get(index);
68     if (TaggedArray::ShouldTrim(capacity, index)) {
69         elements->Trim(thread, index);
70     } else {
71         elements->Set(thread, index, JSTaggedValue::Hole());
72     }
73     receiver->SetArrayLength(thread, index);
74     return result;
75 }
76 
Splice(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv,uint32_t start,uint32_t insertCount,uint32_t actualDeleteCount)77 JSTaggedValue JSStableArray::Splice(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv,
78                                     uint32_t start, uint32_t insertCount, uint32_t actualDeleteCount)
79 {
80     JSThread *thread = argv->GetThread();
81     uint32_t len = receiver->GetArrayLength();
82     uint32_t argc = argv->GetArgsNumber();
83 
84     JSHandle<JSObject> thisObjHandle(receiver);
85     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(actualDeleteCount));
86     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
87     JSHandle<JSObject> newArrayHandle(thread, newArray);
88 
89     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
90     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
91     TaggedArray *srcElements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
92     JSMutableHandle<TaggedArray> srcElementsHandle(thread, srcElements);
93     if (newArray.IsStableJSArray(thread)) {
94         TaggedArray *destElements = TaggedArray::Cast(newArrayHandle->GetElements().GetTaggedObject());
95         if (actualDeleteCount > destElements->GetLength()) {
96             destElements = *JSObject::GrowElementsCapacity(thread, newArrayHandle, actualDeleteCount);
97         }
98 
99         for (uint32_t idx = 0; idx < actualDeleteCount; idx++) {
100             destElements->Set(thread, idx, srcElementsHandle->Get(start + idx));
101         }
102         JSHandle<JSArray>::Cast(newArrayHandle)->SetArrayLength(thread, actualDeleteCount);
103     } else {
104         JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
105         JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
106         uint32_t k = 0;
107         while (k < actualDeleteCount) {
108             uint32_t from = start + k;
109             fromKey.Update(JSTaggedValue(from));
110             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
111             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
112             if (exists) {
113                 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
114                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
115                 toKey.Update(JSTaggedValue(k));
116                 if (newArrayHandle->IsJSProxy()) {
117                     toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue());
118                 }
119                 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue);
120                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
121             }
122             k++;
123         }
124 
125         JSHandle<JSTaggedValue> deleteCount(thread, JSTaggedValue(actualDeleteCount));
126         JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, deleteCount,
127                                    true);
128         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
129     }
130     uint32_t oldCapacity = srcElementsHandle->GetLength();
131     uint32_t newCapacity = len - actualDeleteCount + insertCount;
132     if (insertCount < actualDeleteCount) {
133         JSArray::CheckAndCopyArray(thread, receiver);
134         srcElementsHandle.Update(receiver->GetElements());
135         for (uint32_t idx = start; idx < len - actualDeleteCount; idx++) {
136             auto element = srcElementsHandle->Get(idx + actualDeleteCount);
137             element = element.IsHole() ? JSTaggedValue::Undefined() : element;
138             srcElementsHandle->Set(thread, idx + insertCount, element);
139         }
140 
141         if (TaggedArray::ShouldTrim(oldCapacity, newCapacity)) {
142             srcElementsHandle->Trim(thread, newCapacity);
143         } else {
144             for (uint32_t idx = newCapacity; idx < len; idx++) {
145                 srcElementsHandle->Set(thread, idx, JSTaggedValue::Hole());
146             }
147         }
148     } else {
149         if (newCapacity > oldCapacity) {
150             srcElementsHandle.Update(JSObject::GrowElementsCapacity(thread, thisObjHandle, newCapacity));
151         }
152         for (uint32_t idx = len - actualDeleteCount; idx > start; idx--) {
153             auto element = srcElementsHandle->Get(idx + actualDeleteCount - 1);
154             element = element.IsHole() ? JSTaggedValue::Undefined() : element;
155             srcElementsHandle->Set(thread, idx + insertCount - 1, element);
156         }
157     }
158 
159     for (uint32_t i = 2, idx = start; i < argc; i++, idx++) {
160         srcElementsHandle->Set(thread, idx, argv->GetCallArg(i));
161     }
162 
163     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newCapacity));
164     JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true);
165     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
166     return newArrayHandle.GetTaggedValue();
167 }
168 
Shift(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)169 JSTaggedValue JSStableArray::Shift(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
170 {
171     JSThread *thread = argv->GetThread();
172     uint32_t length = receiver->GetArrayLength();
173     if (length == 0) {
174         return JSTaggedValue::Undefined();
175     }
176     JSArray::CheckAndCopyArray(thread, receiver);
177     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
178     auto result = elements->Get(0);
179     for (uint32_t k = 1; k < length; k++) {
180         auto kValue = elements->Get(k);
181         if (kValue.IsHole()) {
182             elements->Set(thread, k - 1, JSTaggedValue::Undefined());
183         } else {
184             elements->Set(thread, k - 1, kValue);
185         }
186     }
187     uint32_t capacity = elements->GetLength();
188     uint32_t index = length - 1;
189     if (TaggedArray::ShouldTrim(capacity, index)) {
190         elements->Trim(thread, index);
191     } else {
192         elements->Set(thread, index, JSTaggedValue::Hole());
193     }
194     receiver->SetArrayLength(thread, index);
195     return result;
196 }
197 
Join(JSHandle<JSArray> receiver,EcmaRuntimeCallInfo * argv)198 JSTaggedValue JSStableArray::Join(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
199 {
200     JSThread *thread = argv->GetThread();
201     uint32_t length = receiver->GetArrayLength();
202     JSHandle<JSTaggedValue> sepHandle = base::BuiltinsBase::GetCallArg(argv, 0);
203     int sep = ',';
204     uint32_t sepLength = 1;
205     JSHandle<EcmaString> sepStringHandle;
206     if (!sepHandle->IsUndefined()) {
207         if (sepHandle->IsString()) {
208             sepStringHandle = JSHandle<EcmaString>::Cast(sepHandle);
209         } else {
210             sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
211             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
212         }
213         if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) {
214             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
215             sep = EcmaStringAccessor(sepStringHandle).Get(0);
216         } else if (EcmaStringAccessor(sepStringHandle).GetLength() == 0) {
217             sep = JSStableArray::SeparatorFlag::MINUS_TWO;
218             sepLength = 0;
219         } else {
220             sep = JSStableArray::SeparatorFlag::MINUS_ONE;
221             sepLength = EcmaStringAccessor(sepStringHandle).GetLength();
222         }
223     }
224     if (length == 0) {
225         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
226         return globalConst->GetEmptyString();
227     }
228     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
229     size_t allocateLength = 0;
230     bool isOneByte = (sep != JSStableArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8();
231     CVector<JSHandle<EcmaString>> vec;
232     JSMutableHandle<JSTaggedValue> elementHandle(thread, JSTaggedValue::Undefined());
233     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
234     uint32_t elementslength = elements->GetLength();
235     uint32_t len = elementslength > length ? length : elementslength;
236     for (uint32_t k = 0; k < len; k++) {
237         JSTaggedValue element = elements->Get(k);
238         if (!element.IsUndefinedOrNull() && !element.IsHole()) {
239             if (!element.IsString()) {
240                 elementHandle.Update(element);
241                 JSHandle<EcmaString> strElement = JSTaggedValue::ToString(thread, elementHandle);
242                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
243                 element = strElement.GetTaggedValue();
244                 elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
245             }
246             auto nextStr = EcmaString::Cast(element.GetTaggedObject());
247             JSHandle<EcmaString> nextStrHandle(thread, nextStr);
248             vec.push_back(nextStrHandle);
249             isOneByte = EcmaStringAccessor(nextStr).IsUtf8() ? isOneByte : false;
250             allocateLength += EcmaStringAccessor(nextStr).GetLength();
251         } else {
252             vec.push_back(JSHandle<EcmaString>(globalConst->GetHandledEmptyString()));
253         }
254     }
255     if (len > 0) {
256         allocateLength += sepLength * (len - 1);
257     }
258     auto newString = EcmaStringAccessor::AllocStringObject(thread->GetEcmaVM(), allocateLength, isOneByte);
259     int current = 0;
260     DISALLOW_GARBAGE_COLLECTION;
261     for (uint32_t k = 0; k < len; k++) {
262         if (k > 0) {
263             if (sep >= 0) {
264                 EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
265             } else if (sep != JSStableArray::SeparatorFlag::MINUS_TWO) {
266                 EcmaStringAccessor::ReadData(newString, *sepStringHandle, current,
267                     allocateLength - static_cast<uint32_t>(current), sepLength);
268             }
269             current += static_cast<int>(sepLength);
270         }
271         JSHandle<EcmaString> nextStr = vec[k];
272         int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
273         EcmaStringAccessor::ReadData(newString, *nextStr, current,
274             allocateLength - static_cast<uint32_t>(current), nextLength);
275         current += nextLength;
276     }
277     ASSERT_PRINT(
278         isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
279     return JSTaggedValue(newString);
280 }
281 
HandleFindIndexOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)282 JSTaggedValue JSStableArray::HandleFindIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
283                                                      JSHandle<JSTaggedValue> callbackFnHandle,
284                                                      JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
285 {
286     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
287     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
288     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
289     JSTaggedValue callResult = base::BuiltinsBase::GetTaggedBoolean(false);
290     const int32_t argsLength = 3; // 3: ?kValue, k, O?
291     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
292     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
293     while (k < len) {
294         // Elements of thisObjHandle may change.
295         array.Update(thisObjHandle->GetElements());
296         kValue.Update(array->Get(k));
297         EcmaRuntimeCallInfo *info =
298             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
299         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
300         info->SetCallArg(kValue.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
301         callResult = JSFunction::Call(info);
302         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, callResult);
303         if (callResult.ToBoolean()) {
304             return callResult;
305         }
306         if (array->GetLength() < len) {
307             len = array->GetLength();
308         }
309         if (base::ArrayHelper::GetArrayLength(thread, thisObjVal) > static_cast<int64_t>(len)) {
310             array.Update(thisObjHandle->GetElements());
311         }
312         k++;
313         if (!thisObjVal->IsStableJSArray(thread)) {
314             return callResult;
315         }
316     }
317     return callResult;
318 }
319 
HandleEveryOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)320 JSTaggedValue JSStableArray::HandleEveryOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
321                                                  JSHandle<JSTaggedValue> callbackFnHandle,
322                                                  JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
323 {
324     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
325     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
326     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
327     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
328     const int32_t argsLength = 3; // 3: ?kValue, k, O?
329     JSTaggedValue callResult = base::BuiltinsBase::GetTaggedBoolean(true);
330     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
331     while (k < len) {
332         // Elements of thisObjHandle may change.
333         array.Update(thisObjHandle->GetElements());
334         kValue.Update(array->Get(k));
335         if (!kValue.GetTaggedValue().IsHole()) {
336             EcmaRuntimeCallInfo *info =
337                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
338             info->SetCallArg(kValue.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
339             callResult = JSFunction::Call(info);
340             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
341             if (array->GetLength() < len) {
342                 len = array->GetLength();
343             }
344         } else if (JSTaggedValue::HasProperty(thread, thisObjVal, k)) {
345             JSHandle<JSTaggedValue> kValue1 = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
346             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
347             EcmaRuntimeCallInfo *info =
348                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
349             info->SetCallArg(kValue1.GetTaggedValue(), JSTaggedValue(k), thisObjVal.GetTaggedValue());
350             callResult = JSFunction::Call(info);
351             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
352         }
353         if (!callResult.ToBoolean()) {
354             return base::BuiltinsBase::GetTaggedBoolean(false);
355         }
356         k++;
357         if (!thisObjVal->IsStableJSArray(thread)) {
358             return base::BuiltinsBase::GetTaggedBoolean(true);
359         }
360     }
361     return base::BuiltinsBase::GetTaggedBoolean(true);
362 }
363 
HandleforEachOfStable(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> callbackFnHandle,JSHandle<JSTaggedValue> thisArgHandle,uint32_t & k)364 JSTaggedValue JSStableArray::HandleforEachOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
365                                                    JSHandle<JSTaggedValue> callbackFnHandle,
366                                                    JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k)
367 {
368     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
369     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
370     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
371     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
372     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
373     const int32_t argsLength = 3; // 3: ?kValue, k, O?
374     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
375     if (array->GetLength() <= k) {
376         return base::BuiltinsBase::GetTaggedBoolean(false);
377     }
378     while (k < len) {
379         // Elements of thisObjHandle may change.
380         array.Update(thisObjHandle->GetElements());
381         kValue.Update(array->Get(k));
382         if (!kValue.GetTaggedValue().IsHole()) {
383             key.Update(JSTaggedValue(k));
384             EcmaRuntimeCallInfo *info =
385                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
386             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
387             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
388             JSTaggedValue funcResult = JSFunction::Call(info);
389             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
390             if (array->GetLength() < len) {
391                 len = array->GetLength();
392             }
393         } else if (JSTaggedValue::HasProperty(thread, thisObjVal, k)) {
394             key.Update(JSTaggedValue(k));
395             JSHandle<JSTaggedValue> kValue1 = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
396             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
397             EcmaRuntimeCallInfo *info =
398                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
399             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
400             info->SetCallArg(kValue1.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
401             JSTaggedValue funcResult = JSFunction::Call(info);
402             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
403         }
404         k++;
405         if (!thisObjVal->IsStableJSArray(thread)) {
406             break;
407         }
408     }
409     return base::BuiltinsBase::GetTaggedBoolean(true);
410 }
411 
IndexOf(JSThread * thread,JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> searchElement,uint32_t from,uint32_t len)412 JSTaggedValue JSStableArray::IndexOf(JSThread *thread, JSHandle<JSTaggedValue> receiver,
413                                      JSHandle<JSTaggedValue> searchElement, uint32_t from, uint32_t len)
414 {
415     JSHandle<TaggedArray> elements(thread, JSHandle<JSObject>::Cast(receiver)->GetElements());
416     while (from < len) {
417         JSTaggedValue value = elements->Get(from);
418         if (!value.IsUndefined() && !value.IsHole()) {
419             if (JSTaggedValue::StrictEqual(searchElement.GetTaggedValue(), value)) {
420                 return JSTaggedValue(from);
421             }
422         } else {
423             bool exist = JSTaggedValue::HasProperty(thread, receiver, from);
424             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
425             if (exist) {
426                 JSHandle<JSTaggedValue> kValueHandle = JSArray::FastGetPropertyByValue(thread, receiver, from);
427                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
428                 if (JSTaggedValue::StrictEqual(thread, searchElement, kValueHandle)) {
429                     return JSTaggedValue(from);
430                 }
431             }
432         }
433         from++;
434     }
435     return JSTaggedValue(-1);
436 }
437 
Filter(JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,EcmaRuntimeCallInfo * argv,uint32_t & k,uint32_t & toIndex)438 JSTaggedValue JSStableArray::Filter(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle,
439                                     EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t &toIndex)
440 {
441     JSThread *thread = argv->GetThread();
442     JSHandle<JSTaggedValue> callbackFnHandle = base::BuiltinsBase::GetCallArg(argv, 0);
443     JSHandle<JSTaggedValue> thisArgHandle = base::BuiltinsBase::GetCallArg(argv, 1);
444     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
445     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
446     JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined());
447     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
448     const int32_t argsLength = 3; // 3: ?kValue, k, O?
449     uint64_t len = static_cast<uint64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
450     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
451     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
452     while (k < len) {
453         // Elements of thisObjHandle may change.
454         array.Update(thisObjHandle->GetElements());
455         kValue.Update(array->Get(k));
456         if (!kValue.GetTaggedValue().IsHole()) {
457             key.Update(JSTaggedValue(k));
458             EcmaRuntimeCallInfo *info =
459                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
460             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
461             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
462             JSTaggedValue callResult = JSFunction::Call(info);
463             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
464             if (array->GetLength() < len) {
465                 len = array->GetLength();
466             }
467             bool boolResult = callResult.ToBoolean();
468             if (boolResult) {
469                 toIndexHandle.Update(JSTaggedValue(toIndex));
470                 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toIndexHandle, kValue);
471                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
472                 toIndex++;
473             }
474         }
475         k++;
476         if (!thisObjVal->IsStableJSArray(thread)) {
477             break;
478         }
479     }
480     return base::BuiltinsBase::GetTaggedDouble(true);
481 }
482 
Map(JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,EcmaRuntimeCallInfo * argv,uint32_t & k,uint32_t len)483 JSTaggedValue JSStableArray::Map(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle,
484                                  EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t len)
485 {
486     JSThread *thread = argv->GetThread();
487     JSHandle<JSTaggedValue> callbackFnHandle = base::BuiltinsBase::GetCallArg(argv, 0);
488     JSHandle<JSTaggedValue> thisArgHandle = base::BuiltinsBase::GetCallArg(argv, 1);
489     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
490     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
491     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
492     JSMutableHandle<JSTaggedValue> mapResultHandle(thread, JSTaggedValue::Undefined());
493     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
494     const int32_t argsLength = 3; // 3: ?kValue, k, O?
495     JSMutableHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
496     while (k < len) {
497         // Elements of thisObjHandle may change.
498         array.Update(thisObjHandle->GetElements());
499         kValue.Update(array->Get(k));
500         if (!kValue.GetTaggedValue().IsHole()) {
501             key.Update(JSTaggedValue(k));
502             EcmaRuntimeCallInfo *info =
503                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
504             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
505             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
506             JSTaggedValue mapResult = JSFunction::Call(info);
507             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
508             mapResultHandle.Update(mapResult);
509             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle);
510             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
511             if (array->GetLength() < len) {
512                 len = array->GetLength();
513             }
514         }
515         k++;
516         if (!thisObjVal->IsStableJSArray(thread)) {
517             break;
518         }
519     }
520     return base::BuiltinsBase::GetTaggedDouble(true);
521 }
522 
Reverse(JSThread * thread,JSHandle<JSObject> thisObjHandle,JSHandle<JSTaggedValue> thisHandle,int64_t & lower,uint32_t len)523 JSTaggedValue JSStableArray::Reverse(JSThread *thread, JSHandle<JSObject> thisObjHandle,
524                                      JSHandle<JSTaggedValue> thisHandle, int64_t &lower, uint32_t len)
525 {
526     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
527     if (thisObjHandle->IsJSArray()) {
528         JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(thisObjHandle));
529     }
530     JSHandle<TaggedArray> array(thread, thisObjHandle->GetElements());
531     JSMutableHandle<JSTaggedValue> lowerP(thread, JSTaggedValue::Undefined());
532     JSMutableHandle<JSTaggedValue> upperP(thread, JSTaggedValue::Undefined());
533     JSMutableHandle<JSTaggedValue> lowerValueHandle(thread, JSTaggedValue::Undefined());
534     JSMutableHandle<JSTaggedValue> upperValueHandle(thread, JSTaggedValue::Undefined());
535     int64_t middle = std::floor(len / 2);
536     while (lower != middle) {
537         if (array->GetLength() != len) {
538             break;
539         }
540         int64_t upper = static_cast<int64_t>(len) - lower - 1;
541         lowerP.Update(JSTaggedValue(lower));
542         upperP.Update(JSTaggedValue(upper));
543         bool lowerExists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, lowerP));
544         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
545         if (lowerExists) {
546             lowerValueHandle.Update(array->Get(lower));
547         }
548         bool upperExists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, upperP));
549         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
550         if (upperExists) {
551             upperValueHandle.Update(array->Get(upper));
552         }
553         if (lowerExists && upperExists) {
554             array->Set(thread, lower, upperValueHandle.GetTaggedValue());
555             array->Set(thread, upper, lowerValueHandle.GetTaggedValue());
556         } else if (upperExists) {
557             array->Set(thread, lower, upperValueHandle.GetTaggedValue());
558             JSTaggedValue::SetProperty(thread, thisObjVal, lowerP, upperValueHandle, true);
559             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, upperP);
560             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
561         } else if (lowerExists) {
562             array->Set(thread, upper, lowerValueHandle.GetTaggedValue());
563             JSTaggedValue::SetProperty(thread, thisObjVal, upperP, lowerValueHandle, true);
564             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, lowerP);
565             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
566         }
567         lower++;
568     }
569     return base::BuiltinsBase::GetTaggedDouble(true);
570 }
571 
Concat(JSThread * thread,JSHandle<JSObject> newArrayHandle,JSHandle<JSObject> thisObjHandle,int64_t & k,int64_t & n)572 JSTaggedValue JSStableArray::Concat(JSThread *thread, JSHandle<JSObject> newArrayHandle,
573                                     JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &n)
574 {
575     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
576     int64_t thisLen = base::ArrayHelper::GetArrayLength(thread, thisObjVal);
577     JSHandle<TaggedArray> arrayFrom(thread, thisObjHandle->GetElements());
578     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
579     while (k < thisLen) {
580         if (arrayFrom->GetLength() != thisLen) {
581             break;
582         }
583         toKey.Update(JSTaggedValue(n));
584         JSTaggedValue kValue = arrayFrom->Get(k);
585         if (!kValue.IsHole()) {
586             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, JSHandle<JSTaggedValue>(thread, kValue));
587             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
588         }
589         n++;
590         k++;
591     }
592     return base::BuiltinsBase::GetTaggedDouble(true);
593 }
594 
FastCopyFromArrayToTypedArray(JSThread * thread,JSHandle<JSTypedArray> & targetArray,DataViewType targetType,uint32_t targetOffset,uint32_t srcLength,JSHandle<TaggedArray> & elements)595 JSTaggedValue JSStableArray::FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle<JSTypedArray> &targetArray,
596                                                            DataViewType targetType, uint32_t targetOffset,
597                                                            uint32_t srcLength, JSHandle<TaggedArray> &elements)
598 {
599     JSHandle<JSTaggedValue> targetBuffer(thread, targetArray->GetViewedArrayBuffer());
600     // If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
601     if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
602         THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
603                                     JSTaggedValue::Exception());
604     }
605     uint32_t targetLength = targetArray->GetArrayLength();
606     uint32_t targetByteOffset = targetArray->GetByteOffset();
607     uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType);
608     if (srcLength + targetOffset > targetLength) {
609         THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of length and targetOffset is greater than targetLength.",
610                                      JSTaggedValue::Exception());
611     }
612     uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset * targetElementSize + targetByteOffset);
613     JSMutableHandle<JSTaggedValue> elem(thread, JSTaggedValue::Hole());
614     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
615     ContentType contentType = targetArray->GetContentType();
616     for (uint32_t i = 0; i < srcLength; i++) {
617         elem.Update(elements->Get(i));
618         if (contentType == ContentType::BigInt) {
619             kValue.Update(JSTaggedValue::ToBigInt(thread, elem));
620         } else {
621             kValue.Update(JSTaggedValue::ToNumber(thread, elem));
622         }
623         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
624         BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
625                                               targetType, kValue, true);
626         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
627         targetByteIndex += targetElementSize;
628     }
629     return JSTaggedValue::Undefined();
630 }
631 }  // namespace panda::ecmascript
632