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 "memory/universe.hpp"
26 #include "runtime/interfaceSupport.inline.hpp"
27 #include "runtime/lockStack.inline.hpp"
28 #include "runtime/os.hpp"
29 #include "unittest.hpp"
30 #include "utilities/globalDefinitions.hpp"
31
32 class LockStackTest : public ::testing::Test {
33 public:
34 static void push_raw(LockStack& ls, oop obj) {
35 ls._base[ls.to_index(ls._top)] = obj;
36 ls._top += oopSize;
37 }
38
39 static void pop_raw(LockStack& ls) {
40 ls._top -= oopSize;
41 #ifdef ASSERT
42 ls._base[ls.to_index(ls._top)] = nullptr;
43 #endif
44 }
45
46 static oop at(LockStack& ls, int index) {
47 return ls._base[index];
48 }
49
50 static size_t size(LockStack& ls) {
51 return ls.to_index(ls._top);
52 }
53 };
54
55 #define recursive_enter(ls, obj) \
56 do { \
57 bool ret = ls.try_recursive_enter(obj); \
58 EXPECT_TRUE(ret); \
59 } while (false)
60
61 #define recursive_exit(ls, obj) \
62 do { \
63 bool ret = ls.try_recursive_exit(obj); \
64 EXPECT_TRUE(ret); \
65 } while (false)
66
67 TEST_VM_F(LockStackTest, is_recursive) {
68 if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) {
69 return;
70 }
71
72 JavaThread* THREAD = JavaThread::current();
73 // the thread should be in vm to use locks
74 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
75
76 LockStack& ls = THREAD->lock_stack();
77
78 EXPECT_TRUE(ls.is_empty());
79
80 oop obj0 = Universe::int_mirror();
81 oop obj1 = Universe::float_mirror();
82
83 push_raw(ls, obj0);
84
85 // 0
86 EXPECT_FALSE(ls.is_recursive(obj0));
87
88 push_raw(ls, obj1);
89
90 // 0, 1
91 EXPECT_FALSE(ls.is_recursive(obj0));
92 EXPECT_FALSE(ls.is_recursive(obj1));
93
94 push_raw(ls, obj1);
95
96 // 0, 1, 1
97 EXPECT_FALSE(ls.is_recursive(obj0));
98 EXPECT_TRUE(ls.is_recursive(obj1));
99
100 pop_raw(ls);
101 pop_raw(ls);
102 push_raw(ls, obj0);
103
104 // 0, 0
105 EXPECT_TRUE(ls.is_recursive(obj0));
106
107 push_raw(ls, obj0);
108
109 // 0, 0, 0
110 EXPECT_TRUE(ls.is_recursive(obj0));
111
112 pop_raw(ls);
113 push_raw(ls, obj1);
114
115 // 0, 0, 1
116 EXPECT_TRUE(ls.is_recursive(obj0));
117 EXPECT_FALSE(ls.is_recursive(obj1));
118
119 push_raw(ls, obj1);
120
121 // 0, 0, 1, 1
122 EXPECT_TRUE(ls.is_recursive(obj0));
123 EXPECT_TRUE(ls.is_recursive(obj1));
124
125 // Clear stack
126 pop_raw(ls);
127 pop_raw(ls);
128 pop_raw(ls);
129 pop_raw(ls);
130
131 EXPECT_TRUE(ls.is_empty());
132 }
133
134 TEST_VM_F(LockStackTest, try_recursive_enter) {
135 if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) {
136 return;
137 }
138
139 JavaThread* THREAD = JavaThread::current();
140 // the thread should be in vm to use locks
141 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
142
143 LockStack& ls = THREAD->lock_stack();
144
145 EXPECT_TRUE(ls.is_empty());
146
147 oop obj0 = Universe::int_mirror();
148 oop obj1 = Universe::float_mirror();
149
150 ls.push(obj0);
151
152 // 0
153 EXPECT_FALSE(ls.is_recursive(obj0));
154
155 ls.push(obj1);
156
157 // 0, 1
158 EXPECT_FALSE(ls.is_recursive(obj0));
159 EXPECT_FALSE(ls.is_recursive(obj1));
160
161 recursive_enter(ls, obj1);
162
163 // 0, 1, 1
164 EXPECT_FALSE(ls.is_recursive(obj0));
165 EXPECT_TRUE(ls.is_recursive(obj1));
166
167 recursive_exit(ls, obj1);
168 pop_raw(ls);
169 recursive_enter(ls, obj0);
170
171 // 0, 0
172 EXPECT_TRUE(ls.is_recursive(obj0));
173
174 recursive_enter(ls, obj0);
175
176 // 0, 0, 0
177 EXPECT_TRUE(ls.is_recursive(obj0));
178
179 recursive_exit(ls, obj0);
180 push_raw(ls, obj1);
181
182 // 0, 0, 1
183 EXPECT_TRUE(ls.is_recursive(obj0));
184 EXPECT_FALSE(ls.is_recursive(obj1));
185
186 recursive_enter(ls, obj1);
187
188 // 0, 0, 1, 1
189 EXPECT_TRUE(ls.is_recursive(obj0));
190 EXPECT_TRUE(ls.is_recursive(obj1));
191
192 // Clear stack
193 pop_raw(ls);
194 pop_raw(ls);
195 pop_raw(ls);
196 pop_raw(ls);
197
198 EXPECT_TRUE(ls.is_empty());
199 }
200
201 TEST_VM_F(LockStackTest, contains) {
202 if (LockingMode != LM_LIGHTWEIGHT) {
203 return;
204 }
205
206 const bool test_recursive = VM_Version::supports_recursive_lightweight_locking();
207
208 JavaThread* THREAD = JavaThread::current();
209 // the thread should be in vm to use locks
210 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
211
212 LockStack& ls = THREAD->lock_stack();
213
214 EXPECT_TRUE(ls.is_empty());
215
216 oop obj0 = Universe::int_mirror();
217 oop obj1 = Universe::float_mirror();
218
219 EXPECT_FALSE(ls.contains(obj0));
220
221 ls.push(obj0);
222
223 // 0
224 EXPECT_TRUE(ls.contains(obj0));
225 EXPECT_FALSE(ls.contains(obj1));
226
227 if (test_recursive) {
228 push_raw(ls, obj0);
229
230 // 0, 0
231 EXPECT_TRUE(ls.contains(obj0));
232 EXPECT_FALSE(ls.contains(obj1));
233 }
234
235 push_raw(ls, obj1);
236
237 // 0, 0, 1
238 EXPECT_TRUE(ls.contains(obj0));
239 EXPECT_TRUE(ls.contains(obj1));
240
241 if (test_recursive) {
242 push_raw(ls, obj1);
243
244 // 0, 0, 1, 1
245 EXPECT_TRUE(ls.contains(obj0));
246 EXPECT_TRUE(ls.contains(obj1));
247 }
248
249 pop_raw(ls);
250 if (test_recursive) {
251 pop_raw(ls);
252 pop_raw(ls);
253 }
254 push_raw(ls, obj1);
255
256 // 0, 1
257 EXPECT_TRUE(ls.contains(obj0));
258 EXPECT_TRUE(ls.contains(obj1));
259
260 // Clear stack
261 pop_raw(ls);
262 pop_raw(ls);
263
264 EXPECT_TRUE(ls.is_empty());
265 }
266
267 TEST_VM_F(LockStackTest, remove) {
268 if (LockingMode != LM_LIGHTWEIGHT) {
269 return;
270 }
271
272 const bool test_recursive = VM_Version::supports_recursive_lightweight_locking();
273
274 JavaThread* THREAD = JavaThread::current();
275 // the thread should be in vm to use locks
276 ThreadInVMfromNative ThreadInVMfromNative(THREAD);
277
278 LockStack& ls = THREAD->lock_stack();
279
280 EXPECT_TRUE(ls.is_empty());
281
282 oop obj0 = Universe::int_mirror();
283 oop obj1 = Universe::float_mirror();
284 oop obj2 = Universe::short_mirror();
285 oop obj3 = Universe::long_mirror();
286
287 push_raw(ls, obj0);
288
289 // 0
290 {
291 size_t removed = ls.remove(obj0);
292 EXPECT_EQ(removed, 1u);
293 EXPECT_FALSE(ls.contains(obj0));
294 }
295
296 if (test_recursive) {
297 push_raw(ls, obj0);
298 push_raw(ls, obj0);
299
300 // 0, 0
301 {
302 size_t removed = ls.remove(obj0);
303 EXPECT_EQ(removed, 2u);
304 EXPECT_FALSE(ls.contains(obj0));
305 }
306 }
307
308 push_raw(ls, obj0);
309 push_raw(ls, obj1);
310
311 // 0, 1
312 {
313 size_t removed = ls.remove(obj0);
314 EXPECT_EQ(removed, 1u);
315 EXPECT_FALSE(ls.contains(obj0));
316 EXPECT_TRUE(ls.contains(obj1));
317
318 ls.remove(obj1);
319 EXPECT_TRUE(ls.is_empty());
320 }
321
322 push_raw(ls, obj0);
323 push_raw(ls, obj1);
324
325 // 0, 1
326 {
327 size_t removed = ls.remove(obj1);
328 EXPECT_EQ(removed, 1u);
329 EXPECT_FALSE(ls.contains(obj1));
330 EXPECT_TRUE(ls.contains(obj0));
331
332 ls.remove(obj0);
333 EXPECT_TRUE(ls.is_empty());
334 }
335
336 if (test_recursive) {
337 push_raw(ls, obj0);
338 push_raw(ls, obj0);
339 push_raw(ls, obj1);
340
341 // 0, 0, 1
342 {
343 size_t removed = ls.remove(obj0);
344 EXPECT_EQ(removed, 2u);
345 EXPECT_FALSE(ls.contains(obj0));
346 EXPECT_TRUE(ls.contains(obj1));
347
348 ls.remove(obj1);
349 EXPECT_TRUE(ls.is_empty());
350 }
351
352 push_raw(ls, obj0);
353 push_raw(ls, obj1);
354 push_raw(ls, obj1);
355
356 // 0, 1, 1
357 {
358 size_t removed = ls.remove(obj1);
359 EXPECT_EQ(removed, 2u);
360 EXPECT_FALSE(ls.contains(obj1));
361 EXPECT_TRUE(ls.contains(obj0));
362
363 ls.remove(obj0);
364 EXPECT_TRUE(ls.is_empty());
365 }
366
367 push_raw(ls, obj0);
368 push_raw(ls, obj1);
369 push_raw(ls, obj1);
370 push_raw(ls, obj2);
371 push_raw(ls, obj2);
372 push_raw(ls, obj2);
373 push_raw(ls, obj2);
374 push_raw(ls, obj3);
375
376 // 0, 1, 1, 2, 2, 2, 2, 3
377 {
378 EXPECT_EQ(size(ls), 8u);
379
380 size_t removed = ls.remove(obj1);
381 EXPECT_EQ(removed, 2u);
382
383 EXPECT_TRUE(ls.contains(obj0));
384 EXPECT_FALSE(ls.contains(obj1));
385 EXPECT_TRUE(ls.contains(obj2));
386 EXPECT_TRUE(ls.contains(obj3));
387
388 EXPECT_EQ(at(ls, 0), obj0);
389 EXPECT_EQ(at(ls, 1), obj2);
390 EXPECT_EQ(at(ls, 2), obj2);
391 EXPECT_EQ(at(ls, 3), obj2);
392 EXPECT_EQ(at(ls, 4), obj2);
393 EXPECT_EQ(at(ls, 5), obj3);
394 EXPECT_EQ(size(ls), 6u);
395
396 removed = ls.remove(obj2);
397 EXPECT_EQ(removed, 4u);
398
399 EXPECT_TRUE(ls.contains(obj0));
400 EXPECT_FALSE(ls.contains(obj1));
401 EXPECT_FALSE(ls.contains(obj2));
402 EXPECT_TRUE(ls.contains(obj3));
403
404 EXPECT_EQ(at(ls, 0), obj0);
405 EXPECT_EQ(at(ls, 1), obj3);
406 EXPECT_EQ(size(ls), 2u);
407
408 removed = ls.remove(obj0);
409 EXPECT_EQ(removed, 1u);
410
411 EXPECT_FALSE(ls.contains(obj0));
412 EXPECT_FALSE(ls.contains(obj1));
413 EXPECT_FALSE(ls.contains(obj2));
414 EXPECT_TRUE(ls.contains(obj3));
415
416 EXPECT_EQ(at(ls, 0), obj3);
417 EXPECT_EQ(size(ls), 1u);
418
419 removed = ls.remove(obj3);
420 EXPECT_EQ(removed, 1u);
421
422 EXPECT_TRUE(ls.is_empty());
423 EXPECT_EQ(size(ls), 0u);
424 }
425 }
426
427 EXPECT_TRUE(ls.is_empty());
428 }