1 /*
  2  * Copyright (c) 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 /*
 25  * @test
 26  * @bug 8324174
 27  * @summary During deoptimization locking and unlocking for nested locks are executed in incorrect order.
 28  * @requires vm.compMode != "Xint"
 29  * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -Xmx128M
 30  *                   -XX:CompileCommand=exclude,TestNestedRelockAtDeopt::main TestNestedRelockAtDeopt
 31  */
 32 
 33 import java.util.ArrayList;
 34 public class TestNestedRelockAtDeopt {
 35 
 36     static final int CHUNK = 1000;
 37     static ArrayList<Object> arr = null;
 38 
 39     public static void main(String[] args) {
 40         arr = new ArrayList<>();
 41         try {
 42             while (true) {
 43                 test1();
 44             }
 45         } catch (OutOfMemoryError oom) {
 46             arr = null; // Free memory
 47             System.out.println("OOM caught in test1");
 48         }
 49         arr = new ArrayList<>();
 50         try {
 51             while (true) {
 52                 test2();
 53             }
 54         } catch (OutOfMemoryError oom) {
 55             arr = null; // Free memory
 56             System.out.println("OOM caught in test2");
 57         }
 58         arr = new ArrayList<>();
 59         TestNestedRelockAtDeopt obj = new TestNestedRelockAtDeopt();
 60         try {
 61             while (true) {
 62                 test3(obj);
 63             }
 64         } catch (OutOfMemoryError oom) {
 65             arr = null; // Free memory
 66             System.out.println("OOM caught in test3");
 67         }
 68         arr = new ArrayList<>();
 69         try {
 70             while (true) {
 71                 test4(obj);
 72             }
 73         } catch (OutOfMemoryError oom) {
 74             arr = null; // Free memory
 75             System.out.println("OOM caught in test4");
 76         }
 77     }
 78 
 79     // Nested locks in one method
 80     static void test1() { // Nested lock in one method
 81         synchronized (TestNestedRelockAtDeopt.class) {
 82             synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation
 83                 synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
 84                     synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation
 85                         synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
 86                             arr.add(new byte[CHUNK]);
 87                         }
 88                     }
 89                 }
 90             }
 91         }
 92     }
 93 
 94     // Nested locks in inlined method
 95     static void foo() {
 96         synchronized (new TestNestedRelockAtDeopt()) {  // lock eliminated - not escaped allocation
 97             synchronized (TestNestedRelockAtDeopt.class) {  // nested lock eliminated when inlined
 98                 arr.add(new byte[CHUNK]);
 99             }
100         }
101     }
102 
103     static void test2() {
104         synchronized (TestNestedRelockAtDeopt.class) {
105             synchronized (new TestNestedRelockAtDeopt()) {  // lock eliminated - not escaped allocation
106                 synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
107                     foo(); // Inline
108                 }
109             }
110         }
111     }
112 
113     // Nested locks in one method
114     static void test3(TestNestedRelockAtDeopt obj) {
115         synchronized (TestNestedRelockAtDeopt.class) {
116             synchronized (obj) { // lock not eliminated - external object
117                 synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
118                     synchronized (obj) { // nested lock eliminated
119                         synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
120                             arr.add(new byte[CHUNK]);
121                         }
122                     }
123                 }
124             }
125         }
126     }
127 
128     // Nested locks with different objects in inlined method
129     static void bar(TestNestedRelockAtDeopt obj) {
130         synchronized (obj) {  // nested lock eliminated when inlined
131             synchronized (TestNestedRelockAtDeopt.class) {  // nested lock eliminated when inlined
132                 arr.add(new byte[CHUNK]);
133             }
134         }
135     }
136 
137     static void test4(TestNestedRelockAtDeopt obj) {
138         synchronized (TestNestedRelockAtDeopt.class) {
139             synchronized (obj) {  // lock not eliminated - external object
140                 synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated
141                     bar(obj); // Inline
142                 }
143             }
144         }
145     }
146 }