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