Skip to content

Instantly share code, notes, and snippets.

@navyxliu
Created March 28, 2024 05:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save navyxliu/9f2e37e5b5a5d7bba656f8d67a59899e to your computer and use it in GitHub Desktop.
Save navyxliu/9f2e37e5b5a5d7bba656f8d67a59899e to your computer and use it in GitHub Desktop.
EmptyString Example
// ./build/linux-x86_64-server-fastdebug/jdk/bin/java -XX:+PrintCompilation -XX:CompileCommand=compileonly,EmptyString::main  -XX:CompileCommand=quiet -Xbatch -XX:+PrintOptoAssembly -XX:CompileCommand=IGVPrintLevel,EmptyString::main,3 EmptyString
class EmptyString {
  public static void main(String[] args) {
        String msg = "";
        int x = 0;

        for (int i = 0; i < 300_000; ++i)  {
          if (msg.length() > 0) {
            x++;
          }
        }

        System.out.println(x);
  }
}

here is main in bytecode. OSR comples the loop 7-26. LV1 is String msg = "".

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #7                  // String
       2: astore_1
       3: iconst_0
       4: istore_2
       5: iconst_0
       6: istore_3
       7: iload_3
       8: ldc           #9                  // int 300000
      10: if_icmpge     29
      13: aload_1
      14: invokevirtual #10                 // Method java/lang/String.length:()I
      17: ifle          23
      20: iinc          2, 1
      23: iinc          3, 1
      26: goto          7
      29: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      32: iload_2
      33: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      36: return

Here are generated OSR in OptoAssembly.

============================= C2-compiled nmethod ==============================
#r018 rsi:rsi   : parm 0: rawptr:BotPTR
# -- Old rsp -- Framesize: 48 --
#r591 rsp+44: in_preserve
#r590 rsp+40: return address
#r589 rsp+36: in_preserve
#r588 rsp+32: saved fp register
#r587 rsp+28: pad2, stack alignment
#r586 rsp+24: pad2, stack alignment
#r585 rsp+20: Fixed slot 1
#r584 rsp+16: Fixed slot 0
#r595 rsp+12: spill
#r594 rsp+ 8: spill
#r593 rsp+ 4: spill
#r592 rsp+ 0: spill
#
----------------------- MetaData before Compile_id = 28 ------------------------
{method}
 - this oop:          0x00007fd448705308
 - method holder:     'EmptyString'
 - constants:         0x00007fd448705030 constant pool [37] {0x00007fd448705030} for 'EmptyString' cache=0x00007fd448705430
 - access:            0x9  public static 
 - flags:             0x6080  queued_for_compilation has_loops_flag has_loops_flag_init 
 - name:              'main'
 - signature:         '([Ljava/lang/String;)V'
 - max stack:         3
 - max locals:        4
 - size of params:    1
 - method size:       14
 - highest level:     3
 - vtable index:      -2
 - i2i entry:         0x00007fd490423be0
 - adapters:          AHE@0x00007fd49816bba0: 0xb i2c: 0x00007fd490532d60 c2i: 0x00007fd490532e1a c2iUV: 0x00007fd490532df5 c2iNCI: 0x00007fd490532e54
 - compiled entry     0x00007fd489000c20
 - code size:         37
 - code start:        0x00007fd4487052d8
 - code end (excl):   0x00007fd4487052fd
 - method data:       0x00007fd4487054b0
 - checked ex length: 0
 - linenumber start:  0x00007fd4487052fd
 - localvar length:   0
 - compiled code: nmethod366   27       3       EmptyString::main (37 bytes)

------------------------ OptoAssembly for Compile_id = 28 -----------------------
#
#  void ( rawptr:BotPTR )
#
000     N104: #	out( B1 ) <- BLOCK HEAD IS JUNK  Freq: 1
000     # breakpoint
        nop 	# 11 bytes pad for loops and calls

010     B1: #	out( B8 B2 ) <- BLOCK HEAD IS JUNK  Freq: 1
010     # stack bang (144 bytes)
	pushq   rbp	# Save rbp
	subq    rsp, #32	# Create frame

