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