Skip to content

Instantly share code, notes, and snippets.

@rednaxelafx
Created February 14, 2011 02:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rednaxelafx/825394 to your computer and use it in GitHub Desktop.
Save rednaxelafx/825394 to your computer and use it in GitHub Desktop.
a few examples of the implicit null check generated by HotSpot's opto compiler
// java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=compileonly,TestC2NullCheck.getValue -XX:-UseFastAccessorMethods -XX:+PrintAssembly TestC2NullCheck
public class TestC2NullCheck {
public static int getValue(Foo foo) {
return foo.value;
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 120000; i++) {
getValue(new Foo());
}
Thread.sleep(2000);
}
}
class Foo {
public int value;
}
Decoding compiled method 0xb487f408:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
# {method} 'getValue' '(LFoo;)I' in 'TestC2NullCheck'
# parm0: ecx = 'Foo'
# [sp+0x10] (sp of caller)
0xb487f500: mov %eax,-0x4000(%esp)
0xb487f507: push %ebp
0xb487f508: sub $0x8,%esp ;*synchronization entry
; - TestC2NullCheck::getValue@-1 (line 3)
0xb487f50e: mov 0x8(%ecx),%eax ;*getfield value
; - TestC2NullCheck::getValue@1 (line 3)
; implicit exception: dispatches to 0xb487f51c
0xb487f511: add $0x8,%esp
0xb487f514: pop %ebp
0xb487f515: test %eax,0xb77c8000 ; {poll_return}
0xb487f51b: ret
0xb487f51c: mov $0xfffffff6,%ecx
0xb487f521: nop
0xb487f522: nop
0xb487f523: call 0xb4863720 ; OopMap{off=40}
;*getfield value
; - TestC2NullCheck::getValue@1 (line 3)
; {runtime_call}
0xb487f528: call 0x018292a0 ;*getfield value
; - TestC2NullCheck::getValue@1 (line 3)
; {runtime_call}
0xb487f52d: hlt
0xb487f52e: hlt
0xb487f52f: hlt
0xb487f530: hlt
0xb487f531: hlt
0xb487f532: hlt
0xb487f533: hlt
0xb487f534: hlt
0xb487f535: hlt
0xb487f536: hlt
0xb487f537: hlt
0xb487f538: hlt
0xb487f539: hlt
0xb487f53a: hlt
0xb487f53b: hlt
0xb487f53c: hlt
0xb487f53d: hlt
0xb487f53e: hlt
0xb487f53f: hlt
[Exception Handler]
[Stub Code]
0xb487f540: jmp 0xb487dba0 ; {no_reloc}
[Deopt Handler Code]
0xb487f545: push $0xb487f545 ; {section_word}
0xb487f54a: jmp 0xb4864c00 ; {runtime_call}
[Constants]
0xb487f54f: int3
// java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=compileonly,TestC2NullCheck2.getValue -XX:-UseFastAccessorMethods -XX:+PrintAssembly TestC2NullCheck2
public class TestC2NullCheck2 {
public static int getValue(Foo foo) {
return foo.value;
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 120000; i++) {
try { getValue(null); } catch (NullPointerException e) { /* ignore */ }
}
Thread.sleep(2000);
}
}
class Foo {
public int value;
}
Decoding compiled method 0xb489d408:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
# {method} 'getValue' '(LFoo;)I' in 'TestC2NullCheck2'
# parm0: ecx = 'Foo'
# [sp+0x10] (sp of caller)
0xb489d500: push %ebp
0xb489d501: sub $0x8,%esp ;*synchronization entry
; - TestC2NullCheck2::getValue@-1 (line 3)
0xb489d507: test %ecx,%ecx
0xb489d509: je 0xb489d519
0xb489d50b: mov 0x8(%ecx),%eax
0xb489d50e: add $0x8,%esp
0xb489d511: pop %ebp
0xb489d512: test %eax,0xb77e6000 ; {poll_return}
0xb489d518: ret
0xb489d519: mov $0x90f91d68,%ecx ; {oop(a 'java/lang/NullPointerException')}
0xb489d51e: movl $0x0,0xc(%ecx) ;*getfield value
; - TestC2NullCheck2::getValue@1 (line 3)
0xb489d525: add $0x8,%esp
0xb489d528: pop %ebp
0xb489d529: jmp 0xb489cf60 ; {runtime_call}
0xb489d52e: hlt
0xb489d52f: hlt
0xb489d530: hlt
0xb489d531: hlt
0xb489d532: hlt
0xb489d533: hlt
0xb489d534: hlt
0xb489d535: hlt
0xb489d536: hlt
0xb489d537: hlt
0xb489d538: hlt
0xb489d539: hlt
0xb489d53a: hlt
0xb489d53b: hlt
0xb489d53c: hlt
0xb489d53d: hlt
0xb489d53e: hlt
0xb489d53f: hlt
[Exception Handler]
[Stub Code]
0xb489d540: jmp 0xb489bba0 ; {no_reloc}
[Deopt Handler Code]
0xb489d545: push $0xb489d545 ; {section_word}
0xb489d54a: jmp 0xb4882c00 ; {runtime_call}
[Constants]
0xb489d54f: int3
// java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=compileonly,TestC2NullCheck3.getValue -XX:-UseFastAccessorMethods -XX:+PrintAssembly TestC2NullCheck3
public class TestC2NullCheck3 {
public static int getValue(Foo foo) {
if (foo == null) throw new NullPointerException();
return foo.value;
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 120000; i++) {
getValue(new Foo());
}
Thread.sleep(2000);
}
}
class Foo {
public int value;
}
Decoding compiled method 0xb47eb408:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
# {method} 'getValue' '(LFoo;)I' in 'TestC2NullCheck3'
# parm0: ecx = 'Foo'
# [sp+0x20] (sp of caller)
0xb47eb500: mov %eax,-0x4000(%esp)
0xb47eb507: push %ebp
0xb47eb508: sub $0x18,%esp ;*synchronization entry
; - TestC2NullCheck3::getValue@-1 (line 3)
0xb47eb50e: mov 0x8(%ecx),%eax ;*getfield value
; - TestC2NullCheck3::getValue@13 (line 4)
; implicit exception: dispatches to 0xb47eb51c
0xb47eb511: add $0x18,%esp
0xb47eb514: pop %ebp
0xb47eb515: test %eax,0xb7734000 ; {poll_return}
0xb47eb51b: ret
0xb47eb51c: mov %ecx,(%esp)
0xb47eb51f: mov $0xffffffad,%ecx
0xb47eb524: nop
0xb47eb525: nop
0xb47eb526: nop
0xb47eb527: call 0xb47cf720 ; OopMap{[0]=Oop off=44}
;*ifnonnull
; - TestC2NullCheck3::getValue@1 (line 3)
; {runtime_call}
0xb47eb52c: call 0x014352a0 ;*ifnonnull
; - TestC2NullCheck3::getValue@1 (line 3)
; {runtime_call}
0xb47eb531: hlt
0xb47eb532: hlt
0xb47eb533: hlt
0xb47eb534: hlt
0xb47eb535: hlt
0xb47eb536: hlt
0xb47eb537: hlt
0xb47eb538: hlt
0xb47eb539: hlt
0xb47eb53a: hlt
0xb47eb53b: hlt
0xb47eb53c: hlt
0xb47eb53d: hlt
0xb47eb53e: hlt
0xb47eb53f: hlt
[Exception Handler]
[Stub Code]
0xb47eb540: jmp 0xb47e9ba0 ; {no_reloc}
[Deopt Handler Code]
0xb47eb545: push $0xb47eb545 ; {section_word}
0xb47eb54a: jmp 0xb47d0c00 ; {runtime_call}
[Constants]
0xb47eb54f: int3
// java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=compileonly,TestC2NullCheck4.getValue -XX:CompileCommand=compileonly,Preconditions.checkNotNull -XX:-UseFastAccessorMethods -XX:+PrintAssembly TestC2NullCheck4
public class TestC2NullCheck4 {
public static int getValue(Foo foo) {
Preconditions.checkNotNull(foo);
return foo.value;
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 120000; i++) {
getValue(new Foo());
}
Thread.sleep(2000);
}
}
class Foo {
public int value;
}
final class Preconditions {
public static <T> T checkNotNull(T reference) {
if (reference == null) {
// for demo purpose, don't use NullPointerException here
throw new IllegalArgumentException();
}
return reference;
}
}
Decoding compiled method 0x009dc588:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
# {method} 'getValue' '(LFoo;)I' in 'TestC2NullCheck4'
# parm0: ecx = 'Foo'
# [sp+0x30] (sp of caller)
0x009dc690: mov %eax,-0x3000(%esp)
0x009dc697: push %ebp
0x009dc698: sub $0x28,%esp ;*aload_0
; - TestC2NullCheck4::getValue@0 (line 3)
0x009dc69b: cmp $0x0,%ecx
0x009dc69e: je 0x009dc6b2 ;*ifnonnull
; - Preconditions::checkNotNull@1 (line 22)
; - TestC2NullCheck4::getValue@1 (line 3)
0x009dc6a4: mov 0x8(%ecx),%eax ;*getfield value
; - TestC2NullCheck4::getValue@6 (line 5)
; implicit exception: dispatches to 0x009dc715
0x009dc6a7: add $0x28,%esp
0x009dc6aa: pop %ebp
0x009dc6ab: test %eax,0x940100 ; {poll_return}
0x009dc6b1: ret ;*ireturn
; - TestC2NullCheck4::getValue@9 (line 5)
0x009dc6b2: mov %ecx,0x14(%esp)
0x009dc6b6: mov $0x376d3c90,%edx ; {oop('java/lang/IllegalArgumentException')}
0x009dc6bb: cmpl $0x5,0xe4(%edx)
0x009dc6c5: jne 0x009dc71f ; implicit exception: dispatches to 0x009dc71a
0x009dc6cb: mov %fs:0x0(,%eiz,1),%ecx
0x009dc6d3: mov -0xc(%ecx),%ecx
0x009dc6d6: mov 0x34(%ecx),%eax
0x009dc6d9: lea 0x18(%eax),%edi
0x009dc6dc: cmp 0x3c(%ecx),%edi
0x009dc6df: ja 0x009dc71f
0x009dc6e5: mov %edi,0x34(%ecx)
0x009dc6e8: mov 0x68(%edx),%ecx
0x009dc6eb: mov %ecx,(%eax)
0x009dc6ed: mov %edx,0x4(%eax)
0x009dc6f0: xor %ecx,%ecx
0x009dc6f2: mov %ecx,0x8(%eax)
0x009dc6f5: mov %ecx,0xc(%eax)
0x009dc6f8: mov %ecx,0x10(%eax)
0x009dc6fb: mov %ecx,0x14(%eax) ;*new ; - Preconditions::checkNotNull@4 (line 24)
; - TestC2NullCheck4::getValue@1 (line 3)
0x009dc6fe: mov %eax,%ecx ;*invokespecial <init>
; - Preconditions::checkNotNull@8 (line 24)
; - TestC2NullCheck4::getValue@1 (line 3)
0x009dc700: mov %eax,0x10(%esp)
0x009dc704: nop
0x009dc705: nop
0x009dc706: nop
0x009dc707: call 0x0099cf40 ; OopMap{[20]=Oop [16]=Oop off=124}
;*invokespecial <init>
; - Preconditions::checkNotNull@8 (line 24)
; - TestC2NullCheck4::getValue@1 (line 3)
; {optimized virtual_call}
0x009dc70c: mov 0x10(%esp),%eax
0x009dc710: jmp 0x009dc74f
0x009dc715: call 0x009da350 ; OopMap{off=138}
;*getfield value
; - TestC2NullCheck4::getValue@6 (line 5)
; {runtime_call}
0x009dc71a: call 0x009da350 ; OopMap{[20]=Oop off=143}
;*new ; - Preconditions::checkNotNull@4 (line 24)
; - TestC2NullCheck4::getValue@1 (line 3)
; {runtime_call}
0x009dc71f: mov %edx,%edx
0x009dc721: call 0x009da9c0 ; OopMap{[20]=Oop off=150}
;*new ; - Preconditions::checkNotNull@4 (line 24)
; - TestC2NullCheck4::getValue@1 (line 3)
; {runtime_call}
0x009dc726: jmp 0x009dc6fe
0x009dc728: nop
0x009dc729: nop
0x009dc72a: mov %fs:0x0(,%eiz,1),%esi
0x009dc732: mov -0xc(%esi),%esi
0x009dc735: mov 0x170(%esi),%eax
0x009dc73b: movl $0x0,0x170(%esi)
0x009dc745: movl $0x0,0x174(%esi)
0x009dc74f: add $0x28,%esp
0x009dc752: pop %ebp
0x009dc753: jmp 0x009ab580 ; {runtime_call}
0x009dc758: hlt
0x009dc759: hlt
0x009dc75a: hlt
0x009dc75b: hlt
0x009dc75c: hlt
0x009dc75d: hlt
0x009dc75e: hlt
0x009dc75f: hlt
[Stub Code]
0x009dc760: nop ; {no_reloc}
0x009dc761: nop
0x009dc762: mov $0x0,%ebx ; {static_stub}
0x009dc767: jmp 0x009dc767 ; {runtime_call}
[Exception Handler]
0x009dc76c: call 0x009db440 ; {runtime_call}
0x009dc771: push $0x6dab698c ; {external_word}
0x009dc776: call 0x009dc77b
0x009dc77b: pusha
0x009dc77c: call 0x6d8b2a00 ; {runtime_call}
0x009dc781: hlt
[Deopt Handler Code]
0x009dc782: push $0x9dc782 ; {section_word}
0x009dc787: jmp 0x0099d930 ; {runtime_call}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment