1 /*
2 * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include "precompiled.hpp"
25 #include "runtime/interfaceSupport.inline.hpp"
26 #include "runtime/lockStack.inline.hpp"
27 #include "runtime/os.hpp"
28 #include "unittest.hpp"
29 #include "utilities/globalDefinitions.hpp"
30
31 class LockStackTest : public ::testing::Test {
32 public:
33 static void push_raw(LockStack& ls, oop obj) {
34 ls._base[ls.to_index(ls._top)] = obj;
35 ls._top += oopSize;
36 }
37
38 static void pop_raw(LockStack& ls) {
39 ls._top -= oopSize;
40 #ifdef ASSERT
41 ls._base[ls.to_index(ls._top)] = nullptr;
42 #endif
43 }
44
45 static oop at(LockStack& ls, int index) {
46 return ls._base[index];
47 }
48
49 static size_t size(LockStack& ls) {
50 return ls.to_index(ls._top);
51 }
52 };
53
54 #define recursive_enter(ls, obj) \
55 do { \
56 bool ret = ls.try_recursive_enter(obj); \
57 EXPECT_TRUE(ret); \
58 } while (false)
59
60 #define recursive_exit(ls, obj) \
61 do { \
62 bool ret = ls.try_recursive_exit(obj); \
63 EXPECT_TRUE(ret); \
64 } while (false)
65
66 TEST_VM_F(LockStackTest, is_recursive) {
67 if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) {
68 return;
69 }
70
71 JavaThread* THREAD = JavaThread::current();
72 // the thread should be in vm to use locks
73 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
74
75 LockStack& ls = THREAD->lock_stack();
76
77 EXPECT_TRUE(ls.is_empty());
78
79 oop obj0 = Universe::int_mirror();
80 oop obj1 = Universe::float_mirror();
81
82 push_raw(ls, obj0);
83
84 // 0
85 EXPECT_FALSE(ls.is_recursive(obj0));
86
87 push_raw(ls, obj1);
88
89 // 0, 1
90 EXPECT_FALSE(ls.is_recursive(obj0));
91 EXPECT_FALSE(ls.is_recursive(obj1));
92
93 push_raw(ls, obj1);
94
95 // 0, 1, 1
96 EXPECT_FALSE(ls.is_recursive(obj0));
97 EXPECT_TRUE(ls.is_recursive(obj1));
98
99 pop_raw(ls);
100 pop_raw(ls);
101 push_raw(ls, obj0);
102
103 // 0, 0
104 EXPECT_TRUE(ls.is_recursive(obj0));
105
106 push_raw(ls, obj0);
107
108 // 0, 0, 0
109 EXPECT_TRUE(ls.is_recursive(obj0));
110
111 pop_raw(ls);
112 push_raw(ls, obj1);
113
114 // 0, 0, 1
115 EXPECT_TRUE(ls.is_recursive(obj0));
116 EXPECT_FALSE(ls.is_recursive(obj1));
117
118 push_raw(ls, obj1);
119
120 // 0, 0, 1, 1
121 EXPECT_TRUE(ls.is_recursive(obj0));
122 EXPECT_TRUE(ls.is_recursive(obj1));
123
124 // Clear stack
125 pop_raw(ls);
126 pop_raw(ls);
127 pop_raw(ls);
128 pop_raw(ls);
129
130 EXPECT_TRUE(ls.is_empty());
131 }
132
133 TEST_VM_F(LockStackTest, try_recursive_enter) {
134 if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) {
135 return;
136 }
137
138 JavaThread* THREAD = JavaThread::current();
139 // the thread should be in vm to use locks
140 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
141
142 LockStack& ls = THREAD->lock_stack();
143
144 EXPECT_TRUE(ls.is_empty());
145
146 oop obj0 = Universe::int_mirror();
147 oop obj1 = Universe::float_mirror();
148
149 ls.push(obj0);
150
151 // 0
152 EXPECT_FALSE(ls.is_recursive(obj0));
153
154 ls.push(obj1);
155
156 // 0, 1
157 EXPECT_FALSE(ls.is_recursive(obj0));
158 EXPECT_FALSE(ls.is_recursive(obj1));
159
160 recursive_enter(ls, obj1);
161
162 // 0, 1, 1
163 EXPECT_FALSE(ls.is_recursive(obj0));
164 EXPECT_TRUE(ls.is_recursive(obj1));
165
166 recursive_exit(ls, obj1);
167 pop_raw(ls);
168 recursive_enter(ls, obj0);
169
170 // 0, 0
171 EXPECT_TRUE(ls.is_recursive(obj0));
172
173 recursive_enter(ls, obj0);
174
175 // 0, 0, 0
176 EXPECT_TRUE(ls.is_recursive(obj0));
177
178 recursive_exit(ls, obj0);
179 push_raw(ls, obj1);
180
181 // 0, 0, 1
182 EXPECT_TRUE(ls.is_recursive(obj0));
183 EXPECT_FALSE(ls.is_recursive(obj1));
184
185 recursive_enter(ls, obj1);
186
187 // 0, 0, 1, 1
188 EXPECT_TRUE(ls.is_recursive(obj0));
189 EXPECT_TRUE(ls.is_recursive(obj1));
190
191 // Clear stack
192 pop_raw(ls);
193 pop_raw(ls);
194 pop_raw(ls);
195 pop_raw(ls);
196
197 EXPECT_TRUE(ls.is_empty());
198 }
199
200 TEST_VM_F(LockStackTest, contains) {
201 if (LockingMode != LM_LIGHTWEIGHT) {
202 return;
203 }
204
205 const bool test_recursive = VM_Version::supports_recursive_lightweight_locking();
206
207 JavaThread* THREAD = JavaThread::current();
208 // the thread should be in vm to use locks
209 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
210
211 LockStack& ls = THREAD->lock_stack();
212
213 EXPECT_TRUE(ls.is_empty());
214
215 oop obj0 = Universe::int_mirror();
216 oop obj1 = Universe::float_mirror();
217
218 EXPECT_FALSE(ls.contains(obj0));
219
220 ls.push(obj0);
221
222 // 0
223 EXPECT_TRUE(ls.contains(obj0));
224 EXPECT_FALSE(ls.contains(obj1));
225
226 if (test_recursive) {
227 push_raw(ls, obj0);
228
229 // 0, 0
230 EXPECT_TRUE(ls.contains(obj0));
231 EXPECT_FALSE(ls.contains(obj1));
232 }
233
234 push_raw(ls, obj1);
235
236 // 0, 0, 1
237 EXPECT_TRUE(ls.contains(obj0));
238 EXPECT_TRUE(ls.contains(obj1));
239
240 if (test_recursive) {
241 push_raw(ls, obj1);
242
243 // 0, 0, 1, 1
244 EXPECT_TRUE(ls.contains(obj0));
245 EXPECT_TRUE(ls.contains(obj1));
246 }
247
248 pop_raw(ls);
249 if (test_recursive) {
250 pop_raw(ls);
251 pop_raw(ls);
252 }
253 push_raw(ls, obj1);
254
255 // 0, 1
256 EXPECT_TRUE(ls.contains(obj0));
257 EXPECT_TRUE(ls.contains(obj1));
258
259 // Clear stack
260 pop_raw(ls);
261 pop_raw(ls);
262
263 EXPECT_TRUE(ls.is_empty());
264 }
265
266 TEST_VM_F(LockStackTest, remove) {
267 if (LockingMode != LM_LIGHTWEIGHT) {
268 return;
269 }
270
271 const bool test_recursive = VM_Version::supports_recursive_lightweight_locking();
272
273 JavaThread* THREAD = JavaThread::current();
274 // the thread should be in vm to use locks
275 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
276
277 LockStack& ls = THREAD->lock_stack();
278
279 EXPECT_TRUE(ls.is_empty());
280
281 oop obj0 = Universe::int_mirror();
282 oop obj1 = Universe::float_mirror();
283 oop obj2 = Universe::short_mirror();
284 oop obj3 = Universe::long_mirror();
285
286 push_raw(ls, obj0);
287
288 // 0
289 {
290 size_t removed = ls.remove(obj0);
291 EXPECT_EQ(removed, 1u);
292 EXPECT_FALSE(ls.contains(obj0));
293 }
294
295 if (test_recursive) {
296 push_raw(ls, obj0);
297 push_raw(ls, obj0);
298
299 // 0, 0
300 {
301 size_t removed = ls.remove(obj0);
302 EXPECT_EQ(removed, 2u);
303 EXPECT_FALSE(ls.contains(obj0));
304 }
305 }
306
307 push_raw(ls, obj0);
308 push_raw(ls, obj1);
309
310 // 0, 1
311 {
312 size_t removed = ls.remove(obj0);
313 EXPECT_EQ(removed, 1u);
314 EXPECT_FALSE(ls.contains(obj0));
315 EXPECT_TRUE(ls.contains(obj1));
316
317 ls.remove(obj1);
318 EXPECT_TRUE(ls.is_empty());
319 }
320
321 push_raw(ls, obj0);
322 push_raw(ls, obj1);
323
324 // 0, 1
325 {
326 size_t removed = ls.remove(obj1);
327 EXPECT_EQ(removed, 1u);
328 EXPECT_FALSE(ls.contains(obj1));
329 EXPECT_TRUE(ls.contains(obj0));
330
331 ls.remove(obj0);
332 EXPECT_TRUE(ls.is_empty());
333 }
334
335 if (test_recursive) {
336 push_raw(ls, obj0);
337 push_raw(ls, obj0);
338 push_raw(ls, obj1);
339
340 // 0, 0, 1
341 {
342 size_t removed = ls.remove(obj0);
343 EXPECT_EQ(removed, 2u);
344 EXPECT_FALSE(ls.contains(obj0));
345 EXPECT_TRUE(ls.contains(obj1));
346
347 ls.remove(obj1);
348 EXPECT_TRUE(ls.is_empty());
349 }
350
351 push_raw(ls, obj0);
352 push_raw(ls, obj1);
353 push_raw(ls, obj1);
354
355 // 0, 1, 1
356 {
357 size_t removed = ls.remove(obj1);
358 EXPECT_EQ(removed, 2u);
359 EXPECT_FALSE(ls.contains(obj1));
360 EXPECT_TRUE(ls.contains(obj0));
361
362 ls.remove(obj0);
363 EXPECT_TRUE(ls.is_empty());
364 }
365
366 push_raw(ls, obj0);
367 push_raw(ls, obj1);
368 push_raw(ls, obj1);
369 push_raw(ls, obj2);
370 push_raw(ls, obj2);
371 push_raw(ls, obj2);
372 push_raw(ls, obj2);
373 push_raw(ls, obj3);
374
375 // 0, 1, 1, 2, 2, 2, 2, 3
376 {
377 EXPECT_EQ(size(ls), 8u);
378
379 size_t removed = ls.remove(obj1);
380 EXPECT_EQ(removed, 2u);
381
382 EXPECT_TRUE(ls.contains(obj0));
383 EXPECT_FALSE(ls.contains(obj1));
384 EXPECT_TRUE(ls.contains(obj2));
385 EXPECT_TRUE(ls.contains(obj3));
386
387 EXPECT_EQ(at(ls, 0), obj0);
388 EXPECT_EQ(at(ls, 1), obj2);
389 EXPECT_EQ(at(ls, 2), obj2);
390 EXPECT_EQ(at(ls, 3), obj2);
391 EXPECT_EQ(at(ls, 4), obj2);
392 EXPECT_EQ(at(ls, 5), obj3);
393 EXPECT_EQ(size(ls), 6u);
394
395 removed = ls.remove(obj2);
396 EXPECT_EQ(removed, 4u);
397
398 EXPECT_TRUE(ls.contains(obj0));
399 EXPECT_FALSE(ls.contains(obj1));
400 EXPECT_FALSE(ls.contains(obj2));
401 EXPECT_TRUE(ls.contains(obj3));
402
403 EXPECT_EQ(at(ls, 0), obj0);
404 EXPECT_EQ(at(ls, 1), obj3);
405 EXPECT_EQ(size(ls), 2u);
406
407 removed = ls.remove(obj0);
408 EXPECT_EQ(removed, 1u);
409
410 EXPECT_FALSE(ls.contains(obj0));
411 EXPECT_FALSE(ls.contains(obj1));
412 EXPECT_FALSE(ls.contains(obj2));
413 EXPECT_TRUE(ls.contains(obj3));
414
415 EXPECT_EQ(at(ls, 0), obj3);
416 EXPECT_EQ(size(ls), 1u);
417
418 removed = ls.remove(obj3);
419 EXPECT_EQ(removed, 1u);
420
421 EXPECT_TRUE(ls.is_empty());
422 EXPECT_EQ(size(ls), 0u);
423 }
424 }
425
426 EXPECT_TRUE(ls.is_empty());
427 }