• 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 <ctime>
17 
18 #include "gtest/gtest.h"
19 #include "runtime/include/runtime.h"
20 #include "runtime/handle_base-inl.h"
21 
22 namespace ark::concurrency::test {
23 
24 class MonitorTest : public testing::Test {
25 public:
MonitorTest()26     MonitorTest()
27     {
28         // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
29 #ifdef PANDA_NIGHTLY_TEST_ON
30         seed_ = std::time(NULL);
31 #else
32         // NOLINTNEXTLINE(readability-magic-numbers)
33         seed_ = 0xDEADBEEF;
34 #endif
35         srand(seed_);
36         // We need to create a runtime instance to be able to create strings.
37         options_.SetShouldLoadBootPandaFiles(false);
38         options_.SetShouldInitializeIntrinsics(false);
39         Runtime::Create(options_);
40         thread_ = ark::MTManagedThread::GetCurrent();
41         thread_->ManagedCodeBegin();
42     }
43 
~MonitorTest()44     ~MonitorTest() override
45     {
46         thread_->ManagedCodeEnd();
47         Runtime::Destroy();
48         // Logger::Destroy();
49     }
50 
51     NO_COPY_SEMANTIC(MonitorTest);
52     NO_MOVE_SEMANTIC(MonitorTest);
53 
54 protected:
55     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
56     ark::MTManagedThread *thread_ {};
57 
58 private:
59     unsigned seed_ {};
60     RuntimeOptions options_;
61 };
62 
TEST_F(MonitorTest,MonitorEnterTest)63 TEST_F(MonitorTest, MonitorEnterTest)
64 {
65     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
66     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
67     auto header = ObjectHeader::Create(cls);
68     Monitor::MonitorEnter(header);
69     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
70     Monitor::MonitorExit(header);
71     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
72 }
73 
TEST_F(MonitorTest,MonitorDoubleEnterTest)74 TEST_F(MonitorTest, MonitorDoubleEnterTest)
75 {
76     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
77     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
78     auto header = ObjectHeader::Create(cls);
79     Monitor::MonitorEnter(header);
80     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
81     Monitor::MonitorEnter(header);
82     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
83     Monitor::MonitorExit(header);
84     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
85     Monitor::MonitorExit(header);
86     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
87 }
88 
TEST_F(MonitorTest,MonitorDoubleObjectTest)89 TEST_F(MonitorTest, MonitorDoubleObjectTest)
90 {
91     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
92     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
93     auto header1 = ObjectHeader::Create(cls);
94     auto header2 = ObjectHeader::Create(cls);
95     Monitor::MonitorEnter(header1);
96     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
97     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
98     Monitor::MonitorEnter(header2);
99     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
100     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
101     Monitor::MonitorExit(header1);
102     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
103     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
104     Monitor::MonitorExit(header2);
105     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
106     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
107 }
108 
TEST_F(MonitorTest,HeavyMonitorEnterTest)109 TEST_F(MonitorTest, HeavyMonitorEnterTest)
110 {
111     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
112     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
113     auto header = ObjectHeader::Create(cls);
114     auto thread = MTManagedThread::GetCurrent();
115     Monitor::MonitorEnter(header);
116     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
117     ASSERT_TRUE(Monitor::Inflate(header, thread));
118     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
119     Monitor::MonitorExit(header);
120     // We unlock the monitor, but keep the pointer to it
121     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
122     ASSERT_FALSE(Monitor::HoldsLock(header));
123 }
124 
TEST_F(MonitorTest,HeavyMonitorDeflateTest)125 TEST_F(MonitorTest, HeavyMonitorDeflateTest)
126 {
127     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
128     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
129     auto header = ObjectHeader::Create(cls);
130     auto thread = MTManagedThread::GetCurrent();
131     ASSERT_TRUE(Monitor::Inflate(header, thread));
132     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
133     Monitor::MonitorExit(header);
134     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
135     ASSERT_TRUE(Monitor::Deflate(header));
136     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
137 }
138 
TEST_F(MonitorTest,HeavyMonitorDoubleEnterTest)139 TEST_F(MonitorTest, HeavyMonitorDoubleEnterTest)
140 {
141     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
142     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
143     auto header = ObjectHeader::Create(cls);
144     auto thread = MTManagedThread::GetCurrent();
145     Monitor::MonitorEnter(header);
146     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
147     ASSERT_TRUE(Monitor::Inflate(header, thread));
148     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
149     Monitor::MonitorEnter(header);
150     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
151     Monitor::MonitorExit(header);
152     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
153     Monitor::MonitorExit(header);
154     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
155     ASSERT_FALSE(Monitor::HoldsLock(header));
156 }
157 
TEST_F(MonitorTest,HeavyMonitorDoubleObjectTest)158 TEST_F(MonitorTest, HeavyMonitorDoubleObjectTest)
159 {
160     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
161     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
162     auto header1 = ObjectHeader::Create(cls);
163     auto header2 = ObjectHeader::Create(cls);
164     auto thread = MTManagedThread::GetCurrent();
165     ASSERT_TRUE(Monitor::Inflate(header1, thread));
166     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
167     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
168     ASSERT_TRUE(Monitor::Inflate(header2, thread));
169     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
170     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
171     Monitor::MonitorExit(header1);
172     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
173     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
174     Monitor::MonitorExit(header2);
175     ASSERT_TRUE(header1->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
176     ASSERT_TRUE(header2->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
177     ASSERT_FALSE(Monitor::HoldsLock(header1));
178     ASSERT_FALSE(Monitor::HoldsLock(header2));
179 }
180 
TEST_F(MonitorTest,MonitorDoubleObjectHoldsLockTest)181 TEST_F(MonitorTest, MonitorDoubleObjectHoldsLockTest)
182 {
183     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
184     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
185     auto header1 = ObjectHeader::Create(cls);
186     auto header2 = ObjectHeader::Create(cls);
187     ASSERT_FALSE(Monitor::HoldsLock(header1));
188     ASSERT_FALSE(Monitor::HoldsLock(header2));
189     Monitor::MonitorEnter(header1);
190     ASSERT_TRUE(Monitor::HoldsLock(header1));
191     ASSERT_FALSE(Monitor::HoldsLock(header2));
192     Monitor::MonitorEnter(header2);
193     ASSERT_TRUE(Monitor::HoldsLock(header1));
194     ASSERT_TRUE(Monitor::HoldsLock(header2));
195     Monitor::MonitorExit(header1);
196     ASSERT_FALSE(Monitor::HoldsLock(header1));
197     ASSERT_TRUE(Monitor::HoldsLock(header2));
198     Monitor::MonitorExit(header2);
199     ASSERT_FALSE(Monitor::HoldsLock(header1));
200     ASSERT_FALSE(Monitor::HoldsLock(header2));
201 }
202 
TEST_F(MonitorTest,MonitorGenerateHashAndEnterTest)203 TEST_F(MonitorTest, MonitorGenerateHashAndEnterTest)
204 {
205     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
206     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
207     auto header = ObjectHeader::Create(cls);
208     auto hash = header->GetHashCode<PandaAssemblyLanguageConfig::MT_MODE>();
209     Monitor::MonitorEnter(header);
210     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
211     Monitor::MonitorExit(header);
212     // We unlock the monitor, but keep the pointer to it
213     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
214     ASSERT_TRUE(header->GetHashCode<PandaAssemblyLanguageConfig::MT_MODE>() == hash);
215     ASSERT_FALSE(Monitor::HoldsLock(header));
216 }
217 
TEST_F(MonitorTest,MonitorEnterAndGenerateHashTest)218 TEST_F(MonitorTest, MonitorEnterAndGenerateHashTest)
219 {
220     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
221     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
222     auto header = ObjectHeader::Create(cls);
223     Monitor::MonitorEnter(header);
224     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
225     auto hash = header->GetHashCode<PandaAssemblyLanguageConfig::MT_MODE>();
226     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
227     ASSERT_TRUE(header->GetHashCode<PandaAssemblyLanguageConfig::MT_MODE>() == hash);
228     Monitor::MonitorExit(header);
229     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
230     ASSERT_TRUE(header->GetHashCode<PandaAssemblyLanguageConfig::MT_MODE>() == hash);
231     ASSERT_FALSE(Monitor::HoldsLock(header));
232 }
233 
TEST_F(MonitorTest,HeavyMonitorGcTest)234 TEST_F(MonitorTest, HeavyMonitorGcTest)
235 {
236     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
237     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
238     auto thread = MTManagedThread::GetCurrent();
239     auto header = ObjectHeader::Create(cls);
240     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
241     VMHandle<ObjectHeader> objHandle(thread, header);
242     Monitor::MonitorEnter(objHandle.GetPtr());
243     ASSERT_TRUE(objHandle->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
244     ASSERT_TRUE(Monitor::Inflate(objHandle.GetPtr(), thread));
245     ASSERT_TRUE(objHandle->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
246     thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
247     ASSERT_TRUE(objHandle->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
248     Monitor::MonitorExit(objHandle.GetPtr());
249     ASSERT_TRUE(objHandle->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
250     thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
251     ASSERT_TRUE(objHandle->AtomicGetMark().GetState() == MarkWord::STATE_UNLOCKED);
252     ASSERT_FALSE(Monitor::HoldsLock(objHandle.GetPtr()));
253 }
254 
TEST_F(MonitorTest,MonitorTestLightLockOverflow)255 TEST_F(MonitorTest, MonitorTestLightLockOverflow)
256 {
257     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
258     Class *cls = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
259     auto header = ObjectHeader::Create(cls);
260     Monitor::MonitorEnter(header);
261     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_LIGHT_LOCKED);
262     // Set lock count to MAX-1
263     {
264         MarkWord mark = header->AtomicGetMark();
265         MarkWord newMark = mark.DecodeFromLightLock(mark.GetThreadId(), MarkWord::LIGHT_LOCK_LOCK_MAX_COUNT - 1);
266         ASSERT_TRUE(header->AtomicSetMark(mark, newMark));
267     }
268     Monitor::MonitorEnter(header);
269     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
270     // Unlock all recursive locks
271     for (uint64_t cnt = 0; cnt < MarkWord::LIGHT_LOCK_LOCK_MAX_COUNT; cnt++) {
272         Monitor::MonitorExit(header);
273     }
274     ASSERT_TRUE(header->AtomicGetMark().GetState() == MarkWord::STATE_HEAVY_LOCKED);
275     ASSERT_FALSE(Monitor::HoldsLock(header));
276 }
277 
278 }  // namespace ark::concurrency::test
279