Path: blob/master/test/jdk/java/lang/invoke/CallStaticInitOrder.java
41149 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @summary static initializer invocation order26*27* @build indify.Indify28* @compile CallStaticInitOrder.java29* @run main/othervm30* indify.Indify31* --expand-properties --classpath ${test.classes}32* --java test.java.lang.invoke.CallStaticInitOrder33*/3435package test.java.lang.invoke;3637import java.io.*;3839import java.lang.invoke.*;40import static java.lang.invoke.MethodHandles.*;41import static java.lang.invoke.MethodType.*;4243public class CallStaticInitOrder {44private static int TICK;45private static synchronized int tick(String event) {46int n = ++TICK;47System.out.println("event #"+n+" = "+event);48return n;49}5051static int Init1Tick;52private static class Init1 {53static { Init1Tick = tick("foo -> Init1.<clinit>"); }54static int foo() { return Init1Tick; }55}5657static int Init2Tick;58private static class Init2 {59static { Init2Tick = tick("bar -> Init2.<clinit>"); }60static int bar() { return Init2Tick; }61}6263static int Init3Tick;64private static class Init3 {65static { Init3Tick = tick("baz -> Init3.<clinit>"); }66static int baz() { return Init3Tick; }67}6869static int Init4Tick;70private static class Init4 {71static { Init4Tick = tick("bat -> Init4.<clinit>"); }72static int bat() { return Init4Tick; }73}7475static int Init5Tick;76private static class Init5 {77static { Init5Tick = tick("read bang -> Init5.<clinit>"); }78static int bang = Init5Tick;79}8081static int Init6Tick;82private static class Init6 {83static { Init6Tick = tick("write pong -> Init6.<clinit>"); }84static int pong;85}8687private static final MutableCallSite CONSTANT_CS_baz;88private static MethodHandle MH_foo() throws ReflectiveOperationException {89return lookup().findStatic(Init1.class, "foo", methodType(int.class));90}91private static final MethodHandle CONSTANT_MH_bar;92private static MethodHandle MH_baz() throws ReflectiveOperationException {93return lookup().findStatic(Init3.class, "baz", methodType(int.class));94}95private static final MethodHandle CONSTANT_MH_bat;96private static final MethodHandle CONSTANT_MH_bangGetter;97private static final MethodHandle CONSTANT_MH_pongSetter;98static {99try {100int t1 = tick("CallStaticInitOrder.<clinit>");101{102CONSTANT_CS_baz = new MutableCallSite(methodType(int.class));103// MH_foo() := lookup().findStatic(Init1.class, "foo", methodType(int.class));104CONSTANT_MH_bar = lookup().findStatic(Init2.class, "bar", methodType(int.class));105// MH_baz() := lookup().findStatic(Init3.class, "baz", methodType(int.class));106CONSTANT_MH_bat = lookup().unreflect(Init4.class.getDeclaredMethod("bat"));107CONSTANT_MH_bangGetter = lookup().findStaticGetter(Init5.class, "bang", int.class);108MethodHandle pongSetter = lookup().findStaticSetter(Init6.class, "pong", int.class);109MethodHandle tickGetter = lookup().findStaticGetter(CallStaticInitOrder.class, "Init6Tick", int.class);110CONSTANT_MH_pongSetter = filterReturnValue(insertArguments(pongSetter, 0, -99), tickGetter);111}112int t2 = tick("CallStaticInitOrder.<clinit> done");113assertEquals(t1+1, t2); // no ticks in between114} catch (Exception ex) {115throw new InternalError(ex.toString());116}117}118119public static void main(String... av) throws Throwable {120testInit();121if (LAST_LOSER != null) throw LAST_LOSER;122}123124private static Throwable LAST_LOSER;125126private static void assertEquals(int expected, int actual) {127if (expected != actual) {128Throwable loser = new AssertionError("expected: " + expected + ", actual: " + actual);129if (LAST_LOSER != null)130LAST_LOSER.printStackTrace(System.out);131LAST_LOSER = loser;132}133}134135private static void testInit() throws Throwable {136System.out.println("runFoo = "+runFoo());137System.out.println("runBar = "+runBar());138try {139runBaz();140} catch (IllegalStateException ex) {141tick("runBaz throw/catch");142}143CONSTANT_CS_baz.setTarget(MH_baz());144System.out.println("runBaz = "+runBaz());145System.out.println("runBat = "+runBat());146System.out.println("runBang = "+runBang());147System.out.println("runPong = "+runPong());148}149150private static int runFoo() throws Throwable {151assertEquals(Init1Tick, 0); // Init1 not initialized yet152int t1 = tick("runFoo");153int t2 = (int) INDY_foo().invokeExact();154int t3 = tick("runFoo done");155assertEquals(Init1Tick, t2); // when Init1 was initialized156assertEquals(t1+2, t3); // exactly two ticks in between157assertEquals(t1+1, t2); // init happened inside158return t2;159}160private static MethodHandle INDY_foo() throws Throwable {161shouldNotCallThis();162return ((CallSite) MH_bsm().invoke(lookup(), "foo", methodType(int.class))).dynamicInvoker();163}164165private static int runBar() throws Throwable {166assertEquals(Init2Tick, 0); // Init2 not initialized yet167int t1 = tick("runBar");168int t2 = (int) INDY_bar().invokeExact();169int t3 = tick("runBar done");170assertEquals(Init2Tick, t2); // when Init2 was initialized171assertEquals(t1+2, t3); // exactly two ticks in between172assertEquals(t1+1, t2); // init happened inside173return t2;174}175private static MethodHandle INDY_bar() throws Throwable {176shouldNotCallThis();177return ((CallSite) MH_bsm().invoke(lookup(), "bar", methodType(int.class))).dynamicInvoker();178}179180private static int runBaz() throws Throwable {181assertEquals(Init3Tick, 0); // Init3 not initialized yet182int t1 = tick("runBaz");183int t2 = (int) INDY_baz().invokeExact();184int t3 = tick("runBaz done");185assertEquals(Init3Tick, t2); // when Init3 was initialized186assertEquals(t1+2, t3); // exactly two ticks in between187assertEquals(t1+1, t2); // init happened inside188return t2;189}190private static MethodHandle INDY_baz() throws Throwable {191shouldNotCallThis();192return ((CallSite) MH_bsm().invoke(lookup(), "baz", methodType(int.class))).dynamicInvoker();193}194195private static int runBat() throws Throwable {196assertEquals(Init4Tick, 0); // Init4 not initialized yet197int t1 = tick("runBat");198int t2 = (int) INDY_bat().invokeExact();199int t3 = tick("runBat done");200assertEquals(Init4Tick, t2); // when Init4 was initialized201assertEquals(t1+2, t3); // exactly two ticks in between202assertEquals(t1+1, t2); // init happened inside203return t2;204}205private static MethodHandle INDY_bat() throws Throwable {206shouldNotCallThis();207return ((CallSite) MH_bsm().invoke(lookup(), "bat", methodType(int.class))).dynamicInvoker();208}209210private static int runBang() throws Throwable {211assertEquals(Init5Tick, 0); // Init5 not initialized yet212int t1 = tick("runBang");213int t2 = (int) INDY_bang().invokeExact();214int t3 = tick("runBang done");215assertEquals(Init5Tick, t2); // when Init5 was initialized216assertEquals(t1+2, t3); // exactly two ticks in between217assertEquals(t1+1, t2); // init happened inside218return t2;219}220private static MethodHandle INDY_bang() throws Throwable {221shouldNotCallThis();222return ((CallSite) MH_bsm().invoke(lookup(), "bang", methodType(int.class))).dynamicInvoker();223}224225private static int runPong() throws Throwable {226assertEquals(Init6Tick, 0); // Init6 not initialized yet227int t1 = tick("runPong");228int t2 = (int) INDY_pong().invokeExact();229int t3 = tick("runPong done");230assertEquals(Init6Tick, t2); // when Init6 was initialized231assertEquals(t1+2, t3); // exactly two ticks in between232assertEquals(t1+1, t2); // init happened inside233return t2;234}235private static MethodHandle INDY_pong() throws Throwable {236shouldNotCallThis();237return ((CallSite) MH_bsm().invoke(lookup(), "pong", methodType(int.class))).dynamicInvoker();238}239240private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {241System.out.println("bsm "+name+type);242CallSite res;243switch (name) {244case "foo":245res = new ConstantCallSite(MH_foo()); break;246case "bar":247res = new ConstantCallSite(CONSTANT_MH_bar); break;248case "baz":249res = CONSTANT_CS_baz; break;250case "bat":251res = new ConstantCallSite(CONSTANT_MH_bat); break;252case "bang":253res = new ConstantCallSite(CONSTANT_MH_bangGetter); break;254case "pong":255res = new ConstantCallSite(CONSTANT_MH_pongSetter); break;256default:257res = null;258}259if (res == null || !res.type().equals(type)) {260throw new AssertionError(String.valueOf(res));261}262return res;263}264private static MethodHandle MH_bsm() throws ReflectiveOperationException {265shouldNotCallThis();266return lookup().findStatic(lookup().lookupClass(), "bsm",267methodType(CallSite.class, Lookup.class, String.class, MethodType.class));268}269private static void shouldNotCallThis() {270// if this gets called, the transformation has not taken place271throw new AssertionError("this code should be statically transformed away by Indify");272}273}274275276