In previous post we've discussed the speed of access to int[0] vs wrapped field (using MutableInteger).
And we've realised that the access to object's field is much faster then to a first element of array. We've found this interesting and decided to investigate why does this happen.
So let's create a simple test:
The essential is: TTHE ACCESS TO A FIELD IS FASTER THEN TO AN ELEMENT OF ARRAY
So let's create a simple test:
public static void incArray(int[] array) { array[0] = +1; } public static void incObject(MutableInteger integer) { integer.value = +1; }and look at a byte-code "javap -c Calculate"
public static void incArray(int[]); Code: 0: aload_0 1: iconst_0 2: iconst_1 3: iastore 4: return public static void incObject(Calculate$MutableInteger); Code: 0: aload_0 1: iconst_1 2: putfield #2; //Field Calculate$MutableInteger.value:I 5: returnIn fact this gives us nothing cause accessing the field and array uses different commands. So let's take a look at assembler code generated by HotSpot for this method:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly Calculate#in order to get assembler output you need open-jdk + hsdis and follow the instructions by Alex
incArray
[Verified Entry Point] [Constants] # {method} 'incArray' '([I)V' in 'Calculate' # parm0: ecx = '[I' # [sp+0x20] (sp of caller) 0xb58d1b40: mov %eax,-0x3000(%esp) 0xb58d1b47: push %ebp 0xb58d1b48: sub $0x18,%esp ;*aload_0 ; - Calculate::incArray@0 (line 15) 0xb58d1b4b: cmpl $0x0,0x8(%ecx) ; implicit exception: dispatches to 0xb58d1b6a 0xb58d1b52: jbe 0xb58d1b74 0xb58d1b58: movl $0x1,0xc(%ecx) ;*iastore ; - Calculate::incArray@3 (line 15) 0xb58d1b5f: add $0x18,%esp 0xb58d1b62: pop %ebp 0xb58d1b63: test %eax,0xb78c5100 ; {poll_return} 0xb58d1b69: ret 0xb58d1b6a: call 0xb58cf590 ; OopMap{ecx=Oop off=47} ;*iastore ; - Calculate::incArray@3 (line 15) ; {runtime_call} 0xb58d1b6f: call 0xb58cf590 ; OopMap{ecx=Oop off=52} ;*iastore ; - Calculate::incArray@3 (line 15) ; {runtime_call} 0xb58d1b74: movl $0x0,(%esp) 0xb58d1b7b: call 0xb58cf290 ; OopMap{ecx=Oop off=64} ;*iastore ; - Calculate::incArray@3 (line 15) ; {runtime_call} 0xb58d1b80: nop 0xb58d1b81: nop 0xb58d1b82: mov %esp,%esi 0xb58d1b84: shr $0xc,%esi 0xb58d1b87: mov 0x10fee40(,%esi,4),%esi ; {external_word} 0xb58d1b8e: mov 0x17c(%esi),%eax 0xb58d1b94: movl $0x0,0x17c(%esi) 0xb58d1b9e: movl $0x0,0x180(%esi) 0xb58d1ba8: add $0x18,%esp 0xb58d1bab: pop %ebp 0xb58d1bac: jmp 0xb58cf090 ; {runtime_call} [Exception Handler] [Stub Code] 0xb58d1bc0: call 0xb58d06d0 ; {no_reloc} 0xb58d1bc5: push $0x1098018 ; {external_word} 0xb58d1bca: call 0xb58d1bcf 0xb58d1bcf: pusha 0xb58d1bd0: call 0x00ce3650 ; {runtime_call} 0xb58d1bd5: hlt [Deopt Handler Code] 0xb58d1bd6: push $0xb58d1bd6 ; {section_word} 0xb58d1bdb: jmp 0xb5892ae0 ; {runtime_call}incObject
[Verified Entry Point] [Constants] # {method} 'incObject' '(LCalculate$MutableInteger;)V' in 'Calculate' # parm0: ecx = 'Calculate$MutableInteger' # [sp+0x10] (sp of caller) 0xb47292c0: mov %eax,-0x3000(%esp) 0xb47292c7: push %ebp 0xb47292c8: sub $0x8,%esp 0xb47292ce: movl $0x1,0x8(%ecx) ;*synchronization entry ; - Calculate::incObject@-1 (line 19) ; implicit exception: dispatches to 0xb47292e0 0xb47292d5: add $0x8,%esp 0xb47292d8: pop %ebp 0xb47292d9: test %eax,0xb773e000 ; {poll_return} 0xb47292df: ret 0xb47292e0: mov $0xfffffff6,%ecx 0xb47292e5: xchg %ax,%ax 0xb47292e7: call 0xb470a720 ; OopMap{off=44} ;*putfield value ; - Calculate::incObject@2 (line 19) ; {runtime_call} 0xb47292ec: call 0x01400630 ;*putfield value ; - Calculate::incObject@2 (line 19) ; {runtime_call} [Exception Handler] [Stub Code] 0xb4729300: jmp 0xb4725760 ; {no_reloc} [Deopt Handler Code] 0xb4729305: push $0xb4729305 ; {section_word} 0xb472930a: jmp 0xb470bbe0 ; {runtime_call} 0xb472930f: .byte 0x0With a closer look you'll find that these two methods are differ only with
;incArray 0xb58d1b4b: cmpl $0x0,0x8(%ecx) ; implicit exception: dispatches to 0xb58d1b6a 0xb58d1b52: jbe 0xb58d1b74 0xb58d1b58: movl $0x1,0xc(%ecx) ;*iastore ;incObject 0xb47292ce: movl $0x1,0x8(%ecx)which in fact is checking if we are within the bounds of an array. This is the place where we loose the 30% of the time.
The essential is: TTHE ACCESS TO A FIELD IS FASTER THEN TO AN ELEMENT OF ARRAY