1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker public class Main { main(String args[])18*795d594fSAndroid Build Coastguard Worker public static void main(String args[]) { 19*795d594fSAndroid Build Coastguard Worker simpleTest(); 20*795d594fSAndroid Build Coastguard Worker hierarchyTest(); 21*795d594fSAndroid Build Coastguard Worker } 22*795d594fSAndroid Build Coastguard Worker simpleTest()23*795d594fSAndroid Build Coastguard Worker public static void simpleTest() { 24*795d594fSAndroid Build Coastguard Worker // Partial initialization of Bad; ignoring the error. 25*795d594fSAndroid Build Coastguard Worker Error badClinit = null; 26*795d594fSAndroid Build Coastguard Worker try { 27*795d594fSAndroid Build Coastguard Worker new Bad(11); 28*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 29*795d594fSAndroid Build Coastguard Worker badClinit = e; 30*795d594fSAndroid Build Coastguard Worker } 31*795d594fSAndroid Build Coastguard Worker // Call foo() on the escaped instance of Bad. 32*795d594fSAndroid Build Coastguard Worker try { 33*795d594fSAndroid Build Coastguard Worker bad.foo(); 34*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 35*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 36*795d594fSAndroid Build Coastguard Worker } 37*795d594fSAndroid Build Coastguard Worker // Call bar() on the escaped instance of Bad. 38*795d594fSAndroid Build Coastguard Worker try { 39*795d594fSAndroid Build Coastguard Worker bad.bar(); 40*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 41*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 42*795d594fSAndroid Build Coastguard Worker } 43*795d594fSAndroid Build Coastguard Worker 44*795d594fSAndroid Build Coastguard Worker // Test that we handle bad instance correctly in the resolution trampoline. 45*795d594fSAndroid Build Coastguard Worker bad.$noinline$testResolutionTrampoline(); 46*795d594fSAndroid Build Coastguard Worker } 47*795d594fSAndroid Build Coastguard Worker hierarchyTest()48*795d594fSAndroid Build Coastguard Worker public static void hierarchyTest() { 49*795d594fSAndroid Build Coastguard Worker // Partial initialization of BadSuper; ignoring the error. Fully initializes BadSub. 50*795d594fSAndroid Build Coastguard Worker Error badClinit = null; 51*795d594fSAndroid Build Coastguard Worker try { 52*795d594fSAndroid Build Coastguard Worker new BadSuper(0); 53*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 54*795d594fSAndroid Build Coastguard Worker badClinit = e; 55*795d594fSAndroid Build Coastguard Worker } 56*795d594fSAndroid Build Coastguard Worker // Call BadSuper.foo() on the escaped instance of BadSuper. 57*795d594fSAndroid Build Coastguard Worker try { 58*795d594fSAndroid Build Coastguard Worker badSuper.foo(); 59*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 60*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker 63*795d594fSAndroid Build Coastguard Worker // Call BadSub.bar() on the escaped instance of BadSub. 64*795d594fSAndroid Build Coastguard Worker try { 65*795d594fSAndroid Build Coastguard Worker badSub.bar(); 66*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 67*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 68*795d594fSAndroid Build Coastguard Worker } 69*795d594fSAndroid Build Coastguard Worker 70*795d594fSAndroid Build Coastguard Worker // Test that we can even create instances of BadSub with erroneous superclass BadSuper. 71*795d594fSAndroid Build Coastguard Worker try { 72*795d594fSAndroid Build Coastguard Worker new BadSub(-1, -2).bar(); 73*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 74*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 75*795d594fSAndroid Build Coastguard Worker } 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker // Test that we cannot create instances of BadSuper from BadSub. 78*795d594fSAndroid Build Coastguard Worker try { 79*795d594fSAndroid Build Coastguard Worker badSub.allocSuper(11111); // Should throw. 80*795d594fSAndroid Build Coastguard Worker System.out.println("Allocated BadSuper!"); 81*795d594fSAndroid Build Coastguard Worker } catch (NoClassDefFoundError ncdfe) { 82*795d594fSAndroid Build Coastguard Worker checkNcdfe(ncdfe, badClinit); 83*795d594fSAndroid Build Coastguard Worker } 84*795d594fSAndroid Build Coastguard Worker } 85*795d594fSAndroid Build Coastguard Worker checkNcdfe(NoClassDefFoundError ncdfe, Throwable expectedCause)86*795d594fSAndroid Build Coastguard Worker private static void checkNcdfe(NoClassDefFoundError ncdfe, Throwable expectedCause) { 87*795d594fSAndroid Build Coastguard Worker // On RI, the NCDFE has no cause. On ART, the badClinit is the cause. 88*795d594fSAndroid Build Coastguard Worker if (ncdfe.getCause() == expectedCause || ncdfe.getCause() == null) { 89*795d594fSAndroid Build Coastguard Worker System.out.println("Caught NoClassDefFoundError."); 90*795d594fSAndroid Build Coastguard Worker return; 91*795d594fSAndroid Build Coastguard Worker } 92*795d594fSAndroid Build Coastguard Worker // On newer RI, the NCDFE has an ExceptionInInitializerError cause which contains the string of 93*795d594fSAndroid Build Coastguard Worker // the original error, but have a null cause and exception. 94*795d594fSAndroid Build Coastguard Worker if (ncdfe.getCause() instanceof ExceptionInInitializerError) { 95*795d594fSAndroid Build Coastguard Worker ExceptionInInitializerError cause = (ExceptionInInitializerError) ncdfe.getCause(); 96*795d594fSAndroid Build Coastguard Worker if (cause.getException() == null) { 97*795d594fSAndroid Build Coastguard Worker System.out.println("Caught NoClassDefFoundError."); 98*795d594fSAndroid Build Coastguard Worker return; 99*795d594fSAndroid Build Coastguard Worker } 100*795d594fSAndroid Build Coastguard Worker } 101*795d594fSAndroid Build Coastguard Worker ncdfe.printStackTrace(); 102*795d594fSAndroid Build Coastguard Worker } 103*795d594fSAndroid Build Coastguard Worker 104*795d594fSAndroid Build Coastguard Worker public static Bad bad; 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker public static BadSuper badSuper; 107*795d594fSAndroid Build Coastguard Worker public static BadSub badSub; 108*795d594fSAndroid Build Coastguard Worker } 109*795d594fSAndroid Build Coastguard Worker 110*795d594fSAndroid Build Coastguard Worker class Bad { 111*795d594fSAndroid Build Coastguard Worker static { 112*795d594fSAndroid Build Coastguard Worker // Create an instance of Bad and let it escape in Main.bad. 113*795d594fSAndroid Build Coastguard Worker Main.bad = new Bad(33); 114*795d594fSAndroid Build Coastguard Worker staticValue = 42; 115*795d594fSAndroid Build Coastguard Worker if (true) { throw new Error("Bad <clinit>"); } 116*795d594fSAndroid Build Coastguard Worker } foo()117*795d594fSAndroid Build Coastguard Worker public void foo() { 118*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.foo()"); 119*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.instanceValue = " + instanceValue); 120*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.staticValue = " + staticValue); 121*795d594fSAndroid Build Coastguard Worker } bar()122*795d594fSAndroid Build Coastguard Worker public void bar() { 123*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.bar()"); 124*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.staticValue [indirect] = " + Helper.$inline$getBadStaticValue()); 125*795d594fSAndroid Build Coastguard Worker } Bad(int iv)126*795d594fSAndroid Build Coastguard Worker public Bad(int iv) { instanceValue = iv; } 127*795d594fSAndroid Build Coastguard Worker public int instanceValue; 128*795d594fSAndroid Build Coastguard Worker public static int staticValue; 129*795d594fSAndroid Build Coastguard Worker 130*795d594fSAndroid Build Coastguard Worker public static class Helper { $inline$getBadStaticValue()131*795d594fSAndroid Build Coastguard Worker public static int $inline$getBadStaticValue() { 132*795d594fSAndroid Build Coastguard Worker return Bad.staticValue; 133*795d594fSAndroid Build Coastguard Worker } 134*795d594fSAndroid Build Coastguard Worker } 135*795d594fSAndroid Build Coastguard Worker $noinline$testResolutionTrampoline()136*795d594fSAndroid Build Coastguard Worker public void $noinline$testResolutionTrampoline() { 137*795d594fSAndroid Build Coastguard Worker // The first call to private method uses the resolution trampoline when AOT-compiled. 138*795d594fSAndroid Build Coastguard Worker $noinline$testResolutionTrampolineCallee(); 139*795d594fSAndroid Build Coastguard Worker } 140*795d594fSAndroid Build Coastguard Worker $noinline$testResolutionTrampolineCallee()141*795d594fSAndroid Build Coastguard Worker private void $noinline$testResolutionTrampolineCallee() { 142*795d594fSAndroid Build Coastguard Worker System.out.println("Bad.$noinline$testResolutionTrampolineCallee()"); 143*795d594fSAndroid Build Coastguard Worker } 144*795d594fSAndroid Build Coastguard Worker } 145*795d594fSAndroid Build Coastguard Worker 146*795d594fSAndroid Build Coastguard Worker class BadSuper { 147*795d594fSAndroid Build Coastguard Worker static { 148*795d594fSAndroid Build Coastguard Worker Main.badSuper = new BadSuper(1); 149*795d594fSAndroid Build Coastguard Worker Main.badSub = new BadSub(11, 111); // Fully initializes BadSub. 150*795d594fSAndroid Build Coastguard Worker BadSuper.superStaticValue = 42; 151*795d594fSAndroid Build Coastguard Worker BadSub.subStaticValue = 4242; 152*795d594fSAndroid Build Coastguard Worker if (true) { throw new Error("Bad <clinit>"); } 153*795d594fSAndroid Build Coastguard Worker } foo()154*795d594fSAndroid Build Coastguard Worker public void foo() { 155*795d594fSAndroid Build Coastguard Worker System.out.println("BadSuper.foo()"); 156*795d594fSAndroid Build Coastguard Worker System.out.println("BadSuper.superInstanceValue = " + superInstanceValue); 157*795d594fSAndroid Build Coastguard Worker System.out.println("BadSuper.superStaticValue = " + superStaticValue); 158*795d594fSAndroid Build Coastguard Worker } BadSuper(int superiv)159*795d594fSAndroid Build Coastguard Worker public BadSuper(int superiv) { superInstanceValue = superiv; } 160*795d594fSAndroid Build Coastguard Worker public int superInstanceValue; 161*795d594fSAndroid Build Coastguard Worker public static int superStaticValue; 162*795d594fSAndroid Build Coastguard Worker } 163*795d594fSAndroid Build Coastguard Worker 164*795d594fSAndroid Build Coastguard Worker // Note: If we tried to initialize BadSub before BadSuper, it would end up erroneous 165*795d594fSAndroid Build Coastguard Worker // because the superclass fails initialization. However, since we start initializing the 166*795d594fSAndroid Build Coastguard Worker // BadSuper first, BadSub is initialized successfully while BadSuper is "initializing" 167*795d594fSAndroid Build Coastguard Worker // and remains initialized after the BadSuper's class initializer throws. 168*795d594fSAndroid Build Coastguard Worker class BadSub extends BadSuper { bar()169*795d594fSAndroid Build Coastguard Worker public void bar() { 170*795d594fSAndroid Build Coastguard Worker System.out.println("BadSub.bar()"); 171*795d594fSAndroid Build Coastguard Worker System.out.println("BadSub.subInstanceValue = " + subInstanceValue); 172*795d594fSAndroid Build Coastguard Worker System.out.println("BadSub.subStaticValue = " + subStaticValue); 173*795d594fSAndroid Build Coastguard Worker System.out.println("BadSuper.superInstanceValue = " + superInstanceValue); 174*795d594fSAndroid Build Coastguard Worker System.out.println("BadSuper.superStaticValue = " + superStaticValue); 175*795d594fSAndroid Build Coastguard Worker } allocSuper(int superiv)176*795d594fSAndroid Build Coastguard Worker public BadSuper allocSuper(int superiv) { 177*795d594fSAndroid Build Coastguard Worker System.out.println("BadSub.allocSuper(.)"); 178*795d594fSAndroid Build Coastguard Worker return new BadSuper(superiv); 179*795d594fSAndroid Build Coastguard Worker } BadSub(int subiv, int superiv)180*795d594fSAndroid Build Coastguard Worker public BadSub(int subiv, int superiv) { 181*795d594fSAndroid Build Coastguard Worker super(superiv); 182*795d594fSAndroid Build Coastguard Worker subInstanceValue = subiv; 183*795d594fSAndroid Build Coastguard Worker } 184*795d594fSAndroid Build Coastguard Worker public int subInstanceValue; 185*795d594fSAndroid Build Coastguard Worker public static int subStaticValue; 186*795d594fSAndroid Build Coastguard Worker } 187