a few examples of the implicit null check generated by HotSpot's opto compiler
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 -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; | |
} |
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 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 |
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 -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; | |
} |
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 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 |
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 -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; | |
} |
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 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 |
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 -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; | |
} | |
} |
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 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