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