CallStaticInitOrder.java revision 15491:6f390eafc676
1/* 2 * Copyright (c) 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 26 * @summary static initializer invocation order 27 * 28 * @build indify.Indify 29 * @compile CallStaticInitOrder.java 30 * @run main/othervm 31 * indify.Indify 32 * --expand-properties --classpath ${test.classes} 33 * --java test.java.lang.invoke.CallStaticInitOrder 34 */ 35 36package test.java.lang.invoke; 37 38import java.io.*; 39 40import java.lang.invoke.*; 41import static java.lang.invoke.MethodHandles.*; 42import static java.lang.invoke.MethodType.*; 43 44public class CallStaticInitOrder { 45 private static int TICK; 46 private static synchronized int tick(String event) { 47 int n = ++TICK; 48 System.out.println("event #"+n+" = "+event); 49 return n; 50 } 51 52 static int Init1Tick; 53 private static class Init1 { 54 static { Init1Tick = tick("foo -> Init1.<clinit>"); } 55 static int foo() { return Init1Tick; } 56 } 57 58 static int Init2Tick; 59 private static class Init2 { 60 static { Init2Tick = tick("bar -> Init2.<clinit>"); } 61 static int bar() { return Init2Tick; } 62 } 63 64 static int Init3Tick; 65 private static class Init3 { 66 static { Init3Tick = tick("baz -> Init3.<clinit>"); } 67 static int baz() { return Init3Tick; } 68 } 69 70 static int Init4Tick; 71 private static class Init4 { 72 static { Init4Tick = tick("bat -> Init4.<clinit>"); } 73 static int bat() { return Init4Tick; } 74 } 75 76 static int Init5Tick; 77 private static class Init5 { 78 static { Init5Tick = tick("read bang -> Init5.<clinit>"); } 79 static int bang = Init5Tick; 80 } 81 82 static int Init6Tick; 83 private static class Init6 { 84 static { Init6Tick = tick("write pong -> Init6.<clinit>"); } 85 static int pong; 86 } 87 88 private static final MutableCallSite CONSTANT_CS_baz; 89 private static MethodHandle MH_foo() throws ReflectiveOperationException { 90 return lookup().findStatic(Init1.class, "foo", methodType(int.class)); 91 } 92 private static final MethodHandle CONSTANT_MH_bar; 93 private static MethodHandle MH_baz() throws ReflectiveOperationException { 94 return lookup().findStatic(Init3.class, "baz", methodType(int.class)); 95 } 96 private static final MethodHandle CONSTANT_MH_bat; 97 private static final MethodHandle CONSTANT_MH_bangGetter; 98 private static final MethodHandle CONSTANT_MH_pongSetter; 99 static { 100 try { 101 int t1 = tick("CallStaticInitOrder.<clinit>"); 102 { 103 CONSTANT_CS_baz = new MutableCallSite(methodType(int.class)); 104 // MH_foo() := lookup().findStatic(Init1.class, "foo", methodType(int.class)); 105 CONSTANT_MH_bar = lookup().findStatic(Init2.class, "bar", methodType(int.class)); 106 // MH_baz() := lookup().findStatic(Init3.class, "baz", methodType(int.class)); 107 CONSTANT_MH_bat = lookup().unreflect(Init4.class.getDeclaredMethod("bat")); 108 CONSTANT_MH_bangGetter = lookup().findStaticGetter(Init5.class, "bang", int.class); 109 MethodHandle pongSetter = lookup().findStaticSetter(Init6.class, "pong", int.class); 110 MethodHandle tickGetter = lookup().findStaticGetter(CallStaticInitOrder.class, "Init6Tick", int.class); 111 CONSTANT_MH_pongSetter = filterReturnValue(insertArguments(pongSetter, 0, -99), tickGetter); 112 } 113 int t2 = tick("CallStaticInitOrder.<clinit> done"); 114 assertEquals(t1+1, t2); // no ticks in between 115 } catch (Exception ex) { 116 throw new InternalError(ex.toString()); 117 } 118 } 119 120 public static void main(String... av) throws Throwable { 121 testInit(); 122 if (LAST_LOSER != null) throw LAST_LOSER; 123 } 124 125 private static Throwable LAST_LOSER; 126 127 private static void assertEquals(int expected, int actual) { 128 if (expected != actual) { 129 Throwable loser = new AssertionError("expected: " + expected + ", actual: " + actual); 130 if (LAST_LOSER != null) 131 LAST_LOSER.printStackTrace(System.out); 132 LAST_LOSER = loser; 133 } 134 } 135 136 private static void testInit() throws Throwable { 137 System.out.println("runFoo = "+runFoo()); 138 System.out.println("runBar = "+runBar()); 139 try { 140 runBaz(); 141 } catch (IllegalStateException ex) { 142 tick("runBaz throw/catch"); 143 } 144 CONSTANT_CS_baz.setTarget(MH_baz()); 145 System.out.println("runBaz = "+runBaz()); 146 System.out.println("runBat = "+runBat()); 147 System.out.println("runBang = "+runBang()); 148 System.out.println("runPong = "+runPong()); 149 } 150 151 private static int runFoo() throws Throwable { 152 assertEquals(Init1Tick, 0); // Init1 not initialized yet 153 int t1 = tick("runFoo"); 154 int t2 = (int) INDY_foo().invokeExact(); 155 int t3 = tick("runFoo done"); 156 assertEquals(Init1Tick, t2); // when Init1 was initialized 157 assertEquals(t1+2, t3); // exactly two ticks in between 158 assertEquals(t1+1, t2); // init happened inside 159 return t2; 160 } 161 private static MethodHandle INDY_foo() throws Throwable { 162 shouldNotCallThis(); 163 return ((CallSite) MH_bsm().invoke(lookup(), "foo", methodType(int.class))).dynamicInvoker(); 164 } 165 166 private static int runBar() throws Throwable { 167 assertEquals(Init2Tick, 0); // Init2 not initialized yet 168 int t1 = tick("runBar"); 169 int t2 = (int) INDY_bar().invokeExact(); 170 int t3 = tick("runBar done"); 171 assertEquals(Init2Tick, t2); // when Init2 was initialized 172 assertEquals(t1+2, t3); // exactly two ticks in between 173 assertEquals(t1+1, t2); // init happened inside 174 return t2; 175 } 176 private static MethodHandle INDY_bar() throws Throwable { 177 shouldNotCallThis(); 178 return ((CallSite) MH_bsm().invoke(lookup(), "bar", methodType(int.class))).dynamicInvoker(); 179 } 180 181 private static int runBaz() throws Throwable { 182 assertEquals(Init3Tick, 0); // Init3 not initialized yet 183 int t1 = tick("runBaz"); 184 int t2 = (int) INDY_baz().invokeExact(); 185 int t3 = tick("runBaz done"); 186 assertEquals(Init3Tick, t2); // when Init3 was initialized 187 assertEquals(t1+2, t3); // exactly two ticks in between 188 assertEquals(t1+1, t2); // init happened inside 189 return t2; 190 } 191 private static MethodHandle INDY_baz() throws Throwable { 192 shouldNotCallThis(); 193 return ((CallSite) MH_bsm().invoke(lookup(), "baz", methodType(int.class))).dynamicInvoker(); 194 } 195 196 private static int runBat() throws Throwable { 197 assertEquals(Init4Tick, 0); // Init4 not initialized yet 198 int t1 = tick("runBat"); 199 int t2 = (int) INDY_bat().invokeExact(); 200 int t3 = tick("runBat done"); 201 assertEquals(Init4Tick, t2); // when Init4 was initialized 202 assertEquals(t1+2, t3); // exactly two ticks in between 203 assertEquals(t1+1, t2); // init happened inside 204 return t2; 205 } 206 private static MethodHandle INDY_bat() throws Throwable { 207 shouldNotCallThis(); 208 return ((CallSite) MH_bsm().invoke(lookup(), "bat", methodType(int.class))).dynamicInvoker(); 209 } 210 211 private static int runBang() throws Throwable { 212 assertEquals(Init5Tick, 0); // Init5 not initialized yet 213 int t1 = tick("runBang"); 214 int t2 = (int) INDY_bang().invokeExact(); 215 int t3 = tick("runBang done"); 216 assertEquals(Init5Tick, t2); // when Init5 was initialized 217 assertEquals(t1+2, t3); // exactly two ticks in between 218 assertEquals(t1+1, t2); // init happened inside 219 return t2; 220 } 221 private static MethodHandle INDY_bang() throws Throwable { 222 shouldNotCallThis(); 223 return ((CallSite) MH_bsm().invoke(lookup(), "bang", methodType(int.class))).dynamicInvoker(); 224 } 225 226 private static int runPong() throws Throwable { 227 assertEquals(Init6Tick, 0); // Init6 not initialized yet 228 int t1 = tick("runPong"); 229 int t2 = (int) INDY_pong().invokeExact(); 230 int t3 = tick("runPong done"); 231 assertEquals(Init6Tick, t2); // when Init6 was initialized 232 assertEquals(t1+2, t3); // exactly two ticks in between 233 assertEquals(t1+1, t2); // init happened inside 234 return t2; 235 } 236 private static MethodHandle INDY_pong() throws Throwable { 237 shouldNotCallThis(); 238 return ((CallSite) MH_bsm().invoke(lookup(), "pong", methodType(int.class))).dynamicInvoker(); 239 } 240 241 private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException { 242 System.out.println("bsm "+name+type); 243 CallSite res; 244 switch (name) { 245 case "foo": 246 res = new ConstantCallSite(MH_foo()); break; 247 case "bar": 248 res = new ConstantCallSite(CONSTANT_MH_bar); break; 249 case "baz": 250 res = CONSTANT_CS_baz; break; 251 case "bat": 252 res = new ConstantCallSite(CONSTANT_MH_bat); break; 253 case "bang": 254 res = new ConstantCallSite(CONSTANT_MH_bangGetter); break; 255 case "pong": 256 res = new ConstantCallSite(CONSTANT_MH_pongSetter); break; 257 default: 258 res = null; 259 } 260 if (res == null || !res.type().equals(type)) { 261 throw new AssertionError(String.valueOf(res)); 262 } 263 return res; 264 } 265 private static MethodHandle MH_bsm() throws ReflectiveOperationException { 266 shouldNotCallThis(); 267 return lookup().findStatic(lookup().lookupClass(), "bsm", 268 methodType(CallSite.class, Lookup.class, String.class, MethodType.class)); 269 } 270 private static void shouldNotCallThis() { 271 // if this gets called, the transformation has not taken place 272 throw new AssertionError("this code should be statically transformed away by Indify"); 273 } 274} 275