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