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