I want to see the machine code generated by the JVM to call a native method See here for details. I know the Option -XX:+PrintAssembly (Like here: https://stackoverflow.com/a/24718356/13912132) , but it only shows me the JIT-compiled code. I only want to see the short snippet, that sets up the registers/the stack, nothing else. The code to generate machine code for x86_64. Is there any commandline option that allows me to do that?
-XX:+PrintAssembly
shows that, too. But there are nuances.
Even though a native method does not have bytecodes, the activation of the method still requires JVM to do some work. Like with normal Java methods, this activation can be either interpreted or JIT compiled.
A native method always has a special entry point for calling from interpreter. This entry is a part of the interpreter, and is shared between all regular native methods. Or, more precisely, there are two entry points: for synchronized methods and for non-synchronized, see TemplateInterpreterGenerator::generate_native_entry()
.
To print these entry points, use -XX:+UnlockDiagnosticVMOptions -XX:+PrintInterpreter
, then look for method entry point (kind = native)
in the output:
method entry point (kind = native) [0x0000017e83dbefc0, 0x0000017e83dbfa60] 2720 bytes
--------------------------------------------------------------------------------
Argument 0 is unknown.RIP: 0x17e83dbefc0 Code size: 0x00000aa0
0x0000017e83dbefc0: mov rcx,qword ptr [rbx+8h]
0x0000017e83dbefc4: movzx ecx,word ptr [rcx+34h]
0x0000017e83dbefc8: pop rax
0x0000017e83dbefc9: lea r14,[rsp+rcx*8+0fffffffffffffff8h]
0x0000017e83dbefce: push 0h
0x0000017e83dbefd3: push 0h
0x0000017e83dbefd8: push rax
0x0000017e83dbefd9: push rbp
0x0000017e83dbefda: mov rbp,rsp
0x0000017e83dbefdd: push r13
0x0000017e83dbefdf: push 0h
0x0000017e83dbefe4: mov r13,qword ptr [rbx+8h]
...
If a native method is invoked many enough times, it gets JIT-compiled. I mean, the JVM generates a wrapper for calling the target native function from Java. Unlike the shared interpreter native entry, the wrapper is specialized for the particular native method.
When -XX:+PrintCompilation
is on, you'll see native wrappers marked by n
symbol:
667 18 n 0 java.lang.Thread::isAlive (native)
You'll also find these wrappers in -XX:+PrintAssembly
output:
java/lang/Thread.isAlive()Z [0x00000238d2d62740, 0x00000238d2d62988] 584 bytes
Argument 0 is unknown.RIP: 0x238d2d62740 Code size: 0x00000248
[Entry Point]
# {method} {0x00000238e5ebadd8} 'isAlive' '()Z' in 'java/lang/Thread'
# [sp+0x70] (sp of caller)
0x00000238d2d62740: mov r10d,dword ptr [rdx+8h]
0x00000238d2d62744: mov r12,800000000h
0x00000238d2d6274e: add r10,r12
0x00000238d2d62751: xor r12,r12
0x00000238d2d62754: cmp rax,r10
0x00000238d2d62757: je 238d2d62768h
0x00000238d2d6275d: jmp 238cb2c7480h ; {runtime_call ic_miss_stub}
0x00000238d2d62762: nop word ptr [rax+rax+0h]
[Verified Entry Point]
0x00000238d2d62768: mov dword ptr [rsp+0ffffffffffff9000h],eax
0x00000238d2d6276f: push rbp
0x00000238d2d62770: mov rbp,rsp
0x00000238d2d62773: sub rsp,60h
0x00000238d2d62777: mov qword ptr [rsp+20h],rdx
0x00000238d2d6277c: cmp rdx,0h
0x00000238d2d62780: lea rdx,[rsp+20h]
0x00000238d2d62785: cmove rdx,qword ptr [rsp+20h] ; ImmutableOopMap{[32]=Oop }
0x00000238d2d6278b: vzeroupper
...
This code is generated by SharedRuntime::generate_native_wrapper
.