Created
June 26, 2012 07:52
-
-
Save rednaxelafx/2994217 to your computer and use it in GitHub Desktop.
OptimizeStringConcat in HS24 will optimize the result of one StringBuilder to be used multiple times in another StringBuilder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ java -version | |
java version "1.8.0-ea" | |
Java(TM) SE Runtime Environment (build 1.8.0-ea-b43) | |
OpenJDK 64-Bit Server VM (build 24.0-b14-internal-fastdebug, mixed mode) | |
$ java -XX:-TieredCompilation -XX:+PrintCompilation -XX:+PrintOptimizeStringConcat -XX:CompileCommand='exclude,MultipleUse,main' MultipleUse | |
CompilerOracle: exclude MultipleUse.main | |
268 1 java.lang.String::equals (81 bytes) | |
303 2 n java.lang.System::arraycopy (0 bytes) (static) | |
303 3 java.lang.String::length (6 bytes) | |
309 4 java.lang.Object::<init> (1 bytes) | |
312 5 java.lang.AbstractStringBuilder::ensureCapacityInternal (16 bytes) | |
313 6 java.lang.AbstractStringBuilder::append (48 bytes) | |
314 7 java.lang.String::getChars (62 bytes) | |
318 8 java.lang.StringBuilder::append (8 bytes) | |
330 9 java.lang.Math::min (11 bytes) | |
332 10 java.lang.String::<init> (67 bytes) | |
332 11 java.util.Arrays::copyOfRange (63 bytes) | |
338 12 java.lang.AbstractStringBuilder::<init> (12 bytes) | |
339 13 java.lang.StringBuilder::toString (17 bytes) | |
341 14 java.lang.StringBuilder::<init> (18 bytes) | |
349 15 MultipleUse::foo (37 bytes) | |
considering toString call in MultipleUse::foo @ bci:31 | |
fusion would succeed (1 0) for MultipleUse::foo @ bci:19 | |
105 Proj === 85 [[ 161 144 119 144 213 213 ]] #5 Oop:java/lang/String:exact * !jvms: MultipleUse::foo @ bci:15 | |
105 Proj === 85 [[ 161 144 119 144 213 213 ]] #5 Oop:java/lang/String:exact * !jvms: MultipleUse::foo @ bci:15 | |
0--> 161 CallStaticJava === 151 156 157 8 1 ( 136 105 1 ) [[ 162 163 164 166 175 174 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder:exact * ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:28 !jvms: MultipleUse::foo @ bci:28 | |
1--> 179 CallStaticJava === 185 174 175 8 1 ( 192 1 ) [[ 193 194 195 197 206 205 ]] # Static java.lang.StringBuilder::toString java/lang/String:exact * ( java/lang/StringBuilder:NotNull:exact * ) MultipleUse::foo @ bci:31 !jvms: MultipleUse::foo @ bci:31 | |
2--> 144 CallStaticJava === 133 130 118 8 1 ( 136 105 105 136 ) [[ 145 146 147 157 156 ]] # Static java.lang.StringBuilder::<init> void ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:24 !jvms: MultipleUse::foo @ bci:24 | |
3--> 119 Allocate === 108 113 114 8 1 ( 24 22 23 1 105 ) [[ 120 121 122 129 130 131 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) MultipleUse::foo @ bci:19 !jvms: MultipleUse::foo @ bci:19 | |
4--> 185 IfTrue === 184 [[ 179 192 ]] #1 !jvms: MultipleUse::foo @ bci:31 | |
considering toString call in MultipleUse::foo @ bci:15 | |
fusion would succeed (1 0) for MultipleUse::foo @ bci:3 | |
21 ConP === 0 [[ 63 46 26 46 214 214 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
21 ConP === 0 [[ 63 46 26 46 214 214 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
0--> 63 CallStaticJava === 53 58 59 8 1 ( 43 21 1 ) [[ 64 65 66 68 77 76 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder:exact * ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:12 !jvms: MultipleUse::foo @ bci:12 | |
1--> 85 CallStaticJava === 92 76 77 8 1 ( 100 1 ) [[ 101 102 103 105 114 113 ]] # Static java.lang.StringBuilder::toString java/lang/String:exact * ( java/lang/StringBuilder:NotNull:exact * ) MultipleUse::foo @ bci:15 !jvms: MultipleUse::foo @ bci:15 | |
2--> 46 CallStaticJava === 40 37 25 8 1 ( 43 21 21 43 ) [[ 47 48 49 59 58 ]] # Static java.lang.StringBuilder::<init> void ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:8 !jvms: MultipleUse::foo @ bci:8 | |
3--> 26 Allocate === 5 6 7 8 1 ( 24 22 23 1 21 ) [[ 27 28 29 36 37 38 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) MultipleUse::foo @ bci:3 !jvms: MultipleUse::foo @ bci:3 | |
4--> 92 IfTrue === 91 [[ 85 100 ]] #1 !jvms: MultipleUse::foo @ bci:15 | |
considering stacked concats | |
### Excluding compile: static MultipleUse::main | |
fusion would succeed (2 0) for MultipleUse::foo @ bci:3 | |
21 ConP === 0 [[ 63 46 26 46 214 214 215 215 215 215 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
21 ConP === 0 [[ 63 46 26 46 214 214 215 215 215 215 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
21 ConP === 0 [[ 63 46 26 46 214 214 215 215 215 215 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
21 ConP === 0 [[ 63 46 26 46 214 214 215 215 215 215 ]] #java/lang/String:exact * Oop:java/lang/String:exact * | |
0--> 161 CallStaticJava === 151 156 157 8 1 ( 136 105 1 ) [[ 162 163 164 166 175 174 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder:exact * ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:28 !jvms: MultipleUse::foo @ bci:28 | |
1--> 179 CallStaticJava === 185 174 175 8 1 ( 192 1 ) [[ 193 194 195 197 206 205 ]] # Static java.lang.StringBuilder::toString java/lang/String:exact * ( java/lang/StringBuilder:NotNull:exact * ) MultipleUse::foo @ bci:31 !jvms: MultipleUse::foo @ bci:31 | |
2--> 144 CallStaticJava === 133 130 118 8 1 ( 136 105 105 136 ) [[ 145 146 147 157 156 ]] # Static java.lang.StringBuilder::<init> void ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:24 !jvms: MultipleUse::foo @ bci:24 | |
3--> 119 Allocate === 108 113 114 8 1 ( 24 22 23 1 105 ) [[ 120 121 122 129 130 131 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) MultipleUse::foo @ bci:19 !jvms: MultipleUse::foo @ bci:19 | |
4--> 63 CallStaticJava === 53 58 59 8 1 ( 43 21 1 ) [[ 64 65 66 68 77 76 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder:exact * ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:12 !jvms: MultipleUse::foo @ bci:12 | |
5--> 85 CallStaticJava === 92 76 77 8 1 ( 100 1 ) [[ 101 102 103 105 114 113 ]] # Static java.lang.StringBuilder::toString java/lang/String:exact * ( java/lang/StringBuilder:NotNull:exact * ) MultipleUse::foo @ bci:15 !jvms: MultipleUse::foo @ bci:15 | |
6--> 46 CallStaticJava === 40 37 25 8 1 ( 43 21 21 43 ) [[ 47 48 49 59 58 ]] # Static java.lang.StringBuilder::<init> void ( java/lang/StringBuilder:NotNull:exact *, java/lang/String:exact * ) MultipleUse::foo @ bci:8 !jvms: MultipleUse::foo @ bci:8 | |
7--> 26 Allocate === 5 6 7 8 1 ( 24 22 23 1 21 ) [[ 27 28 29 36 37 38 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) MultipleUse::foo @ bci:3 !jvms: MultipleUse::foo @ bci:3 | |
8--> 185 IfTrue === 184 [[ 179 192 ]] #1 !jvms: MultipleUse::foo @ bci:31 | |
9--> 92 IfTrue === 91 [[ 85 100 ]] #1 !jvms: MultipleUse::foo @ bci:15 | |
stacking would succeed | |
done | |
$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Decoding compiled method 0x00007f9877cbbf90: | |
Code: | |
[Entry Point] | |
[Verified Entry Point] | |
[Constants] | |
# {method} 'foo' '()Ljava/lang/String;' in 'MultipleUse' | |
# [sp+0x30] (sp of caller) | |
;; N1: # B1 <- B12 B5 Freq: 1 | |
;; B1: # B6 B2 <- BLOCK HEAD IS JUNK Freq: 1 | |
0x00007f9877cbc100: mov %eax,-0x16000(%rsp) | |
0x00007f9877cbc107: push %rbp | |
0x00007f9877cbc108: sub $0x20,%rsp ;*new ; - MultipleUse::foo@19 (line 5) | |
0x00007f9877cbc10c: mov 0x70(%r15),%rbp | |
0x00007f9877cbc110: mov %rbp,%r10 | |
0x00007f9877cbc113: add $0x48,%r10 | |
0x00007f9877cbc117: cmp 0x80(%r15),%r10 | |
0x00007f9877cbc11e: jae 0x00007f9877cbc353 | |
;; B2: # B3 <- B1 Freq: 0.9999 | |
0x00007f9877cbc124: mov %r10,0x70(%r15) | |
0x00007f9877cbc128: prefetchnta 0xc0(%r10) | |
0x00007f9877cbc130: movq $0x1,0x0(%rbp) | |
0x00007f9877cbc138: prefetchnta 0x100(%r10) | |
0x00007f9877cbc140: movl $0xeffc00ba,0x8(%rbp) ; {oop({type array char})} | |
0x00007f9877cbc147: prefetchnta 0x140(%r10) | |
0x00007f9877cbc14f: movl $0x1c,0xc(%rbp) | |
0x00007f9877cbc156: prefetchnta 0x180(%r10) | |
;; B3: # B8 B4 <- B7 B2 Freq: 1 | |
0x00007f9877cbc15e: mov %rbp,%rbx | |
0x00007f9877cbc161: add $0x3a,%rbx | |
0x00007f9877cbc165: mov %rbp,%r10 | |
0x00007f9877cbc168: add $0x2c,%r10 | |
0x00007f9877cbc16c: mov %r10,(%rsp) | |
0x00007f9877cbc170: mov %rbp,%r13 | |
0x00007f9877cbc173: add $0x1e,%r13 | |
0x00007f9877cbc177: mov %rbp,%rsi | |
0x00007f9877cbc17a: add $0x10,%rsi | |
0x00007f9877cbc17e: mov $0x7d704ef38,%r10 ; {oop([C)} | |
0x00007f9877cbc188: mov $0x7d704ef38,%r14 ; {oop([C)} | |
0x00007f9877cbc192: add $0x10,%r14 | |
0x00007f9877cbc196: mov %r14,%rdi | |
0x00007f9877cbc199: mov $0x7,%edx | |
0x00007f9877cbc19e: mov $0x7f9877c99aa0,%r10 | |
0x00007f9877cbc1a8: callq *%r10 | |
0x00007f9877cbc1ab: mov %r14,%rdi | |
0x00007f9877cbc1ae: mov %r13,%rsi | |
0x00007f9877cbc1b1: mov $0x7,%edx | |
0x00007f9877cbc1b6: mov $0x7f9877c99aa0,%r10 | |
0x00007f9877cbc1c0: callq *%r10 | |
0x00007f9877cbc1c3: mov %r14,%rdi | |
0x00007f9877cbc1c6: mov (%rsp),%rsi | |
0x00007f9877cbc1ca: mov $0x7,%edx | |
0x00007f9877cbc1cf: mov $0x7f9877c99aa0,%r10 | |
0x00007f9877cbc1d9: callq *%r10 | |
0x00007f9877cbc1dc: mov %r14,%rdi | |
0x00007f9877cbc1df: mov %rbx,%rsi | |
0x00007f9877cbc1e2: mov $0x7,%edx | |
0x00007f9877cbc1e7: mov $0x7f9877c99aa0,%r10 | |
0x00007f9877cbc1f1: callq *%r10 | |
0x00007f9877cbc1f4: mov 0x70(%r15),%rax | |
0x00007f9877cbc1f8: mov %rax,%r10 | |
0x00007f9877cbc1fb: add $0x18,%r10 | |
0x00007f9877cbc1ff: cmp 0x80(%r15),%r10 | |
0x00007f9877cbc206: jae 0x00007f9877cbc370 | |
;; B4: # B5 <- B3 Freq: 0.9999 | |
0x00007f9877cbc20c: mov %r10,0x70(%r15) | |
0x00007f9877cbc210: prefetchnta 0xc0(%r10) | |
0x00007f9877cbc218: mov $0xeffc15e7,%r11d ; {oop('java/lang/String')} | |
0x00007f9877cbc21e: mov 0xb0(%r12,%r11,8),%r10 | |
0x00007f9877cbc226: mov %r10,(%rax) | |
0x00007f9877cbc229: movl $0xeffc15e7,0x8(%rax) ; {oop('java/lang/String')} | |
0x00007f9877cbc230: mov %r12,0x10(%rax) | |
;; B5: # N1 <- B9 B4 Freq: 1 | |
0x00007f9877cbc234: push %r10 | |
0x00007f9877cbc236: cmp 0x5481ed3(%rip),%r12 # 0x00007f987d13e110 | |
; {external_word} | |
0x00007f9877cbc23d: je 0x00007f9877cbc2ba | |
0x00007f9877cbc243: mov %rsp,-0x28(%rsp) | |
0x00007f9877cbc248: sub $0x80,%rsp | |
0x00007f9877cbc24f: mov %rax,0x78(%rsp) | |
0x00007f9877cbc254: mov %rcx,0x70(%rsp) | |
0x00007f9877cbc259: mov %rdx,0x68(%rsp) | |
0x00007f9877cbc25e: mov %rbx,0x60(%rsp) | |
0x00007f9877cbc263: mov %rbp,0x50(%rsp) | |
0x00007f9877cbc268: mov %rsi,0x48(%rsp) | |
0x00007f9877cbc26d: mov %rdi,0x40(%rsp) | |
0x00007f9877cbc272: mov %r8,0x38(%rsp) | |
0x00007f9877cbc277: mov %r9,0x30(%rsp) | |
0x00007f9877cbc27c: mov %r10,0x28(%rsp) | |
0x00007f9877cbc281: mov %r11,0x20(%rsp) | |
0x00007f9877cbc286: mov %r12,0x18(%rsp) | |
0x00007f9877cbc28b: mov %r13,0x10(%rsp) | |
0x00007f9877cbc290: mov %r14,0x8(%rsp) | |
0x00007f9877cbc295: mov %r15,(%rsp) | |
0x00007f9877cbc299: mov $0x7f987cc083a8,%rdi ; {external_word} | |
0x00007f9877cbc2a3: mov $0x7f9877cbc243,%rsi ; {internal_word} | |
0x00007f9877cbc2ad: mov %rsp,%rdx | |
0x00007f9877cbc2b0: and $0xfffffffffffffff0,%rsp | |
0x00007f9877cbc2b4: callq 0x00007f987c20b740 ; {runtime_call} | |
0x00007f9877cbc2b9: hlt | |
0x00007f9877cbc2ba: pop %r10 | |
0x00007f9877cbc2bc: test %rbp,%rbp | |
0x00007f9877cbc2bf: jne 0x00007f9877cbc33c | |
0x00007f9877cbc2c5: mov %rsp,-0x28(%rsp) | |
0x00007f9877cbc2ca: sub $0x80,%rsp | |
0x00007f9877cbc2d1: mov %rax,0x78(%rsp) | |
0x00007f9877cbc2d6: mov %rcx,0x70(%rsp) | |
0x00007f9877cbc2db: mov %rdx,0x68(%rsp) | |
0x00007f9877cbc2e0: mov %rbx,0x60(%rsp) | |
0x00007f9877cbc2e5: mov %rbp,0x50(%rsp) | |
0x00007f9877cbc2ea: mov %rsi,0x48(%rsp) | |
0x00007f9877cbc2ef: mov %rdi,0x40(%rsp) | |
0x00007f9877cbc2f4: mov %r8,0x38(%rsp) | |
0x00007f9877cbc2f9: mov %r9,0x30(%rsp) | |
0x00007f9877cbc2fe: mov %r10,0x28(%rsp) | |
0x00007f9877cbc303: mov %r11,0x20(%rsp) | |
0x00007f9877cbc308: mov %r12,0x18(%rsp) | |
0x00007f9877cbc30d: mov %r13,0x10(%rsp) | |
0x00007f9877cbc312: mov %r14,0x8(%rsp) | |
0x00007f9877cbc317: mov %r15,(%rsp) | |
0x00007f9877cbc31b: mov $0x7f987cc083e8,%rdi ; {external_word} | |
0x00007f9877cbc325: mov $0x7f9877cbc2c5,%rsi ; {internal_word} | |
0x00007f9877cbc32f: mov %rsp,%rdx | |
0x00007f9877cbc332: and $0xfffffffffffffff0,%rsp | |
0x00007f9877cbc336: callq 0x00007f987c20b740 ; {runtime_call} | |
0x00007f9877cbc33b: hlt | |
0x00007f9877cbc33c: mov %rbp,%r10 | |
0x00007f9877cbc33f: shr $0x3,%r10 | |
0x00007f9877cbc343: mov %r10d,0xc(%rax) | |
0x00007f9877cbc347: add $0x20,%rsp | |
0x00007f9877cbc34b: pop %rbp | |
0x00007f9877cbc34c: test %eax,0x60ffcae(%rip) # 0x00007f987ddbc000 | |
; {poll_return} | |
0x00007f9877cbc352: retq | |
;; B6: # B11 B7 <- B1 Freq: 0.000100017 | |
0x00007f9877cbc353: mov $0x77fe005d0,%rsi ; {oop({type array char})} | |
0x00007f9877cbc35d: mov $0x1c,%edx | |
0x00007f9877cbc362: nop | |
0x00007f9877cbc363: callq 0x00007f9877cb5160 ; OopMap{off=616} | |
;*new ; - MultipleUse::foo@3 (line 4) | |
; {runtime_call} | |
;; B7: # B3 <- B6 Freq: 0.000100015 | |
0x00007f9877cbc368: mov %rax,%rbp | |
0x00007f9877cbc36b: jmpq 0x00007f9877cbc15e | |
;; B8: # B10 B9 <- B3 Freq: 0.000100017 | |
0x00007f9877cbc370: mov $0x77fe0af38,%rsi ; {oop('java/lang/String')} | |
0x00007f9877cbc37a: nop | |
0x00007f9877cbc37b: callq 0x00007f9877cb5220 ; OopMap{rbp=Oop off=640} | |
;*new ; - MultipleUse::foo@3 (line 4) | |
; {runtime_call} | |
;; B9: # B5 <- B8 Freq: 0.000100015 | |
0x00007f9877cbc380: jmpq 0x00007f9877cbc234 | |
;; B10: # B12 <- B8 Freq: 1.00017e-09 | |
0x00007f9877cbc385: mov %rax,%rsi | |
0x00007f9877cbc388: jmp 0x00007f9877cbc38d | |
;; B11: # B12 <- B6 Freq: 1.00017e-09 | |
0x00007f9877cbc38a: mov %rax,%rsi ;*invokespecial <init> | |
; - MultipleUse::foo@8 (line 4) | |
;; B12: # N1 <- B11 B10 Freq: 2.00033e-09 | |
0x00007f9877cbc38d: add $0x20,%rsp | |
0x00007f9877cbc391: pop %rbp | |
0x00007f9877cbc392: jmpq 0x00007f9877cb7f60 ; {runtime_call} | |
0x00007f9877cbc397: hlt | |
0x00007f9877cbc398: hlt | |
0x00007f9877cbc399: hlt | |
0x00007f9877cbc39a: hlt | |
0x00007f9877cbc39b: hlt | |
0x00007f9877cbc39c: hlt | |
0x00007f9877cbc39d: hlt | |
0x00007f9877cbc39e: hlt | |
0x00007f9877cbc39f: hlt | |
[Exception Handler] | |
[Stub Code] | |
0x00007f9877cbc3a0: jmpq 0x00007f9877c9ea60 ; {no_reloc} | |
[Deopt Handler Code] | |
0x00007f9877cbc3a5: callq 0x00007f9877cbc3aa | |
0x00007f9877cbc3aa: subq $0x5,(%rsp) | |
0x00007f9877cbc3af: jmpq 0x00007f9877c906a0 ; {runtime_call} | |
0x00007f9877cbc3b4: hlt | |
0x00007f9877cbc3b5: hlt | |
0x00007f9877cbc3b6: hlt | |
0x00007f9877cbc3b7: hlt | |
================================================ | |
{method} | |
- klass: {other class} | |
- this oop: 0x000000078004c750 | |
- method holder: 'MultipleUse' | |
- constants: 0x000000078004c2a0 constant pool [80] for 'MultipleUse' cache=0x000000078004cb48 | |
- access: 0x81000009 public static | |
- name: 'foo' | |
- signature: '()Ljava/lang/String;' | |
- max stack: 3 | |
- max locals: 1 | |
- size of params: 0 | |
- method size: 16 | |
- vtable index: -2 | |
- i2i entry: 0x00007ff7a965d2a0 | |
- adapter: 0x0000000000f01378 | |
- compiled entry 0x00007ff7a970d3ad | |
- code size: 37 | |
- code start: 0x000000078004c718 | |
- code end (excl): 0x000000078004c73d | |
- method data: 0x000000078004e4d0 | |
- checked ex length: 0 | |
- linenumber start: 0x000000078004c73d | |
- localvar length: 1 | |
- localvar start: 0x000000078004c742 | |
# | |
# java/lang/String:exact * ( ) | |
# | |
# -- Old rsp -- Framesize: 48 -- | |
#r191 rsp+44: in_preserve | |
#r190 rsp+40: return address | |
#r189 rsp+36: in_preserve | |
#r188 rsp+32: saved fp register | |
#r187 rsp+28: pad2, stack alignment | |
#r186 rsp+24: pad2, stack alignment | |
#r185 rsp+20: Fixed slot 1 | |
#r184 rsp+16: Fixed slot 0 | |
#r195 rsp+12: spill | |
#r194 rsp+ 8: spill | |
#r193 rsp+ 4: spill | |
#r192 rsp+ 0: spill | |
# | |
abababab N1: # B1 <- B12 B5 Freq: 1 | |
abababab | |
000 B1: # B6 B2 <- BLOCK HEAD IS JUNK Freq: 1 | |
000 # stack bang | |
pushq rbp # Save rbp | |
subq rsp, #32 # Create frame | |
00c | |
00c # TLS is in R15 | |
00c movq RBP, [R15 + #112 (8-bit)] # ptr | |
010 movq R10, RBP # spill | |
013 addq R10, #72 # ptr | |
017 # TLS is in R15 | |
017 cmpq R10, [R15 + #128 (32-bit)] # raw ptr | |
01e jnb,u B6 P=0.000100 C=-1.000000 | |
01e | |
024 B2: # B3 <- B1 Freq: 0.9999 | |
024 # TLS is in R15 | |
024 movq [R15 + #112 (8-bit)], R10 # ptr | |
028 PREFETCHNTA [R10 + #192 (32-bit)] # Prefetch allocation to non-temporal cache for write | |
030 movq [RBP], 0x0000000000000001 # ptr | |
038 PREFETCHNTA [R10 + #256 (32-bit)] # Prefetch allocation to non-temporal cache for write | |
040 movl [RBP + #8 (8-bit)], narrowoop: precise klass [C: 0x00007ff7a000f8b8:Constant:exact * # compressed ptr | |
047 PREFETCHNTA [R10 + #320 (32-bit)] # Prefetch allocation to non-temporal cache for write | |
04f movl [RBP + #12 (8-bit)], #28 # int | |
056 PREFETCHNTA [R10 + #384 (32-bit)] # Prefetch allocation to non-temporal cache for write | |
056 | |
05e B3: # B8 B4 <- B7 B2 Freq: 1 | |
05e | |
05e MEMBAR-storestore (empty encoding) | |
05e # checkcastPP of RBP | |
05e movq RBX, RBP # spill | |
061 addq RBX, #58 # ptr | |
065 movq R10, RBP # spill | |
068 addq R10, #44 # ptr | |
06c movq [rsp + #0], R10 # spill | |
070 movq R13, RBP # spill | |
073 addq R13, #30 # ptr | |
077 movq RSI, RBP # spill | |
07a addq RSI, #16 # ptr | |
07e movq R10, char[int:7]<ciTypeArray length=7 type=<ciTypeArrayKlass name=[C ident=712 PERM address=0xa000f8b8> ident=734 SCAVENGABLE address=0x100f5a8> * # ptr | |
088 movq R14, char[int:7]<ciTypeArray length=7 type=<ciTypeArrayKlass name=[C ident=712 PERM address=0xa000f8b8> ident=734 SCAVENGABLE address=0x100f5a8> * # ptr | |
092 addq R14, #16 # ptr | |
096 movq RDI, R14 # spill | |
099 movl RDX, #7 # long (unsigned 32-bit) | |
09e call_leaf_nofp,runtime jshort_disjoint_arraycopy | |
No JVM State Info | |
# | |
0ab movq RDI, R14 # spill | |
0ae movq RSI, R13 # spill | |
0b1 movl RDX, #7 # long (unsigned 32-bit) | |
0b6 call_leaf_nofp,runtime jshort_disjoint_arraycopy | |
No JVM State Info | |
# | |
0c3 movq RDI, R14 # spill | |
0c6 movq RSI, [rsp + #0] # spill | |
0ca movl RDX, #7 # long (unsigned 32-bit) | |
0cf call_leaf_nofp,runtime jshort_disjoint_arraycopy | |
No JVM State Info | |
# | |
0dc movq RDI, R14 # spill | |
0df movq RSI, RBX # spill | |
0e2 movl RDX, #7 # long (unsigned 32-bit) | |
0e7 call_leaf_nofp,runtime jshort_disjoint_arraycopy | |
No JVM State Info | |
# | |
0f4 # TLS is in R15 | |
0f4 movq RAX, [R15 + #112 (8-bit)] # ptr | |
0f8 movq R10, RAX # spill | |
0fb addq R10, #24 # ptr | |
0ff # TLS is in R15 | |
0ff cmpq R10, [R15 + #128 (32-bit)] # raw ptr | |
106 jnb,u B8 P=0.000100 C=-1.000000 | |
106 | |
10c B4: # B5 <- B3 Freq: 0.9999 | |
10c # TLS is in R15 | |
10c movq [R15 + #112 (8-bit)], R10 # ptr | |
110 PREFETCHNTA [R10 + #192 (32-bit)] # Prefetch allocation to non-temporal cache for write | |
118 movl R11, narrowoop: precise klass java/lang/String: 0x0000000000f78498:Constant:exact * # compressed ptr | |
11e movq R10, [R12 + R11 << 3 + #176] (compressed oop addressing) # ptr | |
126 movq [RAX], R10 # ptr | |
129 movl [RAX + #8 (8-bit)], narrowoop: precise klass java/lang/String: 0x0000000000f78498:Constant:exact * # compressed ptr | |
130 movq [RAX + #16 (8-bit)], R12 # long (R12_heapbase==0) | |
130 | |
134 B5: # N1 <- B9 B4 Freq: 1 | |
134 encode_heap_oop_not_null R10,RBP | |
243 movl [RAX + #12 (8-bit)], R10 # compressed ptr | |
247 | |
247 MEMBAR-storestore (empty encoding) | |
247 # checkcastPP of RAX | |
247 addq rsp, 32 # Destroy frame | |
popq rbp | |
testl rax, [rip + #offset_to_poll_page] # Safepoint: poll for GC | |
252 ret | |
252 | |
253 B6: # B11 B7 <- B1 Freq: 0.000100017 | |
253 movq RSI, precise klass [C: 0x00007ff7a000f8b8:Constant:exact * # ptr | |
25d movl RDX, #28 # int | |
nop # 1 bytes pad for loops and calls | |
263 call,static wrapper for: _new_array_Java | |
# MultipleUse::foo @ bci:3 L[0]=#Ptr0x000000000100ba68 | |
# OopMap{off=616} | |
268 | |
268 B7: # B3 <- B6 Freq: 0.000100015 | |
# Block is sole successor of call | |
268 movq RBP, RAX # spill | |
26b jmp B3 | |
26b | |
270 B8: # B10 B9 <- B3 Freq: 0.000100017 | |
270 movq RSI, precise klass java/lang/String: 0x0000000000f78498:Constant:exact * # ptr | |
nop # 1 bytes pad for loops and calls | |
27b call,static wrapper for: _new_instance_Java | |
# MultipleUse::foo @ bci:3 L[0]=#Ptr0x000000000100ba68 | |
# OopMap{rbp=Oop off=640} | |
280 | |
280 B9: # B5 <- B8 Freq: 0.000100015 | |
# Block is sole successor of call | |
280 jmp B5 | |
280 | |
285 B10: # B12 <- B8 Freq: 1.00017e-09 | |
285 # exception oop is in rax; no code emitted | |
285 movq RSI, RAX # spill | |
288 jmp,s B12 | |
288 | |
28a B11: # B12 <- B6 Freq: 1.00017e-09 | |
28a # exception oop is in rax; no code emitted | |
28a movq RSI, RAX # spill | |
28a | |
28d B12: # N1 <- B11 B10 Freq: 2.00033e-09 | |
28d addq rsp, 32 # Destroy frame | |
popq rbp | |
292 jmp rethrow_stub | |
292 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pseudo-code of the actual generated code | |
public static String foo() { | |
// String s = "testing"; | |
// s_value is a oop constant directly embedded in generated code. | |
// The String instance oop is no longer referenced | |
final char[] s_value = "testing".value; | |
final int len = 7 + 7 + 7 + 7; // constant folded to 28 | |
char[] value = allocate_array(char[].klass, len); // skip zeroing contents | |
final char* srcptr = &s_value[0]; | |
// s = new StringBuilder(s).append(s).toString(); | |
// s = new StringBuilder(s).append(s).toString(); | |
// jshort_disjoint_arraycopy(srcptr, dstptr, length); | |
jshort_disjoint_arraycopy(srcptr, &value[0], 7); | |
jshort_disjoint_arraycopy(srcptr, &value[7], 7); | |
jshort_disjoint_arraycopy(srcptr, &value[14], 7); | |
jshort_disjoint_arraycopy(srcptr, &value[21], 7); | |
// This sequence is generated for the case where | |
// String.count and String.offset have been removed. (CR 6924259) | |
String result = allocate_instance(String.klass); | |
result.value = value; | |
return result; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MultipleUse { | |
public static String foo() { | |
String s = "testing"; | |
s = new StringBuilder(s).append(s).toString(); | |
s = new StringBuilder(s).append(s).toString(); | |
return s; | |
} | |
public static void main(String[] args) throws Exception { | |
final String s = "testing"; | |
for (int i = 0; i < 20000; i++) { | |
if (!(s + s + s + s).equals(foo())) { | |
System.out.println("bad string concat"); | |
} | |
} | |
System.out.println("done"); | |
System.in.read(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ javap -verbose -private MultipleUse | |
Compiled from "MultipleUse.java" | |
public class MultipleUse extends java.lang.Object | |
SourceFile: "MultipleUse.java" | |
minor version: 0 | |
major version: 50 | |
Constant pool: | |
const #1 = Method #17.#41; // java/lang/Object."<init>":()V | |
const #2 = String #42; // testing | |
const #3 = class #43; // java/lang/StringBuilder | |
const #4 = Method #3.#44; // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V | |
const #5 = Method #3.#45; // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; | |
const #6 = Method #3.#46; // java/lang/StringBuilder.toString:()Ljava/lang/String; | |
const #7 = String #47; // testingtestingtestingtesting | |
const #8 = Method #16.#48; // MultipleUse.foo:()Ljava/lang/String; | |
const #9 = Method #49.#50; // java/lang/String.equals:(Ljava/lang/Object;)Z | |
const #10 = Field #51.#52; // java/lang/System.out:Ljava/io/PrintStream; | |
const #11 = String #53; // bad string concat | |
const #12 = Method #54.#55; // java/io/PrintStream.println:(Ljava/lang/String;)V | |
const #13 = String #56; // done | |
const #14 = Field #51.#57; // java/lang/System.in:Ljava/io/InputStream; | |
const #15 = Method #58.#59; // java/io/InputStream.read:()I | |
const #16 = class #60; // MultipleUse | |
const #17 = class #61; // java/lang/Object | |
const #18 = Asciz <init>; | |
const #19 = Asciz ()V; | |
const #20 = Asciz Code; | |
const #21 = Asciz LineNumberTable; | |
const #22 = Asciz LocalVariableTable; | |
const #23 = Asciz this; | |
const #24 = Asciz LMultipleUse;; | |
const #25 = Asciz foo; | |
const #26 = Asciz ()Ljava/lang/String;; | |
const #27 = Asciz s; | |
const #28 = Asciz Ljava/lang/String;; | |
const #29 = Asciz main; | |
const #30 = Asciz ([Ljava/lang/String;)V; | |
const #31 = Asciz i; | |
const #32 = Asciz I; | |
const #33 = Asciz args; | |
const #34 = Asciz [Ljava/lang/String;; | |
const #35 = Asciz StackMapTable; | |
const #36 = class #62; // java/lang/String | |
const #37 = Asciz Exceptions; | |
const #38 = class #63; // java/lang/Exception | |
const #39 = Asciz SourceFile; | |
const #40 = Asciz MultipleUse.java; | |
const #41 = NameAndType #18:#19;// "<init>":()V | |
const #42 = Asciz testing; | |
const #43 = Asciz java/lang/StringBuilder; | |
const #44 = NameAndType #18:#64;// "<init>":(Ljava/lang/String;)V | |
const #45 = NameAndType #65:#66;// append:(Ljava/lang/String;)Ljava/lang/StringBuilder; | |
const #46 = NameAndType #67:#26;// toString:()Ljava/lang/String; | |
const #47 = Asciz testingtestingtestingtesting; | |
const #48 = NameAndType #25:#26;// foo:()Ljava/lang/String; | |
const #49 = class #62; // java/lang/String | |
const #50 = NameAndType #68:#69;// equals:(Ljava/lang/Object;)Z | |
const #51 = class #70; // java/lang/System | |
const #52 = NameAndType #71:#72;// out:Ljava/io/PrintStream; | |
const #53 = Asciz bad string concat; | |
const #54 = class #73; // java/io/PrintStream | |
const #55 = NameAndType #74:#64;// println:(Ljava/lang/String;)V | |
const #56 = Asciz done; | |
const #57 = NameAndType #75:#76;// in:Ljava/io/InputStream; | |
const #58 = class #77; // java/io/InputStream | |
const #59 = NameAndType #78:#79;// read:()I | |
const #60 = Asciz MultipleUse; | |
const #61 = Asciz java/lang/Object; | |
const #62 = Asciz java/lang/String; | |
const #63 = Asciz java/lang/Exception; | |
const #64 = Asciz (Ljava/lang/String;)V; | |
const #65 = Asciz append; | |
const #66 = Asciz (Ljava/lang/String;)Ljava/lang/StringBuilder;; | |
const #67 = Asciz toString; | |
const #68 = Asciz equals; | |
const #69 = Asciz (Ljava/lang/Object;)Z; | |
const #70 = Asciz java/lang/System; | |
const #71 = Asciz out; | |
const #72 = Asciz Ljava/io/PrintStream;; | |
const #73 = Asciz java/io/PrintStream; | |
const #74 = Asciz println; | |
const #75 = Asciz in; | |
const #76 = Asciz Ljava/io/InputStream;; | |
const #77 = Asciz java/io/InputStream; | |
const #78 = Asciz read; | |
const #79 = Asciz ()I; | |
{ | |
public MultipleUse(); | |
Code: | |
Stack=1, Locals=1, Args_size=1 | |
0: aload_0 | |
1: invokespecial #1; //Method java/lang/Object."<init>":()V | |
4: return | |
LineNumberTable: | |
line 1: 0 | |
LocalVariableTable: | |
Start Length Slot Name Signature | |
0 5 0 this LMultipleUse; | |
public static java.lang.String foo(); | |
Code: | |
Stack=3, Locals=1, Args_size=0 | |
0: ldc #2; //String testing | |
2: astore_0 | |
3: new #3; //class java/lang/StringBuilder | |
6: dup | |
7: aload_0 | |
8: invokespecial #4; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V | |
11: aload_0 | |
12: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; | |
15: invokevirtual #6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; | |
18: astore_0 | |
19: new #3; //class java/lang/StringBuilder | |
22: dup | |
23: aload_0 | |
24: invokespecial #4; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V | |
27: aload_0 | |
28: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; | |
31: invokevirtual #6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; | |
34: astore_0 | |
35: aload_0 | |
36: areturn | |
LineNumberTable: | |
line 3: 0 | |
line 4: 3 | |
line 5: 19 | |
line 6: 35 | |
LocalVariableTable: | |
Start Length Slot Name Signature | |
3 34 0 s Ljava/lang/String; | |
public static void main(java.lang.String[]) throws java.lang.Exception; | |
Code: | |
Stack=2, Locals=3, Args_size=1 | |
0: ldc #2; //String testing | |
2: astore_1 | |
3: iconst_0 | |
4: istore_2 | |
5: iload_2 | |
6: sipush 20000 | |
9: if_icmpge 37 | |
12: ldc #7; //String testingtestingtestingtesting | |
14: invokestatic #8; //Method foo:()Ljava/lang/String; | |
17: invokevirtual #9; //Method java/lang/String.equals:(Ljava/lang/Object;)Z | |
20: ifne 31 | |
23: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; | |
26: ldc #11; //String bad string concat | |
28: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/String;)V | |
31: iinc 2, 1 | |
34: goto 5 | |
37: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; | |
40: ldc #13; //String done | |
42: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/String;)V | |
45: getstatic #14; //Field java/lang/System.in:Ljava/io/InputStream; | |
48: invokevirtual #15; //Method java/io/InputStream.read:()I | |
51: pop | |
52: return | |
LineNumberTable: | |
line 10: 0 | |
line 11: 3 | |
line 12: 12 | |
line 13: 23 | |
line 11: 31 | |
line 16: 37 | |
line 17: 45 | |
line 18: 52 | |
LocalVariableTable: | |
Start Length Slot Name Signature | |
5 32 2 i I | |
0 53 0 args [Ljava/lang/String; | |
3 50 1 s Ljava/lang/String; | |
StackMapTable: number_of_entries = 3 | |
frame_type = 253 /* append */ | |
offset_delta = 5 | |
locals = [ class java/lang/String, int ] | |
frame_type = 25 /* same */ | |
frame_type = 250 /* chop */ | |
offset_delta = 5 | |
Exceptions: | |
throws java.lang.Exception | |
} | |
$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OptimizeStringConcat | |
// PhaseStringOpts::collect_toString_calls | |
// | |
// Find all StringBuffer.toString() and StringBuilder.toString() calls, | |
// by scanning all control-flow nodes, starting from Root | |
// PhaseStringOpts::build_candidate | |
// | |
// Iterate through all calls related to string concats, | |
// starting from the toString() call, following up by use-def | |
// | |
// During iteration: | |
// 1. Find all append(int)/append(char)/append(String) calls, | |
// record the arguments and their concat modes; | |
// append(Integer.toString(i)) calls are treated as append(i). | |
// If any calls to the SB's other methods are found, give up. | |
// 2. Find the Allocate node of this StringBuffer/StringBuilder; | |
// give up if not found or if the shape looks strange. | |
// 3. Find the constructor call by following the def-use chain of the allocation; | |
// look for <init>()V/<init>(int)V/<init>(String)V versions; | |
// give up if no such constructor call is found, | |
// or if the input to <init>(String)V is proven to be null. | |
// Collect the toString call, all append calls, the constructor call and the | |
// allocation node in _control. | |
// | |
// After all above calls are found, call validate_control_flow(); | |
// return the StringConcat if control-flow is good; return NULL otherwise | |
// StringConcat::validate_control_flow | |
// Give up if too many uncommon traps hit at _begin's bci. | |
// | |
// Search _control and append all known to-be-eliminated nodes onto it. | |
// Known nodes include the Initialize node from Allocate, and its control projection, | |
// and all calls control projection/Catch projection. | |
// | |
// Step backwards from the toString() call, following the control-flow, | |
// and look for unexpected control-flow. | |
// Null-check of the return of append() calls can be eliminated, which is added | |
// to _control; | |
// ditto for a test that leads to an uncommon trap; | |
// other tests are considered unexpected; | |
// Simple diamonds that represent simple data merges are allowed; | |
// all other control-flow shapes are considered unexpected, e.g. no loops allowed. | |
// | |
// Collect all the results produced by calls in the region. | |
// Give up when extra uses of the SB is found. E.g. https://gist.github.com/2994300 | |
// Try to iteratively coalesce separate concats. | |
// Replace the toString result with the all the arguments that made up the other StringConcat. | |
toStrings = collect_toString_calls() | |
foreach(n : toStrings) { | |
sc = build_candidate(n) | |
} | |
// sc1 = second group of strcat | |
sc1 = StringConcat { | |
_begin: bci 19, | |
_end: bci 31, | |
_arguments: { | |
0: result of first group of strcat, | |
1: result of first group of strcat | |
}, | |
_mode: { | |
0: StringNullCheckMode, | |
1: StringMode | |
}, | |
_multiple = false | |
}; | |
// sc2 = first group of strcat | |
sc2 = StringConcat { | |
_begin: bci 3, | |
_end: bci 15, | |
_arguments: { | |
0: s, | |
1: s | |
} | |
_mode: { | |
0: StringNullCheckMode, | |
1: StringMode | |
}, | |
_multiple = false | |
}; | |
// sc3 = merge(sc1, sc2); | |
sc3 = StringConcat { | |
_begin: bci 3, | |
_end: bci 31, | |
_arguments: { | |
0: s, | |
1: s, | |
2: s, | |
3: s | |
} | |
_mode: { | |
0: StringNullCheckMode, | |
1: StringMode | |
2: StringNullCheckMode, | |
3: StringMode | |
}, | |
_multiple = true | |
}; | |
String.length() on a String constant could be folded away in later optimization. When all String arguments of a StringConcat are constants, the length of the new char array could be calculated statically, so we'd be allocating the result char array with a fixed size, as in this Gist's test case. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment