| Vladimir Marko | 552a134 | 2017-10-31 10:56:47 +0000 | [diff] [blame] | 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 { |
| 18 | public static void main(String[] args) { |
| 19 | testAppendStringAndLong(); |
| 20 | testAppendStringAndInt(); |
| 21 | testAppendStringAndString(); |
| 22 | testMiscelaneous(); |
| 23 | testNoArgs(); |
| Vladimir Marko | 56f1332 | 2019-11-15 14:07:19 +0000 | [diff] [blame] | 24 | testInline(); |
| Vladimir Marko | b1fe5e1 | 2020-03-10 14:30:49 +0000 | [diff] [blame] | 25 | testEquals(); |
| Vladimir Marko | 552a134 | 2017-10-31 10:56:47 +0000 | [diff] [blame] | 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 |
| 115 | public static String $noinline$appendStringAndLong(String s, long l) { |
| 116 | return new StringBuilder().append(s).append(l).toString(); |
| 117 | } |
| 118 | |
| 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 |
| 177 | public static String $noinline$appendStringAndInt(String s, int i) { |
| 178 | return new StringBuilder().append(s).append(i).toString(); |
| 179 | } |
| 180 | |
| 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 | |
| 189 | public static String $noinline$appendStringAndString(String s1, String s2) { |
| 190 | return new StringBuilder().append(s1).append(s2).toString(); |
| 191 | } |
| 192 | |
| 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 |
| 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 | |
| 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 | |
| Vladimir Marko | 56f1332 | 2019-11-15 14:07:19 +0000 | [diff] [blame] | 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 |
| 247 | public static String $noinline$testInlineOuter(String s, int i) { |
| 248 | StringBuilder sb = new StringBuilder(); |
| 249 | return $inline$testInlineInner(sb, s, i); |
| 250 | } |
| 251 | |
| 252 | public static void testInline() { |
| 253 | assertEquals("x42", $noinline$testInlineOuter("x", 42)); |
| 254 | } |
| 255 | |
| Vladimir Marko | 552a134 | 2017-10-31 10:56:47 +0000 | [diff] [blame] | 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 |
| 261 | public static String $noinline$appendNothing() { |
| 262 | return new StringBuilder().toString(); |
| 263 | } |
| 264 | |
| 265 | public static void testNoArgs() { |
| 266 | assertEquals("", $noinline$appendNothing()); |
| 267 | } |
| 268 | |
| Vladimir Marko | b1fe5e1 | 2020-03-10 14:30:49 +0000 | [diff] [blame] | 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 |
| 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 | |
| 288 | public static void testEquals() { |
| 289 | if (!$noinline$testAppendEquals("Test", 42)) { |
| 290 | throw new Error("str.equals(str) is false"); |
| 291 | } |
| 292 | } |
| 293 | |
| Vladimir Marko | 552a134 | 2017-10-31 10:56:47 +0000 | [diff] [blame] | 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 | } |