blob: 6514334af1259b4c1fd8d05bd3c85fba263fedb5 [file] [log] [blame]
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001/*
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
17public class Main {
18 public static void main(String[] args) {
19 System.loadLibrary(args[0]);
Vladimir Marko1939a882016-04-07 10:12:31 +010020 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
39 public static void performTest() {
40 new SubMain();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000041 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) {}
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000057 DeoptimizationController.stopDeoptimization();
58
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +000059 $noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
60 if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000061 throw new Error("Unexpected return value");
62 }
Nicolas Geoffrayb88d59e2016-02-17 11:31:49 +000063
64 $noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
65 $noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000066 }
67
68 public static int $noinline$returnInt() {
69 if (doThrow) throw new Error("");
70 int i = 0;
Nicolas Geoffray17fccfb2016-02-12 16:52:16 +000071 for (; i < 100000; ++i) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000072 }
73 while (!ensureInOsrCode()) {}
74 System.out.println(i);
75 return 53;
76 }
77
78 public static float $noinline$returnFloat() {
79 if (doThrow) throw new Error("");
80 int i = 0;
Nicolas Geoffray17fccfb2016-02-12 16:52:16 +000081 for (; i < 200000; ++i) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000082 }
83 while (!ensureInOsrCode()) {}
84 System.out.println(i);
85 return 42.2f;
86 }
87
88 public static double $noinline$returnDouble() {
89 if (doThrow) throw new Error("");
90 int i = 0;
Nicolas Geoffray17fccfb2016-02-12 16:52:16 +000091 for (; i < 300000; ++i) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000092 }
93 while (!ensureInOsrCode()) {}
94 System.out.println(i);
95 return Double.longBitsToDouble(0xF000000000001111L);
96 }
97
98 public static long $noinline$returnLong() {
99 if (doThrow) throw new Error("");
Nicolas Geoffray17fccfb2016-02-12 16:52:16 +0000100 int i = 0;
101 for (; i < 400000; ++i) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000102 }
103 while (!ensureInOsrCode()) {}
104 System.out.println(i);
105 return 0xFFFF000000001111L;
106 }
107
108 public static void $noinline$deopt() {
109 if (doThrow) throw new Error("");
110 int i = 0;
Nicolas Geoffray17fccfb2016-02-12 16:52:16 +0000111 for (; i < 100000; ++i) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000112 }
113 while (!ensureInOsrCode()) {}
114 DeoptimizationController.startDeoptimization();
115 }
116
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +0000117 public static Class $noinline$inlineCache(Main m, boolean isSecondInvocation) {
118 // If we are running in non-JIT mode, or were unlucky enough to get this method
119 // already JITted, just return the expected value.
120 if (!ensureInInterpreter()) {
121 return SubMain.class;
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000122 }
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +0000123
124 ensureHasProfilingInfo();
125
126 // Ensure that we have OSR code to jump to.
127 if (isSecondInvocation) {
128 ensureHasOsrCode();
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000129 }
130
131 // This call will be optimized in the OSR compiled code
132 // to check and deoptimize if m is not of type 'Main'.
133 Main other = m.inlineCache();
134
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +0000135 // Jump to OSR compiled code. The second run
136 // of this method will have 'm' as a SubMain, and the compiled
137 // code we are jumping to will have wrongly optimize other as being a
138 // 'Main'.
139 if (isSecondInvocation) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000140 while (!ensureInOsrCode()) {}
141 }
142
143 // We used to wrongly optimize this call and assume 'other' was a 'Main'.
144 return other.returnClass();
145 }
146
147 public Main inlineCache() {
148 return new Main();
149 }
150
151 public Class returnClass() {
152 return Main.class;
153 }
154
Nicolas Geoffrayb88d59e2016-02-17 11:31:49 +0000155 public void otherInlineCache() {
156 return;
157 }
158
159 public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) {
160 // If we are running in non-JIT mode, or were unlucky enough to get this method
161 // already JITted, just return the expected value.
162 if (!ensureInInterpreter()) {
163 return;
164 }
165
166 // We need a ProfilingInfo object to populate the 'otherInlineCache' call.
167 ensureHasProfilingInfo();
168
169 if (isSecondInvocation) {
170 // Ensure we have an OSR code and we jump to it.
171 while (!ensureInOsrCode()) {}
172 }
173
174 for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) {
175 // The first invocation of $noinline$stackOverflow will populate the inline
176 // cache with Main. The second invocation of the method, will see a SubMain
177 // and will therefore trigger deoptimization.
178 m.otherInlineCache();
179 }
180 }
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000181
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +0000182 public static native boolean ensureInInterpreter();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000183 public static native boolean ensureInOsrCode();
Nicolas Geoffrayd186dd82016-02-16 10:03:44 +0000184 public static native void ensureHasProfilingInfo();
185 public static native void ensureHasOsrCode();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000186
187 public static boolean doThrow = false;
188}
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000189
190class SubMain extends Main {
191 public Class returnClass() {
192 return SubMain.class;
193 }
194
195 public Main inlineCache() {
196 return new SubMain();
197 }
Nicolas Geoffrayb88d59e2016-02-17 11:31:49 +0000198
199 public void otherInlineCache() {
200 return;
201 }
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000202}