[JVM] How to see Assembly code for your Java Program

It's nice to know Java, but knowing how JVM actually executes is like Wow ! 🙂

JVM's support diagnostic options that allows you to dump the actual Assembly that is generated by JVM for the specific runtime. Let's quickly see how to enable this.

To enable dumping Assembly, use following JVM options while running your program

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

The PrintAssembly option dumps the assembly code. Since it's an advanced diagnostic option, you need to use the -XX:+UnlockDiagnosticVMOptions

Let's use Hello World program and see it in action.

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World !");
  }
}

now lets run this program with the options specified above

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly HelloWorld

Here is the output generated

bash-3.2$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly HelloWorld
Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output
Loaded disassembler from /Library/Java/JavaVirtualMachines/jdk1.7.0_10.jdk/Contents/Home/jre/lib/hsdis-amd64.dylib
Decoding compiled method 0x0000000107ee6150:
Code:
[Disassembling for mach='i386:x86-64']
[Entry Point]
[Constants]
  # {method} 'hashCode' '()I' in 'java/lang/String'
  #           [sp+0x30]  (sp of caller)
  0x0000000107ee62a0: mov    0x8(%rsi),%r10d
  0x0000000107ee62a4: shl    $0x3,%r10
  0x0000000107ee62a8: cmp    %r10,%rax
  0x0000000107ee62ab: jne    0x0000000107ebda60  ;   {runtime_call}
  0x0000000107ee62b1: data32 xchg %ax,%ax
  0x0000000107ee62b4: nopl   0x0(%rax,%rax,1)
  0x0000000107ee62bc: data32 data32 xchg %ax,%ax
[Verified Entry Point]
  0x0000000107ee62c0: mov    %eax,-0x14000(%rsp)
  0x0000000107ee62c7: push   %rbp
  0x0000000107ee62c8: sub    $0x20,%rsp         ;*synchronization entry
                                                ; - java.lang.String::hashCode@-1 (line 1446)
  0x0000000107ee62cc: mov    %rsi,%r11
  0x0000000107ee62cf: mov    0x10(%rsi),%eax    ;*getfield hash
                                                ; - java.lang.String::hashCode@1 (line 1446)
  0x0000000107ee62d2: test   %eax,%eax
  0x0000000107ee62d4: jne    0x0000000107ee63d1  ;*ifne
                                                ; - java.lang.String::hashCode@6 (line 1447)
  0x0000000107ee62da: mov    0xc(%rsi),%ebp     ;*getfield value
                                                ; - java.lang.String::hashCode@10 (line 1447)
  0x0000000107ee62dd: mov    0xc(%r12,%rbp,8),%ebx  ;*arraylength
                                                ; - java.lang.String::hashCode@13 (line 1447)
                                                ; implicit exception: dispatches to 0x0000000107ee63f5
  0x0000000107ee62e2: xor    %r10d,%r10d
  0x0000000107ee62e5: test   %ebx,%ebx
  0x0000000107ee62e7: jle    0x0000000107ee63f1  ;*ifle
                                                ; - java.lang.String::hashCode@14 (line 1447)

