Get<type>Field
,高速化版のコードは, JNI_FastGetField クラスのメソッドによって実行時に生成される (See: here for details). プラットフォーム毎およびアクセス対象の型毎に, それぞれ以下のメソッドでコードが生成される.
高速版では様々なチェック処理が省略されている. ただし, フィールドの位置は safepoint 停止時に (オブジェクトごと) 変更されることがあるため, safepoint のチェックだけは必要になる. この safepoint チェックを高速に行うため, 以下のように処理を行っている.
フィールド取得の前後で SafepointSynchronize::_safepoint_counter というカウンタの値を確認する.
もし取得前後で値が同じであれば safepoint が起こらなかったということなので, 取得した値をそのまま使う. 取得前にカウンタ値が奇数(現在 safepoint 実行中)であったり, 取得前後で値に変化があれば, 念のため低速版 (jni_GetXXXField()) にフォールバックする.
((cite: hotspot/src/share/vm/prims/jniFastGetField.hpp))
// Basic logic of a fast version of jni_Get<Primitive>Field:
//
// (See safepoint.hpp for a description of _safepoint_counter)
//
// load _safepoint_counter into old_counter
// IF old_counter is odd THEN
// a safepoint is going on, return jni_GetXXXField
// ELSE
// load the primitive field value into result (speculatively)
// load _safepoint_counter into new_counter
// IF (old_counter == new_counter) THEN
// no safepoint happened during the field access, return result
// ELSE
// a safepoint might have happened in-between, return jni_GetXXXField()
// ENDIF
// ENDIF
//
// LoadLoad membars to maintain the load order may be necessary
// for some platforms.
//
// The fast versions don't check for pending suspension request.
// This is fine since it's totally read-only and doesn't create new race.
//
// There is a hypothetical safepoint counter wraparound. But it's not
// a practical concern.
ただし, 実行タイミングが本当に safepoint 処理と重なった場合, 上のチェックを行っても変なアドレスにアクセスしてメモリアクセス違反を起こすことがある. この場合には signal handler でキャッチして正しい処理へとフォールバックさせている.
このフォールバックを実現するため, あらかじめ JNI_FastGetField 内に 「メモリアクセス違反を起こす危険性のあるロード命令のアドレス」と 「その場合のフォールバック処理のエントリポイント」を記録している. signal handler ではそれを見て対応するエントリポイントに遷移させる.
(メモリアクセス違反を起こす危険性のあるロード命令のアドレスとその場合のフォールバック処理のエントリポイントは, JNI_FastGetField::speculative_load_pclist という配列と JNI_FastGetField::slowcase_entry_pclist という配列にそれぞれ納められている)
((cite: hotspot/src/share/vm/prims/jniFastGetField.cpp))
address JNI_FastGetField::speculative_load_pclist [LIST_CAPACITY];
address JNI_FastGetField::slowcase_entry_pclist [LIST_CAPACITY];
safepoint の開始時と終了時に increment される. (値が変わっていれば safepoint 処理が実行されたということになる. また, 値が奇数であれば現在 safepoint 処理が実行されているということになる)
((cite: hotspot/src/share/vm/runtime/safepoint.hpp))
// This counter is used for fast versions of jni_Get<Primitive>Field.
// An even value means there is no ongoing safepoint operations.
// The counter is incremented ONLY at the beginning and end of each
// safepoint. The fact that Threads_lock is held throughout each pair of
// increments (at the beginning and end of each safepoint) guarantees
// race freedom.
public:
static volatile int _safepoint_counter;
(<= 今の x86 で load-load の追い抜きってあったっけ?? Power とか ARM ならともかく... #TODO)
((cite: hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp))
// Instead of issuing lfence for LoadLoad barrier, we create data dependency
// between loads, which is more efficient than lfence.
// Common register usage:
// rax/xmm0: result
// c_rarg0: jni env
// c_rarg1: obj
// c_rarg2: jfield id
static const Register robj = r9;
static const Register rcounter = r10;
static const Register roffset = r11;
static const Register rcounter_addr = r11;
// Warning: do not use rip relative addressing after the first counter load
// since that may scratch r10!
JNI_FastGetField::generate_fast_get_<type>_field() が生成するコード -> JNI_FastGetField::generate_fast_get_{int|long|float}_field0() が生成するコード -> (高速アクセスが失敗した場合は以下の関数にフォールバック) jni_Get<type>Field()
(See: here for details) -> シグナルハンドラ (JVM_handle_linux_signal() or JVM_handle_solaris_signal() or topLevelExceptionFilter()) -> (1) アクセス違反を起こした pc に対応するフォールバック処理エントリポイントを取得 -> JNI_FastGetField::find_slowcase_pc() (2) ハンドラ終了後、フォールバック位置から再開するように設定
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.