| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| public class Main { |
| public static void main(String[] args) { |
| testAppendStringAndLong(); |
| testAppendStringAndInt(); |
| testAppendStringAndFloat(); |
| testAppendStringAndDouble(); |
| testAppendDoubleAndFloat(); |
| testAppendStringAndString(); |
| testMiscelaneous(); |
| testNoArgs(); |
| testInline(); |
| testEquals(); |
| System.out.println("passed"); |
| } |
| |
| private static final String APPEND_LONG_PREFIX = "Long/"; |
| private static final String[] APPEND_LONG_TEST_CASES = { |
| "Long/0", |
| "Long/1", |
| "Long/9", |
| "Long/10", |
| "Long/99", |
| "Long/100", |
| "Long/999", |
| "Long/1000", |
| "Long/9999", |
| "Long/10000", |
| "Long/99999", |
| "Long/100000", |
| "Long/999999", |
| "Long/1000000", |
| "Long/9999999", |
| "Long/10000000", |
| "Long/99999999", |
| "Long/100000000", |
| "Long/999999999", |
| "Long/1000000000", |
| "Long/9999999999", |
| "Long/10000000000", |
| "Long/99999999999", |
| "Long/100000000000", |
| "Long/999999999999", |
| "Long/1000000000000", |
| "Long/9999999999999", |
| "Long/10000000000000", |
| "Long/99999999999999", |
| "Long/100000000000000", |
| "Long/999999999999999", |
| "Long/1000000000000000", |
| "Long/9999999999999999", |
| "Long/10000000000000000", |
| "Long/99999999999999999", |
| "Long/100000000000000000", |
| "Long/999999999999999999", |
| "Long/1000000000000000000", |
| "Long/9223372036854775807", // Long.MAX_VALUE |
| "Long/-1", |
| "Long/-9", |
| "Long/-10", |
| "Long/-99", |
| "Long/-100", |
| "Long/-999", |
| "Long/-1000", |
| "Long/-9999", |
| "Long/-10000", |
| "Long/-99999", |
| "Long/-100000", |
| "Long/-999999", |
| "Long/-1000000", |
| "Long/-9999999", |
| "Long/-10000000", |
| "Long/-99999999", |
| "Long/-100000000", |
| "Long/-999999999", |
| "Long/-1000000000", |
| "Long/-9999999999", |
| "Long/-10000000000", |
| "Long/-99999999999", |
| "Long/-100000000000", |
| "Long/-999999999999", |
| "Long/-1000000000000", |
| "Long/-9999999999999", |
| "Long/-10000000000000", |
| "Long/-99999999999999", |
| "Long/-100000000000000", |
| "Long/-999999999999999", |
| "Long/-1000000000000000", |
| "Long/-9999999999999999", |
| "Long/-10000000000000000", |
| "Long/-99999999999999999", |
| "Long/-100000000000000000", |
| "Long/-999999999999999999", |
| "Long/-1000000000000000000", |
| "Long/-9223372036854775808", // Long.MIN_VALUE |
| }; |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndLong(java.lang.String, long) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendStringAndLong(String s, long l) { |
| return new StringBuilder().append(s).append(l).toString(); |
| } |
| |
| public static void testAppendStringAndLong() { |
| for (String expected : APPEND_LONG_TEST_CASES) { |
| long l = Long.valueOf(expected.substring(APPEND_LONG_PREFIX.length())); |
| String result = $noinline$appendStringAndLong(APPEND_LONG_PREFIX, l); |
| assertEquals(expected, result); |
| } |
| } |
| |
| private static final String APPEND_INT_PREFIX = "Int/"; |
| private static final String[] APPEND_INT_TEST_CASES = { |
| "Int/0", |
| "Int/1", |
| "Int/9", |
| "Int/10", |
| "Int/99", |
| "Int/100", |
| "Int/999", |
| "Int/1000", |
| "Int/9999", |
| "Int/10000", |
| "Int/99999", |
| "Int/100000", |
| "Int/999999", |
| "Int/1000000", |
| "Int/9999999", |
| "Int/10000000", |
| "Int/99999999", |
| "Int/100000000", |
| "Int/999999999", |
| "Int/1000000000", |
| "Int/2147483647", // Integer.MAX_VALUE |
| "Int/-1", |
| "Int/-9", |
| "Int/-10", |
| "Int/-99", |
| "Int/-100", |
| "Int/-999", |
| "Int/-1000", |
| "Int/-9999", |
| "Int/-10000", |
| "Int/-99999", |
| "Int/-100000", |
| "Int/-999999", |
| "Int/-1000000", |
| "Int/-9999999", |
| "Int/-10000000", |
| "Int/-99999999", |
| "Int/-100000000", |
| "Int/-999999999", |
| "Int/-1000000000", |
| "Int/-2147483648", // Integer.MIN_VALUE |
| }; |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndInt(java.lang.String, int) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendStringAndInt(String s, int i) { |
| return new StringBuilder().append(s).append(i).toString(); |
| } |
| |
| public static void testAppendStringAndInt() { |
| for (String expected : APPEND_INT_TEST_CASES) { |
| int i = Integer.valueOf(expected.substring(APPEND_INT_PREFIX.length())); |
| String result = $noinline$appendStringAndInt(APPEND_INT_PREFIX, i); |
| assertEquals(expected, result); |
| } |
| } |
| |
| private static final String APPEND_FLOAT_PREFIX = "Float/"; |
| private static final String[] APPEND_FLOAT_TEST_CASES = { |
| // We're testing only exact values here, i.e. values that do not require rounding. |
| "Float/1.0", |
| "Float/9.0", |
| "Float/10.0", |
| "Float/99.0", |
| "Float/100.0", |
| "Float/999.0", |
| "Float/1000.0", |
| "Float/9999.0", |
| "Float/10000.0", |
| "Float/99999.0", |
| "Float/100000.0", |
| "Float/999999.0", |
| "Float/1000000.0", |
| "Float/9999999.0", |
| "Float/1.0E7", |
| "Float/1.0E10", |
| "Float/-1.0", |
| "Float/-9.0", |
| "Float/-10.0", |
| "Float/-99.0", |
| "Float/-100.0", |
| "Float/-999.0", |
| "Float/-1000.0", |
| "Float/-9999.0", |
| "Float/-10000.0", |
| "Float/-99999.0", |
| "Float/-100000.0", |
| "Float/-999999.0", |
| "Float/-1000000.0", |
| "Float/-9999999.0", |
| "Float/-1.0E7", |
| "Float/-1.0E10", |
| "Float/0.25", |
| "Float/1.625", |
| "Float/9.3125", |
| "Float/-0.25", |
| "Float/-1.625", |
| "Float/-9.3125", |
| }; |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndFloat(java.lang.String, float) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndFloat(java.lang.String, float) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendStringAndFloat(String s, float f) { |
| return new StringBuilder().append(s).append(f).toString(); |
| } |
| |
| public static void testAppendStringAndFloat() { |
| for (String expected : APPEND_FLOAT_TEST_CASES) { |
| float f = Float.valueOf(expected.substring(APPEND_FLOAT_PREFIX.length())); |
| String result = $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, f); |
| assertEquals(expected, result); |
| } |
| // Special values. |
| assertEquals("Float/NaN", $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.NaN)); |
| assertEquals("Float/Infinity", |
| $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.POSITIVE_INFINITY)); |
| assertEquals("Float/-Infinity", |
| $noinline$appendStringAndFloat(APPEND_FLOAT_PREFIX, Float.NEGATIVE_INFINITY)); |
| } |
| |
| private static final String APPEND_DOUBLE_PREFIX = "Double/"; |
| private static final String[] APPEND_DOUBLE_TEST_CASES = { |
| // We're testing only exact values here, i.e. values that do not require rounding. |
| "Double/1.0", |
| "Double/9.0", |
| "Double/10.0", |
| "Double/99.0", |
| "Double/100.0", |
| "Double/999.0", |
| "Double/1000.0", |
| "Double/9999.0", |
| "Double/10000.0", |
| "Double/99999.0", |
| "Double/100000.0", |
| "Double/999999.0", |
| "Double/1000000.0", |
| "Double/9999999.0", |
| "Double/1.0E7", |
| "Double/1.0E24", |
| "Double/-1.0", |
| "Double/-9.0", |
| "Double/-10.0", |
| "Double/-99.0", |
| "Double/-100.0", |
| "Double/-999.0", |
| "Double/-1000.0", |
| "Double/-9999.0", |
| "Double/-10000.0", |
| "Double/-99999.0", |
| "Double/-100000.0", |
| "Double/-999999.0", |
| "Double/-1000000.0", |
| "Double/-9999999.0", |
| "Double/-1.0E7", |
| "Double/-1.0E24", |
| "Double/0.25", |
| "Double/1.625", |
| "Double/9.3125", |
| "Double/-0.25", |
| "Double/-1.625", |
| "Double/-9.3125", |
| }; |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndDouble(java.lang.String, double) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendStringAndDouble(java.lang.String, double) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendStringAndDouble(String s, double d) { |
| return new StringBuilder().append(s).append(d).toString(); |
| } |
| |
| public static void testAppendStringAndDouble() { |
| for (String expected : APPEND_DOUBLE_TEST_CASES) { |
| double f = Double.valueOf(expected.substring(APPEND_DOUBLE_PREFIX.length())); |
| String result = $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, f); |
| assertEquals(expected, result); |
| } |
| // Special values. |
| assertEquals( |
| "Double/NaN", |
| $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.NaN)); |
| assertEquals( |
| "Double/Infinity", |
| $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.POSITIVE_INFINITY)); |
| assertEquals( |
| "Double/-Infinity", |
| $noinline$appendStringAndDouble(APPEND_DOUBLE_PREFIX, Double.NEGATIVE_INFINITY)); |
| } |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendDoubleAndFloat(double, float) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendDoubleAndFloat(double, float) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendDoubleAndFloat(double d, float f) { |
| return new StringBuilder().append(d).append(f).toString(); |
| } |
| |
| public static void testAppendDoubleAndFloat() { |
| assertEquals("1.50.325", $noinline$appendDoubleAndFloat(1.5, 0.325f)); |
| assertEquals("1.5E170.3125", $noinline$appendDoubleAndFloat(1.5E17, 0.3125f)); |
| assertEquals("1.0E8NaN", $noinline$appendDoubleAndFloat(1.0E8, Float.NaN)); |
| assertEquals("Infinity0.5", $noinline$appendDoubleAndFloat(Double.POSITIVE_INFINITY, 0.5f)); |
| assertEquals("2.5-Infinity", $noinline$appendDoubleAndFloat(2.5, Float.NEGATIVE_INFINITY)); |
| } |
| |
| public static String $noinline$appendStringAndString(String s1, String s2) { |
| return new StringBuilder().append(s1).append(s2).toString(); |
| } |
| |
| public static void testAppendStringAndString() { |
| assertEquals("nullnull", $noinline$appendStringAndString(null, null)); |
| assertEquals("nullTEST", $noinline$appendStringAndString(null, "TEST")); |
| assertEquals("TESTnull", $noinline$appendStringAndString("TEST", null)); |
| assertEquals("abcDEFGH", $noinline$appendStringAndString("abc", "DEFGH")); |
| // Test with a non-ASCII character. |
| assertEquals("test\u0131", $noinline$appendStringAndString("test", "\u0131")); |
| assertEquals("\u0131test", $noinline$appendStringAndString("\u0131", "test")); |
| assertEquals("\u0131test\u0131", $noinline$appendStringAndString("\u0131", "test\u0131")); |
| } |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendSLILC(java.lang.String, long, int, long, char) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$appendSLILC(String s, |
| long l1, |
| int i, |
| long l2, |
| char c) { |
| return new StringBuilder().append(s) |
| .append(l1) |
| .append(i) |
| .append(l2) |
| .append(c).toString(); |
| } |
| |
| public static void testMiscelaneous() { |
| assertEquals("x17-1q", |
| $noinline$appendSLILC("x", 1L, 7, -1L, 'q')); |
| assertEquals("null17-1q", |
| $noinline$appendSLILC(null, 1L, 7, -1L, 'q')); |
| assertEquals("x\u013117-1q", |
| $noinline$appendSLILC("x\u0131", 1L, 7, -1L, 'q')); |
| assertEquals("x427-1q", |
| $noinline$appendSLILC("x", 42L, 7, -1L, 'q')); |
| assertEquals("x1-42-1q", |
| $noinline$appendSLILC("x", 1L, -42, -1L, 'q')); |
| assertEquals("x17424242q", |
| $noinline$appendSLILC("x", 1L, 7, 424242L, 'q')); |
| assertEquals("x17-1\u0131", |
| $noinline$appendSLILC("x", 1L, 7, -1L, '\u0131')); |
| } |
| |
| public static String $inline$testInlineInner(StringBuilder sb, String s, int i) { |
| return sb.append(s).append(i).toString(); |
| } |
| |
| /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$testInlineOuter(java.lang.String, int) instruction_simplifier$after_inlining (after) |
| /// CHECK: StringBuilderAppend |
| public static String $noinline$testInlineOuter(String s, int i) { |
| StringBuilder sb = new StringBuilder(); |
| return $inline$testInlineInner(sb, s, i); |
| } |
| |
| public static void testInline() { |
| assertEquals("x42", $noinline$testInlineOuter("x", 42)); |
| } |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: java.lang.String Main.$noinline$appendNothing() instruction_simplifier (after) |
| /// CHECK-NOT: StringBuilderAppend |
| public static String $noinline$appendNothing() { |
| return new StringBuilder().toString(); |
| } |
| |
| public static void testNoArgs() { |
| assertEquals("", $noinline$appendNothing()); |
| } |
| |
| /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (before) |
| /// CHECK-NOT: StringBuilderAppend |
| |
| /// CHECK-START: boolean Main.$noinline$testAppendEquals(java.lang.String, int) instruction_simplifier (after) |
| /// CHECK: StringBuilderAppend |
| public static boolean $noinline$testAppendEquals(String s, int i) { |
| // Regression test for b/151107293 . |
| // When a string is used as both receiver and argument of String.equals(), we DCHECK() |
| // that it cannot be null. However, when replacing the call to StringBuilder.toString() |
| // with the HStringBuilderAppend(), the former reported CanBeNull() as false and |
| // therefore no explicit null checks were needed, but the replacement reported |
| // CanBeNull() as true, so when the result was used in String.equals() for both |
| // receiver and argument, the DCHECK() failed. This was fixed by overriding |
| // CanBeNull() in HStringBuilderAppend to correctly return false; the string that |
| // previously didn't require null check still does not require it. |
| String str = new StringBuilder().append(s).append(i).toString(); |
| return str.equals(str); |
| } |
| |
| public static void testEquals() { |
| if (!$noinline$testAppendEquals("Test", 42)) { |
| throw new Error("str.equals(str) is false"); |
| } |
| } |
| |
| public static void assertEquals(String expected, String actual) { |
| if (!expected.equals(actual)) { |
| throw new AssertionError("Expected: " + expected + ", actual: " + actual); |
| } |
| } |
| } |