0x0000000107ee62ed: test   %ebx,%ebx
  0x0000000107ee62ef: jbe    0x0000000107ee63dd
  0x0000000107ee62f5: mov    %ebx,%edx
  0x0000000107ee62f7: dec    %edx
  0x0000000107ee62f9: cmp    %ebx,%edx
  0x0000000107ee62fb: jae    0x0000000107ee63dd
  0x0000000107ee6301: lea    (%r12,%rbp,8),%rdi
  0x0000000107ee6305: xor    %esi,%esi          ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x0000000107ee6307: movzwl 0x10(%rdi,%r10,2),%r9d
  0x0000000107ee630d: add    %r9d,%esi          ;*iadd
                                                ; - java.lang.String::hashCode@40 (line 1451)
  0x0000000107ee6310: inc    %r10d              ;*iinc
                                                ; - java.lang.String::hashCode@42 (line 1450)
  0x0000000107ee6313: mov    %esi,%r8d
  0x0000000107ee6316: shl    $0x5,%r8d
  0x0000000107ee631a: mov    %r8d,%eax
  0x0000000107ee631d: sub    %esi,%eax          ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x0000000107ee631f: cmp    $0x1,%r10d
  0x0000000107ee6323: jge    0x0000000107ee6329  ;*if_icmpge
                                                ; - java.lang.String::hashCode@30 (line 1450)
  0x0000000107ee6325: mov    %eax,%esi
  0x0000000107ee6327: jmp    0x0000000107ee6307
  0x0000000107ee6329: mov    %ebx,%ecx
  0x0000000107ee632b: add    $0xfffffffffffffffd,%ecx
  0x0000000107ee632e: mov    $0x80000000,%r9d
  0x0000000107ee6334: cmp    %ecx,%edx
  0x0000000107ee6336: cmovl  %r9d,%ecx
  0x0000000107ee633a: cmp    %ecx,%r10d
  0x0000000107ee633d: jl     0x0000000107ee6375
  0x0000000107ee633f: mov    %r8d,%eax
  0x0000000107ee6342: mov    %r10d,%edx
  0x0000000107ee6345: jmpq   0x0000000107ee63c7
  0x0000000107ee634a: mov    %eax,%r10d
  0x0000000107ee634d: shl    $0x5,%r10d         ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x0000000107ee6351: mov    %eax,%esi
  0x0000000107ee6353: mov    %r10d,%eax         ;*bipush
                                                ; - java.lang.String::hashCode@33 (line 1451)
  0x0000000107ee6356: movzwl 0x10(%rdi,%rdx,2),%r8d
  0x0000000107ee635c: sub    %esi,%eax
  0x0000000107ee635e: add    %r8d,%eax          ;*iadd
                                                ; - java.lang.String::hashCode@40 (line 1451)
  0x0000000107ee6361: inc    %edx               ;*iinc
                                                ; - java.lang.String::hashCode@42 (line 1450)
  0x0000000107ee6363: cmp    %ebx,%edx
  0x0000000107ee6365: jl     0x0000000107ee634a  ;*if_icmpge
                                                ; - java.lang.String::hashCode@30 (line 1450)
  0x0000000107ee6367: jmp    0x0000000107ee63cd
  0x0000000107ee6369: nopl   0x0(%rax)
  0x0000000107ee6370: sub    %esi,%eax
  0x0000000107ee6372: mov    %edx,%r10d         ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x0000000107ee6375: movzwl 0x10(%rdi,%r10,2),%r9d
  0x0000000107ee637b: add    %r9d,%eax          ;*iadd
                                                ; - java.lang.String::hashCode@40 (line 1451)
  0x0000000107ee637e: mov    %r10d,%edx
  0x0000000107ee6381: add    $0x4,%edx          ;*iinc
                                                ; - java.lang.String::hashCode@42 (line 1450)
  0x0000000107ee6384: mov    %eax,%r9d
  0x0000000107ee6387: shl    $0x5,%r9d
  0x0000000107ee638b: sub    %eax,%r9d
  0x0000000107ee638e: movslq %r10d,%r10
  0x0000000107ee6391: movzwl 0x12(%rdi,%r10,2),%r8d
  0x0000000107ee6397: movzwl 0x16(%rdi,%r10,2),%ebp
  0x0000000107ee639d: movzwl 0x14(%rdi,%r10,2),%r10d
  0x0000000107ee63a3: add    %r8d,%r9d
  0x0000000107ee63a6: mov    %r9d,%r8d
  0x0000000107ee63a9: shl    $0x5,%r8d
  0x0000000107ee63ad: sub    %r9d,%r8d
  0x0000000107ee63b0: add    %r10d,%r8d
  0x0000000107ee63b3: mov    %r8d,%esi
  0x0000000107ee63b6: shl    $0x5,%esi
  0x0000000107ee63b9: sub    %r8d,%esi
  0x0000000107ee63bc: add    %ebp,%esi          ;*iadd
                                                ; - java.lang.String::hashCode@40 (line 1451)
  0x0000000107ee63be: mov    %esi,%eax
  0x0000000107ee63c0: shl    $0x5,%eax          ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x0000000107ee63c3: cmp    %ecx,%edx
  0x0000000107ee63c5: jl     0x0000000107ee6370  ;*if_icmpge
                                                ; - java.lang.String::hashCode@30 (line 1450)
  0x0000000107ee63c7: cmp    %ebx,%edx
  0x0000000107ee63c9: jl     0x0000000107ee6356
  0x0000000107ee63cb: mov    %esi,%eax
  0x0000000107ee63cd: mov    %eax,0x10(%r11)    ;*synchronization entry
                                                ; - java.lang.String::hashCode@-1 (line 1446)
  0x0000000107ee63d1: add    $0x20,%rsp
  0x0000000107ee63d5: pop    %rbp
  0x0000000107ee63d6: test   %eax,-0xf63dc(%rip)        # 0x0000000107df0000
                                                ;   {poll_return}
  0x0000000107ee63dc: retq   
  0x0000000107ee63dd: mov    $0xffffff86,%esi
  0x0000000107ee63e2: mov    %r11,(%rsp)
  0x0000000107ee63e6: nop
  0x0000000107ee63e7: callq  0x0000000107ebf020  ; OopMap{rbp=NarrowOop [0]=Oop off=332}
                                                ;*bipush
                                                ; - java.lang.String::hashCode@33 (line 1451)
                                                ;   {runtime_call}
  0x0000000107ee63ec: callq  0x00000001075b9d8e  ;*bipush
                                                ; - java.lang.String::hashCode@33 (line 1451)
                                                ;   {runtime_call}
  0x0000000107ee63f1: xor    %eax,%eax
  0x0000000107ee63f3: jmp    0x0000000107ee63d1
  0x0000000107ee63f5: mov    $0xfffffff6,%esi
  0x0000000107ee63fa: nop
  0x0000000107ee63fb: callq  0x0000000107ebf020  ; OopMap{off=352}
                                                ;*arraylength
                                                ; - java.lang.String::hashCode@13 (line 1447)
                                                ;   {runtime_call}
  0x0000000107ee6400: callq  0x00000001075b9d8e  ;*arraylength
                                                ; - java.lang.String::hashCode@13 (line 1447)
                                                ;   {runtime_call}
  0x0000000107ee6405: hlt    
  0x0000000107ee6406: hlt    
  0x0000000107ee6407: hlt    
  0x0000000107ee6408: hlt    
  0x0000000107ee6409: hlt    
  0x0000000107ee640a: hlt    
  0x0000000107ee640b: hlt    
  0x0000000107ee640c: hlt    
  0x0000000107ee640d: hlt    
  0x0000000107ee640e: hlt    
  0x0000000107ee640f: hlt    
  0x0000000107ee6410: hlt    
  0x0000000107ee6411: hlt    
  0x0000000107ee6412: hlt    
  0x0000000107ee6413: hlt    
  0x0000000107ee6414: hlt    
  0x0000000107ee6415: hlt    
  0x0000000107ee6416: hlt    
  0x0000000107ee6417: hlt    
  0x0000000107ee6418: hlt    
  0x0000000107ee6419: hlt    
  0x0000000107ee641a: hlt    
  0x0000000107ee641b: hlt    
  0x0000000107ee641c: hlt    
  0x0000000107ee641d: hlt    
  0x0000000107ee641e: hlt    
  0x0000000107ee641f: hlt    
[Exception Handler]
[Stub Code]
  0x0000000107ee6420: jmpq   0x0000000107ee4ea0  ;   {no_reloc}
[Deopt Handler Code]
  0x0000000107ee6425: callq  0x0000000107ee642a
  0x0000000107ee642a: subq   $0x5,(%rsp)
  0x0000000107ee642f: jmpq   0x0000000107ebec00  ;   {runtime_call}
  0x0000000107ee6434: hlt    
  0x0000000107ee6435: hlt    
  0x0000000107ee6436: hlt    
  0x0000000107ee6437: hlt    
Hello World !

The output contains the memory address, op code and byte code instruction being executed.

This can be a lot helpful for debugging and optimizing extreme performance applications.

Not to spoil the fun, read a bit more on this here

You may run into the issue shown in the image below

hsdis lib not found

This is due to a missing dll, Please follow the following links to solve the same

http://www.nitschinger.at/Printing-JVM-generated-Assembler-on-Mac-OS-X
http://psy-lob-saw.blogspot.in/2013/01/java-print-assembly.html

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.