• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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