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::CopyObject<false, false>(thread, nullptr, 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 } // namespace panda::ecmascript
296