(See: JVMTI 仕様)
JvmtiEnv::SetBreakpoint() や JvmtiEnv::ClearBreakpoint() による breakpoint の追加/削除は, VM operation で (より具体的には VM_ChangeBreakpoints::doit() で) 行っている. 追加/削除で行う作業は以下の通り.
JvmtiBreakpoints オブジェクトが内部で持つ JvmtiBreakpointCache に対して登録/削除する
(JvmtiBreakpointCache 自体も, 内部で持つ GrowableCache に対して登録/削除しているだけ)
methodOop の中のバイトコード列の該当個所を bytecode 命令に書き換える/元に戻す
(bytecode 命令にした場合には, ついでに deopt もかけている)
JVMTI のブレークポイントは以下のクラス群によって管理されている.
実際のブレークポイント情報を記録しているのは BreakpointInfo クラスと JvmtiBreakpoint クラス. 使い分けとしては, JvmtiBreakpoint は高速化のためのキャッシュを作るために使われている模様 (See: JvmtiCurrentBreakpoints::is_breakpoint()). (<= とはいえこの関数自体が使われていないので, あまり有効に活用されている気がしないが...)
BreakpointInfo
ブレークポイントの位置を表すクラス. 各 instanceKlass 内に格納されている. 1つのブレークポイントに付き1つの BreakpointInfo オブジェクトが対応.
JvmtiCurrentBreakpoints
ブレークポイント処理関係の親玉. AllStatic クラス.
JvmtiBreakpoints
JvmtiCurrentBreakpoints クラスが内部で使用している補助クラス. JvmtiBreakpoint オブジェクトを入れるための配列のようなもの. (JvmtiCurrentBreakpoints は, 内部的には JvmtiBreakpoints オブジェクトの中に JvmtiBreakpoint オブジェクトを格納して管理)
JvmtiBreakpointCache
JvmtiBreakpoints クラスが内部で使用している補助クラス. JvmtiBreakpoint オブジェクトを入れるための配列のようなもの. (JvmtiBreakpoints は, 内部的には JvmtiBreakpointCache オブジェクトの中に JvmtiBreakpoint オブジェクトを格納して管理)
GrowableCache
JvmtiBreakpointCache クラスが内部で使用している補助クラス. JvmtiBreakpoint オブジェクトを入れるための配列のようなもの. (JvmtiBreakpointCache は, 内部的には GrowableCache オブジェクトの中に JvmtiBreakpoint オブジェクトを格納して管理)
GrowableElement
GrowableCache 内に格納されるオブジェクト. このクラス自体は abstract class であり, 実際に使われるのはサブクラスである JvmtiBreakpoint (See above).
break point 機能を利用するためには, callback の設定と通知の有効化だけでなく, JvmtiEnv::SetBreakpoint() で監視対象を指定する必要が有る.
breakpoint が埋め込まれているメソッドに付いては, JIT Compile の対象にならない.
まず JIT Compile が開始されない. (See methodOopDesc::number_of_breakpoints()
次に, JIT Compile が始まった後で breakpoint が埋め込まれた場合についても, ciEnv::register_method() 直前にチェックするため, 結局使用されない.
(ciEnv::system_dictionary_modification_counter_changed() でチェックし, ダメだったら record_failure() するので, ciEnv::register_method() 内での "if (failing())" でひっかかる) (See: ciEnv::check_for_system_dictionary_modification())
そして, JIT が終わった後で breakpoint が埋められたら deopt されるので, どうあっても使われない.
(なお, C2 では parse 段階では見つけても流してしまうが, C1 では parse 段階でも見つけたら落としている?? #TODO)
parse 段階での処理
((cite: hotspot/src/share/vm/opto/parse2.cpp))
case Bytecodes::_breakpoint:
// Breakpoint set concurrently to compile
// %%% use an uncommon trap?
C->record_failure("breakpoint in method");
return;
((cite: hotspot/src/share/vm/c1/c1_GraphBuilder.cpp))
case Bytecodes::_breakpoint : BAILOUT_("concurrent setting of breakpoint", NULL);
break point や singlestep を有効にした場合は, 重複してイベントを送信しないように, 現在の実行地点を記録する処理が行われる.
(See: JvmtiEnvThreadState::reset_current_location()) (<= ここのコメントで詳しく説明されているような... #TODO)
(See: JvmtiEnvThreadState::compare_and_set_current_location() )
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html
以下, 引用.
"If a singleStep event or breakpoint event is triggered at the current location, the event is defined to occur immediately before the code at the current location is executed. These events are reported before any events which are triggered by the execution of code at the current location in the same thread (specifically: exception, fieldAccess, and fieldModification). If both a step and breakpoint event are triggered for the same thread and location, the step event is reported before the breakpoint event."
"Co-located events can be triggered during the processing of some other event by the agent at the same location in the same thread. If such an event, of type y, is triggered during the processing of an event of type x, and if x precedes y in the ordering specified above, the co-located event y is reported for the current thread and location. If x does not precede y, y is not reported for the current thread and location. For example, if a breakpoint is set at the current location during the processing of SingleStep, that breakpoint will be reported before the thread moves off the current location."
breakpoint capability を取得にした場合に true になる JvmtiExport::can_* フィールドは以下の通り. (<= それぞれどういう影響が有る? #TODO)
((cite: hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp))
JvmtiExport::set_can_hotswap_or_post_breakpoint(
avail.can_generate_breakpoint_events ||
avail.can_redefine_classes ||
avail.can_retransform_classes);
JvmtiExport::set_can_modify_any_class(
avail.can_generate_breakpoint_events ||
avail.can_generate_all_class_hook_events);
...
JvmtiExport::set_can_access_local_variables(
avail.can_access_local_variables ||
avail.can_generate_breakpoint_events ||
avail.can_generate_frame_pop_events);
...
JvmtiExport::set_can_post_breakpoint(avail.can_generate_breakpoint_events);
...
JvmtiExport::set_should_clean_up_heap_objects(avail.can_generate_breakpoint_events);
(See: here for details)
なお breakpoint 用の capability を取得すると, (JvmtiExport::can_*() が変更されることに加えて) 以下の最適化オプションが無効になる (See: JvmtiManageCapabilities::update()).
(See: here for details)
(なお breakpoint の場合には, JvmtiEventControllerPrivate::recompute_enabled() の中で JvmtiEnvThreadState::reset_current_location() が行われる. #TODO)
(See: here for details)
(なお breakpoint の場合には, JvmtiEventControllerPrivate::recompute_enabled() の中で JvmtiEnvThreadState::reset_current_location() が行われる. #TODO)
JvmtiEnv::SetBreakpoint() -> JvmtiBreakpoints::set() -> VMThread::execute() -> (略) (See: here for details) -> VM_ChangeBreakpoints::doit() (<= コンストラクタ引数は VM_ChangeBreakpoints::SET_BREAKPOINT) -> JvmtiBreakpoints::set_at_safepoint() -> JvmtiBreakpointCache::append() -> GrowableCache::append() -> GrowableCache::recache() -> JvmtiBreakpoint::set() -> JvmtiBreakpoint::each_method_version_do() (<= 引数は methodOopDesc::set_breakpoint) -> methodOopDesc::set_breakpoint() -> BreakpointInfo::BreakpointInfo() -> BreakpointInfo::set()
(interpreter が breakpoint 命令を踏むとイベントが送信される)
* Template Interpreter の場合 TemplateTable::_breakpoint() が生成したコード -> InterpreterRuntime::_breakpoint() -> JvmtiExport::post_raw_breakpoint() -> (登録されているコールバックを呼び出す) * C++ Interpreter の場合 BytecodeInterpreter::run() 又は BytecodeInterpreter::runWithChecks() -> InterpreterRuntime::_breakpoint() -> (同上)
JvmtiEnv::ClearBreakpoint() -> JvmtiBreakpoints::clear() -> VMThread::execute() -> (略) (See: here for details) -> VM_ChangeBreakpoints::doit() (<= コンストラクタ引数は VM_ChangeBreakpoints::CLEAR_BREAKPOINT) -> JvmtiBreakpoints::clear_at_safepoint() -> JvmtiBreakpointCache::remove() -> GrowableCache::remove() -> GrowableCache::recache() -> JvmtiBreakpoint::clear() -> JvmtiBreakpoint::each_method_version_do() (<= 引数は methodOopDesc::clear_breakpoint) -> methodOopDesc::clear_breakpoint() -> clear_matches() -> BreakpointInfo::clear()
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
(#Under Construction) 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
(#Under Construction) 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.