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