1 /* 2 * Copyright (c) 2019, 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 package runtime.valhalla.valuetypes; 24 25 import jdk.test.lib.Asserts; 26 27 /* 28 * @test 29 * @summary Test initialization of static inline fields with circularity 30 * @library /test/lib 31 * @compile CircularityTest.java 32 * @run main/othervm -Xint -XX:+EnableValhalla runtime.valhalla.valuetypes.CircularityTest 33 */ 34 35 36 public class CircularityTest { 37 static boolean b = true; 38 static int counter = 0; 39 40 static inline class A { 41 static B b; 42 static C c; 43 int i = 0; 44 } 45 46 static inline class B { 47 static { 48 Asserts.assertNotNull(A.c, "Should have returned C's default value"); 49 } 50 int i = 0; 51 } 52 53 static inline class C { 54 int i; 55 public C(int i) { 56 this.i = i; 57 } 58 } 59 60 static inline class D { 61 static C c; 62 int i = 0; 63 static { 64 if (CircularityTest.b) { 65 // throw an exception to cause D's initialization to fail 66 throw new RuntimeException(); 67 } 68 } 69 } 70 71 static inline class E { 72 static F f; 73 static C c; 74 int i = 0; 75 } 76 77 static inline class F { 78 int i = 0; 79 static { 80 E.c = new C(5); 81 } 82 } 83 84 static inline class G { 85 static H h; 86 int i = 0; 87 } 88 89 static inline class H { 90 int i = 0; 91 static { 92 if (CircularityTest.b) { 93 // throw an exception to cause H's initialization to fail 94 throw new RuntimeException(); 95 } 96 } 97 } 98 99 static inline class I { 100 static J j; 101 static H h; 102 int i = 0; 103 } 104 105 static inline class J { 106 int i = 0; 107 static { 108 CircularityTest.counter = 1; 109 H h = I.h; 110 CircularityTest.counter = 2; 111 } 112 } 113 114 static public void main(String[] args) { 115 Throwable exception = null; 116 // Test 1: 117 // Initialization of A will trigger initialization of B which, in its static 118 // initializer will access a static inline field c of A that has not been initialized 119 // yet. The access must succeed (no exception) because the field is being 120 // accessed during the initialization of D, by the thread initializing D, 121 // and the value must be the default value of C (not null). 122 try { 123 A a = new A(); 124 } catch (Throwable t) { 125 exception = t; 126 } 127 Asserts.assertNull(exception, "Circularity should not have caused exceptions"); 128 129 // Test 2: 130 // Class D will fail to initialized (exception thrown in its static initializer). 131 // Attempt to access a static inline field of D *after* its failed initialization 132 // should trigger an exception. 133 exception = null; 134 try { 135 D d = new D(); 136 } catch (Throwable t) { 137 // ignoring the exception thrown to cause initialization failure 138 } 139 try { 140 C c = D.c; 141 } catch (Throwable t) { 142 exception = t; 143 } 144 Asserts.assertNotNull(exception, "Accessing static fields of a class which failed to initialized should throw an exception"); 145 Asserts.assertEquals(exception.getClass(), java.lang.NoClassDefFoundError.class, "Wrong exception class"); 146 // Test 3: 147 // Initialization of E will trigger the initialization of F which, in its static initalizer, 148 // will initialized a static inline field of F before the JVM does. The JVM must not 149 // overwrite the value set by user code. 150 E e = new E(); 151 Asserts.assertEquals(E.c.i, 5, "JVM must not overwrite fields initialized by user code"); 152 153 // Test 4: 154 // Initialization of G should fail because its static inline field h 155 exception = null; 156 try { 157 G g = new G(); 158 } catch(Throwable t) { 159 exception = t; 160 } 161 Asserts.assertNotNull(exception, "G's initialization should have failed"); 162 Asserts.assertEquals(exception.getClass(), java.lang.ExceptionInInitializerError.class, "Wrong exception"); 163 164 // Test 5: 165 // Initialization of of I should fail when J tries to access I.h 166 exception = null; 167 try { 168 I i = new I(); 169 } catch(Throwable t) { 170 exception = t; 171 } 172 Asserts.assertNotNull(exception, "I's initialization should have failed"); 173 Asserts.assertEquals(exception.getClass(), java.lang.NoClassDefFoundError.class, "Wrong exception"); 174 Asserts.assertEquals(CircularityTest.counter, 1, "Didn't failed at the right place"); 175 } 176 }