1 /*
2 * Copyright (c) 2022-2024 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_api/js_api_lightweightset.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_function.h"
22
23 #include <codecvt>
24
25 namespace panda::ecmascript {
26 using ContainerError = containers::ContainerError;
27 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,const JSHandle<JSTaggedValue> & value)28 bool JSAPILightWeightSet::Add(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
29 const JSHandle<JSTaggedValue> &value)
30 {
31 CheckAndCopyValues(thread, obj);
32 uint32_t hashCode = obj->Hash(thread, value.GetTaggedValue());
33 JSHandle<TaggedArray> hashArray(thread, obj->GetHashes(thread));
34 JSHandle<TaggedArray> valueArray(thread, obj->GetValues(thread));
35 int32_t size = static_cast<int32_t>(obj->GetLength());
36 int32_t index = obj->GetHashIndex(thread, value, size);
37 if (index >= 0) {
38 return false;
39 }
40 index ^= JSAPILightWeightSet::HASH_REBELLION;
41 if (index < size) {
42 obj->AdjustArray(thread, hashArray, index, size, true);
43 obj->AdjustArray(thread, valueArray, index, size, true);
44 }
45 uint32_t capacity = hashArray->GetLength();
46 if (size + 1 >= static_cast<int32_t>(capacity)) {
47 // need expanding
48 uint32_t newCapacity = capacity << 1U;
49 hashArray = thread->GetEcmaVM()->GetFactory()->CopyArray(hashArray, capacity, newCapacity);
50 valueArray = thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
51 obj->SetHashes(thread, hashArray);
52 obj->SetValues(thread, valueArray);
53 }
54 hashArray->Set(thread, index, JSTaggedValue(hashCode));
55 valueArray->Set(thread, index, value.GetTaggedValue());
56 size++;
57 obj->SetLength(size);
58 return true;
59 }
60
Get(const JSThread * thread,const uint32_t index)61 JSTaggedValue JSAPILightWeightSet::Get(const JSThread *thread, const uint32_t index)
62 {
63 TaggedArray *valueArray = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
64 return valueArray->Get(thread, index);
65 }
66
CreateSlot(const JSThread * thread,const uint32_t capacity)67 JSHandle<TaggedArray> JSAPILightWeightSet::CreateSlot(const JSThread *thread, const uint32_t capacity)
68 {
69 ASSERT_PRINT(capacity > 0, "size must be a non-negative integer");
70 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
71 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity);
72 for (uint32_t i = 0; i < capacity; i++) {
73 taggedArray->Set(thread, i, JSTaggedValue::Hole());
74 }
75 return taggedArray;
76 }
77
GetHashIndex(const JSThread * thread,const JSHandle<JSTaggedValue> & value,int32_t size)78 int32_t JSAPILightWeightSet::GetHashIndex(const JSThread *thread, const JSHandle<JSTaggedValue> &value, int32_t size)
79 {
80 uint32_t hashCode = Hash(thread, value.GetTaggedValue());
81 int32_t index = BinarySearchHashes(thread, hashCode, size);
82 if (index < 0) {
83 return index;
84 }
85 TaggedArray *valueArray = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
86 if (index < size && (JSTaggedValue::SameValue(thread, valueArray->Get(thread, index), value.GetTaggedValue()))) {
87 return index;
88 }
89 TaggedArray *hashArray = TaggedArray::Cast(GetHashes(thread).GetTaggedObject());
90 int32_t right = index;
91 while (right < size && (hashArray->Get(thread, right).GetNumber() == hashCode)) {
92 if (JSTaggedValue::SameValue(thread, valueArray->Get(thread, right), value.GetTaggedValue())) {
93 return right;
94 }
95 right++;
96 }
97 int32_t left = index - 1;
98 while (left >= 0 && ((hashArray->Get(thread, left).GetNumber() == hashCode))) {
99 if (JSTaggedValue::SameValue(thread, valueArray->Get(thread, left), value.GetTaggedValue())) {
100 return left;
101 }
102 left--;
103 }
104 return -right;
105 }
106
BinarySearchHashes(const JSThread * thread,uint32_t hash,int32_t size)107 int32_t JSAPILightWeightSet::BinarySearchHashes(const JSThread *thread, uint32_t hash, int32_t size)
108 {
109 int32_t low = 0;
110 int32_t high = size - 1;
111 TaggedArray *hashArray = TaggedArray::Cast(GetHashes(thread).GetTaggedObject());
112 while (low <= high) {
113 int32_t mid = (low + high) >> 1U;
114 uint32_t midVal = (uint32_t)(hashArray->Get(thread, static_cast<uint32_t>(mid)).GetNumber());
115 if (midVal < hash) {
116 low = mid + 1;
117 } else {
118 if (midVal <= hash) {
119 return mid;
120 }
121 high = mid - 1;
122 }
123 }
124 return -(low + 1);
125 }
126
AddAll(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,const JSHandle<JSTaggedValue> & value)127 bool JSAPILightWeightSet::AddAll(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
128 const JSHandle<JSTaggedValue> &value)
129 {
130 bool changed = false;
131 JSHandle<JSAPILightWeightSet> srcLightWeightSet = JSHandle<JSAPILightWeightSet>::Cast(value);
132 uint32_t srcSize = srcLightWeightSet->GetSize();
133 uint32_t size = obj->GetSize();
134 obj->EnsureCapacity(thread, obj, size + srcSize);
135 JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
136 for (uint32_t i = 0; i < srcSize; i++) {
137 element.Update(srcLightWeightSet->GetValueAt(thread, i));
138 changed |= JSAPILightWeightSet::Add(thread, obj, element);
139 }
140 return changed;
141 }
142
EnsureCapacity(const JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,uint32_t minimumCapacity)143 void JSAPILightWeightSet::EnsureCapacity(const JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
144 uint32_t minimumCapacity)
145 {
146 TaggedArray *hashes = TaggedArray::Cast(obj->GetValues(thread).GetTaggedObject());
147 uint32_t capacity = hashes->GetLength();
148 uint32_t newCapacity = capacity;
149 if (capacity > minimumCapacity) {
150 return;
151 }
152 // adjust
153 while (newCapacity <= minimumCapacity) {
154 newCapacity = newCapacity << 1U;
155 }
156 obj->SizeCopy(thread, obj, capacity, newCapacity);
157 }
158
SizeCopy(const JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,uint32_t capacity,uint32_t newCapacity)159 void JSAPILightWeightSet::SizeCopy(const JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
160 uint32_t capacity, uint32_t newCapacity)
161 {
162 JSHandle<TaggedArray> hashArray(thread, obj->GetHashes(thread));
163 JSHandle<TaggedArray> valueArray(thread, obj->GetValues(thread));
164 hashArray = thread->GetEcmaVM()->GetFactory()->CopyArray(hashArray, capacity, newCapacity);
165 valueArray = thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
166
167 obj->SetValues(thread, hashArray);
168 obj->SetHashes(thread, valueArray);
169 }
170
IsEmpty()171 bool JSAPILightWeightSet::IsEmpty()
172 {
173 return GetLength() == 0;
174 }
175
GetValueAt(const JSThread * thread,int32_t index)176 JSTaggedValue JSAPILightWeightSet::GetValueAt(const JSThread *thread, int32_t index)
177 {
178 int32_t size = static_cast<int32_t>(GetLength());
179 if (index < 0 || index >= size) {
180 return JSTaggedValue::Undefined();
181 }
182 TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
183 return values->Get(thread, index);
184 }
185
GetHashAt(const JSThread * thread,int32_t index)186 JSTaggedValue JSAPILightWeightSet::GetHashAt(const JSThread *thread, int32_t index)
187 {
188 int32_t size = static_cast<int32_t>(GetLength());
189 if (index < 0 || index >= size) {
190 return JSTaggedValue::Undefined();
191 }
192 TaggedArray *values = TaggedArray::Cast(GetHashes(thread).GetTaggedObject());
193 return values->Get(thread, index);
194 }
195
HasAll(const JSThread * thread,const JSHandle<JSTaggedValue> & value)196 bool JSAPILightWeightSet::HasAll(const JSThread *thread, const JSHandle<JSTaggedValue> &value)
197 {
198 bool result = false;
199 uint32_t relocate = 0;
200 JSAPILightWeightSet *lightweightSet = JSAPILightWeightSet::Cast(value.GetTaggedValue().GetTaggedObject());
201 uint32_t size = GetLength();
202 uint32_t destSize = lightweightSet->GetLength();
203 TaggedArray *hashes = TaggedArray::Cast(GetHashes(thread).GetTaggedObject());
204 TaggedArray *destHashes = TaggedArray::Cast(lightweightSet->GetHashes(thread).GetTaggedObject());
205 if (destSize > size) {
206 return result;
207 }
208 for (uint32_t i = 0; i < destSize; i++) {
209 uint32_t destHashCode = destHashes->Get(thread, i).GetNumber();
210 result = false;
211 for (uint32_t j = relocate; j < size; j++) {
212 uint32_t hashCode = hashes->Get(thread, j).GetNumber();
213 if (destHashCode == hashCode) {
214 result = true;
215 relocate = j + 1;
216 break;
217 }
218 }
219 if (!result) {
220 break;
221 }
222 }
223 return result;
224 }
225
Has(const JSThread * thread,const JSHandle<JSTaggedValue> & value)226 bool JSAPILightWeightSet::Has(const JSThread *thread, const JSHandle<JSTaggedValue> &value)
227 {
228 uint32_t size = GetLength();
229 int32_t index = GetHashIndex(thread, value, size);
230 if (index < 0) {
231 return false;
232 }
233 return true;
234 }
235
HasHash(const JSThread * thread,const JSHandle<JSTaggedValue> & hashCode)236 bool JSAPILightWeightSet::HasHash(const JSThread *thread, const JSHandle<JSTaggedValue> &hashCode)
237 {
238 uint32_t size = GetLength();
239 int32_t index = BinarySearchHashes(thread, hashCode.GetTaggedValue().GetNumber(), size);
240 if (index < 0) {
241 return false;
242 }
243 return true;
244 }
245
Equal(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,const JSHandle<JSTaggedValue> & value)246 bool JSAPILightWeightSet::Equal(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
247 const JSHandle<JSTaggedValue> &value)
248 {
249 bool result = false;
250 JSHandle<TaggedArray> destHashes(thread, obj->GetValues(thread));
251 uint32_t destSize = obj->GetLength();
252 uint32_t srcSize = 0;
253 JSMutableHandle<TaggedArray> srcHashes(thread, obj->GetHashes(thread));
254 if (value.GetTaggedValue().IsJSAPILightWeightSet()) {
255 JSAPILightWeightSet *srcLightWeightSet = JSAPILightWeightSet::Cast(value.GetTaggedValue().GetTaggedObject());
256 srcSize = srcLightWeightSet->GetLength();
257 if (srcSize == 0 || destSize == 0) {
258 return false;
259 }
260 srcHashes.Update(srcLightWeightSet->GetHashes(thread));
261 }
262 if (value.GetTaggedValue().IsJSArray()) {
263 srcHashes.Update(JSArray::ToTaggedArray(thread, value));
264 srcSize = srcHashes->GetLength();
265 if (srcSize == 0 || destSize == 0) {
266 return false;
267 }
268 }
269 if (srcSize != destSize) {
270 return false;
271 }
272 for (uint32_t i = 0; i < destSize; i++) {
273 JSTaggedValue compareValue = destHashes->Get(thread, i);
274 JSTaggedValue values = srcHashes->Get(thread, i);
275 if (compareValue.IsNumber() && values.IsNumber()) {
276 result = JSTaggedValue::SameValueNumberic(compareValue, values);
277 }
278 if (compareValue.IsString() && values.IsString()) {
279 result =
280 JSTaggedValue::StringCompare(thread,
281 EcmaString::Cast(compareValue.GetTaggedObject()),
282 EcmaString::Cast(values.GetTaggedObject()));
283 }
284 if (!result) {
285 return result;
286 }
287 }
288 return result;
289 }
290
IncreaseCapacityTo(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,int32_t minCapacity)291 void JSAPILightWeightSet::IncreaseCapacityTo(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
292 int32_t minCapacity)
293 {
294 uint32_t capacity = TaggedArray::Cast(obj->GetValues(thread).GetTaggedObject())->GetLength();
295 int32_t intCapacity = static_cast<int32_t>(capacity);
296 if (minCapacity <= 0 || intCapacity >= minCapacity) {
297 std::ostringstream oss;
298 oss << "The value of \"minimumCapacity\" is out of range. It must be > " << intCapacity
299 << ". Received value is: " << minCapacity;
300 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
301 THROW_NEW_ERROR_AND_RETURN(thread, error);
302 }
303 JSHandle<TaggedArray> hashArray(thread, obj->GetHashes(thread));
304 JSHandle<TaggedArray> newElements =
305 thread->GetEcmaVM()->GetFactory()->NewAndCopyTaggedArray(hashArray,
306 static_cast<uint32_t>(minCapacity), capacity);
307 obj->SetHashes(thread, newElements);
308 }
309
GetIteratorObj(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj,IterationKind kind)310 JSHandle<JSTaggedValue> JSAPILightWeightSet::GetIteratorObj(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj,
311 IterationKind kind)
312 {
313 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
314 JSHandle<JSTaggedValue> iter =
315 JSHandle<JSTaggedValue>::Cast(factory->NewJSAPILightWeightSetIterator(obj, kind));
316 return iter;
317 }
318
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)319 JSTaggedValue JSAPILightWeightSet::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
320 const JSHandle<JSTaggedValue> &callbackFn,
321 const JSHandle<JSTaggedValue> &thisArg)
322 {
323 JSHandle<JSAPILightWeightSet> lightweightset = JSHandle<JSAPILightWeightSet>::Cast(thisHandle);
324 CheckAndCopyValues(thread, lightweightset);
325 uint32_t length = lightweightset->GetSize();
326 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
327 for (uint32_t k = 0; k < length; k++) {
328 JSTaggedValue kValue = lightweightset->GetValueAt(thread, k);
329 EcmaRuntimeCallInfo *info =
330 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3:three args
331 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
332 info->SetCallArg(kValue, kValue, thisHandle.GetTaggedValue());
333 JSTaggedValue funcResult = JSFunction::Call(info);
334 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
335 if (lightweightset->GetSize() != length) { // prevent length change
336 length = lightweightset->GetSize();
337 }
338 }
339 return JSTaggedValue::Undefined();
340 }
341
GetIndexOf(const JSThread * thread,JSHandle<JSTaggedValue> & value)342 int32_t JSAPILightWeightSet::GetIndexOf(const JSThread *thread, JSHandle<JSTaggedValue> &value)
343 {
344 uint32_t size = GetLength();
345 int32_t index = GetHashIndex(thread, value, size);
346 return index;
347 }
348
Remove(JSThread * thread,JSHandle<JSTaggedValue> & value)349 JSTaggedValue JSAPILightWeightSet::Remove(JSThread *thread, JSHandle<JSTaggedValue> &value)
350 {
351 uint32_t size = GetLength();
352 TaggedArray *valueArray = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
353 int32_t index = GetHashIndex(thread, value, size);
354 if (index < 0) {
355 return JSTaggedValue::Undefined();
356 }
357 JSTaggedValue result = valueArray->Get(thread, index);
358 RemoveAt(thread, index);
359 return result;
360 }
361
RemoveAt(JSThread * thread,int32_t index)362 bool JSAPILightWeightSet::RemoveAt(JSThread *thread, int32_t index)
363 {
364 uint32_t size = GetLength();
365 if (index < 0 || index >= static_cast<int32_t>(size)) {
366 return false;
367 }
368 JSHandle<TaggedArray> valueArray(thread, GetValues(thread));
369 JSHandle<TaggedArray> hashArray(thread, GetHashes(thread));
370 RemoveValue(thread, hashArray, static_cast<uint32_t>(index), true);
371 RemoveValue(thread, valueArray, static_cast<uint32_t>(index));
372 SetLength(size - 1);
373 return true;
374 }
375
RemoveValue(const JSThread * thread,JSHandle<TaggedArray> & taggedArray,uint32_t index,bool isHash)376 void JSAPILightWeightSet::RemoveValue(const JSThread *thread, JSHandle<TaggedArray> &taggedArray,
377 uint32_t index, bool isHash)
378 {
379 uint32_t len = GetLength();
380 ASSERT(index < len);
381 TaggedArray::RemoveElementByIndex(thread, taggedArray, index, len, isHash);
382 }
383
AdjustArray(JSThread * thread,JSHandle<TaggedArray> srcArray,uint32_t fromIndex,uint32_t toIndex,bool direction)384 void JSAPILightWeightSet::AdjustArray(JSThread *thread, JSHandle<TaggedArray> srcArray, uint32_t fromIndex,
385 uint32_t toIndex, bool direction)
386 {
387 uint32_t size = GetLength();
388 uint32_t idx = size - 1;
389 if (direction) {
390 while (fromIndex < toIndex) {
391 JSTaggedValue value = srcArray->Get(thread, idx);
392 srcArray->Set(thread, idx + 1, value);
393 idx--;
394 fromIndex++;
395 }
396 } else {
397 uint32_t moveSize = size - fromIndex;
398 for (uint32_t i = 0; i < moveSize; i++) {
399 if ((fromIndex + i) < size) {
400 JSTaggedValue value = srcArray->Get(thread, fromIndex + i);
401 srcArray->Set(thread, toIndex + i, value);
402 } else {
403 srcArray->Set(thread, toIndex + i, JSTaggedValue::Hole());
404 }
405 }
406 }
407 }
408
ToString(JSThread * thread,const JSHandle<JSAPILightWeightSet> & obj)409 JSTaggedValue JSAPILightWeightSet::ToString(JSThread *thread, const JSHandle<JSAPILightWeightSet> &obj)
410 {
411 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
412 std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
413
414 uint32_t length = obj->GetSize();
415 JSHandle<TaggedArray> valueArray(thread, obj->GetValues(thread));
416 std::u16string concatStr;
417 JSMutableHandle<JSTaggedValue> values(thread, JSTaggedValue::Undefined());
418 for (uint32_t k = 0; k < length; k++) {
419 std::u16string nextStr;
420 values.Update(valueArray->Get(thread, k));
421 if (!values->IsUndefined() && !values->IsNull()) {
422 JSHandle<EcmaString> nextStringHandle = JSTaggedValue::ToString(thread, values);
423 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
424 nextStr = EcmaStringAccessor(nextStringHandle).ToU16String(thread);
425 }
426 if (k > 0) {
427 concatStr.append(sepStr);
428 concatStr.append(nextStr);
429 continue;
430 }
431 concatStr.append(nextStr);
432 }
433 char16_t *char16tData = concatStr.data();
434 auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
435 uint32_t u16strSize = concatStr.size();
436 return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
437 }
438
Clear(JSThread * thread)439 void JSAPILightWeightSet::Clear(JSThread *thread)
440 {
441 TaggedArray *hashArray = TaggedArray::Cast(GetHashes(thread).GetTaggedObject());
442 TaggedArray *valueArray = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
443 uint32_t size = GetLength();
444 for (uint32_t index = 0; index < size; index++) {
445 hashArray->Set(thread, index, JSTaggedValue::Hole());
446 valueArray->Set(thread, index, JSTaggedValue::Hole());
447 }
448 SetLength(0);
449 }
450
Hash(const JSThread * thread,JSTaggedValue key)451 uint32_t JSAPILightWeightSet::Hash(const JSThread *thread, JSTaggedValue key)
452 {
453 if (key.IsDouble() && key.GetDouble() == 0.0) {
454 key = JSTaggedValue(0);
455 }
456 if (key.IsSymbol()) {
457 auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
458 return symbolString->GetHashField();
459 }
460 if (key.IsString()) {
461 auto keyString = EcmaString::Cast(key.GetTaggedObject());
462 return EcmaStringAccessor(keyString).GetHashcode(thread);
463 }
464 if (key.IsECMAObject()) {
465 uint32_t hash = static_cast<uint32_t>(ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread));
466 if (hash == 0) {
467 hash = static_cast<uint32_t>(base::RandomGenerator::GenerateIdentityHash());
468 JSHandle<ECMAObject> ecmaObj(thread, key);
469 ECMAObject::SetHash(thread, hash, ecmaObj);
470 }
471 return hash;
472 }
473 if (key.IsInt()) {
474 uint32_t hash = static_cast<uint32_t>(key.GetInt());
475 return hash;
476 }
477 uint64_t keyValue = key.GetRawData();
478 return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
479 }
480
CheckAndCopyValues(const JSThread * thread,JSHandle<JSAPILightWeightSet> obj)481 void JSAPILightWeightSet::CheckAndCopyValues(const JSThread *thread, JSHandle<JSAPILightWeightSet> obj)
482 {
483 JSHandle<TaggedArray> values(thread, obj->GetValues(thread));
484 // Check whether array is shared in the nonmovable space before set properties and elements.
485 // If true, then really copy array in the semi space.
486 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
487 if (values.GetTaggedValue().IsCOWArray()) {
488 auto newArray = factory->CopyArray(values, values->GetLength(), values->GetLength(),
489 JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
490 obj->SetValues(thread, newArray.GetTaggedValue());
491 }
492 }
493 } // namespace panda::ecmascript
494