1 /*
2  * Copyright (c) 2012, 2019, 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 8004741
27  * @summary Missing compiled exception handle table entry for multidimensional array allocation
28  *
29  * @requires !vm.graal.enabled
30  * @library /test/lib
31  *
32  * @build sun.hotspot.WhiteBox
33  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
34  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
35  *
36  * @run main/othervm -Xmx128m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
37  *    -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers
38  *    -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100
39  *    -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
40  *    compiler.c2.Test8004741
41  *
42  * @run main/othervm -Xmx128m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
43  *    -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers
44  *    -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
45  *    compiler.c2.Test8004741
46  */
47 
48 package compiler.c2;
49 
50 import sun.hotspot.WhiteBox;
51 
52 public class Test8004741 extends Thread {
53 
54   static int passed = 0;
55 
56   /**
57    * Loop forever allocating 2-d arrays.
58    * Catches and rethrows all exceptions; in the case of ThreadDeath, increments passed.
59    * Note that passed is incremented here because this is the exception handler with
60    * the smallest scope; we only want to declare success in the case where it is highly
61    * likely that the test condition
62    * (exception in 2-d array alloc interrupted by ThreadDeath)
63    * actually occurs.
64    */
test(int a, int b)65   static int[][] test(int a, int b) throws Exception {
66     int[][] ar;
67     try {
68       ar = new int[a][b];
69     } catch (ThreadDeath e) {
70       System.out.println("test got ThreadDeath");
71       passed++;
72       throw e;
73     }
74     return ar;
75   }
76 
77   /* Cookbook wait-notify to track progress of test thread. */
78   Object progressLock = new Object();
79   private static final int NOT_STARTED = 0;
80   private static final int RUNNING = 1;
81   private static final int STOPPING = 2;
82 
83   int progressState = NOT_STARTED;
84 
toState(int state)85   void toState(int state) {
86     synchronized (progressLock) {
87       progressState = state;
88       progressLock.notify();
89     }
90   }
91 
waitFor(int state)92   void waitFor(int state) {
93     synchronized (progressLock) {
94       while (progressState < state) {
95         try {
96           progressLock.wait();
97         } catch (InterruptedException e) {
98           throw new Error("unexpected InterruptedException", e);
99         }
100       }
101       if (progressState > state) {
102         throw new Error("unexpected test state change, state = " + state + ", progressState = " + progressState);
103       }
104     }
105   }
106 
107   /**
108    * Loops running test until some sort of an exception or error,
109    * expects to see ThreadDeath.
110    */
run()111   public void run() {
112     try {
113       // Print before state change, so that other thread is most likely
114       // to see this thread executing calls to test() in a loop.
115       System.out.println("thread running");
116       toState(RUNNING);
117       while (true) {
118         // (2,2) (2,10) (2,100) were observed to tickle the bug;
119         test(2, 100);
120       }
121     } catch (ThreadDeath e) {
122       // nothing to say, passing was incremented by the test.
123     } catch (Throwable e) {
124       throw new Error("unexpected Throwable " + e, e);
125     }
126     toState(STOPPING);
127   }
128 
129   /**
130    * Runs a single trial of the test in a thread.
131    * No single trial is definitive, since the ThreadDeath
132    * exception might not land in the tested region of code.
133    */
threadTest()134   public static void threadTest() throws InterruptedException {
135     Test8004741 t = new Test8004741();
136     t.start();
137     t.waitFor(RUNNING);
138     Thread.sleep(100);
139     System.out.println("stopping thread");
140     t.stop();
141     t.waitFor(STOPPING);
142     t.join();
143   }
144 
main(String[] args)145   public static void main(String[] args) throws Exception {
146     // Warm up "test"
147     // t will never be started.
148     for (int n = 0; n < 11000; n++) {
149       test(2, 100);
150     }
151 
152     var method = Test8004741.class.getDeclaredMethod("test", int.class, int.class);
153     if (!WhiteBox.getWhiteBox().isMethodCompiled(method)) {
154         throw new Error("test method didn't get compiled");
155     }
156 
157     try {
158       test(-1, 100);
159       throw new AssertionError("Missing NegativeArraySizeException");
160     } catch (NegativeArraySizeException e) {
161       System.out.println("Saw expected NegativeArraySizeException #1");
162     }
163 
164     try {
165       test(100, -1);
166       throw new AssertionError("Missing NegativeArraySizeException");
167     } catch (NegativeArraySizeException e) {
168       System.out.println("Saw expected NegativeArraySizeException #2");
169     }
170 
171     /* Test repetitions.  If the test succeeds-mostly, it succeeds,
172      * as long as it does not crash (the outcome if the exception range
173      * table entry for the array allocation is missing).
174      */
175     passed = 0;
176     int limit = 6;
177     while (passed != limit) {
178       threadTest();
179     }
180   }
181 }
182