diff options
author | 2016-11-16 10:17:46 -0800 | |
---|---|---|
committer | 2016-11-30 13:21:21 -0800 | |
commit | 71bf7b43380eb445973f32a7f789d9670f8cc97d (patch) | |
tree | 76425f8578b247a845fe61724d71efc63059760f /test/624-checker-stringops/src/Main.java | |
parent | 52f52361c2ea37941fbda71e3c653bb8096bf516 (diff) |
Optimizations around escape analysis. With tests.
Details:
(1) added new intrinsics
(2) implemented optimizations
more !can be null information
more null check removals
replace return-this uses with incoming parameter
remove dead StringBuffer/Builder calls (with escape analysis)
(3) Fixed exposed bug in CanBeMoved()
Performance gain:
This improves CafeineString by about 360%
(removes null check from first loop, eliminates second loop completely)
Test: test-art-host
Change-Id: Iaf16a1b9cab6a7386f43d71c6b51dd59600e81c1
Diffstat (limited to 'test/624-checker-stringops/src/Main.java')
-rw-r--r-- | test/624-checker-stringops/src/Main.java | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java index 34e82831a8..d965e3ffce 100644 --- a/test/624-checker-stringops/src/Main.java +++ b/test/624-checker-stringops/src/Main.java @@ -98,9 +98,170 @@ public class Main { return k; } + // + // Allows combining of returned "this". Also ensures that similar looking append() calls + // are not combined somehow through returned result. + // + /// CHECK-START: int Main.bufferLen2() instruction_simplifier (before) + /// CHECK-DAG: <<New:l\d+>> NewInstance + /// CHECK-DAG: <<String1:l\d+>> LoadString + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend + /// CHECK-DAG: <<String2:l\d+>> LoadString + /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<Append1>>] + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null1>>,<<String2>>] intrinsic:StringBufferAppend + /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append2>>] + /// CHECK-DAG: InvokeVirtual [<<Null2>>] intrinsic:StringBufferLength + // + /// CHECK-START: int Main.bufferLen2() instruction_simplifier (after) + /// CHECK-DAG: <<New:l\d+>> NewInstance + /// CHECK-DAG: <<String1:l\d+>> LoadString + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend + /// CHECK-DAG: <<String2:l\d+>> LoadString + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBufferAppend + /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBufferLength + static int bufferLen2() { + StringBuffer s = new StringBuffer(); + return s.append("x").append("x").length(); + } + + // + // Allows combining of returned "this". Also ensures that similar looking append() calls + // are not combined somehow through returned result. + // + /// CHECK-START: int Main.builderLen2() instruction_simplifier (before) + /// CHECK-DAG: <<New:l\d+>> NewInstance + /// CHECK-DAG: <<String1:l\d+>> LoadString + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend + /// CHECK-DAG: <<String2:l\d+>> LoadString + /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>] + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBuilderAppend + /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>] + /// CHECK-DAG: InvokeVirtual [<<Null3>>] intrinsic:StringBuilderLength + // + /// CHECK-START: int Main.builderLen2() instruction_simplifier (after) + /// CHECK-DAG: <<New:l\d+>> NewInstance + /// CHECK-DAG: <<String1:l\d+>> LoadString + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend + /// CHECK-DAG: <<String2:l\d+>> LoadString + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBuilderAppend + /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBuilderLength + static int builderLen2() { + StringBuilder s = new StringBuilder(); + return s.append("x").append("x").length(); + } + + // + // Similar situation in a loop. + // + /// CHECK-START: int Main.bufferLoopAppender() instruction_simplifier (before) + /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none + /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>> + /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<New>>] loop:<<Loop>> + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<Null1>>,<<String1>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>] loop:<<Loop>> + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>] loop:<<Loop>> + /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<Null3>>,<<String3>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: <<Null4:l\d+>> NullCheck [<<New>>] loop:none + /// CHECK-DAG: InvokeVirtual [<<Null4>>] intrinsic:StringBufferLength loop:none + // + /// CHECK-START: int Main.bufferLoopAppender() instruction_simplifier (after) + /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none + /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>> + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<New>>,<<String3>>] intrinsic:StringBufferAppend loop:<<Loop>> + /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBufferLength loop:none + static int bufferLoopAppender() { + StringBuffer b = new StringBuffer(); + for (int i = 0; i < 10; i++) { + b.append("x").append("y").append("z"); + } + return b.length(); + } + + // + // Similar situation in a loop. + // + /// CHECK-START: int Main.builderLoopAppender() instruction_simplifier (before) + /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none + /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>> + /// CHECK-DAG: <<Null1:l\d+>> NullCheck [<<New>>] loop:<<Loop>> + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<Null1>>,<<String1>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Null2:l\d+>> NullCheck [<<Append1>>] loop:<<Loop>> + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<Null2>>,<<String2>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Null3:l\d+>> NullCheck [<<Append2>>] loop:<<Loop>> + /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<Null3>>,<<String3>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: <<Null4:l\d+>> NullCheck [<<New>>] loop:none + /// CHECK-DAG: InvokeVirtual [<<Null4>>] intrinsic:StringBuilderLength loop:none + // + /// CHECK-START: int Main.builderLoopAppender() instruction_simplifier (after) + /// CHECK-DAG: <<New:l\d+>> NewInstance loop:none + /// CHECK-DAG: <<String1:l\d+>> LoadString loop:<<Loop:B\d+>> + /// CHECK-DAG: <<Append1:l\d+>> InvokeVirtual [<<New>>,<<String1>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: <<String2:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Append2:l\d+>> InvokeVirtual [<<New>>,<<String2>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: <<String3:l\d+>> LoadString loop:<<Loop>> + /// CHECK-DAG: <<Append3:l\d+>> InvokeVirtual [<<New>>,<<String3>>] intrinsic:StringBuilderAppend loop:<<Loop>> + /// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBuilderLength loop:none + static int builderLoopAppender() { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 10; i++) { + b.append("x").append("y").append("z"); + } + return b.length(); + } + + // + // All calls in the loop-body and thus loop can be eliminated. + // + /// CHECK-START: int Main.bufferDeadLoop() instruction_simplifier (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> + /// CHECK-DAG: InvokeVirtual intrinsic:StringBufferToString loop:<<Loop>> + /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:<<Loop>> + // + /// CHECK-START: int Main.bufferDeadLoop() loop_optimization (after) + /// CHECK-NOT: Phi + /// CHECK-NOT: InvokeVirtual intrinsic:StringBufferToString + /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter + static int bufferDeadLoop() { + StringBuffer b = new StringBuffer(); + for (int i = 0; i < 10; i++) { + int d = b.toString().indexOf("x", 1); + } + return b.length(); + } + + // + // All calls in the loop-body and thus loop can be eliminated. + // + /// CHECK-START: int Main.builderDeadLoop() instruction_simplifier (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> + /// CHECK-DAG: InvokeVirtual intrinsic:StringBuilderToString loop:<<Loop>> + /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:<<Loop>> + // + /// CHECK-START: int Main.builderDeadLoop() loop_optimization (after) + /// CHECK-NOT: Phi + /// CHECK-NOT: InvokeVirtual intrinsic:StringBuilderToString + /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter + static int builderDeadLoop() { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 10; i++) { + int d = b.toString().indexOf("x", 1); + } + return b.length(); + } + public static void main(String[] args) { expectEquals(1865, liveIndexOf()); expectEquals(29, deadIndexOf()); + try { indexOfExceptions(null, XYZ); throw new Error("Expected: NPE"); @@ -113,6 +274,13 @@ public class Main { } expectEquals(598, indexOfExceptions(ABC, XYZ)); + expectEquals(2, bufferLen2()); + expectEquals(2, builderLen2()); + expectEquals(30, bufferLoopAppender()); + expectEquals(30, builderLoopAppender()); + expectEquals(0, bufferDeadLoop()); + expectEquals(0, builderDeadLoop()); + System.out.println("passed"); } |