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