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 }