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();
19 }
20 
21 public class Main implements Itf {
assertEquals(Object expected, Object actual)22   public static void assertEquals(Object expected, Object actual) {
23     if (expected != actual) {
24       throw new Error("Expected " + expected  + ", got " + actual);
25     }
26   }
27 
assertEquals(int expected, int actual)28   public static void assertEquals(int expected, int actual) {
29     if (expected != actual) {
30       throw new Error("Expected " + expected  + ", got " + actual);
31     }
32   }
33 
main(String[] args)34   public static void main(String[] args) throws Exception {
35     System.loadLibrary(args[0]);
36     Main[] mains = new Main[3];
37     Itf[] itfs = new Itf[3];
38     itfs[0] = mains[0] = new Main();
39     itfs[1] = mains[1] = new Subclass();
40     itfs[2] = mains[2] = new OtherSubclass();
41 
42     // Make testInvokeVirtual and testInvokeInterface hot to get them jitted.
43     // We pass Main and Subclass to get polymorphic inlining based on calling
44     // the same method.
45     for (int i = 0; i < 10000; ++i) {
46       testInvokeVirtual(mains[0]);
47       testInvokeVirtual(mains[1]);
48       testInvokeInterface(itfs[0]);
49       testInvokeInterface(itfs[1]);
50       $noinline$testInlineToSameTarget(mains[0]);
51       $noinline$testInlineToSameTarget(mains[1]);
52     }
53 
54     ensureJittedAndPolymorphicInline();
55 
56     // At this point, the JIT should have compiled both methods, and inline
57     // sameInvokeVirtual and sameInvokeInterface.
58     assertEquals(Main.class, testInvokeVirtual(mains[0]));
59     assertEquals(Main.class, testInvokeVirtual(mains[1]));
60 
61     assertEquals(Itf.class, testInvokeInterface(itfs[0]));
62     assertEquals(Itf.class, testInvokeInterface(itfs[1]));
63 
64     // This will trigger a deoptimization of the compiled code.
65     assertEquals(OtherSubclass.class, testInvokeVirtual(mains[2]));
66     assertEquals(OtherSubclass.class, testInvokeInterface(itfs[2]));
67 
68     // Run this once to make sure we execute the JITted code.
69     $noinline$testInlineToSameTarget(mains[0]);
70     assertEquals(20001, counter);
71   }
72 
sameInvokeVirtual()73   public Class sameInvokeVirtual() {
74     field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo
75     return Main.class;
76   }
77 
sameInvokeInterface()78   public Class sameInvokeInterface() {
79     field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo
80     return Itf.class;
81   }
82 
testInvokeInterface(Itf i)83   public static Class testInvokeInterface(Itf i) {
84     return i.sameInvokeInterface();
85   }
86 
testInvokeVirtual(Main m)87   public static Class testInvokeVirtual(Main m) {
88     return m.sameInvokeVirtual();
89   }
90 
$noinline$testInlineToSameTarget(Main m)91   public static void $noinline$testInlineToSameTarget(Main m) {
92     if (doThrow) throw new Error("");
93     m.increment();
94   }
95 
96   public Object field = new Object();
97 
ensureJittedAndPolymorphicInline()98   public static native void ensureJittedAndPolymorphicInline();
99 
increment()100   public void increment() {
101     counter++;
102   }
103   public static int counter = 0;
104   public static boolean doThrow = false;
105 }
106 
107 class Subclass extends Main {
108 }
109 
110 class OtherSubclass extends Main {
sameInvokeVirtual()111   public Class sameInvokeVirtual() {
112     return OtherSubclass.class;
113   }
114 
sameInvokeInterface()115   public Class sameInvokeInterface() {
116     return OtherSubclass.class;
117   }
118 }
119