1 /*
2 * Copyright (c) 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_array.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/tests/test_helper.h"
19
20 using namespace panda::ecmascript;
21
22 namespace panda::test {
23 class BarrierTest : public BaseTestWithScope<true> {
24 };
25
HWTEST_F_L0(BarrierTest,YoungToYoungBatchCopy)26 HWTEST_F_L0(BarrierTest, YoungToYoungBatchCopy)
27 {
28 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
29 uint32_t arrayLength = 10;
30 JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
31 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
32 for (uint32_t i = 0; i < arrayLength; i++) {
33 JSHandle<JSFunction> newFun = factory->NewJSFunction(env);
34 srcArray->Set(thread, i, newFun);
35 }
36
37 JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
38 std::set<uintptr_t> LocalToShareBeforeCopy;
39
40 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
41 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
42 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
43 return true;
44 });
45
46 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
47 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
48 Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
49
50 // young to young, all the bitset should not be changed.
51 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
52 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
53 return true;
54 });
55
56 // check
57 for (uint32_t i = 0; i < arrayLength; i++) {
58 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
59 }
60 }
61
HWTEST_F_L0(BarrierTest,BatchCopyNoBarrier)62 HWTEST_F_L0(BarrierTest, BatchCopyNoBarrier)
63 {
64 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
65 uint32_t arrayLength = 10;
66 JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
67 for (uint32_t i = 0; i < arrayLength; i++) {
68 srcArray->Set(thread, i, JSTaggedValue(i));
69 }
70
71 JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
72 std::set<uintptr_t> LocalToShareBeforeCopy;
73
74 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
75 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
76 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
77 return true;
78 });
79
80 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
81 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
82 Barriers::CopyObjectPrimitive<false>(to, from, arrayLength);
83
84 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
85 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
86 return true;
87 });
88
89 // check
90 for (uint32_t i = 0; i < arrayLength; i++) {
91 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
92 }
93
94 JSHandle<TaggedArray> dstArray2 = factory->NewTaggedArray(arrayLength);
95 JSTaggedValue* to2 = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray2->GetData()));
96 JSTaggedValue* from2 = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
97 // barrier should also work for no heap value
98 Barriers::CopyObject<true, false>(thread, *dstArray, to2, from2, arrayLength);
99 // check
100 for (uint32_t i = 0; i < arrayLength; i++) {
101 EXPECT_EQ(dstArray2->Get(thread, i), srcArray->Get(thread, i));
102 }
103 }
104
HWTEST_F_L0(BarrierTest,LocalToShareBatchCopy)105 HWTEST_F_L0(BarrierTest, LocalToShareBatchCopy)
106 {
107 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
108 uint32_t arrayLength = 10;
109 JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
110 for (uint32_t i = 0; i < arrayLength; i++) {
111 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
112 // string longer than 1 will be in sweepable shared heap
113 srcArray->Set(thread, i, str);
114 }
115
116 JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
117 std::set<uintptr_t> LocalToShareBeforeCopy;
118
119 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
120 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
121 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
122 return true;
123 });
124
125 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
126 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
127 Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
128
129 std::set<uintptr_t> LocalToShareSlot;
130 for (uint32_t i = 0; i < arrayLength; i++) {
131 LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
132 }
133 // young to young, all the bitset should not be changed.
134 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy, &dstArray, arrayLength](
135 void* mem) {
136 if (!LocalToShareBeforeCopy.count(ToUintPtr(mem))) {
137 EXPECT_GE(ToUintPtr(mem), ToUintPtr(dstArray->GetData()));
138 EXPECT_LT(ToUintPtr(mem), ToUintPtr(dstArray->GetData()+arrayLength));
139 LocalToShareSlot.erase(ToUintPtr(mem));
140 } else {
141 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
142 }
143 return true;
144 });
145 EXPECT_TRUE(LocalToShareSlot.empty());
146 // check
147 for (uint32_t i = 0; i < arrayLength; i++) {
148 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
149 }
150 }
151
HWTEST_F_L0(BarrierTest,LocalToReadOnlyShareBatchCopy)152 HWTEST_F_L0(BarrierTest, LocalToReadOnlyShareBatchCopy)
153 {
154 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
155 uint32_t arrayLength = 10;
156 JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
157 for (uint32_t i = 0; i < arrayLength; i++) {
158 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i));
159 // One byte string is in readonly
160 srcArray->Set(thread, i, str);
161 }
162
163 JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
164 std::set<uintptr_t> LocalToShareBeforeCopy;
165
166 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
167 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
168 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
169 return true;
170 });
171
172 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
173 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
174 Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
175
176 std::set<uintptr_t> LocalToShareSlot;
177 for (uint32_t i = 0; i < arrayLength; i++) {
178 LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
179 }
180 // young to young, all the bitset should not be changed.
181 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy](
182 void* mem) {
183 EXPECT_FALSE(LocalToShareSlot.count(ToUintPtr(mem)));
184 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
185 return true;
186 });
187 // check
188 for (uint32_t i = 0; i < arrayLength; i++) {
189 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
190 }
191 }
192
HWTEST_F_L0(BarrierTest,LocalToShareMixBatchCopy)193 HWTEST_F_L0(BarrierTest, LocalToShareMixBatchCopy)
194 {
195 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
196 uint32_t arrayLength = 10;
197 JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
198 for (uint32_t i = 0; i < arrayLength; i++) {
199 if (i % 2 == 0) {
200 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
201 // One byte string is in readonly
202 srcArray->Set(thread, i, str);
203 } else {
204 srcArray->Set(thread, i, JSTaggedValue(i));
205 }
206 }
207
208 JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
209 std::set<uintptr_t> LocalToShareBeforeCopy;
210
211 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
212 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
213 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
214 return true;
215 });
216
217 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
218 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
219 Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
220
221 std::set<uintptr_t> LocalToShareSlot;
222 for (uint32_t i = 0; i < arrayLength; i++) {
223 if (i % 2 == 0) {
224 LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
225 }
226 }
227 // young to young, all the bitset should not be changed.
228 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy, &dstArray, arrayLength](
229 void* mem) {
230 if (!LocalToShareBeforeCopy.count(ToUintPtr(mem))) {
231 EXPECT_GE(ToUintPtr(mem), ToUintPtr(dstArray->GetData()));
232 EXPECT_LT(ToUintPtr(mem), ToUintPtr(dstArray->GetData()+arrayLength));
233 LocalToShareSlot.erase(ToUintPtr(mem));
234 } else {
235 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
236 }
237 return true;
238 });
239 EXPECT_TRUE(LocalToShareSlot.empty());
240 // check
241 for (uint32_t i = 0; i < arrayLength; i++) {
242 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
243 }
244 }
245
HWTEST_F_L0(BarrierTest,OldToNewBatchCopy)246 HWTEST_F_L0(BarrierTest, OldToNewBatchCopy)
247 {
248 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
249 uint32_t arrayLength = 10;
250 // length 50 will be in old
251 JSHandle<TaggedArray> srcArray = factory->NewOldSpaceTaggedArray(arrayLength);
252 JSHandle<TaggedArray> dstArray = factory->NewOldSpaceTaggedArray(arrayLength);
253
254 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
255 JSHandle<JSFunction> newFun = factory->NewJSFunction(env); // in young
256 for (uint32_t i = 0; i < 10; i++) {
257 srcArray->Set(thread, i, newFun);
258 }
259
260 std::set<uintptr_t> OldToNewSlot;
261 for (uint32_t i = 0; i < arrayLength; i++) {
262 if (Region::ObjectAddressToRange(srcArray->Get(thread, i).GetTaggedObject())->InYoungSpace()) {
263 OldToNewSlot.insert(ToUintPtr(dstArray->GetData() + i));
264 }
265 }
266 EXPECT_TRUE(!OldToNewSlot.empty());
267
268 std::set<uintptr_t> OldToNewBeforeCopy;
269 std::set<uintptr_t> LocalToShareBeforeCopy;
270
271 Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
272 dstRegion->IterateAllOldToNewBits([&OldToNewBeforeCopy](void* mem) {
273 OldToNewBeforeCopy.emplace(ToUintPtr(mem));
274 return true;
275 });
276 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
277 LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
278 return true;
279 });
280
281 JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
282 JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
283 Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
284
285 // young to young, all the bitset should not be changed.
286 dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
287 EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
288 return true;
289 });
290 // check
291 for (uint32_t i = 0; i < arrayLength; i++) {
292 EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
293 }
294 }
295
HWTEST_F_L0(BarrierTest,LocalToShareUnshift)296 HWTEST_F_L0(BarrierTest, LocalToShareUnshift)
297 {
298 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
299 uint32_t arrayLength = 40;
300 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
301 for (uint32_t i = 0; i < arrayLength; i++) {
302 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
303 // string longer than 1 will be in sweepable shared heap
304 array->Set(thread, i, str);
305 }
306 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
307
308 JSHandle<EcmaString> unshiftStr = factory->NewFromStdString("unshift");
309 auto unshiftFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
310 JSHandle<JSTaggedValue>(unshiftStr)).GetValue();
311 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, unshiftFunc.GetTaggedValue(),
312 jsArray.GetTaggedValue(),
313 thread->GlobalConstants()->GetUndefined(), 1);
314 info->SetCallArg(thread->GlobalConstants()->GetUndefined());
315 EcmaInterpreter::Execute(info);
316
317 array = JSHandle<TaggedArray>(thread, jsArray->GetElements());
318 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
319 std::set<uintptr_t> LocalToShareSlot;
320 for (uint32_t i = 1; i < arrayLength + 1; i++) {
321 LocalToShareSlot.insert(ToUintPtr(array->GetData() + i));
322 }
323 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot](void *mem) {
324 LocalToShareSlot.erase(ToUintPtr(mem));
325 return true;
326 });
327
328 EXPECT_TRUE(LocalToShareSlot.empty());
329 }
330
HWTEST_F_L0(BarrierTest,UnshiftBarrierMoveForward)331 HWTEST_F_L0(BarrierTest, UnshiftBarrierMoveForward)
332 {
333 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
334 uint32_t arrayLength = 3;
335 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
336 for (uint32_t i = 0; i < arrayLength; i++) {
337 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
338 // string longer than 1 will be in sweepable shared heap
339 array->Set(thread, i, str);
340 }
341 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
342
343 JSHandle<EcmaString> unshiftStr = factory->NewFromStdString("unshift");
344 auto unshiftFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
345 JSHandle<JSTaggedValue>(unshiftStr)).GetValue();
346 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, unshiftFunc.GetTaggedValue(),
347 jsArray.GetTaggedValue(),
348 thread->GlobalConstants()->GetUndefined(), 3);
349 info->SetCallArg(thread->GlobalConstants()->GetUndefined(), thread->GlobalConstants()->GetUndefined(),
350 thread->GlobalConstants()->GetUndefined());
351 EcmaInterpreter::Execute(info);
352
353 array = JSHandle<TaggedArray>(thread, jsArray->GetElements());
354 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
355 std::set<uintptr_t> LocalToShareSlot;
356 for (uint32_t i = 3; i < arrayLength + 3; i++) {
357 LocalToShareSlot.insert(ToUintPtr(array->GetData() + i));
358 }
359 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot](void *mem) {
360 LocalToShareSlot.erase(ToUintPtr(mem));
361 return true;
362 });
363
364 EXPECT_TRUE(LocalToShareSlot.empty());
365 }
366
HWTEST_F_L0(BarrierTest,UnshiftBarrierMoveBackward)367 HWTEST_F_L0(BarrierTest, UnshiftBarrierMoveBackward)
368 {
369 if (!thread->IsAsmInterpreter()) {
370 return;
371 }
372 #ifdef ENABLE_NEXT_OPTIMIZATION
373 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
374 uint32_t arrayLength = 20;
375 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
376 for (uint32_t i = 0; i < arrayLength; i++) {
377 if (i % 2 == 0) {
378 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
379 // string longer than 1 will be in sweepable shared heap
380 array->Set(thread, i, str);
381 continue;
382 }
383 array->Set(thread, i, JSTaggedValue(1));
384 }
385 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
386
387 JSHandle<EcmaString> unshiftStr = factory->NewFromStdString("unshift");
388 auto unshiftFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
389 JSHandle<JSTaggedValue>(unshiftStr)).GetValue();
390 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, unshiftFunc.GetTaggedValue(),
391 jsArray.GetTaggedValue(),
392 thread->GlobalConstants()->GetUndefined(), 1);
393 info->SetCallArg(thread->GlobalConstants()->GetUndefined());
394 EcmaInterpreter::Execute(info);
395
396 array = JSHandle<TaggedArray>(thread, jsArray->GetElements());
397 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
398 std::set<uintptr_t> LocalToShareSlot;
399 std::set<uintptr_t> LocalTaggedIntSlot;
400 for (uint32_t i = 1; i < arrayLength + 1; i++) {
401 if (i % 2 != 0) {
402 LocalToShareSlot.insert(ToUintPtr(array->GetData() + i));
403 continue;
404 }
405 LocalTaggedIntSlot.insert(ToUintPtr(array->GetData() + i));
406 }
407 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalTaggedIntSlot](void *mem) {
408 EXPECT_FALSE(LocalTaggedIntSlot.count(ToUintPtr(mem)));
409 LocalToShareSlot.erase(ToUintPtr(mem));
410 return true;
411 });
412
413 EXPECT_TRUE(LocalToShareSlot.empty());
414 #endif
415 }
416
HWTEST_F_L0(BarrierTest,UnshiftBarrierMoveForward1)417 HWTEST_F_L0(BarrierTest, UnshiftBarrierMoveForward1)
418 {
419 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
420 uint32_t arrayLength = 3;
421 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
422 for (uint32_t i = 0; i < arrayLength; i++) {
423 if (i % 2 != 0) {
424 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
425 // string longer than 1 will be in sweepable shared heap
426 array->Set(thread, i, str);
427 continue;
428 }
429 array->Set(thread, i, JSTaggedValue(1));
430 }
431 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
432
433 JSHandle<EcmaString> unshiftStr = factory->NewFromStdString("unshift");
434 auto unshiftFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
435 JSHandle<JSTaggedValue>(unshiftStr)).GetValue();
436 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, unshiftFunc.GetTaggedValue(),
437 jsArray.GetTaggedValue(),
438 thread->GlobalConstants()->GetUndefined(), 3);
439 info->SetCallArg(thread->GlobalConstants()->GetUndefined(), thread->GlobalConstants()->GetUndefined(),
440 thread->GlobalConstants()->GetUndefined());
441 EcmaInterpreter::Execute(info);
442
443 array = JSHandle<TaggedArray>(thread, jsArray->GetElements());
444 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
445 std::set<uintptr_t> LocalToShareSlot;
446 std::set<uintptr_t> LocalTaggedIntSlot;
447 for (uint32_t i = 3; i < arrayLength + 3; i++) {
448 if (i % 2 == 0) {
449 LocalToShareSlot.insert(ToUintPtr(array->GetData() + i));
450 continue;
451 }
452 LocalTaggedIntSlot.insert(ToUintPtr(array->GetData() + i));
453 }
454 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalTaggedIntSlot](void *mem) {
455 EXPECT_FALSE(LocalTaggedIntSlot.count(ToUintPtr(mem)));
456 LocalToShareSlot.erase(ToUintPtr(mem));
457 return true;
458 });
459
460 EXPECT_TRUE(LocalToShareSlot.empty());
461 }
462
HWTEST_F_L0(BarrierTest,SliceBarrierMove)463 HWTEST_F_L0(BarrierTest, SliceBarrierMove)
464 {
465 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
466 uint32_t arrayLength = 20;
467 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
468 for (uint32_t i = 0; i < arrayLength; i++) {
469 if (i % 2 == 0) {
470 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
471 // string longer than 1 will be in sweepable shared heap
472 array->Set(thread, i, str);
473 continue;
474 }
475 array->Set(thread, i, JSTaggedValue(1));
476 }
477 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
478
479 JSHandle<EcmaString> sliceStr = factory->NewFromStdString("slice");
480 auto unshiftFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
481 JSHandle<JSTaggedValue>(sliceStr)).GetValue();
482 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, unshiftFunc.GetTaggedValue(),
483 jsArray.GetTaggedValue(),
484 thread->GlobalConstants()->GetUndefined(), 1);
485 info->SetCallArg(JSTaggedValue(10));
486 JSTaggedValue result = EcmaInterpreter::Execute(info);
487 JSArray *resultArray = JSArray::Cast(result.GetTaggedObject());
488 array = JSHandle<TaggedArray>(thread, resultArray->GetElements());
489 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
490 std::set<uintptr_t> LocalToShareSlot;
491 std::set<uintptr_t> LocalTaggedIntSlot;
492 for (uint32_t i = 0; i < 10; i++) {
493 if (i % 2 == 0) {
494 LocalToShareSlot.insert(ToUintPtr(array->GetData() + i));
495 continue;
496 }
497 LocalTaggedIntSlot.insert(ToUintPtr(array->GetData() + i));
498 }
499 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalTaggedIntSlot](void *mem) {
500 EXPECT_FALSE(LocalTaggedIntSlot.count(ToUintPtr(mem)));
501 LocalToShareSlot.erase(ToUintPtr(mem));
502 return true;
503 });
504
505 EXPECT_TRUE(LocalToShareSlot.empty());
506 }
507
HWTEST_F_L0(BarrierTest,LocalToShareReverse)508 HWTEST_F_L0(BarrierTest, LocalToShareReverse)
509 {
510 if (!thread->IsAsmInterpreter()) {
511 return;
512 }
513 #ifdef ENABLE_NEXT_OPTIMIZATION
514 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
515 uint32_t arrayLength = 40;
516 JSHandle<TaggedArray> array = factory->NewTaggedArray(arrayLength);
517 for (uint32_t i = 0; i < arrayLength; i++) {
518 if (i % 2 == 0) {
519 JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
520 array->Set(thread, i, str);
521 } else {
522 array->Set(thread, i, JSTaggedValue(i));
523 }
524 }
525 JSHandle<JSArray> jsArray = JSArray::CreateArrayFromList(thread, array);
526
527 JSHandle<EcmaString> reverseStr = factory->NewFromStdString("reverse");
528 auto reverseFunc = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(jsArray),
529 JSHandle<JSTaggedValue>(reverseStr)).GetValue();
530 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, reverseFunc.GetTaggedValue(),
531 jsArray.GetTaggedValue(),
532 thread->GlobalConstants()->GetUndefined(), 0);
533 EcmaInterpreter::Execute(info);
534
535 array = JSHandle<TaggedArray>(thread, jsArray->GetElements());
536 Region *dstRegion = Region::ObjectAddressToRange(array.GetObject<TaggedArray>());
537 std::set<uintptr_t> LocalToShareSlot1;
538 std::set<uintptr_t> LocalToShareSlot2;
539 for (uint32_t i = 0; i < arrayLength; i++) {
540 if (i % 2 == 1) {
541 LocalToShareSlot1.insert(ToUintPtr(array->GetData() + i));
542 } else {
543 LocalToShareSlot2.insert(ToUintPtr(array->GetData() + i));
544 }
545 }
546 dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot1, &LocalToShareSlot2](void *mem) {
547 LocalToShareSlot1.erase(ToUintPtr(mem));
548 LocalToShareSlot2.erase(ToUintPtr(mem));
549 return true;
550 });
551 EXPECT_TRUE(LocalToShareSlot1.empty());
552 EXPECT_EQ(LocalToShareSlot2.size(), arrayLength / 2);
553 #endif
554 }
555
556 } // namespace panda::ecmascript
557