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 public class Main { 18 private static boolean usingDalvik = "Dalvik".equals(System.getProperty("java.vm.name")); 19 expectSameString(String expected, String actual)20 public static void expectSameString(String expected, String actual) { 21 if (expected != actual) { 22 throw new Error("Expected " + expected + ", got " + actual + " (different object)"); 23 } 24 } 25 expectDefault(Super target)26 public static void expectDefault(Super target) { 27 String output = target.testMethod(); // invoke-virtual Super.testMethod() 28 Abstract abstractTarget = target; 29 String output2 = abstractTarget.testMethod(); // invoke-interface Abstract.testMethod() 30 expectSameString(output, output2); 31 System.out.println("Output from " + target.getClass().getName() + ": " + output); 32 } 33 expectConflict(Super target)34 public static void expectConflict(Super target) { 35 try { 36 String output = target.testMethod(); // invoke-virtual Super.testMethod() 37 throw new Error("Unexpected success for " + target.getClass().getName() + 38 " output: " + output); 39 } catch (AbstractMethodError ame) { 40 if (usingDalvik) { 41 throw new Error("Unexpected AbstractMethodError", ame); 42 } // else the AME is expected on RI. 43 } catch (IncompatibleClassChangeError expected) { 44 } 45 try { 46 Abstract abstractTarget = target; 47 String output = abstractTarget.testMethod(); // invoke-interface Abstract.testMethod() 48 throw new Error("Unexpected success for " + target.getClass().getName() + 49 " output: " + output); 50 } catch (AbstractMethodError ame) { 51 if (usingDalvik) { 52 throw new Error("Unexpected AbstractMethodError", ame); 53 } // else the AME is expected on RI. 54 } catch (IncompatibleClassChangeError expected) { 55 } 56 System.out.println("Conflict in class " + target.getClass().getName()); 57 } 58 expectMiranda(Super target)59 public static void expectMiranda(Super target) { 60 try { 61 String output = target.testMethod(); // invoke-virtual Super.testMethod() 62 throw new Error("Unexpected success for " + target.getClass().getName() + 63 " output: " + output); 64 } catch (AbstractMethodError expected) { 65 } 66 try { 67 Abstract abstractTarget = target; 68 String output = abstractTarget.testMethod(); // invoke-interface Abstract.testMethod() 69 throw new Error("Unexpected success for " + target.getClass().getName() + 70 " output: " + output); 71 } catch (AbstractMethodError expected) { 72 } 73 System.out.println("Miranda in class " + target.getClass().getName()); 74 } 75 main(String args[])76 public static void main(String args[]) { 77 // Basic tests that have the interfaces D<n> with default method and/or 78 // D<n>M interfaces that mask the default method ordered by <n>. 79 expectMiranda(new Super()); 80 expectDefault(new Default_D1()); 81 expectDefault(new Default_D2()); 82 expectDefault(new Default_D3()); 83 expectMiranda(new Miranda_D1M()); 84 expectMiranda(new Miranda_D2M()); 85 expectMiranda(new Miranda_D3M()); 86 expectConflict(new Conflict_D1_D2()); 87 expectDefault(new Default_D1_D2M()); 88 expectDefault(new Default_D1M_D2()); 89 expectMiranda(new Miranda_D1M_D2M()); 90 expectConflict(new Conflict_D1_D2_D3()); 91 expectConflict(new Conflict_D1_D2_D3M()); 92 expectConflict(new Conflict_D1_D2M_D3()); 93 expectDefault(new Default_D1_D2M_D3M()); 94 expectConflict(new Conflict_D1M_D2_D3()); 95 expectDefault(new Default_D1M_D2_D3M()); 96 expectDefault(new Default_D1M_D2M_D3()); 97 expectMiranda(new Miranda_D1M_D2M_D3M()); 98 99 // Cases where one interface masks the method in more than one superinterface. 100 expectMiranda(new Miranda_D1D2M()); 101 expectDefault(new Default_D1D2D()); 102 expectMiranda(new Miranda_AD1D2M()); 103 expectDefault(new Default_AD1D2D()); 104 105 // Cases where the interface D2 is early in the interface table but masked by D2M later. 106 expectDefault(new Default_D2_D1_D2M()); 107 expectMiranda(new Miranda_D2_D1M_D2M()); 108 109 // Cases that involve a superclass with miranda method in the vtable. 110 // Note: The above cases also include a miranda method in the superclass vtable 111 // anyway because we want to test `invoke-virtual Super.testMethod()` as well 112 // as the `invoke-interface Abstract.testMethod()`. However, miranda methods in 113 // superclass vtable mean that all default methods in superclass interfaces, 114 // if any, have been masked by abstract method, so processing them is a no-op. 115 expectDefault(new Default_D1M_x_D2()); 116 expectMiranda(new Miranda_D1M_x_D2M()); 117 expectConflict(new Conflict_D1M_x_D2_D3()); 118 expectDefault(new Default_D1M_x_D2_D3M()); 119 expectDefault(new Default_D1M_x_D2M_D3()); 120 expectMiranda(new Miranda_D1M_x_D2M_D3M()); 121 122 // Cases that involve a superclass with default method in the vtable. 123 expectConflict(new Conflict_D1_x_D2()); 124 expectDefault(new Default_D1_x_D2M()); 125 expectDefault(new Default_D1_x_D1MD()); 126 expectMiranda(new Miranda_D1_x_D1M()); 127 expectConflict(new Conflict_D1_x_D2_D3()); 128 expectConflict(new Conflict_D1_x_D2_D3M()); 129 expectConflict(new Conflict_D1_x_D2M_D3()); 130 expectDefault(new Default_D1_x_D2M_D3M()); 131 expectConflict(new Conflict_D1_x_D1MD_D2()); 132 expectDefault(new Default_D1_x_D1MD_D2M()); 133 expectDefault(new Default_D1_x_D1M_D2()); 134 expectMiranda(new Miranda_D1_x_D1M_D2M()); 135 136 // Cases that involve a superclass with conflict method in the vtable. 137 expectDefault(new Default_D1_D2_x_D2M()); 138 expectDefault(new Default_D1_D2_x_D1M()); 139 expectMiranda(new Miranda_D1_D2_x_D1M_D2M()); 140 expectDefault(new Default_D1_D2_x_D1MD_D2M()); 141 expectConflict(new Conflict_D1_D2_x_D1M_D3()); 142 expectDefault(new Default_D1_D2_x_D1M_D3M()); 143 expectConflict(new Conflict_D1_D2_x_D2M_D3()); 144 expectDefault(new Default_D1_D2_x_D2M_D3M()); 145 expectConflict(new Conflict_D1_D2_x_D1MD_D3()); 146 expectConflict(new Conflict_D1_D2_x_D1MD_D3M()); 147 expectDefault(new Default_D1_D2_D3M_x_D1MD_D2M()); 148 expectMiranda(new Miranda_D1_D2_D3M_x_D1M_D2M()); 149 expectDefault(new Default_D1_D2_x_D1D2D()); 150 expectMiranda(new Miranda_D1_D2_x_D1D2M()); 151 expectDefault(new Default_D1_D2_x_AD1D2D()); 152 expectMiranda(new Miranda_D1_D2_x_AD1D2M()); 153 expectConflict(new Conflict_D1_D2_D3_x_D1D2D()); 154 expectDefault(new Default_D1_D2_D3_x_D1D2M()); 155 expectConflict(new Conflict_D1_D2_D3_x_AD1D2D()); 156 expectDefault(new Default_D1_D2_D3_x_AD1D2M()); 157 expectDefault(new Default_D1_D2_D3M_x_D1D2D()); 158 expectMiranda(new Miranda_D1_D2_D3M_x_D1D2M()); 159 expectDefault(new Default_D1_D2_D3M_x_AD1D2D()); 160 expectMiranda(new Miranda_D1_D2_D3M_x_AD1D2M()); 161 162 regressionTestB215510819(); 163 } 164 regressionTestB215510819()165 static public void regressionTestB215510819() { 166 // The failure to fill IMT correctly would have resulted in calling the wrong method, 167 // or triggering a check when interpreting in debug mode. 168 Abstract abstractTarget = new B215510819Test(); 169 String result = abstractTarget.testMethod(); 170 System.out.println("B215510819 test result: " + result); 171 } 172 } 173 174 class Default_D1 extends Super implements Abstract, D1 {} 175 class Default_D2 extends Super implements Abstract, D2 {} 176 class Default_D3 extends Super implements Abstract, D3 {} 177 class Miranda_D1M extends Super implements Abstract, D1M {} 178 class Miranda_D2M extends Super implements Abstract, D2M {} 179 class Miranda_D3M extends Super implements Abstract, D3M {} 180 class Conflict_D1_D2 extends Super implements Abstract, D1, D2 {} 181 class Default_D1_D2M extends Super implements Abstract, D1, D2M {} 182 class Default_D1M_D2 extends Super implements Abstract, D1M, D2 {} 183 class Miranda_D1M_D2M extends Super implements Abstract, D1M, D2M {} 184 class Conflict_D1_D2_D3 extends Super implements Abstract, D1, D2, D3 {} 185 class Conflict_D1_D2_D3M extends Super implements Abstract, D1, D2, D3M {} 186 class Conflict_D1_D2M_D3 extends Super implements Abstract, D1, D2M, D3 {} 187 class Default_D1_D2M_D3M extends Super implements Abstract, D1, D2M, D3M {} 188 class Conflict_D1M_D2_D3 extends Super implements Abstract, D1M, D2, D3 {} 189 class Default_D1M_D2_D3M extends Super implements Abstract, D1M, D2, D3M {} 190 class Default_D1M_D2M_D3 extends Super implements Abstract, D1M, D2M, D3 {} 191 class Miranda_D1M_D2M_D3M extends Super implements Abstract, D1M, D2M, D3M {} 192 193 class Miranda_D1D2M extends Super implements D1D2M {} 194 class Default_D1D2D extends Super implements D1D2D {} 195 class Miranda_AD1D2M extends Super implements AD1D2M {} 196 class Default_AD1D2D extends Super implements AD1D2D {} 197 198 class Default_D2_D1_D2M extends Super implements Abstract, D1, D2M {} 199 class Miranda_D2_D1M_D2M extends Super implements Abstract, D1M, D2M {} 200 201 class Default_D1M_x_D2 extends Miranda_D1M implements D2 {} 202 class Miranda_D1M_x_D2M extends Miranda_D1M implements D2M {} 203 class Conflict_D1M_x_D2_D3 extends Miranda_D1M implements D2, D3 {} 204 class Default_D1M_x_D2_D3M extends Miranda_D1M implements D2, D3M {} 205 class Default_D1M_x_D2M_D3 extends Miranda_D1M implements D2M, D3 {} 206 class Miranda_D1M_x_D2M_D3M extends Miranda_D1M implements D2M, D3M {} 207 208 class Conflict_D1_x_D2 extends Default_D1 implements D2 {} 209 class Default_D1_x_D2M extends Default_D1 implements D2M {} 210 class Default_D1_x_D1MD extends Default_D1 implements D1MD {} 211 class Miranda_D1_x_D1M extends Default_D1 implements D1M {} 212 class Conflict_D1_x_D2_D3 extends Default_D1 implements D2, D3 {} 213 class Conflict_D1_x_D2_D3M extends Default_D1 implements D2, D3M {} 214 class Conflict_D1_x_D2M_D3 extends Default_D1 implements D2M, D3 {} 215 class Default_D1_x_D2M_D3M extends Default_D1 implements D2M, D3M {} 216 class Conflict_D1_x_D1MD_D2 extends Default_D1 implements D1MD, D2 {} 217 class Default_D1_x_D1MD_D2M extends Default_D1 implements D1MD, D2M {} 218 class Default_D1_x_D1M_D2 extends Default_D1 implements D1M, D2 {} 219 class Miranda_D1_x_D1M_D2M extends Default_D1 implements D1M, D2M {} 220 221 class Default_D1_D2_x_D2M extends Conflict_D1_D2 implements D2M {} 222 class Default_D1_D2_x_D1M extends Conflict_D1_D2 implements D1M {} 223 class Miranda_D1_D2_x_D1M_D2M extends Conflict_D1_D2 implements D1M, D2M {} 224 class Default_D1_D2_x_D1MD_D2M extends Conflict_D1_D2 implements D1MD, D2M {} 225 class Conflict_D1_D2_x_D1M_D3 extends Conflict_D1_D2 implements D1M, D3 {} 226 class Default_D1_D2_x_D1M_D3M extends Conflict_D1_D2 implements D1M, D3M {} 227 class Conflict_D1_D2_x_D2M_D3 extends Conflict_D1_D2 implements D2M, D3 {} 228 class Default_D1_D2_x_D2M_D3M extends Conflict_D1_D2 implements D2M, D3M {} 229 class Conflict_D1_D2_x_D1MD_D3 extends Conflict_D1_D2 implements D1MD, D3 {} 230 class Conflict_D1_D2_x_D1MD_D3M extends Conflict_D1_D2 implements D1MD, D3M {} 231 class Default_D1_D2_D3M_x_D1MD_D2M extends Conflict_D1_D2_D3M implements D1MD, D2M {} 232 class Miranda_D1_D2_D3M_x_D1M_D2M extends Conflict_D1_D2_D3M implements D1M, D2M {} 233 class Miranda_D1_D2_x_D1D2M extends Conflict_D1_D2 implements D1D2M {} 234 class Default_D1_D2_x_D1D2D extends Conflict_D1_D2 implements D1D2D {} 235 class Miranda_D1_D2_x_AD1D2M extends Conflict_D1_D2 implements AD1D2M {} 236 class Default_D1_D2_x_AD1D2D extends Conflict_D1_D2 implements AD1D2D {} 237 class Default_D1_D2_D3_x_D1D2M extends Conflict_D1_D2_D3 implements D1D2M {} 238 class Conflict_D1_D2_D3_x_D1D2D extends Conflict_D1_D2_D3 implements D1D2D {} 239 class Default_D1_D2_D3_x_AD1D2M extends Conflict_D1_D2_D3 implements AD1D2M {} 240 class Conflict_D1_D2_D3_x_AD1D2D extends Conflict_D1_D2_D3 implements AD1D2D {} 241 class Miranda_D1_D2_D3M_x_D1D2M extends Conflict_D1_D2_D3M implements D1D2M {} 242 class Default_D1_D2_D3M_x_D1D2D extends Conflict_D1_D2_D3M implements D1D2D {} 243 class Miranda_D1_D2_D3M_x_AD1D2M extends Conflict_D1_D2_D3M implements AD1D2M {} 244 class Default_D1_D2_D3M_x_AD1D2D extends Conflict_D1_D2_D3M implements AD1D2D {} 245 246 interface B215510819Iface { 247 // The IMT size is currently 43 and we want to cover all 43 indexes with non-copied 248 // implementations. The IMT index for abstract methods is calculated with a hash that 249 // includes the method name, so 43 consecutive characters in the method name would be best. 250 // (The fact that the name hash is multiplied by 16 is OK because the size of the IMT is a 251 // prime number and thus GCD(16, 43) = 1.) However, we do not have a contiguous range of 43 252 // valid characters, so we need to rely on the `hash % 43` to mask out the difference when 253 // we use `0`..`5` between `Z` and `a`. ('Z' + 1 - 43 = '0' and '5' + 1 + 43 = 'a'.) method_A()254 String method_A(); method_B()255 String method_B(); method_C()256 String method_C(); method_D()257 String method_D(); method_E()258 String method_E(); method_F()259 String method_F(); method_G()260 String method_G(); method_H()261 String method_H(); method_I()262 String method_I(); method_J()263 String method_J(); method_K()264 String method_K(); method_L()265 String method_L(); method_M()266 String method_M(); method_N()267 String method_N(); method_O()268 String method_O(); method_P()269 String method_P(); method_Q()270 String method_Q(); method_R()271 String method_R(); method_S()272 String method_S(); method_T()273 String method_T(); method_U()274 String method_U(); method_V()275 String method_V(); method_W()276 String method_W(); method_X()277 String method_X(); method_Y()278 String method_Y(); method_Z()279 String method_Z(); method_0()280 String method_0(); method_1()281 String method_1(); method_2()282 String method_2(); method_3()283 String method_3(); method_4()284 String method_4(); method_5()285 String method_5(); method_a()286 String method_a(); method_b()287 String method_b(); method_c()288 String method_c(); method_d()289 String method_d(); method_e()290 String method_e(); method_f()291 String method_f(); method_g()292 String method_g(); method_h()293 String method_h(); method_i()294 String method_i(); method_j()295 String method_j(); method_k()296 String method_k(); 297 } 298 // Note: Marked as abstract to avoid IMT table in this class. 299 abstract class B215510819Base extends Default_D1 implements B215510819Iface { method_A()300 public String method_A() { return "B215510819 - wrong method_A!"; } method_B()301 public String method_B() { return "B215510819 - wrong method_B!"; } method_C()302 public String method_C() { return "B215510819 - wrong method_C!"; } method_D()303 public String method_D() { return "B215510819 - wrong method_D!"; } method_E()304 public String method_E() { return "B215510819 - wrong method_E!"; } method_F()305 public String method_F() { return "B215510819 - wrong method_F!"; } method_G()306 public String method_G() { return "B215510819 - wrong method_G!"; } method_H()307 public String method_H() { return "B215510819 - wrong method_H!"; } method_I()308 public String method_I() { return "B215510819 - wrong method_I!"; } method_J()309 public String method_J() { return "B215510819 - wrong method_J!"; } method_K()310 public String method_K() { return "B215510819 - wrong method_K!"; } method_L()311 public String method_L() { return "B215510819 - wrong method_L!"; } method_M()312 public String method_M() { return "B215510819 - wrong method_M!"; } method_N()313 public String method_N() { return "B215510819 - wrong method_N!"; } method_O()314 public String method_O() { return "B215510819 - wrong method_O!"; } method_P()315 public String method_P() { return "B215510819 - wrong method_P!"; } method_Q()316 public String method_Q() { return "B215510819 - wrong method_Q!"; } method_R()317 public String method_R() { return "B215510819 - wrong method_R!"; } method_S()318 public String method_S() { return "B215510819 - wrong method_S!"; } method_T()319 public String method_T() { return "B215510819 - wrong method_T!"; } method_U()320 public String method_U() { return "B215510819 - wrong method_U!"; } method_V()321 public String method_V() { return "B215510819 - wrong method_V!"; } method_W()322 public String method_W() { return "B215510819 - wrong method_W!"; } method_X()323 public String method_X() { return "B215510819 - wrong method_X!"; } method_Y()324 public String method_Y() { return "B215510819 - wrong method_Y!"; } method_Z()325 public String method_Z() { return "B215510819 - wrong method_Z!"; } method_0()326 public String method_0() { return "B215510819 - wrong method_0!"; } method_1()327 public String method_1() { return "B215510819 - wrong method_1!"; } method_2()328 public String method_2() { return "B215510819 - wrong method_2!"; } method_3()329 public String method_3() { return "B215510819 - wrong method_3!"; } method_4()330 public String method_4() { return "B215510819 - wrong method_4!"; } method_5()331 public String method_5() { return "B215510819 - wrong method_5!"; } method_a()332 public String method_a() { return "B215510819 - wrong method_a!"; } method_b()333 public String method_b() { return "B215510819 - wrong method_b!"; } method_c()334 public String method_c() { return "B215510819 - wrong method_c!"; } method_d()335 public String method_d() { return "B215510819 - wrong method_d!"; } method_e()336 public String method_e() { return "B215510819 - wrong method_e!"; } method_f()337 public String method_f() { return "B215510819 - wrong method_f!"; } method_g()338 public String method_g() { return "B215510819 - wrong method_g!"; } method_h()339 public String method_h() { return "B215510819 - wrong method_h!"; } method_i()340 public String method_i() { return "B215510819 - wrong method_i!"; } method_j()341 public String method_j() { return "B215510819 - wrong method_j!"; } method_k()342 public String method_k() { return "B215510819 - wrong method_k!"; } 343 } 344 // Regression test for bug 215510819 where we failed to properly fill the IMT table 345 // when there were no new methods or interfaces and the superclass did not have an IMT 346 // table, so we filled the IMT from the superclass IfTable and erroneously ignored 347 // copied implementation methods in the process. Thus calls that should go to copied 348 // methods via an IMT conflict resolution trampoline would just end up in unrelated 349 // concrete method when called from compiled code or from interpreter in release mode. 350 // In debug mode, interpreter would fail a debug check. 351 class B215510819Test extends B215510819Base {} // No new interfaces or virtuals. 352