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_array.h"
17
18 #include "ecmascript/accessor_data.h"
19 #include "ecmascript/base/array_helper.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/js_tagged_value-inl.h"
23 #include "ecmascript/object_factory.h"
24 #include "ecmascript/object_fast_operator-inl.h"
25
26 namespace panda::ecmascript {
LengthGetter(JSThread * thread,const JSHandle<JSObject> & self)27 JSTaggedValue JSArray::LengthGetter([[maybe_unused]] JSThread *thread, const JSHandle<JSObject> &self)
28 {
29 return JSArray::Cast(*self)->GetLength();
30 }
31
LengthSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)32 bool JSArray::LengthSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
33 bool mayThrow)
34 {
35 uint32_t newLen = 0;
36 if (!JSTaggedValue::ToArrayLength(thread, value, &newLen) && mayThrow) {
37 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
38 }
39
40 if (!IsArrayLengthWritable(thread, self)) {
41 if (mayThrow) {
42 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property", false);
43 }
44 return false;
45 }
46
47 uint32_t oldLen = JSArray::Cast(*self)->GetArrayLength();
48 JSArray::SetCapacity(thread, self, oldLen, newLen);
49 return true;
50 }
51
ArrayCreate(JSThread * thread,JSTaggedNumber length)52 JSHandle<JSTaggedValue> JSArray::ArrayCreate(JSThread *thread, JSTaggedNumber length)
53 {
54 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
55 JSHandle<JSTaggedValue> arrayFunction = env->GetArrayFunction();
56 return JSArray::ArrayCreate(thread, length, arrayFunction);
57 }
58
59 // 9.4.2.2 ArrayCreate(length, proto)
ArrayCreate(JSThread * thread,JSTaggedNumber length,const JSHandle<JSTaggedValue> & newTarget)60 JSHandle<JSTaggedValue> JSArray::ArrayCreate(JSThread *thread, JSTaggedNumber length,
61 const JSHandle<JSTaggedValue> &newTarget)
62 {
63 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
64 // Assert: length is an integer Number ≥ 0.
65 ASSERT_PRINT(length.IsInteger() && length.GetNumber() >= 0, "length must be positive integer");
66 // 2. If length is −0, let length be +0.
67 double arrayLength = length.GetNumber();
68 if (arrayLength > MAX_ARRAY_INDEX) {
69 JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
70 THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception);
71 }
72 uint32_t normalArrayLength = length.ToUint32();
73
74 // 8. Set the [[Prototype]] internal slot of A to proto.
75 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
76 JSHandle<JSFunction> arrayFunc(env->GetArrayFunction());
77 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(arrayFunc), newTarget);
78 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
79 // 9. Set the [[Extensible]] internal slot of A to true.
80 obj->GetJSHClass()->SetExtensible(true);
81
82 // 10. Perform OrdinaryDefineOwnProperty(A, "length", PropertyDescriptor{[[Value]]: length, [[Writable]]:
83 // true, [[Enumerable]]: false, [[Configurable]]: false}).
84 JSArray::Cast(*obj)->SetArrayLength(thread, normalArrayLength);
85
86 return JSHandle<JSTaggedValue>(obj);
87 }
88
89 // 9.4.2.3 ArraySpeciesCreate(originalArray, length)
ArraySpeciesCreate(JSThread * thread,const JSHandle<JSObject> & originalArray,JSTaggedNumber length)90 JSTaggedValue JSArray::ArraySpeciesCreate(JSThread *thread, const JSHandle<JSObject> &originalArray,
91 JSTaggedNumber length)
92 {
93 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
94 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
95 // Assert: length is an integer Number ≥ 0.
96 ASSERT_PRINT(length.IsInteger() && length.GetNumber() >= 0, "length must be positive integer");
97 // If length is −0, let length be +0.
98 int64_t arrayLength = length.GetNumber();
99 if (arrayLength == -0) {
100 arrayLength = +0;
101 }
102 // Let C be undefined.
103 // Let isArray be IsArray(originalArray).
104 JSHandle<JSTaggedValue> originalValue(originalArray);
105 bool isArray = originalValue->IsArray(thread);
106 // ReturnIfAbrupt(isArray).
107 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
108 // If isArray is true, then
109 JSHandle<JSTaggedValue> constructor(thread, JSTaggedValue::Undefined());
110 if (isArray) {
111 // Let C be Get(originalArray, "constructor").
112 auto *hclass = originalArray->GetJSHClass();
113 if (hclass->IsJSArray() && !hclass->HasConstructor()) {
114 return JSArray::ArrayCreate(thread, length).GetTaggedValue();
115 }
116 JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
117 constructor = JSTaggedValue::GetProperty(thread, originalValue, constructorKey).GetValue();
118 // ReturnIfAbrupt(C).
119 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
120 // If IsConstructor(C) is true, then
121 if (constructor->IsConstructor()) {
122 // Let thisRealm be the running execution context’s Realm.
123 // Let realmC be GetFunctionRealm(C).
124 JSHandle<GlobalEnv> realmC = JSObject::GetFunctionRealm(thread, constructor);
125 // ReturnIfAbrupt(realmC).
126 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
127 // If thisRealm and realmC are not the same Realm Record, then
128 if (*realmC != *env) {
129 JSTaggedValue realmArrayConstructor = realmC->GetArrayFunction().GetTaggedValue();
130 // If SameValue(C, realmC.[[intrinsics]].[[%Array%]]) is true, let C be undefined.
131 if (JSTaggedValue::SameValue(constructor.GetTaggedValue(), realmArrayConstructor)) {
132 return JSArray::ArrayCreate(thread, length).GetTaggedValue();
133 }
134 }
135 }
136
137 // If Type(C) is Object, then
138 if (constructor->IsECMAObject()) {
139 // Let C be Get(C, @@species).
140 JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
141 constructor = JSTaggedValue::GetProperty(thread, constructor, speciesSymbol).GetValue();
142 // ReturnIfAbrupt(C).
143 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
144 // If C is null, let C be undefined.
145 if (constructor->IsNull()) {
146 return JSArray::ArrayCreate(thread, length).GetTaggedValue();
147 }
148 }
149 }
150
151 // If C is undefined, return ArrayCreate(length).
152 if (constructor->IsUndefined()) {
153 return JSArray::ArrayCreate(thread, length).GetTaggedValue();
154 }
155 // If IsConstructor(C) is false, throw a TypeError exception.
156 if (!constructor->IsConstructor()) {
157 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a constructor", JSTaggedValue::Exception());
158 }
159 // Return Construct(C, «length»).
160 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
161 EcmaRuntimeCallInfo *info =
162 EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 1);
163 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
164 info->SetCallArg(JSTaggedValue(arrayLength));
165 JSTaggedValue result = JSFunction::Construct(info);
166
167 // NOTEIf originalArray was created using the standard built-in Array constructor for
168 // a Realm that is not the Realm of the running execution context, then a new Array is
169 // created using the Realm of the running execution context. This maintains compatibility
170 // with Web browsers that have historically had that behaviour for the Array.prototype methods
171 // that now are defined using ArraySpeciesCreate.
172 return result;
173 }
174
SetCapacity(JSThread * thread,const JSHandle<JSObject> & array,uint32_t oldLen,uint32_t newLen)175 void JSArray::SetCapacity(JSThread *thread, const JSHandle<JSObject> &array, uint32_t oldLen, uint32_t newLen)
176 {
177 TaggedArray *element = TaggedArray::Cast(array->GetElements().GetTaggedObject());
178
179 if (element->IsDictionaryMode()) {
180 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
181 uint32_t numOfElements = array->GetNumberOfElements();
182 uint32_t newNumOfElements = newLen;
183 if (newLen < oldLen && numOfElements != 0U) {
184 JSHandle<NumberDictionary> dictHandle(thread, element);
185 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(numOfElements);
186 GetAllElementKeys(thread, array, 0, newArr);
187 for (uint32_t i = numOfElements - 1; i >= newLen; i--) {
188 JSTaggedValue value = newArr->Get(i);
189 uint32_t output = 0;
190 JSTaggedValue::StringToElementIndex(value, &output);
191 JSTaggedValue key(static_cast<int>(output));
192 int entry = dictHandle->FindEntry(key);
193 uint32_t attr = dictHandle->GetAttributes(entry).GetValue();
194 PropertyAttributes propAttr(attr);
195 if (propAttr.IsConfigurable()) {
196 JSHandle<NumberDictionary> newDict = NumberDictionary::Remove(thread, dictHandle, entry);
197 array->SetElements(thread, newDict);
198 if (i == 0) {
199 newNumOfElements = i;
200 break;
201 }
202 } else {
203 newNumOfElements = i + 1;
204 break;
205 }
206 }
207 }
208 JSArray::Cast(*array)->SetArrayLength(thread, newNumOfElements);
209 return;
210 }
211 uint32_t capacity = element->GetLength();
212 if (newLen <= capacity) {
213 // judge if need to cut down the array size, else fill the unused tail with holes
214 CheckAndCopyArray(thread, JSHandle<JSArray>(array));
215 array->FillElementsWithHoles(thread, newLen, oldLen < capacity ? oldLen : capacity);
216 }
217 if (JSObject::ShouldTransToDict(oldLen, newLen)) {
218 JSObject::ElementsToDictionary(thread, array);
219 } else if (newLen > capacity) {
220 JSObject::GrowElementsCapacity(thread, array, newLen);
221 }
222 JSArray::Cast(*array)->SetArrayLength(thread, newLen);
223 }
224
ArraySetLength(JSThread * thread,const JSHandle<JSObject> & array,const PropertyDescriptor & desc)225 bool JSArray::ArraySetLength(JSThread *thread, const JSHandle<JSObject> &array, const PropertyDescriptor &desc)
226 {
227 JSHandle<JSTaggedValue> lengthKeyHandle(thread->GlobalConstants()->GetHandledLengthString());
228
229 // 1. If the [[Value]] field of Desc is absent, then
230 if (!desc.HasValue()) {
231 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
232 return JSObject::OrdinaryDefineOwnProperty(thread, array, lengthKeyHandle, desc);
233 }
234 // 2. Let newLenDesc be a copy of Desc.
235 // (Actual copying is not necessary.)
236 PropertyDescriptor newLenDesc = desc;
237 // 3. - 7. Convert Desc.[[Value]] to newLen.
238 uint32_t newLen = 0;
239 if (!JSTaggedValue::ToArrayLength(thread, desc.GetValue(), &newLen)) {
240 THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", false);
241 }
242 // 8. Set newLenDesc.[[Value]] to newLen.
243 // (Done below, if needed.)
244 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
245 PropertyDescriptor oldLenDesc(thread);
246 [[maybe_unused]] bool success = GetOwnProperty(thread, array, lengthKeyHandle, oldLenDesc);
247 // 10. (Assert)
248 ASSERT(success);
249
250 // 11. Let oldLen be oldLenDesc.[[Value]].
251 uint32_t oldLen = 0;
252 JSTaggedValue::ToArrayLength(thread, oldLenDesc.GetValue(), &oldLen);
253 // 12. If newLen >= oldLen, then
254 if (newLen >= oldLen) {
255 // 8. Set newLenDesc.[[Value]] to newLen.
256 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
257 newLenDesc.SetValue(JSHandle<JSTaggedValue>(thread, JSTaggedValue(newLen)));
258 return JSObject::OrdinaryDefineOwnProperty(thread, array, lengthKeyHandle, newLenDesc);
259 }
260 // 13. If oldLenDesc.[[Writable]] is false, return false.
261 if (!oldLenDesc.IsWritable() ||
262 // Also handle the {configurable: true} case since we later use
263 // JSArray::SetLength instead of OrdinaryDefineOwnProperty to change
264 // the length, and it doesn't have access to the descriptor anymore.
265 newLenDesc.IsConfigurable()) {
266 return false;
267 }
268 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
269 // let newWritable be true.
270 bool newWritable = false;
271 if (!newLenDesc.HasWritable() || newLenDesc.IsWritable()) {
272 newWritable = true;
273 }
274 // 15. Else,
275 // 15a. Need to defer setting the [[Writable]] attribute to false in case
276 // any elements cannot be deleted.
277 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
278 // 15c. Set newLenDesc.[[Writable]] to true.
279 // (Not needed.)
280
281 // Most of steps 16 through 19 is implemented by JSArray::SetCapacity.
282 JSArray::SetCapacity(thread, array, oldLen, newLen);
283 // Steps 19d-ii, 20.
284 if (!newWritable) {
285 PropertyDescriptor readonly(thread);
286 readonly.SetWritable(false);
287 success = JSObject::DefineOwnProperty(thread, array, lengthKeyHandle, readonly);
288 ASSERT_PRINT(success, "DefineOwnProperty of length must be success here!");
289 }
290
291 // Steps 19d-v, 21. Return false if there were non-deletable elements.
292 uint32_t arrayLength = JSArray::Cast(*array)->GetArrayLength();
293 return arrayLength == newLen;
294 }
295
PropertyKeyToArrayIndex(JSThread * thread,const JSHandle<JSTaggedValue> & key,uint32_t * output)296 bool JSArray::PropertyKeyToArrayIndex(JSThread *thread, const JSHandle<JSTaggedValue> &key, uint32_t *output)
297 {
298 return JSTaggedValue::ToArrayLength(thread, key, output) && *output <= JSArray::MAX_ARRAY_INDEX;
299 }
300
301 // 9.4.2.1 [[DefineOwnProperty]] ( P, Desc)
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & array,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)302 bool JSArray::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, const JSHandle<JSTaggedValue> &key,
303 const PropertyDescriptor &desc)
304 {
305 // 1. Assert: IsPropertyKey(P) is true.
306 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key!");
307 // 2. If P is "length", then
308 if (IsLengthString(thread, key)) {
309 // a. Return ArraySetLength(A, Desc).
310 return ArraySetLength(thread, array, desc);
311 }
312 // 3. Else if P is an array index, then
313 // already do in step 4.
314 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
315 bool success = JSObject::OrdinaryDefineOwnProperty(thread, array, key, desc);
316 if (success) {
317 JSTaggedValue constructorKey = thread->GlobalConstants()->GetConstructorString();
318 if (key.GetTaggedValue() == constructorKey) {
319 array->GetJSHClass()->SetHasConstructor(true);
320 return true;
321 }
322 }
323 return success;
324 }
325
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & array,uint32_t index,const PropertyDescriptor & desc)326 bool JSArray::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, uint32_t index,
327 const PropertyDescriptor &desc)
328 {
329 return JSObject::OrdinaryDefineOwnProperty(thread, array, index, desc);
330 }
331
IsLengthString(JSThread * thread,const JSHandle<JSTaggedValue> & key)332 bool JSArray::IsLengthString(JSThread *thread, const JSHandle<JSTaggedValue> &key)
333 {
334 return key.GetTaggedValue() == thread->GlobalConstants()->GetLengthString();
335 }
336
337 // ecma6 7.3 Operations on Objects
CreateArrayFromList(JSThread * thread,const JSHandle<TaggedArray> & elements)338 JSHandle<JSArray> JSArray::CreateArrayFromList(JSThread *thread, const JSHandle<TaggedArray> &elements)
339 {
340 // Assert: elements is a List whose elements are all ECMAScript language values.
341 // 2. Let array be ArrayCreate(0) (see 9.4.2.2).
342 uint32_t length = elements->GetLength();
343
344 // 4. For each element e of elements
345 auto env = thread->GetEcmaVM()->GetGlobalEnv();
346 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
347 JSHandle<JSFunction> arrayFunc(env->GetArrayFunction());
348 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(arrayFunc);
349 obj->GetJSHClass()->SetExtensible(true);
350 JSArray::Cast(*obj)->SetArrayLength(thread, length);
351
352 obj->SetElements(thread, elements);
353
354 return JSHandle<JSArray>(obj);
355 }
356
FastGetPropertyByValue(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index)357 JSHandle<JSTaggedValue> JSArray::FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
358 uint32_t index)
359 {
360 auto result = ObjectFastOperator::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), index);
361 return JSHandle<JSTaggedValue>(thread, result);
362 }
363
FastGetPropertyByValue(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)364 JSHandle<JSTaggedValue> JSArray::FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
365 const JSHandle<JSTaggedValue> &key)
366 {
367 auto result = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), key.GetTaggedValue());
368 return JSHandle<JSTaggedValue>(thread, result);
369 }
370
FastSetPropertyByValue(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value)371 bool JSArray::FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
372 const JSHandle<JSTaggedValue> &value)
373 {
374 return ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), index, value.GetTaggedValue());
375 }
376
FastSetPropertyByValue(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)377 bool JSArray::FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
378 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
379 {
380 return ObjectFastOperator::FastSetPropertyByValue(thread, obj.GetTaggedValue(), key.GetTaggedValue(),
381 value.GetTaggedValue());
382 }
383
Sort(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & fn)384 void JSArray::Sort(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &fn)
385 {
386 if (!fn->IsUndefined() && !fn->IsCallable()) {
387 THROW_TYPE_ERROR(thread, "Callable is false");
388 }
389
390 // 2. Let len be ToLength(Get(obj, "length")).
391 int64_t len = base::ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(obj));
392 // 3. ReturnIfAbrupt(len).
393 RETURN_IF_ABRUPT_COMPLETION(thread);
394
395 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
396 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
397 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
398 for (int64_t i = 1; i < len; i++) {
399 int64_t beginIndex = 0;
400 int64_t endIndex = i;
401 presentValue.Update(ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), i));
402 RETURN_IF_ABRUPT_COMPLETION(thread);
403 while (beginIndex < endIndex) {
404 int64_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
405 middleValue.Update(
406 ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), middleIndex));
407 RETURN_IF_ABRUPT_COMPLETION(thread);
408 int32_t compareResult = base::ArrayHelper::SortCompare(thread, fn, middleValue, presentValue);
409 RETURN_IF_ABRUPT_COMPLETION(thread);
410 if (compareResult > 0) {
411 endIndex = middleIndex;
412 } else {
413 beginIndex = middleIndex + 1;
414 }
415 }
416
417 if (endIndex >= 0 && endIndex < i) {
418 for (int64_t j = i; j > endIndex; j--) {
419 previousValue.Update(
420 ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), j - 1));
421 RETURN_IF_ABRUPT_COMPLETION(thread);
422 ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), j,
423 previousValue.GetTaggedValue());
424 RETURN_IF_ABRUPT_COMPLETION(thread);
425 }
426 ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), endIndex,
427 presentValue.GetTaggedValue());
428 RETURN_IF_ABRUPT_COMPLETION(thread);
429 }
430 }
431 }
432
IncludeInSortedValue(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & value)433 bool JSArray::IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
434 const JSHandle<JSTaggedValue> &value)
435 {
436 ASSERT(obj->IsJSArray());
437 JSHandle<JSArray> arrayObj = JSHandle<JSArray>::Cast(obj);
438 int32_t length = static_cast<int32_t>(arrayObj->GetArrayLength());
439 if (length == 0) {
440 return false;
441 }
442 int32_t left = 0;
443 int32_t right = length - 1;
444 while (left <= right) {
445 int32_t middle = (left + right) / 2;
446 JSHandle<JSTaggedValue> vv = JSArray::FastGetPropertyByValue(thread, obj, middle);
447 ComparisonResult res = JSTaggedValue::Compare(thread, vv, value);
448 if (res == ComparisonResult::EQUAL) {
449 return true;
450 } else if (res == ComparisonResult::LESS) {
451 left = middle + 1;
452 } else {
453 right = middle - 1;
454 }
455 }
456 return false;
457 }
458
ToTaggedArray(JSThread * thread,const JSHandle<JSTaggedValue> & obj)459 JSHandle<TaggedArray> JSArray::ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
460 {
461 ASSERT(obj->IsJSArray());
462 JSHandle<JSArray> arrayObj = JSHandle<JSArray>::Cast(obj);
463 uint32_t length = arrayObj->GetArrayLength();
464 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
465 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(length);
466 for (uint32_t idx = 0; idx < length; idx++) {
467 JSHandle<JSTaggedValue> vv = JSArray::FastGetPropertyByValue(thread, obj, idx);
468 taggedArray->Set(thread, idx, vv);
469 }
470 return taggedArray;
471 }
472
CheckAndCopyArray(const JSThread * thread,JSHandle<JSArray> obj)473 void JSArray::CheckAndCopyArray(const JSThread *thread, JSHandle<JSArray> obj)
474 {
475 JSHandle<TaggedArray> arr(thread, obj->GetElements());
476 // Check whether array is shared in the nonmovable space before set properties and elements.
477 // If true, then really copy array in the semi space.
478 if (arr.GetTaggedValue().IsCOWArray()) {
479 auto newArray = thread->GetEcmaVM()->GetFactory()->CopyArray(arr, arr->GetLength(), arr->GetLength(),
480 JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
481 obj->SetElements(thread, newArray.GetTaggedValue());
482 }
483 JSHandle<TaggedArray> prop(thread, obj->GetProperties());
484 if (prop.GetTaggedValue().IsCOWArray()) {
485 auto newProps = thread->GetEcmaVM()->GetFactory()->CopyArray(prop,
486 prop->GetLength(), prop->GetLength(), JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
487 obj->SetProperties(thread, newProps.GetTaggedValue());
488 }
489 }
490 } // namespace panda::ecmascript
491