如何查看为 JNI 调用生成的机器代码?
How to see the machine code generated for JNI-Calls?
我想查看 JVM 生成的机器码以调用本地方法 See here for details。
我知道选项 -XX:+PrintAssembly(像这里一样:) , 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。
是否有任何命令行选项允许我这样做?
-XX:+PrintAssembly
也表明了这一点。但也有细微差别。
即使native方法没有字节码,方法的激活仍然需要JVM做some work。与普通 Java 方法一样,此激活可以解释或 JIT 编译。
本地方法总是有一个特殊的入口点用于从解释器调用。此条目是解释器的一部分,并在所有常规本机方法之间共享。或者,更准确地说,有两个入口点:同步方法和非同步方法,请参阅 TemplateInterpreterGenerator::generate_native_entry()
。
要打印这些入口点,请使用 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInterpreter
,然后在输出中查找 method entry point (kind = native)
:
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]
...
如果本地方法被调用的次数足够多,它就会进行 JIT 编译。我的意思是,JVM 生成一个 wrapper 用于从 Java 调用目标本机函数。与共享解释器本机条目不同,包装器专门用于特定的本机方法。
当 -XX:+PrintCompilation
开启时,您会看到用 n
符号标记的原生包装器:
667 18 n 0 java.lang.Thread::isAlive (native)
您还会在 -XX:+PrintAssembly
输出中找到这些包装器:
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
...
我想查看 JVM 生成的机器码以调用本地方法 See here for details。 我知道选项 -XX:+PrintAssembly(像这里一样:) , 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。 是否有任何命令行选项允许我这样做?
-XX:+PrintAssembly
也表明了这一点。但也有细微差别。
即使native方法没有字节码,方法的激活仍然需要JVM做some work。与普通 Java 方法一样,此激活可以解释或 JIT 编译。
本地方法总是有一个特殊的入口点用于从解释器调用。此条目是解释器的一部分,并在所有常规本机方法之间共享。或者,更准确地说,有两个入口点:同步方法和非同步方法,请参阅 TemplateInterpreterGenerator::generate_native_entry()
。
要打印这些入口点,请使用 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInterpreter
,然后在输出中查找 method entry point (kind = native)
:
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]
...
如果本地方法被调用的次数足够多,它就会进行 JIT 编译。我的意思是,JVM 生成一个 wrapper 用于从 Java 调用目标本机函数。与共享解释器本机条目不同,包装器专门用于特定的本机方法。
当 -XX:+PrintCompilation
开启时,您会看到用 n
符号标记的原生包装器:
667 18 n 0 java.lang.Thread::isAlive (native)
您还会在 -XX:+PrintAssembly
输出中找到这些包装器:
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
...