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 }