1 /**
2 * Copyright (c) 2021-2022 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 <random>
17
18 #include "gtest/gtest.h"
19 #include "runtime/include/managed_thread.h"
20 #include "runtime/mark_word.cpp"
21
22 namespace panda {
23
24 class MarkWordTest : public testing::Test {
25 public:
MarkWordTest()26 MarkWordTest() {}
27
28 protected:
SetUp()29 void SetUp() override
30 {
31 // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
32 }
33
TearDown()34 void TearDown() override
35 {
36 // Logger::Destroy();
37 }
38
39 enum MarkWordFieldsMaxValues : MarkWord::markWordSize {
40 MAX_THREAD_ID = (1UL << MarkWord::MarkWordRepresentation::LIGHT_LOCK_THREADID_SIZE) - 1UL,
41 MAX_LOCK_COUNT = (1UL << MarkWord::MarkWordRepresentation::LIGHT_LOCK_LOCK_COUNT_SIZE) - 1UL,
42 MAX_MONITOR_ID = (1UL << MarkWord::MarkWordRepresentation::MONITOR_POINTER_SIZE) - 1UL,
43 MAX_HASH = (1UL << MarkWord::MarkWordRepresentation::HASH_SIZE) - 1UL,
44 MAX_FORWARDING_ADDRESS = std::numeric_limits<MarkWord::markWordSize>::max() &
45 MarkWord::MarkWordRepresentation::FORWARDING_ADDRESS_MASK_IN_PLACE,
46 };
47
48 class RandomTestValuesGetter {
49 public:
50 using MarkWordDistribution = std::uniform_int_distribution<MarkWord::markWordSize>;
51
RandomTestValuesGetter()52 RandomTestValuesGetter()
53 {
54 #ifdef PANDA_NIGHTLY_TEST_ON
55 seed_ = std::random_device()();
56 #else
57 seed_ = 0xC0E67D50;
58 #endif
59 gen_ = std::mt19937(seed_);
60
61 threadIdRange_ = MarkWordDistribution(0, MAX_THREAD_ID);
62 lockCountRange_ = MarkWordDistribution(0, MAX_LOCK_COUNT);
63 monitorIdRange_ = MarkWordDistribution(0, MAX_MONITOR_ID);
64 hashRange_ = MarkWordDistribution(0, MAX_HASH);
65 forwardingAddressRange_ = MarkWordDistribution(0, MAX_FORWARDING_ADDRESS);
66 }
67
GetThreadId()68 ManagedThread::ThreadId GetThreadId()
69 {
70 return threadIdRange_(gen_);
71 }
72
GetLockCount()73 uint32_t GetLockCount()
74 {
75 return lockCountRange_(gen_);
76 }
77
GetMonitorId()78 Monitor::MonitorId GetMonitorId()
79 {
80 return monitorIdRange_(gen_);
81 }
82
GetHash()83 uint32_t GetHash()
84 {
85 return hashRange_(gen_);
86 }
87
GetForwardingAddress()88 MarkWord::markWordSize GetForwardingAddress()
89 {
90 return forwardingAddressRange_(gen_) & MarkWord::MarkWordRepresentation::FORWARDING_ADDRESS_MASK_IN_PLACE;
91 }
92
GetSeed()93 uint32_t GetSeed()
94 {
95 return seed_;
96 }
97
98 private:
99 uint32_t seed_;
100 std::mt19937 gen_;
101 MarkWordDistribution threadIdRange_;
102 MarkWordDistribution lockCountRange_;
103 MarkWordDistribution monitorIdRange_;
104 MarkWordDistribution hashRange_;
105 MarkWordDistribution forwardingAddressRange_;
106 };
107
108 class MaxTestValuesGetter {
109 public:
GetThreadId() const110 ManagedThread::ThreadId GetThreadId() const
111 {
112 return MAX_THREAD_ID;
113 }
114
GetLockCount() const115 uint32_t GetLockCount() const
116 {
117 return MAX_LOCK_COUNT;
118 }
119
GetMonitorId() const120 Monitor::MonitorId GetMonitorId() const
121 {
122 return static_cast<Monitor::MonitorId>(MAX_MONITOR_ID);
123 }
124
GetHash() const125 uint32_t GetHash() const
126 {
127 return static_cast<uint32_t>(MAX_HASH);
128 }
129
GetForwardingAddress() const130 MarkWord::markWordSize GetForwardingAddress() const
131 {
132 return MAX_FORWARDING_ADDRESS;
133 }
134
GetSeed() const135 uint32_t GetSeed() const
136 {
137 // We don't have a seed for this case
138 return 0;
139 }
140 };
141
142 template <class Getter>
143 class MarkWordWrapper {
144 public:
MarkWordWrapper(bool isMarkedForGC=false,bool isReadBarrierSet=false)145 MarkWordWrapper(bool isMarkedForGC = false, bool isReadBarrierSet = false)
146 {
147 if (isMarkedForGC) {
148 mw_ = mw_.SetMarkedForGC();
149 }
150 if (isReadBarrierSet) {
151 mw_ = mw_.SetReadBarrier();
152 }
153 };
154
CheckUnlocked(bool isMarkedForGC=false,bool isReadBarrierSet=false)155 void CheckUnlocked(bool isMarkedForGC = false, bool isReadBarrierSet = false)
156 {
157 ASSERT_EQ(mw_.GetState(), MarkWord::ObjectState::STATE_UNLOCKED) << " seed = " << paramGetter_.GetSeed();
158 ASSERT_EQ(mw_.IsMarkedForGC(), isMarkedForGC) << " seed = " << paramGetter_.GetSeed();
159 ASSERT_EQ(mw_.IsReadBarrierSet(), isReadBarrierSet) << " seed = " << paramGetter_.GetSeed();
160 }
161
CheckLightweightLock(const ManagedThread::ThreadId tId,const uint32_t lockCount,bool isMarkedForGC,bool isReadBarrierSet=false)162 void CheckLightweightLock(const ManagedThread::ThreadId tId, const uint32_t lockCount, bool isMarkedForGC,
163 bool isReadBarrierSet = false)
164 {
165 ASSERT_EQ(mw_.GetState(), MarkWord::ObjectState::STATE_LIGHT_LOCKED)
166 << " seed = " << paramGetter_.GetSeed();
167 ASSERT_EQ(mw_.GetThreadId(), tId) << " seed = " << paramGetter_.GetSeed();
168 ASSERT_EQ(mw_.GetLockCount(), lockCount) << " seed = " << paramGetter_.GetSeed();
169 ASSERT_EQ(mw_.IsMarkedForGC(), isMarkedForGC) << " seed = " << paramGetter_.GetSeed();
170 ASSERT_EQ(mw_.IsReadBarrierSet(), isReadBarrierSet) << " seed = " << paramGetter_.GetSeed();
171 }
172
CheckHeavyweightLock(const Monitor::MonitorId mId,bool isMarkedForGC,bool isReadBarrierSet=false)173 void CheckHeavyweightLock(const Monitor::MonitorId mId, bool isMarkedForGC, bool isReadBarrierSet = false)
174 {
175 ASSERT_EQ(mw_.GetState(), MarkWord::ObjectState::STATE_HEAVY_LOCKED)
176 << " seed = " << paramGetter_.GetSeed();
177 ASSERT_EQ(mw_.GetMonitorId(), mId) << " seed = " << paramGetter_.GetSeed();
178 ASSERT_EQ(mw_.IsMarkedForGC(), isMarkedForGC) << " seed = " << paramGetter_.GetSeed();
179 ASSERT_EQ(mw_.IsReadBarrierSet(), isReadBarrierSet) << " seed = " << paramGetter_.GetSeed();
180 }
181
CheckHashed(uint32_t hash,bool isMarkedForGC,bool isReadBarrierSet=false)182 void CheckHashed(uint32_t hash, bool isMarkedForGC, bool isReadBarrierSet = false)
183 {
184 if (mw_.CONFIG_IS_HASH_IN_OBJ_HEADER) {
185 ASSERT_EQ(mw_.GetState(), MarkWord::ObjectState::STATE_HASHED) << " seed = " << paramGetter_.GetSeed();
186 ASSERT_EQ(mw_.GetHash(), hash) << " seed = " << paramGetter_.GetSeed();
187 ASSERT_EQ(mw_.IsMarkedForGC(), isMarkedForGC) << " seed = " << paramGetter_.GetSeed();
188 ASSERT_EQ(mw_.IsReadBarrierSet(), isReadBarrierSet) << " seed = " << paramGetter_.GetSeed();
189 }
190 }
191
CheckGC(MarkWord::markWordSize forwardingAddress)192 void CheckGC(MarkWord::markWordSize forwardingAddress)
193 {
194 ASSERT_EQ(mw_.GetState(), MarkWord::ObjectState::STATE_GC) << " seed = " << paramGetter_.GetSeed();
195 ASSERT_EQ(mw_.GetForwardingAddress(), forwardingAddress) << " seed = " << paramGetter_.GetSeed();
196 }
197
DecodeLightLock(ManagedThread::ThreadId tId,uint32_t lCount)198 void DecodeLightLock(ManagedThread::ThreadId tId, uint32_t lCount)
199 {
200 mw_ = mw_.DecodeFromLightLock(tId, lCount);
201 }
202
DecodeHeavyLock(Monitor::MonitorId mId)203 void DecodeHeavyLock(Monitor::MonitorId mId)
204 {
205 mw_ = mw_.DecodeFromMonitor(mId);
206 }
207
DecodeHash(uint32_t hash)208 void DecodeHash(uint32_t hash)
209 {
210 mw_ = mw_.DecodeFromHash(hash);
211 }
212
DecodeForwardingAddress(MarkWord::markWordSize fAddress)213 void DecodeForwardingAddress(MarkWord::markWordSize fAddress)
214 {
215 mw_ = mw_.DecodeFromForwardingAddress(fAddress);
216 }
217
DecodeAndCheckLightLock(bool isMarkedForGC=false,bool isReadBarrierSet=false)218 void DecodeAndCheckLightLock(bool isMarkedForGC = false, bool isReadBarrierSet = false)
219 {
220 auto tId = paramGetter_.GetThreadId();
221 auto lCount = paramGetter_.GetLockCount();
222 DecodeLightLock(tId, lCount);
223 CheckLightweightLock(tId, lCount, isMarkedForGC, isReadBarrierSet);
224 }
225
DecodeAndCheckHeavyLock(bool isMarkedForGC=false,bool isReadBarrierSet=false)226 void DecodeAndCheckHeavyLock(bool isMarkedForGC = false, bool isReadBarrierSet = false)
227 {
228 auto mId = paramGetter_.GetMonitorId();
229 DecodeHeavyLock(mId);
230 CheckHeavyweightLock(mId, isMarkedForGC, isReadBarrierSet);
231 }
232
DecodeAndCheckHashed(bool isMarkedForGC=false,bool isReadBarrierSet=false)233 void DecodeAndCheckHashed(bool isMarkedForGC = false, bool isReadBarrierSet = false)
234 {
235 auto hash = paramGetter_.GetHash();
236 DecodeHash(hash);
237 CheckHashed(hash, isMarkedForGC, isReadBarrierSet);
238 }
239
DecodeAndCheckGC()240 void DecodeAndCheckGC()
241 {
242 auto fAddress = paramGetter_.GetForwardingAddress();
243 DecodeForwardingAddress(fAddress);
244 CheckGC(fAddress);
245 }
246
SetMarkedForGC()247 void SetMarkedForGC()
248 {
249 mw_ = mw_.SetMarkedForGC();
250 }
251
SetReadBarrier()252 void SetReadBarrier()
253 {
254 mw_ = mw_.SetReadBarrier();
255 }
256
257 private:
258 MarkWord mw_;
259 Getter paramGetter_;
260 };
261
262 template <class Getter>
263 void CheckMakeHashed(bool isMarkedForGC, bool isReadBarrierSet);
264
265 template <class Getter>
266 void CheckMakeLightweightLock(bool isMarkedForGC, bool isReadBarrierSet);
267
268 template <class Getter>
269 void CheckMakeHeavyweightLock(bool isMarkedForGC, bool isReadBarrierSet);
270
271 template <class Getter>
272 void CheckMakeGC();
273
274 template <class Getter>
275 void CheckMarkingWithGC();
276
277 template <class Getter>
278 void CheckReadBarrierSet();
279 };
280
281 template <class Getter>
CheckMakeHashed(bool isMarkedForGC,bool isReadBarrierSet)282 void MarkWordTest::CheckMakeHashed(bool isMarkedForGC, bool isReadBarrierSet)
283 {
284 // nothing, gc = markedForGC, rb = readBarrierSet, state = unlocked
285 MarkWordWrapper<Getter> wrapper(isMarkedForGC, isReadBarrierSet);
286
287 // check new hash
288 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
289 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
290
291 // check after lightweight lock
292 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
293 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
294
295 // check after heavyweight lock
296 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
297 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
298 }
299
TEST_F(MarkWordTest,CreateHashedWithRandValues)300 TEST_F(MarkWordTest, CreateHashedWithRandValues)
301 {
302 CheckMakeHashed<RandomTestValuesGetter>(false, false);
303 CheckMakeHashed<RandomTestValuesGetter>(false, true);
304 CheckMakeHashed<RandomTestValuesGetter>(true, false);
305 CheckMakeHashed<RandomTestValuesGetter>(true, true);
306 }
307
TEST_F(MarkWordTest,CreateHashedWithMaxValues)308 TEST_F(MarkWordTest, CreateHashedWithMaxValues)
309 {
310 CheckMakeHashed<MaxTestValuesGetter>(false, false);
311 CheckMakeHashed<MaxTestValuesGetter>(false, true);
312 CheckMakeHashed<MaxTestValuesGetter>(true, false);
313 CheckMakeHashed<MaxTestValuesGetter>(true, true);
314 }
315
316 template <class Getter>
CheckMakeLightweightLock(bool isMarkedForGC,bool isReadBarrierSet)317 void MarkWordTest::CheckMakeLightweightLock(bool isMarkedForGC, bool isReadBarrierSet)
318 {
319 // nothing, gc = markedForGC, rb = readBarrierSet, state = unlocked
320 MarkWordWrapper<Getter> wrapper(isMarkedForGC, isReadBarrierSet);
321
322 // check new lightweight lock
323 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
324 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
325
326 // check after hash
327 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
328 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
329
330 // check after heavyweight lock
331 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
332 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
333 }
334
TEST_F(MarkWordTest,CreateLightweightLockWithRandValues)335 TEST_F(MarkWordTest, CreateLightweightLockWithRandValues)
336 {
337 CheckMakeLightweightLock<RandomTestValuesGetter>(false, false);
338 CheckMakeLightweightLock<RandomTestValuesGetter>(false, true);
339 CheckMakeLightweightLock<RandomTestValuesGetter>(true, false);
340 CheckMakeLightweightLock<RandomTestValuesGetter>(true, true);
341 }
342
TEST_F(MarkWordTest,CreateLightweightLockWithMaxValues)343 TEST_F(MarkWordTest, CreateLightweightLockWithMaxValues)
344 {
345 CheckMakeLightweightLock<MaxTestValuesGetter>(false, false);
346 CheckMakeLightweightLock<MaxTestValuesGetter>(false, true);
347 CheckMakeLightweightLock<MaxTestValuesGetter>(true, false);
348 CheckMakeLightweightLock<MaxTestValuesGetter>(true, true);
349 }
350
351 template <class Getter>
CheckMakeHeavyweightLock(bool isMarkedForGC,bool isReadBarrierSet)352 void MarkWordTest::CheckMakeHeavyweightLock(bool isMarkedForGC, bool isReadBarrierSet)
353 {
354 // nothing, gc = markedForGC, rb = readBarrierSet, state = unlocked
355 MarkWordWrapper<Getter> wrapper(isMarkedForGC, isReadBarrierSet);
356
357 // check new heavyweight lock
358 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
359 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
360
361 // check after hash
362 wrapper.DecodeAndCheckHashed(isMarkedForGC, isReadBarrierSet);
363 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
364
365 // check after lightweight lock
366 wrapper.DecodeAndCheckLightLock(isMarkedForGC, isReadBarrierSet);
367 wrapper.DecodeAndCheckHeavyLock(isMarkedForGC, isReadBarrierSet);
368 }
369
TEST_F(MarkWordTest,CreateHeavyweightLockWithRandValues)370 TEST_F(MarkWordTest, CreateHeavyweightLockWithRandValues)
371 {
372 CheckMakeHeavyweightLock<RandomTestValuesGetter>(false, false);
373 CheckMakeHeavyweightLock<RandomTestValuesGetter>(false, true);
374 CheckMakeHeavyweightLock<RandomTestValuesGetter>(true, false);
375 CheckMakeHeavyweightLock<RandomTestValuesGetter>(true, true);
376 }
377
TEST_F(MarkWordTest,CreateHeavyweightLockWithMaxValues)378 TEST_F(MarkWordTest, CreateHeavyweightLockWithMaxValues)
379 {
380 CheckMakeHeavyweightLock<MaxTestValuesGetter>(false, false);
381 CheckMakeHeavyweightLock<MaxTestValuesGetter>(false, true);
382 CheckMakeHeavyweightLock<MaxTestValuesGetter>(true, false);
383 CheckMakeHeavyweightLock<MaxTestValuesGetter>(true, true);
384 }
385
386 template <class Getter>
CheckMakeGC()387 void MarkWordTest::CheckMakeGC()
388 {
389 // check new gc
390 {
391 MarkWordWrapper<Getter> wrapper;
392 wrapper.DecodeAndCheckGC();
393 wrapper.DecodeAndCheckGC();
394 }
395
396 // check after hash
397 {
398 MarkWordWrapper<Getter> wrapper;
399 wrapper.DecodeAndCheckHashed();
400 wrapper.DecodeAndCheckGC();
401 }
402
403 // check after lightweight lock
404 {
405 MarkWordWrapper<Getter> wrapper;
406 wrapper.DecodeAndCheckLightLock();
407 wrapper.DecodeAndCheckGC();
408 }
409
410 // check after heavyweight lock
411 {
412 MarkWordWrapper<Getter> wrapper;
413 wrapper.DecodeAndCheckHeavyLock();
414 wrapper.DecodeAndCheckGC();
415 }
416 }
417
TEST_F(MarkWordTest,CreateGCWithRandomValues)418 TEST_F(MarkWordTest, CreateGCWithRandomValues)
419 {
420 CheckMakeGC<RandomTestValuesGetter>();
421 }
422
TEST_F(MarkWordTest,CreateGCWithMaxValues)423 TEST_F(MarkWordTest, CreateGCWithMaxValues)
424 {
425 CheckMakeGC<MaxTestValuesGetter>();
426 }
427
428 template <class Getter>
CheckMarkingWithGC()429 void MarkWordTest::CheckMarkingWithGC()
430 {
431 Getter paramGetter;
432
433 // with unlocked
434 {
435 MarkWordWrapper<Getter> wrapper;
436
437 wrapper.SetMarkedForGC();
438 wrapper.CheckUnlocked(true);
439 }
440
441 // with lightweight locked
442 {
443 MarkWordWrapper<Getter> wrapper;
444 auto tId = paramGetter.GetThreadId();
445 auto lCount = paramGetter.GetLockCount();
446 wrapper.DecodeLightLock(tId, lCount);
447
448 wrapper.SetMarkedForGC();
449 wrapper.CheckLightweightLock(tId, lCount, true);
450 }
451
452 // with heavyweight locked
453 {
454 MarkWordWrapper<Getter> wrapper;
455 auto mId = paramGetter.GetMonitorId();
456 wrapper.DecodeHeavyLock(mId);
457
458 wrapper.SetMarkedForGC();
459 wrapper.CheckHeavyweightLock(mId, true);
460 }
461
462 // with hashed
463 {
464 MarkWordWrapper<Getter> wrapper;
465 auto hash = paramGetter.GetHash();
466 wrapper.DecodeHash(hash);
467
468 wrapper.SetMarkedForGC();
469 wrapper.CheckHashed(hash, true);
470 }
471 }
472
TEST_F(MarkWordTest,MarkWithGCWithRandValues)473 TEST_F(MarkWordTest, MarkWithGCWithRandValues)
474 {
475 CheckMarkingWithGC<RandomTestValuesGetter>();
476 }
477
TEST_F(MarkWordTest,MarkWithGCWithMaxValues)478 TEST_F(MarkWordTest, MarkWithGCWithMaxValues)
479 {
480 CheckMarkingWithGC<MaxTestValuesGetter>();
481 }
482
483 template <class Getter>
CheckReadBarrierSet()484 void MarkWordTest::CheckReadBarrierSet()
485 {
486 Getter paramGetter;
487
488 // with unlocked
489 {
490 MarkWordWrapper<Getter> wrapper;
491
492 wrapper.SetReadBarrier();
493 wrapper.CheckUnlocked(false, true);
494 }
495
496 // with lightweight locked
497 {
498 MarkWordWrapper<Getter> wrapper;
499 auto tId = paramGetter.GetThreadId();
500 auto lCount = paramGetter.GetLockCount();
501 wrapper.DecodeLightLock(tId, lCount);
502
503 wrapper.SetReadBarrier();
504 wrapper.CheckLightweightLock(tId, lCount, false, true);
505 }
506
507 // with heavyweight locked
508 {
509 MarkWordWrapper<Getter> wrapper;
510 auto mId = paramGetter.GetMonitorId();
511 wrapper.DecodeHeavyLock(mId);
512
513 wrapper.SetReadBarrier();
514 wrapper.CheckHeavyweightLock(mId, false, true);
515 }
516
517 // with hashed
518 {
519 MarkWordWrapper<Getter> wrapper;
520 auto hash = paramGetter.GetHash();
521 wrapper.DecodeHash(hash);
522
523 wrapper.SetReadBarrier();
524 wrapper.CheckHashed(hash, false, true);
525 }
526 }
527
TEST_F(MarkWordTest,ReadBarrierSetWithRandValues)528 TEST_F(MarkWordTest, ReadBarrierSetWithRandValues)
529 {
530 CheckReadBarrierSet<RandomTestValuesGetter>();
531 }
532
TEST_F(MarkWordTest,ReadBarrierSetWithMaxValues)533 TEST_F(MarkWordTest, ReadBarrierSetWithMaxValues)
534 {
535 CheckReadBarrierSet<MaxTestValuesGetter>();
536 }
537
538 } // namespace panda
539