02a     movq    RBP, [RSI + #16 (8-bit)]	# ptr
02e     movl    RBX, [RSI + #8 (8-bit)]	# int
031     movl    R13, [RSI]	# int
034     movq    RDI, RSI	# spill
037     call_leaf,runtime  OSR_migration_end
        No JVM State Info
        # 
04c     testq   RBP, RBP	# ptr
04f     je,s   B8  P=0.000001 C=-1.000000

051     B2: #	out( B10 B3 ) <- in( B1 )  Freq: 0.999999
051     movl    R10, [RBP + #8 (8-bit)]	# compressed klass ptr
055     cmpl    R10, narrowklass: precise java/lang/String: 0x00007fd498320c18 (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):Constant:exact *	# compressed klass ptr
05c     jne,u   B10  P=0.000001 C=-1.000000

062     B3: #	out( B9 B4 ) <- in( B2 )  Freq: 0.999998
062     # checkcastPP of RBP
062     movl    R10, [RBP + #20 (8-bit)]	# compressed ptr ! Field: java/lang/String.value (constant)
066     movl    R11, [R12 + R10 << 3 + #12] (compressed oop addressing)	# range
06b     NullCheck R10

06b     B4: #	out( B9 B5 ) <- in( B3 )  Freq: 0.999997
06b     movsbl  R10, [RBP + #16 (8-bit)]	# byte ! Field: java/lang/String.coder (constant)
070     sarxl   R11, R11, R10
075     testl   R11, R11
078     jg,s   B9  P=0.000001 C=-1.000000

07a     B5: #	out( B7 B6 ) <- in( B4 )  Freq: 0.999996
07a     cmpl    R13, #300000
081     jge,s   B7  P=0.000001 C=40960.000000

083     B6: #	out( B7 ) <- in( B5 )  Freq: 0.999995
083     movl    R13, #300000	# int

089     B7: #	out( N104 ) <- in( B5 B6 )  Freq: 0.999996
089     movl    RSI, #-187	# int
08e     movl    RBP, RBX	# spill
090     movl    [rsp + #0], R13	# spill
        nop 	# 3 bytes pad for loops and calls
097     call,static  wrapper for: uncommon_trap(reason='unstable_if' action='reinterpret' debug_id='0')
        # EmptyString::main @ bci:10 (line 6) L[0]=_ L[1]=_ L[2]=RBP L[3]=_ STK[0]=rsp + #0 STK[1]=#300000
        # OopMap {off=156/0x9c}
0a4     stop	# ShouldNotReachHere

0b8     B8: #	out( B9 ) <- in( B1 )  Freq: 1.01328e-06
0b8     xorl    RBP, RBP	# ptr

0ba     B9: #	out( N104 ) <- in( B4 B8 B3 )  Freq: 3.03983e-06
0ba     movl    RSI, #-138	# int
0bf     movl    [rsp + #0], RBX	# spill
0c2     movl    [rsp + #4], R13	# spill
0c7     call,static  wrapper for: uncommon_trap(reason='predicate' action='maybe_recompile' debug_id='0')
        # EmptyString::main @ bci:7 (line 6) L[0]=_ L[1]=RBP L[2]=rsp + #0 L[3]=rsp + #4
        # OopMap {rbp=Oop off=204/0xcc}
0d4     stop	# ShouldNotReachHere

0e8     B10: #	out( N104 ) <- in( B2 )  Freq: 9.99999e-07
0e8     movl    RSI, #-115	# int
0ed     movl    [rsp + #0], RBX	# spill
0f0     movl    [rsp + #4], R13	# spill
        nop 	# 2 bytes pad for loops and calls
0f7     call,static  wrapper for: uncommon_trap(reason='constraint' action='reinterpret' debug_id='0')
        # EmptyString::main @ bci:7 (line 6) L[0]=_ L[1]=RBP L[2]=rsp + #0 L[3]=rsp + #4
        # OopMap {rbp=Oop off=252/0xfc}
104     stop	# ShouldNotReachHere

--------------------------------------------------------------------------------
366   26 %     3       EmptyString::main @ 7 (37 bytes)   made not entrant
366   28 %     4       EmptyString::main @ 7 (37 bytes)   made not entrant
@navyxliu
Copy link
Author

LoadRange (get the length of an array) node before optimizer
before_optimzer

LoadRange after optimizer.
before_codegen

LoadRange after codegen.
after_codegen

@navyxliu
Copy link
Author

if C2 compiles this method in non-OSR way, it can get away msg.length().

  public static int foo() {
    String msg = "";
    int x = 0;

    return x + msg.length();
  }

This is still true even we disable 'FoldStableValues'. it simply knows that msg.value is byte[0].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment