1 /* 2 * Copyright (C) 2016 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 interface Itf { sameInvokeInterface()18 public Class<?> sameInvokeInterface(); sameInvokeInterface2()19 public Class<?> sameInvokeInterface2(); sameInvokeInterface3()20 public Class<?> sameInvokeInterface3(); 21 } 22 23 public class Main implements Itf { assertEquals(Object expected, Object actual)24 public static void assertEquals(Object expected, Object actual) { 25 if (expected != actual) { 26 throw new Error("Expected " + expected + ", got " + actual); 27 } 28 } 29 assertEquals(int expected, int actual)30 public static void assertEquals(int expected, int actual) { 31 if (expected != actual) { 32 throw new Error("Expected " + expected + ", got " + actual); 33 } 34 } 35 main(String[] args)36 public static void main(String[] args) throws Exception { 37 System.loadLibrary(args[0]); 38 Main[] mains = new Main[3]; 39 Itf[] itfs = new Itf[3]; 40 itfs[0] = mains[0] = new Main(); 41 itfs[1] = mains[1] = new Subclass(); 42 itfs[2] = mains[2] = new OtherSubclass(); 43 44 // Make $noinline$testInvokeVirtual and $noinline$testInvokeInterface hot to get them jitted. 45 // We pass Main and Subclass to get polymorphic inlining based on calling 46 // the same method. 47 for (int i = 0; i < 0x30000; ++i) { 48 $noinline$testInvokeVirtual(mains[0]); 49 $noinline$testInvokeVirtual(mains[1]); 50 $noinline$testInvokeInterface(itfs[0]); 51 $noinline$testInvokeInterface(itfs[1]); 52 $noinline$testInvokeInterface2(itfs[0]); 53 $noinline$testInvokeInterface2(itfs[1]); 54 $noinline$testInlineToSameTarget(mains[0]); 55 $noinline$testInlineToSameTarget(mains[1]); 56 } 57 58 ensureJittedAndPolymorphicInline("$noinline$testInvokeVirtual"); 59 ensureJittedAndPolymorphicInline("$noinline$testInvokeInterface"); 60 ensureJittedAndPolymorphicInline("$noinline$testInvokeInterface2"); 61 ensureJittedAndPolymorphicInline("$noinline$testInlineToSameTarget"); 62 63 // At this point, the JIT should have compiled both methods, and inline 64 // sameInvokeVirtual and sameInvokeInterface. 65 assertEquals(Main.class, $noinline$testInvokeVirtual(mains[0])); 66 assertEquals(Main.class, $noinline$testInvokeVirtual(mains[1])); 67 68 assertEquals(Itf.class, $noinline$testInvokeInterface(itfs[0])); 69 assertEquals(Itf.class, $noinline$testInvokeInterface(itfs[1])); 70 71 assertEquals(Itf.class, $noinline$testInvokeInterface2(itfs[0])); 72 assertEquals(Itf.class, $noinline$testInvokeInterface2(itfs[1])); 73 74 // This will trigger a deoptimization of the compiled code. 75 assertEquals(OtherSubclass.class, $noinline$testInvokeVirtual(mains[2])); 76 assertEquals(OtherSubclass.class, $noinline$testInvokeInterface(itfs[2])); 77 assertEquals(null, $noinline$testInvokeInterface2(itfs[2])); 78 79 // Run this once to make sure we execute the JITted code. 80 $noinline$testInlineToSameTarget(mains[0]); 81 assertEquals(0x60000 + 1, counter); 82 } 83 sameInvokeVirtual()84 public Class<?> sameInvokeVirtual() { 85 field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo. 86 return Main.class; 87 } 88 sameInvokeInterface()89 public Class<?> sameInvokeInterface() { 90 field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo. 91 return Itf.class; 92 } 93 sameInvokeInterface2()94 public Class<?> sameInvokeInterface2() { 95 field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo. 96 return Itf.class; 97 } 98 sameInvokeInterface3()99 public Class<?> sameInvokeInterface3() { 100 field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo. 101 return Itf.class; 102 } 103 $noinline$testInvokeInterface(Itf i)104 public static Class<?> $noinline$testInvokeInterface(Itf i) { 105 return i.sameInvokeInterface(); 106 } 107 $noinline$testInvokeInterface2(Itf i)108 public static Class<?> $noinline$testInvokeInterface2(Itf i) { 109 // Make three interface calls that will do a ClassTableGet to ensure bogus code 110 // generation of ClassTableGet will crash. 111 i.sameInvokeInterface(); 112 i.sameInvokeInterface2(); 113 return i.sameInvokeInterface3(); 114 } 115 $noinline$testInvokeVirtual(Main m)116 public static Class<?> $noinline$testInvokeVirtual(Main m) { 117 return m.sameInvokeVirtual(); 118 } 119 $noinline$testInlineToSameTarget(Main m)120 public static void $noinline$testInlineToSameTarget(Main m) { 121 if (doThrow) throw new Error(""); 122 m.increment(); 123 } 124 125 public Object field = new Object(); 126 ensureJittedAndPolymorphicInline(String methodName)127 public static void ensureJittedAndPolymorphicInline(String methodName) { 128 if (!ensureJittedAndPolymorphicInline566(methodName)) { 129 throw new Error("Didn't find an inlined method in " + methodName); 130 } 131 } 132 ensureJittedAndPolymorphicInline566(String methodName)133 public static native boolean ensureJittedAndPolymorphicInline566(String methodName); 134 increment()135 public void increment() { 136 field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo 137 counter++; 138 } 139 public static int counter = 0; 140 public static boolean doThrow = false; 141 } 142 143 class Subclass extends Main { 144 } 145 146 class OtherSubclass extends Main { sameInvokeVirtual()147 public Class<?> sameInvokeVirtual() { 148 return OtherSubclass.class; 149 } 150 sameInvokeInterface()151 public Class<?> sameInvokeInterface() { 152 return OtherSubclass.class; 153 } 154 sameInvokeInterface2()155 public Class<?> sameInvokeInterface2() { 156 return null; 157 } sameInvokeInterface3()158 public Class<?> sameInvokeInterface3() { 159 return null; 160 } 161 } 162