JDK-6908239 : HotSpot compiler should refactor helper arrays after inlining
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7
  • Priority: P5
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2009-12-08
  • Updated: 2011-02-16
  • Resolved: 2010-01-07
Description
A DESCRIPTION OF THE REQUEST :
In lack of multiple return values, we often see:

int divide(int[] mod, int a, int b) {
    int result = a / b;
    mod[0] = a % b;
    return result;
}

int[] mod = new int[1];
int quotient = devide(mod, 103, 25);
int remainder = mod[0];


JUSTIFICATION :
Indirection via array wastes performance.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Hotspot compiler should refactor those helper arrays into normal fields after inlining.

CUSTOMER SUBMITTED WORKAROUND :
Do not use methods, if multiple values are expected, or expensively instantiate multiple value objects as return value and unbox them later.
Escape Analysis does this optimization. I am closing this bug if there is no objection.

% cat Test.java
public class Test {
    static int divide(int[] mod, int a, int b) {
        int result = a / b;
        mod[0] = a % b;
        return result;
    }

    static int test() {
        int[] mod = new int[1];
        int quotient = divide(mod, 103, 25);
        int remainder = mod[0];
        return quotient + remainder;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            int r = test();
        }
    }
}

% java -XX:+PrintCompilation -XX:+PrintInlining -XX:CompileCommand=print,Test::test -XX:+DoEscapeAnalysis Test
VM option '+PrintCompilation'
VM option '+PrintInlining'
VM option 'CompileCommand=print,Test::test'
VM option '+DoEscapeAnalysis'
CompilerOracle: print Test.test
  1       Test::test (21 bytes)
      @ 9   Test::divide  inline (hot)
  2       Test::divide (12 bytes)
  1%      Test::main @ 2 (19 bytes)
{method} 
 - klass: {other class}
 - method holder:     'Test'
 - constants:         0xfe7dd59b{constant pool}
 - access:            0x81000008  static 
 - name:              'test'
 - signature:         '()I'
 - max stack:         3
 - max locals:        3
 - size of params:    0
 - method size:       20
 - vtable index:      -2
 - i2i entry:         0xf940b220
 - adapter:           0x0812db08
 - compiled entry     0xf94aaa01
 - code size:         21
 - code start:        0xb51e6850
 - code end (excl):   0xb51e6865
 - method data:       0xb51e6e48
 - checked ex length: 0
 - linenumber start:  0xb51e6865
 - localvar length:   0
#
#  int (  )
#
# -- Old esp -- Framesize: 16 --
#r045 esp+12: return address
#r044 esp+ 8: pad2, in_preserve
#r043 esp+ 4: pad2, in_preserve
#r042 esp+ 0: Fixed slot 0
#
abababab   N1: #	B1 <- B1  Freq: 1
abababab
000   B1: #	N1 <- BLOCK HEAD IS JUNK   Freq: 1
000   	PUSHL  EBP
	SUB    ESP,8	# Create frame
007   	MOV    EAX,#7
00c   	ADD    ESP,8	# Destroy frame
	POPL   EBP
	TEST   PollPage,EAX	! Poll Safepoint
	
016   	RET
016

Comments
EVALUATION Escape Analysis does this optimization. Note: you should use jdk 7 or 6u20 (in 6u18/6u19 EA is disabled) with flag -XX:+DoEscapeAnalysis. I am closing this bug if there is no objection. % cat Test.java public class Test { static int divide(int[] mod, int a, int b) { int result = a / b; mod[0] = a % b; return result; } static int test() { int[] mod = new int[1]; int quotient = divide(mod, 103, 25); int remainder = mod[0]; return quotient + remainder; } public static void main(String[] args) { for (int i = 0; i < 100000; i++) { int r = test(); } } } % java -XX:+PrintCompilation -XX:+PrintInlining -XX:CompileCommand=print,Test::test -XX:+DoEscapeAnalysis Test VM option '+PrintCompilation' VM option '+PrintInlining' VM option 'CompileCommand=print,Test::test' VM option '+DoEscapeAnalysis' CompilerOracle: print Test.test 1 Test::test (21 bytes) @ 9 Test::divide inline (hot) 2 Test::divide (12 bytes) 1% Test::main @ 2 (19 bytes) {method} - klass: {other class} - method holder: 'Test' - constants: 0xfe7dd59b{constant pool} - access: 0x81000008 static - name: 'test' - signature: '()I' - max stack: 3 - max locals: 3 - size of params: 0 - method size: 20 - vtable index: -2 - i2i entry: 0xf940b220 - adapter: 0x0812db08 - compiled entry 0xf94aaa01 - code size: 21 - code start: 0xb51e6850 - code end (excl): 0xb51e6865 - method data: 0xb51e6e48 - checked ex length: 0 - linenumber start: 0xb51e6865 - localvar length: 0 # # int ( ) # # -- Old esp -- Framesize: 16 -- #r045 esp+12: return address #r044 esp+ 8: pad2, in_preserve #r043 esp+ 4: pad2, in_preserve #r042 esp+ 0: Fixed slot 0 # abababab N1: # B1 <- B1 Freq: 1 abababab 000 B1: # N1 <- BLOCK HEAD IS JUNK Freq: 1 000 PUSHL EBP SUB ESP,8 # Create frame 007 MOV EAX,#7 00c ADD ESP,8 # Destroy frame POPL EBP TEST PollPage,EAX ! Poll Safepoint 016 RET 016
08-03-2010

PUBLIC COMMENTS I close this bug since Escape Analysis does this optimization.
07-01-2010