Как увидеть машинный код, сгенерированный для JNI-вызовов? - PullRequest
0 голосов
/ 13 июля 2020

Я хочу увидеть машинный код, сгенерированный JVM для вызова собственного метода Подробнее см. Здесь . Я знаю опцию -XX: + PrintAssembly (как здесь: { ссылка }), но она показывает мне только код, скомпилированный JIT. Я хочу увидеть только короткий фрагмент, который настраивает регистры / стек, ничего больше. Код для генерации машинного кода для x86_64 . Есть ли какой-нибудь параметр командной строки, который позволяет мне это сделать?

1 Ответ

3 голосов
/ 13 июля 2020

-XX:+PrintAssembly это тоже показывает. Но есть нюансы.

Несмотря на то, что собственный метод не имеет байт-кодов, активация метода все же требует, чтобы JVM выполняла некоторую работу . Как и в случае с обычными 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 генерирует оболочку для вызова целевой нативной функции из 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.

...