diff options
author | 2019-12-13 12:53:39 +0000 | |
---|---|---|
committer | 2020-01-08 14:50:06 +0000 | |
commit | a18f5aeaecf9088f1ba1c43e7577dc149f85673f (patch) | |
tree | 88a98d98edab2c83821a8df17768788245c039a1 /test/699-checker-string-append2 | |
parent | 7ee34a1eeba20c1b438f7bcad75adba65dd2a840 (diff) |
Fix StringBuilder append assumptions.
Do not rely on use ordering, it can be different because of
SimplifyReturnThis(); just use HBackwardInstructionIterator.
Instead of checking that we find a StringBuilder.toString(),
check that it is the invoke we're trying to simplify.
Add regression test 699-checker-string-append2.
Test: testrunner.py --host --jvm -t 699-checker-string-append2
Bug: 19575890
Bug: 146014745
Change-Id: I7b16f376c16ba5a4107e9718e0acf17d82280f54
Diffstat (limited to 'test/699-checker-string-append2')
-rw-r--r-- | test/699-checker-string-append2/expected.txt | 1 | ||||
-rw-r--r-- | test/699-checker-string-append2/info.txt | 1 | ||||
-rw-r--r-- | test/699-checker-string-append2/smali/B146014745.smali | 163 | ||||
-rw-r--r-- | test/699-checker-string-append2/src/Main.java | 40 |
4 files changed, 205 insertions, 0 deletions
diff --git a/test/699-checker-string-append2/expected.txt b/test/699-checker-string-append2/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/699-checker-string-append2/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/699-checker-string-append2/info.txt b/test/699-checker-string-append2/info.txt new file mode 100644 index 0000000000..1bd4a1a297 --- /dev/null +++ b/test/699-checker-string-append2/info.txt @@ -0,0 +1 @@ +Regression tests for String append pattern recognition bugs. b/146014745 diff --git a/test/699-checker-string-append2/smali/B146014745.smali b/test/699-checker-string-append2/smali/B146014745.smali new file mode 100644 index 0000000000..0a20b41a68 --- /dev/null +++ b/test/699-checker-string-append2/smali/B146014745.smali @@ -0,0 +1,163 @@ +# Copyright (C) 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. + +.class public LB146014745; +.super Ljava/lang/Object; + +## CHECK-START: java.lang.String B146014745.$noinline$testAppend1(java.lang.String, int) instruction_simplifier (before) +## CHECK-NOT: StringBuilderAppend + +## CHECK-START: java.lang.String B146014745.$noinline$testAppend1(java.lang.String, int) instruction_simplifier (after) +## CHECK: StringBuilderAppend + +.method public static $noinline$testAppend1(Ljava/lang/String;I)Ljava/lang/String; + .registers 4 +# StringBuilder sb = new StringBuilder(); + new-instance v0, Ljava/lang/StringBuilder; + invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V +# sb.append(s).append(i); + invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; +# return sb.append(s).append(i).toString(); + invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 + return-object v1 +.end method + +## CHECK-START: java.lang.String B146014745.$noinline$testAppend2(java.lang.String, int) instruction_simplifier (after) +## CHECK-NOT: StringBuilderAppend + +.method public static $noinline$testAppend2(Ljava/lang/String;I)Ljava/lang/String; + .registers 4 +# StringBuilder sb = new StringBuilder(); + new-instance v0, Ljava/lang/StringBuilder; + invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V +# String s2 = sb.append(s).append(i).toString(); + invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 +# return sb.append(s2).toString(); + invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 + return-object v1 +.end method + +## CHECK-START: java.lang.String B146014745.$noinline$testAppend3(java.lang.String, int) instruction_simplifier (after) +## CHECK-NOT: StringBuilderAppend + +.method public static $noinline$testAppend3(Ljava/lang/String;I)Ljava/lang/String; + .registers 5 +# StringBuilder sb = new StringBuilder(); + new-instance v0, Ljava/lang/StringBuilder; + invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V +# String s2 = sb.append(s).toString(); + invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v2 + invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v2 +# return sb.append(i).append(s2).append(i); + invoke-virtual {v0, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; +# return sb.toString(); + invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 + return-object v1 +.end method + +# The following is a jasmin version. +# Unfortunately, this would be translated without the required move-result-object, +# instead using the register initialized by new-instance for subsequent calls. + +#.class public B146014745 +#.super java/lang/Object + +#.method public static $noinline$testAppend1(Ljava/lang/String;I)Ljava/lang/String; +# .limit stack 3 +# .limit locals 2 +#; StringBuilder sb = new StringBuilder(); +# new java/lang/StringBuilder +# dup +# invokespecial java.lang.StringBuilder.<init>()V +#; sb.append(s).append(i); +# dup +# aload_0 +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# iload_1 +# invokevirtual java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder; +# pop +#; return sb.append(s).append(i).toString(); +# aload_0 +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# iload_1 +# invokevirtual java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder; +# invokevirtual java.lang.StringBuilder.toString()Ljava/lang/String; +# areturn +#.end method + +#.method public static $noinline$testAppend2(Ljava/lang/String;I)Ljava/lang/String; +# .limit stack 3 +# .limit locals 2 +#; StringBuilder sb = new StringBuilder(); +# new java/lang/StringBuilder +# dup +# invokespecial java.lang.StringBuilder.<init>()V +#; String s2 = sb.append(s).append(i).toString(); +# dup +# aload_0 +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# iload_1 +# invokevirtual java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder; +# invokevirtual java.lang.StringBuilder.toString()Ljava/lang/String; +#; return sb.append(s2).toString(); +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# invokevirtual java.lang.StringBuilder.toString()Ljava/lang/String; +# areturn +#.end method + +#.method public static $noinline$testAppend3(Ljava/lang/String;I)Ljava/lang/String; +# .limit stack 3 +# .limit locals 3 +#; StringBuilder sb = new StringBuilder(); +# new java/lang/StringBuilder +# dup +# invokespecial java.lang.StringBuilder.<init>()V +#; String s2 = sb.append(s).toString(); +# dup +# aload_0 +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# invokevirtual java.lang.StringBuilder.toString()Ljava/lang/String; +# astore_2 +#; return sb.append(i).append(s2).append(i); +# iload_1 +# invokevirtual java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder; +# aload_2 +# invokevirtual java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; +# iload_1 +# invokevirtual java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder; +# invokevirtual java.lang.StringBuilder.toString()Ljava/lang/String; +# areturn +#.end method diff --git a/test/699-checker-string-append2/src/Main.java b/test/699-checker-string-append2/src/Main.java new file mode 100644 index 0000000000..3753af603b --- /dev/null +++ b/test/699-checker-string-append2/src/Main.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) throws Exception { + Class<?> c = Class.forName("B146014745"); + Method m1 = c.getDeclaredMethod("$noinline$testAppend1", String.class, int.class); + String b146014745_result1 = (String) m1.invoke(null, "x", 42); + assertEquals("x42x42", b146014745_result1); + Method m2 = c.getDeclaredMethod("$noinline$testAppend2", String.class, int.class); + String b146014745_result2 = (String) m2.invoke(null, "x", 42); + assertEquals("x42x42", b146014745_result2); + Method m3 = c.getDeclaredMethod("$noinline$testAppend3", String.class, int.class); + String b146014745_result3 = (String) m3.invoke(null, "x", 42); + assertEquals("x42x42", b146014745_result3); + + System.out.println("passed"); + } + + public static void assertEquals(String expected, String actual) { + if (!expected.equals(actual)) { + throw new AssertionError("Expected: " + expected + ", actual: " + actual); + } + } +} |