• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     Thread testThread = new Thread() {
21       public void run() {
22         performTest();
23       }
24     };
25     testThread.start();
26     try {
27       testThread.join(20 * 1000);  // 20s timeout.
28     } catch (InterruptedException ie) {
29       System.out.println("Interrupted.");
30       System.exit(1);
31     }
32     Thread.State state = testThread.getState();
33     if (state != Thread.State.TERMINATED) {
34       System.out.println("Test timed out, current state: " + state);
35       System.exit(1);
36     }
37   }
38 
performTest()39   public static void performTest() {
40     new SubMain();
41     if ($noinline$returnInt() != 53) {
42       throw new Error("Unexpected return value");
43     }
44     if ($noinline$returnFloat() != 42.2f) {
45       throw new Error("Unexpected return value");
46     }
47     if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) {
48       throw new Error("Unexpected return value ");
49     }
50     if ($noinline$returnLong() != 0xFFFF000000001111L) {
51       throw new Error("Unexpected return value");
52     }
53 
54     try {
55       $noinline$deopt();
56     } catch (Exception e) {}
57     DeoptimizationController.stopDeoptimization();
58 
59     $noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
60     if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
61       throw new Error("Unexpected return value");
62     }
63 
64     $noinline$inlineCache2(new Main(), /* isSecondInvocation */ false);
65     if ($noinline$inlineCache2(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
66       throw new Error("Unexpected return value");
67     }
68 
69     // Test polymorphic inline cache to the same target (inlineCache3).
70     $noinline$inlineCache3(new Main(), /* isSecondInvocation */ false);
71     $noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ false);
72     if ($noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ true) != null) {
73       throw new Error("Unexpected return value");
74     }
75 
76     $noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
77     $noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
78 
79     $opt$noinline$testOsrInlineLoop(null);
80     System.out.println("b28210356 passed.");
81   }
82 
$noinline$returnInt()83   public static int $noinline$returnInt() {
84     if (doThrow) throw new Error("");
85     int i = 0;
86     for (; i < 100000; ++i) {
87     }
88     while (!isInOsrCode("$noinline$returnInt")) {}
89     System.out.println(i);
90     return 53;
91   }
92 
$noinline$returnFloat()93   public static float $noinline$returnFloat() {
94     if (doThrow) throw new Error("");
95     int i = 0;
96     for (; i < 200000; ++i) {
97     }
98     while (!isInOsrCode("$noinline$returnFloat")) {}
99     System.out.println(i);
100     return 42.2f;
101   }
102 
$noinline$returnDouble()103   public static double $noinline$returnDouble() {
104     if (doThrow) throw new Error("");
105     int i = 0;
106     for (; i < 300000; ++i) {
107     }
108     while (!isInOsrCode("$noinline$returnDouble")) {}
109     System.out.println(i);
110     return Double.longBitsToDouble(0xF000000000001111L);
111   }
112 
$noinline$returnLong()113   public static long $noinline$returnLong() {
114     if (doThrow) throw new Error("");
115     int i = 0;
116     for (; i < 400000; ++i) {
117     }
118     while (!isInOsrCode("$noinline$returnLong")) {}
119     System.out.println(i);
120     return 0xFFFF000000001111L;
121   }
122 
$noinline$deopt()123   public static void $noinline$deopt() {
124     if (doThrow) throw new Error("");
125     int i = 0;
126     for (; i < 100000; ++i) {
127     }
128     while (!isInOsrCode("$noinline$deopt")) {}
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     if (doThrow) throw new Error();
266     assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5));
267     // Since we cannot have a loop directly in this method, we need to force the OSR
268     // compilation from native code.
269     ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop");
270     ensureHasOsrCode("$opt$noinline$testOsrInlineLoop");
271   }
272 
$opt$inline$testRemoveSuspendCheck(int x, int y)273   public static int $opt$inline$testRemoveSuspendCheck(int x, int y) {
274     // For this test we need an inlined loop and have DCE re-run loop analysis
275     // after inlining.
276     while (y > 0) {
277       while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) {
278         x++;
279       }
280       y--;
281     }
282     return x;
283   }
284 
$opt$inline$inlineTrue()285   public static boolean $opt$inline$inlineTrue() {
286     return true;
287   }
288 
$opt$inline$inlineFalse()289   public static boolean $opt$inline$inlineFalse() {
290     return false;
291   }
292 
assertIntEquals(int expected, int result)293   public static void assertIntEquals(int expected, int result) {
294     if (expected != result) {
295       throw new Error("Expected: " + expected + ", found: " + result);
296     }
297   }
298 
isInOsrCode(String methodName)299   public static native boolean isInOsrCode(String methodName);
isInInterpreter(String methodName)300   public static native boolean isInInterpreter(String methodName);
ensureHasProfilingInfo(String methodName)301   public static native void ensureHasProfilingInfo(String methodName);
ensureHasOsrCode(String methodName)302   public static native void ensureHasOsrCode(String methodName);
303 
304   public static boolean doThrow = false;
305 }
306 
307 class SubMain extends Main {
returnClass()308   public Class returnClass() {
309     return SubMain.class;
310   }
311 
inlineCache()312   public Main inlineCache() {
313     return new SubMain();
314   }
315 
inlineCache2()316   public Main inlineCache2() {
317     return new SubMain();
318   }
319 
otherInlineCache()320   public void otherInlineCache() {
321     return;
322   }
323 }
324