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 }