【问题标题】:How to see the machine code generated for JNI-Calls?如何查看为 JNI 调用生成的机器代码?
【发布时间】:2020-07-13 06:37:24
【问题描述】:

我想看看JVM生成的机器码调用一个native方法See here for details。 我知道 Option -XX:+PrintAssembly (Like here: https://stackoverflow.com/a/24718356/13912132) ,但它只显示了 JIT 编译的代码。我只想查看设置寄存器/堆栈的短 sn-p,仅此而已。 The code to generate machine code for x86_64。 是否有任何命令行选项可以让我这样做?

【问题讨论】:

    标签: assembly jvm hotspot


    【解决方案1】:

    -XX:+PrintAssembly 也表明了这一点。但也有细微差别。

    即使本地方法没有字节码,方法的激活仍然需要 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
      ...
    

    此代码由SharedRuntime::generate_native_wrapper生成。

    【讨论】:

    • 感谢您的精彩回答
    猜你喜欢
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多