blob: d965e3ffce759f003caa0a3a44b22742e0f8fd2f [file] [log] [blame]
Aart Bikff7d89c2016-11-07 08:49:28 -08001/*
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/**
18 * Tests properties of some string operations represented by intrinsics.
19 */
20public class Main {
21
22 static final String ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
23 static final String XYZ = "XYZ";
24
25 //
26 // Variant intrinsics remain in the loop, but invariant references are hoisted out of the loop.
27 //
28 /// CHECK-START: int Main.liveIndexOf() licm (before)
29 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
30 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
31 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOf loop:{{B\d+}} outer_loop:none
32 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:{{B\d+}} outer_loop:none
33 //
34 /// CHECK-START: int Main.liveIndexOf() licm (after)
35 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
36 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
37 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOf loop:none
38 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:none
39 static int liveIndexOf() {
40 int k = ABC.length() + XYZ.length(); // does LoadString before loops
41 for (char c = 'A'; c <= 'Z'; c++) {
42 k += ABC.indexOf(c);
43 }
44 for (char c = 'A'; c <= 'Z'; c++) {
45 k += ABC.indexOf(c, 4);
46 }
47 for (char c = 'A'; c <= 'Z'; c++) {
48 k += ABC.indexOf(XYZ);
49 }
50 for (char c = 'A'; c <= 'Z'; c++) {
51 k += ABC.indexOf(XYZ, 2);
52 }
53 return k;
54 }
55
56 //
57 // All dead intrinsics can be removed completely.
58 //
59 /// CHECK-START: int Main.deadIndexOf() dead_code_elimination$initial (before)
60 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
61 /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
62 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOf loop:{{B\d+}} outer_loop:none
63 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:{{B\d+}} outer_loop:none
64 //
65 /// CHECK-START: int Main.deadIndexOf() dead_code_elimination$initial (after)
66 /// CHECK-NOT: InvokeVirtual intrinsic:StringIndexOf
67 /// CHECK-NOT: InvokeVirtual intrinsic:StringIndexOfAfter
68 /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOf
69 /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
70 static int deadIndexOf() {
71 int k = ABC.length() + XYZ.length(); // does LoadString before loops
72 for (char c = 'A'; c <= 'Z'; c++) {
73 int d = ABC.indexOf(c);
74 }
75 for (char c = 'A'; c <= 'Z'; c++) {
76 int d = ABC.indexOf(c, 4);
77 }
78 for (char c = 'A'; c <= 'Z'; c++) {
79 int d = ABC.indexOf(XYZ);
80 }
81 for (char c = 'A'; c <= 'Z'; c++) {
82 int d = ABC.indexOf(XYZ, 2);
83 }
84 return k;
85 }
86
87 //
88 // Explicit null check on receiver, implicit null check on argument prevents hoisting.
89 //
90 /// CHECK-START: int Main.indexOfExceptions(java.lang.String, java.lang.String) licm (after)
91 /// CHECK-DAG: <<String:l\d+>> NullCheck loop:<<Loop:B\d+>> outer_loop:none
92 /// CHECK-DAG: InvokeVirtual [<<String>>,{{l\d+}}] intrinsic:StringStringIndexOf loop:<<Loop>> outer_loop:none
93 static int indexOfExceptions(String s, String t) {
94 int k = 0;
95 for (char c = 'A'; c <= 'Z'; c++) {
96 k += s.indexOf(t);
97 }
98 return k;
99 }
100
Aart Bik71bf7b42016-11-16 10:17:46 -0800101 //
102 // Allows combining of returned "this". Also ensures that similar looking append() calls
103 // are not combined somehow through returned result.
104 //
105 /// CHECK-START: int Main.bufferLen2() instruction_simplifier (before)
106 /// CHECK-DAG: <<New:l\d+>> NewInstance
107 /// CHECK-DAG: <<String1:l\d+>> LoadString
108 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend
109 /// CHECK-DAG: <<String2:l\d+>> LoadString
110 /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<Append1>>]
111 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null1>>,<<String2>>] intrinsic:StringBufferAppend
112 /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append2>>]
113 /// CHECK-DAG: InvokeVirtual [<<Null2>>] intrinsic:StringBufferLength
114 //
115 /// CHECK-START: int Main.bufferLen2() instruction_simplifier (after)
116 /// CHECK-DAG: <<New:l\d+>> NewInstance
117 /// CHECK-DAG: <<String1:l\d+>> LoadString
118 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend
119 /// CHECK-DAG: <<String2:l\d+>> LoadString
120 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBufferAppend
121 /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBufferLength
122 static int bufferLen2() {
123 StringBuffer s = new StringBuffer();
124 return s.append("x").append("x").length();
125 }
126
127 //
128 // Allows combining of returned "this". Also ensures that similar looking append() calls
129 // are not combined somehow through returned result.
130 //
131 /// CHECK-START: int Main.builderLen2() instruction_simplifier (before)
132 /// CHECK-DAG: <<New:l\d+>> NewInstance
133 /// CHECK-DAG: <<String1:l\d+>> LoadString
134 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend
135 /// CHECK-DAG: <<String2:l\d+>> LoadString
136 /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>]
137 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBuilderAppend
138 /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>]
139 /// CHECK-DAG: InvokeVirtual [<<Null3>>] intrinsic:StringBuilderLength
140 //
141 /// CHECK-START: int Main.builderLen2() instruction_simplifier (after)
142 /// CHECK-DAG: <<New:l\d+>> NewInstance
143 /// CHECK-DAG: <<String1:l\d+>> LoadString
144 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend
145 /// CHECK-DAG: <<String2:l\d+>> LoadString
146 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBuilderAppend
147 /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBuilderLength
148 static int builderLen2() {
149 StringBuilder s = new StringBuilder();
150 return s.append("x").append("x").length();
151 }
152
153 //
154 // Similar situation in a loop.
155 //
156 /// CHECK-START: int Main.bufferLoopAppender() instruction_simplifier (before)
157 /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none
158 /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>>
159 /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<New>>] loop:<<Loop>>
160 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<Null1>>,<<String1>>] intrinsic:StringBufferAppend loop:<<Loop>>
161 /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>>
162 /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>] loop:<<Loop>>
163 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBufferAppend loop:<<Loop>>
164 /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>>
165 /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>] loop:<<Loop>>
166 /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<Null3>>,<<String3>>] intrinsic:StringBufferAppend loop:<<Loop>>
167 /// CHECK-DAG: <<Null4:l\d+>> NullCheck [<<New>>] loop:none
168 /// CHECK-DAG: InvokeVirtual [<<Null4>>] intrinsic:StringBufferLength loop:none
169 //
170 /// CHECK-START: int Main.bufferLoopAppender() instruction_simplifier (after)
171 /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none
172 /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>>
173 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend loop:<<Loop>>
174 /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>>
175 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBufferAppend loop:<<Loop>>
176 /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>>
177 /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<New>>,<<String3>>] intrinsic:StringBufferAppend loop:<<Loop>>
178 /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBufferLength loop:none
179 static int bufferLoopAppender() {
180 StringBuffer b = new StringBuffer();
181 for (int i = 0; i < 10; i++) {
182 b.append("x").append("y").append("z");
183 }
184 return b.length();
185 }
186
187 //
188 // Similar situation in a loop.
189 //
190 /// CHECK-START: int Main.builderLoopAppender() instruction_simplifier (before)
191 /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none
192 /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>>
193 /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<New>>] loop:<<Loop>>
194 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<Null1>>,<<String1>>] intrinsic:StringBuilderAppend loop:<<Loop>>
195 /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>>
196 /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>] loop:<<Loop>>
197 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBuilderAppend loop:<<Loop>>
198 /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>>
199 /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>] loop:<<Loop>>
200 /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<Null3>>,<<String3>>] intrinsic:StringBuilderAppend loop:<<Loop>>
201 /// CHECK-DAG: <<Null4:l\d+>> NullCheck [<<New>>] loop:none
202 /// CHECK-DAG: InvokeVirtual [<<Null4>>] intrinsic:StringBuilderLength loop:none
203 //
204 /// CHECK-START: int Main.builderLoopAppender() instruction_simplifier (after)
205 /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none
206 /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>>
207 /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend loop:<<Loop>>
208 /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>>
209 /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBuilderAppend loop:<<Loop>>
210 /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>>
211 /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<New>>,<<String3>>] intrinsic:StringBuilderAppend loop:<<Loop>>
212 /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBuilderLength loop:none
213 static int builderLoopAppender() {
214 StringBuilder b = new StringBuilder();
215 for (int i = 0; i < 10; i++) {
216 b.append("x").append("y").append("z");
217 }
218 return b.length();
219 }
220
221 //
222 // All calls in the loop-body and thus loop can be eliminated.
223 //
224 /// CHECK-START: int Main.bufferDeadLoop() instruction_simplifier (before)
225 /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
226 /// CHECK-DAG: InvokeVirtual intrinsic:StringBufferToString loop:<<Loop>>
227 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:<<Loop>>
228 //
229 /// CHECK-START: int Main.bufferDeadLoop() loop_optimization (after)
230 /// CHECK-NOT: Phi
231 /// CHECK-NOT: InvokeVirtual intrinsic:StringBufferToString
232 /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
233 static int bufferDeadLoop() {
234 StringBuffer b = new StringBuffer();
235 for (int i = 0; i < 10; i++) {
236 int d = b.toString().indexOf("x", 1);
237 }
238 return b.length();
239 }
240
241 //
242 // All calls in the loop-body and thus loop can be eliminated.
243 //
244 /// CHECK-START: int Main.builderDeadLoop() instruction_simplifier (before)
245 /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
246 /// CHECK-DAG: InvokeVirtual intrinsic:StringBuilderToString loop:<<Loop>>
247 /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:<<Loop>>
248 //
249 /// CHECK-START: int Main.builderDeadLoop() loop_optimization (after)
250 /// CHECK-NOT: Phi
251 /// CHECK-NOT: InvokeVirtual intrinsic:StringBuilderToString
252 /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
253 static int builderDeadLoop() {
254 StringBuilder b = new StringBuilder();
255 for (int i = 0; i < 10; i++) {
256 int d = b.toString().indexOf("x", 1);
257 }
258 return b.length();
259 }
260
Aart Bikff7d89c2016-11-07 08:49:28 -0800261 public static void main(String[] args) {
262 expectEquals(1865, liveIndexOf());
263 expectEquals(29, deadIndexOf());
Aart Bik71bf7b42016-11-16 10:17:46 -0800264
Aart Bikff7d89c2016-11-07 08:49:28 -0800265 try {
266 indexOfExceptions(null, XYZ);
267 throw new Error("Expected: NPE");
268 } catch (NullPointerException e) {
269 }
270 try {
271 indexOfExceptions(ABC, null);
272 throw new Error("Expected: NPE");
273 } catch (NullPointerException e) {
274 }
275 expectEquals(598, indexOfExceptions(ABC, XYZ));
276
Aart Bik71bf7b42016-11-16 10:17:46 -0800277 expectEquals(2, bufferLen2());
278 expectEquals(2, builderLen2());
279 expectEquals(30, bufferLoopAppender());
280 expectEquals(30, builderLoopAppender());
281 expectEquals(0, bufferDeadLoop());
282 expectEquals(0, builderDeadLoop());
283
Aart Bikff7d89c2016-11-07 08:49:28 -0800284 System.out.println("passed");
285 }
286
287 private static void expectEquals(int expected, int result) {
288 if (expected != result) {
289 throw new Error("Expected: " + expected + ", found: " + result);
290 }
291 }
292}