xref: /aosp_15_r20/art/test/174-escaping-instance-of-bad-class/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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