blob: 20e6d723d19bf3fb890dc58e22528cd2e15248b1 [file] [log] [blame]
Nicolas Geoffray1a0a5192017-06-22 11:56:01 +01001/*
2 * Copyright (C) 2017 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) throws Exception {
19 System.loadLibrary(args[0]);
20
21 $noinline$intUpdate(new Main());
22 ensureJitCompiled(Main.class, "$noinline$intUpdate");
23 $noinline$intUpdate(new SubMain());
24 if (myIntStatic != 5000) {
25 throw new Error("Expected 5000, got " + myIntStatic);
26 }
27
28 $noinline$objectUpdate(new Main());
29 ensureJitCompiled(Main.class, "$noinline$objectUpdate");
30 $noinline$objectUpdate(new SubMain());
31
32 $noinline$loopIncrement(new Main());
33 ensureJitCompiled(Main.class, "$noinline$loopIncrement");
34 $noinline$loopIncrement(new SubMain());
Nicolas Geoffraydf5a5232017-06-26 16:01:55 +010035
36 $noinline$objectReturned(new Main());
37 ensureJitCompiled(Main.class, "$noinline$objectReturned");
38 Object o = $noinline$objectReturned(new SubMain());
39 // We used to get 0xebadde09 in 'o' here and therefore crash
40 // both interpreter and compiled code.
41 if (o instanceof Cloneable) {
42 System.out.println("Unexpected object type " + o.getClass());
43 }
Nicolas Geoffray1a0a5192017-06-22 11:56:01 +010044 }
45
46 public boolean doCheck() {
47 return false;
48 }
49
50 public static void $noinline$intUpdate(Main m) {
51 int a = 0;
52 // We used to kill 'a' when the inline cache of 'doCheck' only
53 // contains 'Main' (which makes the only branch using 'a' dead).
54 // So the deoptimization at the inline cache was incorrectly assuming
55 // 'a' was dead.
56 for (int i = 0; i < 5000; i++) {
57 if (m.doCheck()) {
58 a++;
59 // We make this branch the only true user of the 'a' phi. All other uses
60 // of 'a' are phi updates.
61 myIntStatic = a;
62 } else if (myIntStatic == 42) {
63 a = 1;
64 }
65 }
66 }
67
68 public static void $noinline$objectUpdate(Main m) {
69 Object o = new Object();
70 // We used to kill 'o' when the inline cache of 'doCheck' only
Nicolas Geoffraydf5a5232017-06-26 16:01:55 +010071 // contains 'Main' (which makes the only branch using 'o' dead).
Nicolas Geoffray1a0a5192017-06-22 11:56:01 +010072 // So the deoptimization at the inline cache was incorrectly assuming
73 // 'o' was dead.
74 // This lead to a NPE on the 'toString' call just after deoptimizing.
75 for (int i = 0; i < 5000; i++) {
76 if (m.doCheck()) {
77 // We make this branch the only true user of the 'o' phi. All other uses
78 // of 'o' are phi updates.
79 o.toString();
80 } else if (myIntStatic == 42) {
81 o = m;
82 }
83 }
84 }
85
86 public static void $noinline$loopIncrement(Main m) {
87 int k = 0;
88 // We used to kill 'k' and replace it with 5000 when the inline cache
89 // of 'doCheck' only contains 'Main'.
90 // So the deoptimization at the inline cache was incorrectly assuming
91 // 'k' was 5000.
92 for (int i = 0; i < 5000; i++, k++) {
93 if (m.doCheck()) {
Nicolas Geoffraydf5a5232017-06-26 16:01:55 +010094 // We make this branch the only true user of the 'k' phi. All other uses
95 // of 'k' are phi updates.
Nicolas Geoffray1a0a5192017-06-22 11:56:01 +010096 myIntStatic = k;
97 }
98 }
99 if (k != 5000) {
100 throw new Error("Expected 5000, got " + k);
101 }
102 }
103
Nicolas Geoffraydf5a5232017-06-26 16:01:55 +0100104 public static Object $noinline$objectReturned(Main m) {
105 Object o = new Object();
106 // We used to kill 'o' when the inline cache of 'doCheck' only
107 // contains 'Main' (which makes the only branch using 'o' dead).
108 // So the deoptimization at the inline cache was incorrectly assuming
109 // 'o' was dead.
110 // We also need to make 'o' escape through a return instruction, as mterp
111 // executes the same code for return and return-object, and the 0xebadde09
112 // sentinel for dead value is only pushed to non-object dex registers.
113 Object myReturnValue = null;
114 for (int i = 0; i < 5000; i++) {
115 if (m.doCheck()) {
116 // We make this branch the only true user of the 'o' phi. All other uses
117 // of 'o' are phi updates.
118 myReturnValue = o;
119 } else if (myIntStatic == 42) {
120 o = m;
121 }
122 }
123 return myReturnValue;
124 }
125
Nicolas Geoffray1a0a5192017-06-22 11:56:01 +0100126 public static int myIntStatic = 0;
127
128 public static native void ensureJitCompiled(Class<?> itf, String name);
129}
130
131class SubMain extends Main {
132 public boolean doCheck() {
133 return true;
134 }
135}