1 /* 2 * Copyright 2019 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 testAppendStringAndLong(); 20 testAppendStringAndInt(); 21 testAppendStringAndFloat(); 22 testAppendStringAndDouble(); 23 testAppendDoubleAndFloat(); 24 testAppendStringAndString(); 25 testMiscelaneous(); 26 testNoArgs(); 27 testInline(); 28 testEquals(); 29 System.out.println("passed"); 30 } 31 32 private static final String APPEND_LONG_PREFIX = "Long/"; 33 private static final String[] APPEND_LONG_TEST_CASES = { 34 "Long/0", 35 "Long/1", 36 "Long/9", 37 "Long/10", 38 "Long/99", 39 "Long/100", 40 "Long/999", 41 "Long/1000", 42 "Long/9999", 43 "Long/10000", 44 "Long/99999", 45 "Long/100000", 46 "Long/999999", 47 "Long/1000000", 48 "Long/9999999", 49 "Long/10000000", 50 "Long/99999999", 51 "Long/100000000", 52 "Long/999999999", 53 "Long/1000000000", 54 "Long/9999999999", 55 "Long/10000000000", 56 "Long/99999999999", 57 "Long/100000000000", 58 "Long/999999999999", 59 "Long/1000000000000", 60 "Long/9999999999999", 61 "Long/10000000000000", 62 "Long/99999999999999", 63 "Long/100000000000000", 64 "Long/999999999999999", 65 "Long/1000000000000000", 66 "Long/9999999999999999", 67 "Long/10000000000000000", 68 "Long/99999999999999999", 69 "Long/100000000000000000", 70 "Long/999999999999999999", 71 "Long/1000000000000000000", 72 "Long/9223372036854775807", // Long.MAX_VALUE 73 "Long/-1", 74 "Long/-9", 75 "Long/-10", 76 "Long/-99", 77 "Long/-100", 78 "Long/-999", 79 "Long/-1000", 80 "Long/-9999", 81 "Long/-10000", 82 "Long/-99999", 83 "Long/-100000", 84 "Long/-999999", 85 "Long/-1000000", 86 "Long/-9999999", 87 "Long/-10000000", 88 "Long/-99999999", 89 "Long/-100000000", 90 "Long/-999999999", 91 "Long/-1000000000", 92 "Long/-9999999999", 93 "Long/-10000000000", 94 "Long/-99999999999", 95 "Long/-100000000000", 96 "Long/-999999999999", 97 "Long/-1000000000000", 98 "Long/-9999999999999", 99 "Long/-10000000000000", 100 "Long/-99999999999999", 101 "Long/-100000000000000", 102 "Long/-999999999999999", 103 "Long/-1000000000000000", 104 "Long/-9999999999999999", 105 "Long/-10000000000000000", 106 "Long/-99999999999999999", 107 "Long/-100000000000000000", 108 "Long/-999999999999999999", 109 "Long/-1000000000000000000", 110 "Long/-9223372036854775808", // Long.MIN_VALUE 111 }; 112 113 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (before) 114 /// CHECK-NOT: StringBuilderAppend 115 116 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (after) 117 /// CHECK: StringBuilderAppend $noinline$appendStringAndLong(String s, long l)118 public static String $noinline$appendStringAndLong(String s, long l) { 119 return new StringBuilder().append(s).append(l).toString(); 120 } 121 testAppendStringAndLong()122 public static void testAppendStringAndLong() { 123 for (String expected : APPEND_LONG_TEST_CASES) { 124 long l = Long.valueOf(expected.substring(APPEND_LONG_PREFIX.length())); 125 String result = $noinline$appendStringAndLong(APPEND_LONG_PREFIX, l); 126 assertEquals(expected, result); 127 } 128 } 129 130 private static final String APPEND_INT_PREFIX = "Int/"; 131 private static final String[] APPEND_INT_TEST_CASES = { 132 "Int/0", 133 "Int/1", 134 "Int/9", 135 "Int/10", 136 "Int/99", 137 "Int/100", 138 "Int/999", 139 "Int/1000", 140 "Int/9999", 141 "Int/10000", 142 "Int/99999", 143 "Int/100000", 144 "Int/999999", 145 "Int/1000000", 146 "Int/9999999", 147 "Int/10000000", 148 "Int/99999999", 149 "Int/100000000", 150 "Int/999999999", 151 "Int/1000000000", 152 "Int/2147483647", // Integer.MAX_VALUE 153 "Int/-1", 154 "Int/-9", 155 "Int/-10", 156 "Int/-99", 157 "Int/-100", 158 "Int/-999", 159 "Int/-1000", 160 "Int/-9999", 161 "Int/-10000", 162 "Int/-99999", 163 "Int/-100000", 164 "Int/-999999", 165 "Int/-1000000", 166 "Int/-9999999", 167 "Int/-10000000", 168 "Int/-99999999", 169 "Int/-100000000", 170 "Int/-999999999", 171 "Int/-1000000000", 172 "Int/-2147483648", // Integer.MIN_VALUE 173 }; 174 175 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (before) 176 /// CHECK-NOT: StringBuilderAppend 177 178 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (after) 179 /// CHECK: StringBuilderAppend $noinline$appendStringAndInt(String s, int i)180 public static String $noinline$appendStringAndInt(String s, int i) { 181 return new StringBuilder().append(s).append(i).toString(); 182 } 183 testAppendStringAndInt()184 public static void testAppendStringAndInt() { 185 for (String expected : APPEND_INT_TEST_CASES) { 186 int i = Integer.valueOf(expected.substring(APPEND_INT_PREFIX.length())); 187 String result = $noinline$appendStringAndInt(APPEND_INT_PREFIX, i); 188 assertEquals(expected, result); 189 } 190 } 191 192 private static final String APPEND_FLOAT_PREFIX = "Float/"; 193 private static final String[] APPEND_FLOAT_TEST_CASES = { 194 // We're testing only exact values here, i.e. values that do not require rounding. 195 "Float/1.0", 196 "Float/9.0", 197 "Float/10.0", 198 "Float/99.0", 199 "Float/100.0", 200 "Float/999.0", 201 "Float/1000.0", 202 "Float/9999.0", 203 "Float/10000.0", 204 "Float/99999.0", 205 "Float/100000.0", 206 "Float/999999.0", 207 "Float/1000000.0", 208 "Float/9999999.0", 209 "Float/1.0E7", 210 "Float/1.0E10", 211 "Float/-1.0", 212 "Float/-9.0", 213 "Float/-10.0", 214 "Float/-99.0", 215 "Float/-100.0", 216 "Float/-999.0", 217 "Float/-1000.0", 218 "Float/-9999.0", 219 "Float/-10000.0", 220 "Float/-99999.0", 221 "Float/-100000.0", 222 "Float/-999999.0", 223 "Float/-1000000.0", 224 "Float/-9999999.0", 225 "Float/-1.0E7", 226 "Float/-1.0E10", 227 "Float/0.25", 228 "Float/1.625", 229 "Float/9.3125", 230 "Float/-0.25", 231 "Float/-1.625", 232 "Float/-9.3125", 233 }; 234 235 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndFloat(java.lang.String, float) instruction_simplifier (before) 236 /// CHECK-NOT: StringBuilderAppend 237 238 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndFloat(java.lang.String, float) instruction_simplifier (after) 239 /// CHECK: StringBuilderAppend $noinline$appendStringAndFloat(String s, float f)240 public static String $noinline$appendStringAndFloat(String s, float f) { 241 return new StringBuilder().append(s).append(f).toString(); 242 } 243 testAppendStringAndFloat()244 public static void testAppendStringAndFloat() { 245 for (String expected : APPEND_FLOAT_TEST_CASES) { 246 float f = Float.valueOf(expected.substring(APPEND_FLOAT_PREFIX.length())); 247 String result = $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, f); 248 assertEquals(expected, result); 249 } 250 // Special values. 251 assertEquals("Float/NaN", $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.NaN)); 252 assertEquals("Float/Infinity", 253 $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.POSITIVE_INFINITY)); 254 assertEquals("Float/-Infinity", 255 $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.NEGATIVE_INFINITY)); 256 } 257 258 private static final String APPEND_DOUBLE_PREFIX = "Double/"; 259 private static final String[] APPEND_DOUBLE_TEST_CASES = { 260 // We're testing only exact values here, i.e. values that do not require rounding. 261 "Double/1.0", 262 "Double/9.0", 263 "Double/10.0", 264 "Double/99.0", 265 "Double/100.0", 266 "Double/999.0", 267 "Double/1000.0", 268 "Double/9999.0", 269 "Double/10000.0", 270 "Double/99999.0", 271 "Double/100000.0", 272 "Double/999999.0", 273 "Double/1000000.0", 274 "Double/9999999.0", 275 "Double/1.0E7", 276 "Double/1.0E24", 277 "Double/-1.0", 278 "Double/-9.0", 279 "Double/-10.0", 280 "Double/-99.0", 281 "Double/-100.0", 282 "Double/-999.0", 283 "Double/-1000.0", 284 "Double/-9999.0", 285 "Double/-10000.0", 286 "Double/-99999.0", 287 "Double/-100000.0", 288 "Double/-999999.0", 289 "Double/-1000000.0", 290 "Double/-9999999.0", 291 "Double/-1.0E7", 292 "Double/-1.0E24", 293 "Double/0.25", 294 "Double/1.625", 295 "Double/9.3125", 296 "Double/-0.25", 297 "Double/-1.625", 298 "Double/-9.3125", 299 }; 300 301 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndDouble(java.lang.String, double) instruction_simplifier (before) 302 /// CHECK-NOT: StringBuilderAppend 303 304 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndDouble(java.lang.String, double) instruction_simplifier (after) 305 /// CHECK: StringBuilderAppend $noinline$appendStringAndDouble(String s, double d)306 public static String $noinline$appendStringAndDouble(String s, double d) { 307 return new StringBuilder().append(s).append(d).toString(); 308 } 309 testAppendStringAndDouble()310 public static void testAppendStringAndDouble() { 311 for (String expected : APPEND_DOUBLE_TEST_CASES) { 312 double f = Double.valueOf(expected.substring(APPEND_DOUBLE_PREFIX.length())); 313 String result = $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, f); 314 assertEquals(expected, result); 315 } 316 // Special values. 317 assertEquals( 318 "Double/NaN", 319 $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.NaN)); 320 assertEquals( 321 "Double/Infinity", 322 $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.POSITIVE_INFINITY)); 323 assertEquals( 324 "Double/-Infinity", 325 $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.NEGATIVE_INFINITY)); 326 } 327 328 /// CHECK-START: java.lang.String Main.$noinline$appendDoubleAndFloat(double, float) instruction_simplifier (before) 329 /// CHECK-NOT: StringBuilderAppend 330 331 /// CHECK-START: java.lang.String Main.$noinline$appendDoubleAndFloat(double, float) instruction_simplifier (after) 332 /// CHECK: StringBuilderAppend $noinline$appendDoubleAndFloat(double d, float f)333 public static String $noinline$appendDoubleAndFloat(double d, float f) { 334 return new StringBuilder().append(d).append(f).toString(); 335 } 336 testAppendDoubleAndFloat()337 public static void testAppendDoubleAndFloat() { 338 assertEquals("1.50.325", $noinline$appendDoubleAndFloat(1.5, 0.325f)); 339 assertEquals("1.5E170.3125", $noinline$appendDoubleAndFloat(1.5E17, 0.3125f)); 340 assertEquals("1.0E8NaN", $noinline$appendDoubleAndFloat(1.0E8, Float.NaN)); 341 assertEquals("Infinity0.5", $noinline$appendDoubleAndFloat(Double.POSITIVE_INFINITY, 0.5f)); 342 assertEquals("2.5-Infinity", $noinline$appendDoubleAndFloat(2.5, Float.NEGATIVE_INFINITY)); 343 } 344 $noinline$appendStringAndString(String s1, String s2)345 public static String $noinline$appendStringAndString(String s1, String s2) { 346 return new StringBuilder().append(s1).append(s2).toString(); 347 } 348 testAppendStringAndString()349 public static void testAppendStringAndString() { 350 assertEquals("nullnull", $noinline$appendStringAndString(null, null)); 351 assertEquals("nullTEST", $noinline$appendStringAndString(null, "TEST")); 352 assertEquals("TESTnull", $noinline$appendStringAndString("TEST", null)); 353 assertEquals("abcDEFGH", $noinline$appendStringAndString("abc", "DEFGH")); 354 // Test with a non-ASCII character. 355 assertEquals("test\u0131", $noinline$appendStringAndString("test", "\u0131")); 356 assertEquals("\u0131test", $noinline$appendStringAndString("\u0131", "test")); 357 assertEquals("\u0131test\u0131", $noinline$appendStringAndString("\u0131", "test\u0131")); 358 } 359 360 /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (before) 361 /// CHECK-NOT: StringBuilderAppend 362 363 /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (after) 364 /// CHECK: StringBuilderAppend $noinline$appendSLILC(String s, long l1, int i, long l2, char c)365 public static String $noinline$appendSLILC(String s, 366 long l1, 367 int i, 368 long l2, 369 char c) { 370 return new StringBuilder().append(s) 371 .append(l1) 372 .append(i) 373 .append(l2) 374 .append(c).toString(); 375 } 376 testMiscelaneous()377 public static void testMiscelaneous() { 378 assertEquals("x17-1q", 379 $noinline$appendSLILC("x", 1L, 7, -1L, 'q')); 380 assertEquals("null17-1q", 381 $noinline$appendSLILC(null, 1L, 7, -1L, 'q')); 382 assertEquals("x\u013117-1q", 383 $noinline$appendSLILC("x\u0131", 1L, 7, -1L, 'q')); 384 assertEquals("x427-1q", 385 $noinline$appendSLILC("x", 42L, 7, -1L, 'q')); 386 assertEquals("x1-42-1q", 387 $noinline$appendSLILC("x", 1L, -42, -1L, 'q')); 388 assertEquals("x17424242q", 389 $noinline$appendSLILC("x", 1L, 7, 424242L, 'q')); 390 assertEquals("x17-1\u0131", 391 $noinline$appendSLILC("x", 1L, 7, -1L, '\u0131')); 392 } 393 $inline$testInlineInner(StringBuilder sb, String s, int i)394 public static String $inline$testInlineInner(StringBuilder sb, String s, int i) { 395 return sb.append(s).append(i).toString(); 396 } 397 398 /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (before) 399 /// CHECK-NOT: StringBuilderAppend 400 401 /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (after) 402 /// CHECK: StringBuilderAppend $noinline$testInlineOuter(String s, int i)403 public static String $noinline$testInlineOuter(String s, int i) { 404 StringBuilder sb = new StringBuilder(); 405 return $inline$testInlineInner(sb, s, i); 406 } 407 testInline()408 public static void testInline() { 409 assertEquals("x42", $noinline$testInlineOuter("x", 42)); 410 } 411 412 /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (before) 413 /// CHECK-NOT: StringBuilderAppend 414 415 /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (after) 416 /// CHECK-NOT: StringBuilderAppend $noinline$appendNothing()417 public static String $noinline$appendNothing() { 418 return new StringBuilder().toString(); 419 } 420 testNoArgs()421 public static void testNoArgs() { 422 assertEquals("", $noinline$appendNothing()); 423 } 424 425 /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (before) 426 /// CHECK-NOT: StringBuilderAppend 427 428 /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (after) 429 /// CHECK: StringBuilderAppend $noinline$testAppendEquals(String s, int i)430 public static boolean $noinline$testAppendEquals(String s, int i) { 431 // Regression test for b/151107293 . 432 // When a string is used as both receiver and argument of String.equals(), we DCHECK() 433 // that it cannot be null. However, when replacing the call to StringBuilder.toString() 434 // with the HStringBuilderAppend(), the former reported CanBeNull() as false and 435 // therefore no explicit null checks were needed, but the replacement reported 436 // CanBeNull() as true, so when the result was used in String.equals() for both 437 // receiver and argument, the DCHECK() failed. This was fixed by overriding 438 // CanBeNull() in HStringBuilderAppend to correctly return false; the string that 439 // previously didn't require null check still does not require it. 440 String str = new StringBuilder().append(s).append(i).toString(); 441 return str.equals(str); 442 } 443 testEquals()444 public static void testEquals() { 445 if (!$noinline$testAppendEquals("Test", 42)) { 446 throw new Error("str.equals(str) is false"); 447 } 448 } 449 assertEquals(String expected, String actual)450 public static void assertEquals(String expected, String actual) { 451 if (!expected.equals(actual)) { 452 throw new AssertionError("Expected: " + expected + ", actual: " + actual); 453 } 454 } 455 } 456