Skip to content

Latest commit

 

History

History

jvmci-jmp

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

概要

JVMCI を使って、JNIを経由せずに直接ライブラリ関数を呼び出すサンプルです。

JVMCIの詳細については Java Day Tokyo 2017の資料 、および サンプル をご覧ください。この資料との違いは、コールフレームに関する呼び出しオーバーヘッドを削減するために、JVMCIでターゲット関数へ直接ジャンプするようなコードになっているところです。

このサンプルでは glibc(libc.so)の提供する getpid()src/main/native で生成する libnative.so が提供する call_native() の2つの呼び出しをテストできます。

前提条件

  • JDK 11以降
  • Maven

ネイティブコード( src/main/native )呼び出しテストを行う場合は、上記に加えて以下のものも必要です。

  • GNU make
  • GCC

あらかじめ src/main/nativemake して libnative.so を生成しておいてください。

試してみる

$ mvn package exec:exec

生成コードの確認

生成された機械語は、以下の2つの方法で確認することができます。

1. デバッガ

jcmd <PID> Compiler.codelist でインストールした機械語のアドレスを確認し、デバッガでディスアセンブルします。 jcmd を実行するタイミングは mvn exec:exec したコンソールで "Press any key to exit..." と表示されているときです。

以下、確認例です。
PID 6069がテストコードで、そこのコードキャッシュの中から機械語のアドレス範囲を確認します。

$ jcmd
6069 com.yasuenag.garakuta.jvmci.jmp/com.yasuenag.garakuta.jvmci.jmp.CFuncTest
6021 org.codehaus.plexus.classworlds.launcher.Launcher exec:exec
6090 sun.tools.jcmd.JCmd
$ jcmd 6069 Compiler.codelist | grep yasuenag
289 4 0 com.yasuenag.garakuta.jvmci.jmp.helper.FuncLoader.getFuncAddr(J[B)J [0x00007f1c74732290, 0x00007f1c74732420 - 0x00007f1c74732438]
292 4 0 com.yasuenag.garakuta.jvmci.jmp.CFuncTest$GetPID.getPid()I [0x00007f1c74732490, 0x00007f1c74732620 - 0x00007f1c74732630]

例えば getFuncAddr の場合、アドレス範囲が 0x00007f1c74732420 から 0x00007f1c74732438 なので、ここをGDBでディスアセンブルします。

$ gdb -p 6069

    :

(gdb) disas 0x00007f1c74732420, 0x00007f1c74732438
Dump of assembler code from 0x7f1c74732420 to 0x7f1c74732438:
   0x00007f1c74732420:  mov    %rsi,%rdi
   0x00007f1c74732423:  lea    0x10(%rdx),%rsi
   0x00007f1c7473242a:  movabs $0x7f1c8c0ec4f0,%rax
   0x00007f1c74732434:  jmpq   *%rax
   0x00007f1c74732436:  hlt
   0x00007f1c74732437:  hlt
End of assembler dump.

2. hsdis

HotSpotのディスアセンブルライブラリであるhsdisを使う方法です。hsdisはOpenJDKのソースコードから自分でビルドすることをお奨めしますが、ビルド方法については こちら をご覧ください。

hsdisが組み込まれたJDKで mvn exec:exec する場合、引数に -Ddisas=true を追加することでインストールしたメソッドがディスアセンブルされます。

$ mvn exec:exec -Ddisas=true

    :

com/yasuenag/garakuta/jvmci/jmp/helper/FuncLoader.getFuncAddr(J[B)J (getFuncAddr)  [0x00007f1c307317a0, 0x00007f1c307317b8]  24 bytes
[Disassembling for mach='i386:x86-64']
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x00007f1c19c02d08} 'getFuncAddr' '(J[B)J' in 'com/yasuenag/garakuta/jvmci/jmp/helper/FuncLoader'
  # parm0:    rsi:rsi   = long
  # parm1:    rdx:rdx   = '[B'
  #           [sp+0x10]  (sp of caller)
  0x00007f1c307317a0: mov    %rsi,%rdi
  0x00007f1c307317a3: lea    0x10(%rdx),%rsi
  0x00007f1c307317aa: movabs $0x7f1c4722c4f0,%rax
  0x00007f1c307317b4: jmpq   *%rax

    :