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 testAppendStringAndString(); 22 testMiscelaneous(); 23 testNoArgs(); 24 testInline(); 25 testEquals(); 26 System.out.println("passed"); 27 } 28 29 private static final String APPEND_LONG_PREFIX = "Long/"; 30 private static final String[] APPEND_LONG_TEST_CASES = { 31 "Long/0", 32 "Long/1", 33 "Long/9", 34 "Long/10", 35 "Long/99", 36 "Long/100", 37 "Long/999", 38 "Long/1000", 39 "Long/9999", 40 "Long/10000", 41 "Long/99999", 42 "Long/100000", 43 "Long/999999", 44 "Long/1000000", 45 "Long/9999999", 46 "Long/10000000", 47 "Long/99999999", 48 "Long/100000000", 49 "Long/999999999", 50 "Long/1000000000", 51 "Long/9999999999", 52 "Long/10000000000", 53 "Long/99999999999", 54 "Long/100000000000", 55 "Long/999999999999", 56 "Long/1000000000000", 57 "Long/9999999999999", 58 "Long/10000000000000", 59 "Long/99999999999999", 60 "Long/100000000000000", 61 "Long/999999999999999", 62 "Long/1000000000000000", 63 "Long/9999999999999999", 64 "Long/10000000000000000", 65 "Long/99999999999999999", 66 "Long/100000000000000000", 67 "Long/999999999999999999", 68 "Long/1000000000000000000", 69 "Long/9223372036854775807", // Long.MAX_VALUE 70 "Long/-1", 71 "Long/-9", 72 "Long/-10", 73 "Long/-99", 74 "Long/-100", 75 "Long/-999", 76 "Long/-1000", 77 "Long/-9999", 78 "Long/-10000", 79 "Long/-99999", 80 "Long/-100000", 81 "Long/-999999", 82 "Long/-1000000", 83 "Long/-9999999", 84 "Long/-10000000", 85 "Long/-99999999", 86 "Long/-100000000", 87 "Long/-999999999", 88 "Long/-1000000000", 89 "Long/-9999999999", 90 "Long/-10000000000", 91 "Long/-99999999999", 92 "Long/-100000000000", 93 "Long/-999999999999", 94 "Long/-1000000000000", 95 "Long/-9999999999999", 96 "Long/-10000000000000", 97 "Long/-99999999999999", 98 "Long/-100000000000000", 99 "Long/-999999999999999", 100 "Long/-1000000000000000", 101 "Long/-9999999999999999", 102 "Long/-10000000000000000", 103 "Long/-99999999999999999", 104 "Long/-100000000000000000", 105 "Long/-999999999999999999", 106 "Long/-1000000000000000000", 107 "Long/-9223372036854775808", // Long.MIN_VALUE 108 }; 109 110 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (before) 111 /// CHECK-NOT: StringBuilderAppend 112 113 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (after) 114 /// CHECK: StringBuilderAppend $noinline$appendStringAndLong(String s, long l)115 public static String $noinline$appendStringAndLong(String s, long l) { 116 return new StringBuilder().append(s).append(l).toString(); 117 } 118 testAppendStringAndLong()119 public static void testAppendStringAndLong() { 120 for (String expected : APPEND_LONG_TEST_CASES) { 121 long l = Long.valueOf(expected.substring(APPEND_LONG_PREFIX.length())); 122 String result = $noinline$appendStringAndLong(APPEND_LONG_PREFIX, l); 123 assertEquals(expected, result); 124 } 125 } 126 127 private static final String APPEND_INT_PREFIX = "Int/"; 128 private static final String[] APPEND_INT_TEST_CASES = { 129 "Int/0", 130 "Int/1", 131 "Int/9", 132 "Int/10", 133 "Int/99", 134 "Int/100", 135 "Int/999", 136 "Int/1000", 137 "Int/9999", 138 "Int/10000", 139 "Int/99999", 140 "Int/100000", 141 "Int/999999", 142 "Int/1000000", 143 "Int/9999999", 144 "Int/10000000", 145 "Int/99999999", 146 "Int/100000000", 147 "Int/999999999", 148 "Int/1000000000", 149 "Int/2147483647", // Integer.MAX_VALUE 150 "Int/-1", 151 "Int/-9", 152 "Int/-10", 153 "Int/-99", 154 "Int/-100", 155 "Int/-999", 156 "Int/-1000", 157 "Int/-9999", 158 "Int/-10000", 159 "Int/-99999", 160 "Int/-100000", 161 "Int/-999999", 162 "Int/-1000000", 163 "Int/-9999999", 164 "Int/-10000000", 165 "Int/-99999999", 166 "Int/-100000000", 167 "Int/-999999999", 168 "Int/-1000000000", 169 "Int/-2147483648", // Integer.MIN_VALUE 170 }; 171 172 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (before) 173 /// CHECK-NOT: StringBuilderAppend 174 175 /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (after) 176 /// CHECK: StringBuilderAppend $noinline$appendStringAndInt(String s, int i)177 public static String $noinline$appendStringAndInt(String s, int i) { 178 return new StringBuilder().append(s).append(i).toString(); 179 } 180 testAppendStringAndInt()181 public static void testAppendStringAndInt() { 182 for (String expected : APPEND_INT_TEST_CASES) { 183 int i = Integer.valueOf(expected.substring(APPEND_INT_PREFIX.length())); 184 String result = $noinline$appendStringAndInt(APPEND_INT_PREFIX, i); 185 assertEquals(expected, result); 186 } 187 } 188 $noinline$appendStringAndString(String s1, String s2)189 public static String $noinline$appendStringAndString(String s1, String s2) { 190 return new StringBuilder().append(s1).append(s2).toString(); 191 } 192 testAppendStringAndString()193 public static void testAppendStringAndString() { 194 assertEquals("nullnull", $noinline$appendStringAndString(null, null)); 195 assertEquals("nullTEST", $noinline$appendStringAndString(null, "TEST")); 196 assertEquals("TESTnull", $noinline$appendStringAndString("TEST", null)); 197 assertEquals("abcDEFGH", $noinline$appendStringAndString("abc", "DEFGH")); 198 // Test with a non-ASCII character. 199 assertEquals("test\u0131", $noinline$appendStringAndString("test", "\u0131")); 200 assertEquals("\u0131test", $noinline$appendStringAndString("\u0131", "test")); 201 assertEquals("\u0131test\u0131", $noinline$appendStringAndString("\u0131", "test\u0131")); 202 } 203 204 /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (before) 205 /// CHECK-NOT: StringBuilderAppend 206 207 /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (after) 208 /// CHECK: StringBuilderAppend $noinline$appendSLILC(String s, long l1, int i, long l2, char c)209 public static String $noinline$appendSLILC(String s, 210 long l1, 211 int i, 212 long l2, 213 char c) { 214 return new StringBuilder().append(s) 215 .append(l1) 216 .append(i) 217 .append(l2) 218 .append(c).toString(); 219 } 220 testMiscelaneous()221 public static void testMiscelaneous() { 222 assertEquals("x17-1q", 223 $noinline$appendSLILC("x", 1L, 7, -1L, 'q')); 224 assertEquals("null17-1q", 225 $noinline$appendSLILC(null, 1L, 7, -1L, 'q')); 226 assertEquals("x\u013117-1q", 227 $noinline$appendSLILC("x\u0131", 1L, 7, -1L, 'q')); 228 assertEquals("x427-1q", 229 $noinline$appendSLILC("x", 42L, 7, -1L, 'q')); 230 assertEquals("x1-42-1q", 231 $noinline$appendSLILC("x", 1L, -42, -1L, 'q')); 232 assertEquals("x17424242q", 233 $noinline$appendSLILC("x", 1L, 7, 424242L, 'q')); 234 assertEquals("x17-1\u0131", 235 $noinline$appendSLILC("x", 1L, 7, -1L, '\u0131')); 236 } 237 $inline$testInlineInner(StringBuilder sb, String s, int i)238 public static String $inline$testInlineInner(StringBuilder sb, String s, int i) { 239 return sb.append(s).append(i).toString(); 240 } 241 242 /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (before) 243 /// CHECK-NOT: StringBuilderAppend 244 245 /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (after) 246 /// CHECK: StringBuilderAppend $noinline$testInlineOuter(String s, int i)247 public static String $noinline$testInlineOuter(String s, int i) { 248 StringBuilder sb = new StringBuilder(); 249 return $inline$testInlineInner(sb, s, i); 250 } 251 testInline()252 public static void testInline() { 253 assertEquals("x42", $noinline$testInlineOuter("x", 42)); 254 } 255 256 /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (before) 257 /// CHECK-NOT: StringBuilderAppend 258 259 /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (after) 260 /// CHECK-NOT: StringBuilderAppend $noinline$appendNothing()261 public static String $noinline$appendNothing() { 262 return new StringBuilder().toString(); 263 } 264 testNoArgs()265 public static void testNoArgs() { 266 assertEquals("", $noinline$appendNothing()); 267 } 268 269 /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (before) 270 /// CHECK-NOT: StringBuilderAppend 271 272 /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (after) 273 /// CHECK: StringBuilderAppend $noinline$testAppendEquals(String s, int i)274 public static boolean $noinline$testAppendEquals(String s, int i) { 275 // Regression test for b/151107293 . 276 // When a string is used as both receiver and argument of String.equals(), we DCHECK() 277 // that it cannot be null. However, when replacing the call to StringBuilder.toString() 278 // with the HStringBuilderAppend(), the former reported CanBeNull() as false and 279 // therefore no explicit null checks were needed, but the replacement reported 280 // CanBeNull() as true, so when the result was used in String.equals() for both 281 // receiver and argument, the DCHECK() failed. This was fixed by overriding 282 // CanBeNull() in HStringBuilderAppend to correctly return false; the string that 283 // previously didn't require null check still does not require it. 284 String str = new StringBuilder().append(s).append(i).toString(); 285 return str.equals(str); 286 } 287 testEquals()288 public static void testEquals() { 289 if (!$noinline$testAppendEquals("Test", 42)) { 290 throw new Error("str.equals(str) is false"); 291 } 292 } 293 assertEquals(String expected, String actual)294 public static void assertEquals(String expected, String actual) { 295 if (!expected.equals(actual)) { 296 throw new AssertionError("Expected: " + expected + ", actual: " + actual); 297 } 298 } 299 } 300