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