1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import pkg1.A; 18 import pkg1.C; 19 import pkg1.C2; 20 import pkg1.C2I1; 21 import pkg1.C2I2; 22 import pkg1.CXI1; 23 import pkg1.CXI2; 24 import pkg1.I1; 25 import pkg2.B; 26 import pkg2.D; 27 import pkg2.D2; 28 import pkg2.D2I1; 29 import pkg2.D2I2; 30 import pkg2.DXI1; 31 import pkg2.DXI2; 32 import pkg2.I2; 33 34 public class Main { main(String args[])35 public static void main(String args[]) { 36 try { 37 Class.forName("dalvik.system.PathClassLoader"); 38 } catch (ClassNotFoundException e) { 39 usingRI = true; 40 } 41 42 // A single method signature can result in multiple vtable entries 43 // when package-private methods from different packages are involved. 44 // All classes here define the method `void foo()` but classes 45 // class pkg1.A { ... } 46 // class pkg2.B extends pkg1.A { ... } 47 // class pkg1.C extends pkg2.B { ... } 48 // class pkg2.D extends pkg1.C { ... } 49 // define it as package-private and classes 50 // class pkg1.C2 extends pkg2.B { ... } 51 // class pkg2.D2 extends pkg1.C2 { ... } 52 // define it as public, so that we can test different cases of overriding. 53 54 A a = new A(); 55 a.callAFoo(); // pkg1.A.foo 56 57 B b = new B(); 58 b.callAFoo(); // pkg1.A.foo (not overridden by pkg2.B.foo) 59 b.callBFoo(); // pkg2.B.foo 60 61 C c = new C(); 62 c.callAFoo(); // pkg1.C.foo (overriddes pkg1.A.foo) 63 c.callBFoo(); // pkg2.B.foo (not overridden by pkg1.C.foo) 64 c.callCFoo(); // pkg1.C.foo 65 66 D d = new D(); 67 d.callAFoo(); // pkg1.C.foo (not overridden by pkg2.D.foo) 68 d.callBFoo(); // pkg2.D.foo (overrides pkg2.B.foo) 69 d.callCFoo(); // pkg1.C.foo (not overridden by pkg2.D.foo) 70 d.callDFoo(); // pkg2.D.foo 71 72 C2 c2 = new C2(); 73 c2.callAFoo(); // pkg1.C2.foo (overriddes pkg1.A.foo) 74 c2.callBFoo(); // pkg2.B.foo (not overridden by pkg1.C2.foo) 75 c2.callC2Foo(); // pkg1.C2.foo 76 77 D2 d2 = new D2(); 78 d2.callAFoo(); // pkg2.D2.foo (overrides public pkg2.C2.foo which overrides pkg1.A.foo) 79 d2.callBFoo(); // pkg2.D2.foo (overrides package-private pkg2.B.foo in the same package) 80 d2.callC2Foo(); // pkg2.D2.foo (overrides public pkg2.C2.foo) 81 d2.callD2Foo(); // pkg2.D2.foo 82 83 // Interface methods always target the method in the most-derived class with implementation 84 // even when package-private methods from different packages are involved. 85 // 86 // Test interface calls through the following interfaces: 87 // interface pkg1.I1 { ... } 88 // interface pkg2.I2 { ... } 89 // that declare a public `void foo()` for concrete classes 90 // class pkg1.C2I1 extends pkg1.C2 implements pkg1.I1 {} 91 // class pkg1.C2I2 extends pkg1.C2 implements pkg2.I2 {} 92 // class pkg2.D2I1 extends pkg2.D2 implements pkg1.I1 {} 93 // class pkg2.D2I2 extends pkg2.D2 implements pkg2.I2 {} 94 // class pkg1.CXI1 extends pkg1.CX implements pkg1.I1 {} 95 // class pkg1.CXI2 extends pkg1.CX implements pkg2.I2 {} 96 // class pkg2.DXI1 extends pkg2.DX implements pkg1.I1 {} 97 // class pkg2.DXI2 extends pkg2.DX implements pkg2.I2 {} 98 // with helper classes `pkg1.C2` and `pkg2.D2` from previous tests and helper class 99 // class pkg2.BX extends pkg1.A { ... } 100 // defining a public `void foo()` but helper classes 101 // class pkg1.CX extends pkg2.BX { ... } 102 // class pkg2.DX extends pkg1.CX { ... } 103 // defining a package-private `void foo()`. This is a compilation error in Java, 104 // so we're using different definitions for `pkg1.I1`, `pkg2.I2` and `pkg2.BX` in 105 // src/ for compiling other classes and in src2/ for their run-time definition. 106 107 C2I1 c2i1 = new C2I1(); 108 I1.callI1Foo(c2i1); // pkg1.C2.foo 109 110 C2I2 c2i2 = new C2I2(); 111 I2.callI2Foo(c2i2); // pkg1.C2.foo 112 113 D2I1 d2i1 = new D2I1(); 114 I1.callI1Foo(d2i1); // pkg1.D2.foo 115 116 D2I2 d2i2 = new D2I2(); 117 I2.callI2Foo(d2i2); // pkg1.D2.foo 118 119 try { 120 CXI1 cxi1 = new CXI1(); 121 I1.callI1Foo(cxi1); 122 } catch (IllegalAccessError expected) { 123 printOnDalvik("Calling pkg1.I1.foo on pkg1.CXI1"); 124 System.out.println("Caught IllegalAccessError"); 125 } 126 127 try { 128 CXI2 cxi2 = new CXI2(); 129 I2.callI2Foo(cxi2); 130 } catch (IllegalAccessError expected) { 131 printOnDalvik("Calling pkg2.I2.foo on pkg1.CXI2"); 132 System.out.println("Caught IllegalAccessError"); 133 } 134 135 try { 136 DXI1 dxi1 = new DXI1(); 137 I1.callI1Foo(dxi1); 138 } catch (IllegalAccessError expected) { 139 printOnDalvik("Calling pkg1.I1.foo on pkg2.DXI1"); 140 System.out.println("Caught IllegalAccessError"); 141 } 142 143 try { 144 DXI2 dxi2 = new DXI2(); 145 I2.callI2Foo(dxi2); 146 } catch (IllegalAccessError expected) { 147 printOnDalvik("Calling pkg2.I2.foo on pkg2.DXI2"); 148 System.out.println("Caught IllegalAccessError"); 149 } 150 } 151 printOnDalvik(String line)152 private static void printOnDalvik(String line) { 153 if (!usingRI) { 154 // FIXME: Delay IAE until calling the method. Bug: 211854716 155 System.out.println(line); 156 } 157 } 158 159 private static boolean usingRI = false; 160 } 161