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 public class Main {
main(String[] args)18   public static void main(String[] args) {
19     System.loadLibrary(args[0]);
20     new SubMain();
21     if ($noinline$returnInt() != 53) {
22       throw new Error("Unexpected return value");
23     }
24     if ($noinline$returnFloat() != 42.2f) {
25       throw new Error("Unexpected return value");
26     }
27     if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) {
28       throw new Error("Unexpected return value ");
29     }
30     if ($noinline$returnLong() != 0xFFFF000000001111L) {
31       throw new Error("Unexpected return value");
32     }
33 
34     try {
35       $noinline$deopt();
36     } catch (Exception e) {}
37     DeoptimizationController.stopDeoptimization();
38 
39     $noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
40     if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
41       throw new Error("Unexpected return value");
42     }
43 
44     $noinline$inlineCache2(new Main(), /* isSecondInvocation */ false);
45     if ($noinline$inlineCache2(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
46       throw new Error("Unexpected return value");
47     }
48 
49     // Test polymorphic inline cache to the same target (inlineCache3).
50     $noinline$inlineCache3(new Main(), /* isSecondInvocation */ false);
51     $noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ false);
52     if ($noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ true) != null) {
53       throw new Error("Unexpected return value");
54     }
55 
56     $noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
57     $noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
58 
59     $opt$noinline$testOsrInlineLoop(null);
60     System.out.println("b28210356 passed.");
61   }
62 
$noinline$returnInt()63   public static int $noinline$returnInt() {
64     // If we are running in non-JIT mode, or were unlucky enough to get this method
65     // already JITted, skip the wait for OSR code.
66     boolean interpreting = isInInterpreter("$noinline$returnInt");
67     int i = 0;
68     for (; i < 100000; ++i) {
69     }
70     if (interpreting) {
71       while (!isInOsrCode("$noinline$returnInt")) {}
72     }
73     System.out.println(i);
74     return 53;
75   }
76 
$noinline$returnFloat()77   public static float $noinline$returnFloat() {
78     // If we are running in non-JIT mode, or were unlucky enough to get this method
79     // already JITted, skip the wait for OSR code.
80     boolean interpreting = isInInterpreter("$noinline$returnFloat");
81     int i = 0;
82     for (; i < 200000; ++i) {
83     }
84     if (interpreting) {
85       while (!isInOsrCode("$noinline$returnFloat")) {}
86     }
87     System.out.println(i);
88     return 42.2f;
89   }
90 
$noinline$returnDouble()91   public static double $noinline$returnDouble() {
92     // If we are running in non-JIT mode, or were unlucky enough to get this method
93     // already JITted, skip the wait for OSR code.
94     boolean interpreting = isInInterpreter("$noinline$returnDouble");
95     int i = 0;
96     for (; i < 300000; ++i) {
97     }
98     if (interpreting) {
99       while (!isInOsrCode("$noinline$returnDouble")) {}
100     }
101     System.out.println(i);
102     return Double.longBitsToDouble(0xF000000000001111L);
103   }
104 
$noinline$returnLong()105   public static long $noinline$returnLong() {
106     // If we are running in non-JIT mode, or were unlucky enough to get this method
107     // already JITted, skip the wait for OSR code.
108     boolean interpreting = isInInterpreter("$noinline$returnLong");
109     int i = 0;
110     for (; i < 400000; ++i) {
111     }
112     if (interpreting) {
113       while (!isInOsrCode("$noinline$returnLong")) {}
114     }
115     System.out.println(i);
116     return 0xFFFF000000001111L;
117   }
118 
$noinline$deopt()119   public static void $noinline$deopt() {
120     // If we are running in non-JIT mode, or were unlucky enough to get this method
121     // already JITted, skip the wait for OSR code.
122     boolean interpreting = isInInterpreter("$noinline$deopt");
123     int i = 0;
124     for (; i < 100000; ++i) {
125     }
126     if (interpreting) {
127       while (!isInOsrCode("$noinline$deopt")) {}
128     }
129     DeoptimizationController.startDeoptimization();
130   }
131 
$noinline$inlineCache(Main m, boolean isSecondInvocation)132   public static Class<?> $noinline$inlineCache(Main m, boolean isSecondInvocation) {
133     // If we are running in non-JIT mode, or were unlucky enough to get this method
134     // already JITted, just return the expected value.
135     if (!isInInterpreter("$noinline$inlineCache")) {
136       return SubMain.class;
137     }
138 
139     ensureHasProfilingInfo("$noinline$inlineCache");
140 
141     // Ensure that we have OSR code to jump to.
142     if (isSecondInvocation) {
143       ensureHasOsrCode("$noinline$inlineCache");
144     }
145 
146     // This call will be optimized in the OSR compiled code
147     // to check and deoptimize if m is not of type 'Main'.
148     Main other = m.inlineCache();
149 
150     // Jump to OSR compiled code. The second run
151     // of this method will have 'm' as a SubMain, and the compiled
152     // code we are jumping to will have wrongly optimize other as being a
153     // 'Main'.
154     if (isSecondInvocation) {
155       while (!isInOsrCode("$noinline$inlineCache")) {}
156     }
157 
158     // We used to wrongly optimize this call and assume 'other' was a 'Main'.
159     return other.returnClass();
160   }
161 
$noinline$inlineCache2(Main m, boolean isSecondInvocation)162   public static Class<?> $noinline$inlineCache2(Main m, boolean isSecondInvocation) {
163     // If we are running in non-JIT mode, or were unlucky enough to get this method
164     // already JITted, just return the expected value.
165     if (!isInInterpreter("$noinline$inlineCache2")) {
166       return SubMain.class;
167     }
168 
169     ensureHasProfilingInfo("$noinline$inlineCache2");
170 
171     // Ensure that we have OSR code to jump to.
172     if (isSecondInvocation) {
173       ensureHasOsrCode("$noinline$inlineCache2");
174     }
175 
176     // This call will be optimized in the OSR compiled code
177     // to check and deoptimize if m is not of type 'Main'.
178     Main other = m.inlineCache2();
179 
180     // Jump to OSR compiled code. The second run
181     // of this method will have 'm' as a SubMain, and the compiled
182     // code we are jumping to will have wrongly optimize other as being null.
183     if (isSecondInvocation) {
184       while (!isInOsrCode("$noinline$inlineCache2")) {}
185     }
186 
187     // We used to wrongly optimize this code and assume 'other' was always null.
188     return (other == null) ? null : other.returnClass();
189   }
190 
$noinline$inlineCache3(Main m, boolean isSecondInvocation)191   public static Class<?> $noinline$inlineCache3(Main m, boolean isSecondInvocation) {
192     // If we are running in non-JIT mode, or were unlucky enough to get this method
193     // already JITted, just return the expected value.
194     if (!isInInterpreter("$noinline$inlineCache3")) {
195       return null;
196     }
197 
198     ensureHasProfilingInfo("$noinline$inlineCache3");
199 
200     // Ensure that we have OSR code to jump to.
201     if (isSecondInvocation) {
202       ensureHasOsrCode("$noinline$inlineCache3");
203     }
204 
205     // This call will be optimized in the OSR compiled code
206     // to check and deoptimize if m is not of type 'Main'.
207     Main other = m.inlineCache3();
208 
209     // Jump to OSR compiled code. The second run
210     // of this method will have 'm' as a SubMain, and the compiled
211     // code we are jumping to will have wrongly optimize other as being null.
212     if (isSecondInvocation) {
213       while (!isInOsrCode("$noinline$inlineCache3")) {}
214     }
215 
216     // We used to wrongly optimize this code and assume 'other' was always null.
217     return (other == null) ? null : other.returnClass();
218   }
219 
inlineCache()220   public Main inlineCache() {
221     return new Main();
222   }
223 
inlineCache2()224   public Main inlineCache2() {
225     return null;
226   }
227 
inlineCache3()228   public Main inlineCache3() {
229     return null;
230   }
231 
returnClass()232   public Class<?> returnClass() {
233     return Main.class;
234   }
235 
otherInlineCache()236   public void otherInlineCache() {
237     return;
238   }
239 
$noinline$stackOverflow(Main m, boolean isSecondInvocation)240   public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) {
241     // If we are running in non-JIT mode, or were unlucky enough to get this method
242     // already JITted, just return the expected value.
243     if (!isInInterpreter("$noinline$stackOverflow")) {
244       return;
245     }
246 
247     // We need a ProfilingInfo object to populate the 'otherInlineCache' call.
248     ensureHasProfilingInfo("$noinline$stackOverflow");
249 
250     if (isSecondInvocation) {
251       // Ensure we have an OSR code and we jump to it.
252       while (!isInOsrCode("$noinline$stackOverflow")) {}
253     }
254 
255     for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) {
256       // The first invocation of $noinline$stackOverflow will populate the inline
257       // cache with Main. The second invocation of the method, will see a SubMain
258       // and will therefore trigger deoptimization.
259       m.otherInlineCache();
260     }
261   }
262 
$opt$noinline$testOsrInlineLoop(String[] args)263   public static void $opt$noinline$testOsrInlineLoop(String[] args) {
264     // Regression test for inlining a method with a loop to a method without a loop in OSR mode.
265     assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5));
266     // Since we cannot have a loop directly in this method, we need to force the OSR
267     // compilation from native code.
268     ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop");
269     ensureHasOsrCode("$opt$noinline$testOsrInlineLoop");
270   }
271 
$opt$inline$testRemoveSuspendCheck(int x, int y)272   public static int $opt$inline$testRemoveSuspendCheck(int x, int y) {
273     // For this test we need an inlined loop and have DCE re-run loop analysis
274     // after inlining.
275     while (y > 0) {
276       while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) {
277         x++;
278       }
279       y--;
280     }
281     return x;
282   }
283 
$opt$inline$inlineTrue()284   public static boolean $opt$inline$inlineTrue() {
285     return true;
286   }
287 
$opt$inline$inlineFalse()288   public static boolean $opt$inline$inlineFalse() {
289     return false;
290   }
291 
assertIntEquals(int expected, int result)292   public static void assertIntEquals(int expected, int result) {
293     if (expected != result) {
294       throw new Error("Expected: " + expected + ", found: " + result);
295     }
296   }
297 
isInOsrCode(String methodName)298   public static native boolean isInOsrCode(String methodName);
isInInterpreter(String methodName)299   public static native boolean isInInterpreter(String methodName);
ensureHasProfilingInfo(String methodName)300   public static native void ensureHasProfilingInfo(String methodName);
ensureHasOsrCode(String methodName)301   public static native void ensureHasOsrCode(String methodName);
302 }
303 
304 class SubMain extends Main {
returnClass()305   public Class<?> returnClass() {
306     return SubMain.class;
307   }
308 
inlineCache()309   public Main inlineCache() {
310     return new SubMain();
311   }
312 
inlineCache2()313   public Main inlineCache2() {
314     return new SubMain();
315   }
316 
otherInlineCache()317   public void otherInlineCache() {
318     return;
319   }
320 }
321