hotspot/src/share/vm/runtime/vmThread.cpp
void VMThread::execute(VM_Operation* op) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Thread* t = Thread::current();
{- -------------------------------------------
(1) (以下では, 呼び出し元のスレッドが VMThread かそうでないかに応じて処理を分ける)
---------------------------------------- -}
{- -------------------------------------------
(1) (以下は VMThread 以外から呼び出されたケース (nested VM Operation ではない場合) の処理)
---------------------------------------- -}
if (!t->is_VM_thread()) {
{- -------------------------------------------
(1.1) (デバッグ用の処理)
(See: SkipGCALot, No_Safepoint_Verifier)
---------------------------------------- -}
SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot
// JavaThread or WatcherThread
t->check_for_valid_safepoint_state(true);
{- -------------------------------------------
(1.1) VM_Operation::doit_prologue() を呼び出す.
doit_prologue() が false を返せば, VM_Operation はキャンセルされたと見なし, ここで終了.
---------------------------------------- -}
// New request from Java thread, evaluate prologue
if (!op->doit_prologue()) {
return; // op was cancelled
}
{- -------------------------------------------
(1.1) VM_Operation オブジェクトのフィールドを初期化.
---------------------------------------- -}
// Setup VM_operations for execution
op->set_calling_thread(t, Thread::get_priority(t));
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
// It does not make sense to execute the epilogue, if the VM operation object is getting
// deallocated by the VM thread.
bool concurrent = op->evaluate_concurrently();
bool execute_epilog = !op->is_cheap_allocated();
assert(!concurrent || op->is_cheap_allocated(), "concurrent => cheap_allocated");
{- -------------------------------------------
(1.1) もし VM Operation の完了を待つ必要があれば,
現在の vm_operation_ticket() を取得しておく.
---------------------------------------- -}
// Get ticket number for non-concurrent VM operations
int ticket = 0;
if (!concurrent) {
ticket = t->vm_operation_ticket();
}
{- -------------------------------------------
(1.1) _vm_queue に VM_Operation オブジェクトを追加する.
その後, VMOperationQueue_lock の Monitor::notify() を呼び出して
追加したことを VMThread に通知する.
---------------------------------------- -}
// Add VM operation to list of waiting threads. We are guaranteed not to block while holding the
// VMOperationQueue_lock, so we can block without a safepoint check. This allows vm operation requests
// to be queued up during a safepoint synchronization.
{
VMOperationQueue_lock->lock_without_safepoint_check();
bool ok = _vm_queue->add(op);
op->set_timestamp(os::javaTimeMillis());
VMOperationQueue_lock->notify();
VMOperationQueue_lock->unlock();
// VM_Operation got skipped
if (!ok) {
assert(concurrent, "can only skip concurrent tasks");
if (op->is_cheap_allocated()) delete op;
return;
}
}
{- -------------------------------------------
(1.1) もし VM Operation の完了を待つ必要があれば,
VMOperationRequest_lock の Monitor::wait() を呼び出して VM Operation の完了を待つ
(See: VMThread::evaluate_operation(), VMThread::loop())
---------------------------------------- -}
if (!concurrent) {
// Wait for completion of request (non-concurrent)
// Note: only a JavaThread triggers the safepoint check when locking
MutexLocker mu(VMOperationRequest_lock);
while(t->vm_operation_completed_count() < ticket) {
VMOperationRequest_lock->wait(!t->is_Java_thread());
}
}
{- -------------------------------------------
(1.1) もし VMThread によって delete されない種類の VM_Operation オブジェクトであれば,
VM_Operation::doit_epilogue() を呼び出す.
---------------------------------------- -}
if (execute_epilog) {
op->doit_epilogue();
}
{- -------------------------------------------
(1) (以下は VMThread から呼び出されたケース (nested VM Operation 等の場合) の処理)
---------------------------------------- -}
} else {
{- -------------------------------------------
(1.1) (assert)
---------------------------------------- -}
// invoked by VM thread; usually nested VM operation
assert(t->is_VM_thread(), "must be a VM thread");
{- -------------------------------------------
(1.1) もし現在実行中の VM_Operation があった場合は (= _cur_vm_operation が NULL ではない場合は),
新しい VM_Operation の呼び出し元や優先度は現在実行中のものに合わせておく.
(なお, 実行中だった VM_Operation は, ここでいったん待避しておく)
(なお, 実行中の VM_Operation が入れ子になった実行ができない種類のもの
(= VM_Operation::allow_nested_vm_operations() が false) だった場合には,
ここで fatal() によって異常終了.)
---------------------------------------- -}
VM_Operation* prev_vm_operation = vm_operation();
if (prev_vm_operation != NULL) {
// Check the VM operation allows nested VM operation. This normally not the case, e.g., the compiler
// does not allow nested scavenges or compiles.
if (!prev_vm_operation->allow_nested_vm_operations()) {
fatal(err_msg("Nested VM operation %s requested by operation %s",
op->name(), vm_operation()->name()));
}
op->set_calling_thread(prev_vm_operation->calling_thread(), prev_vm_operation->priority());
}
{- -------------------------------------------
(1.1) (トレース出力) (See: EventMark)
---------------------------------------- -}
EventMark em("Executing %s VM operation: %s", prev_vm_operation ? "nested" : "", op->name());
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
// Release all internal handles after operation is evaluated
HandleMark hm(t);
{- -------------------------------------------
(1.1) VM_Operation::evaluate() を呼び出して VM Operation を実行する.
(なお safepoint 停止が必要であれば, 前後で
SafepointSynchronize::begin() と SafepointSynchronize::end() の呼び出しも行う)
---------------------------------------- -}
_cur_vm_operation = op;
if (op->evaluate_at_safepoint() && !SafepointSynchronize::is_at_safepoint()) {
SafepointSynchronize::begin();
op->evaluate();
SafepointSynchronize::end();
} else {
op->evaluate();
}
{- -------------------------------------------
(1.1) もし VM_Operation オブジェクトが C ヒープ上に確保されたものであれば delete しておく.
---------------------------------------- -}
// Free memory if needed
if (op->is_cheap_allocated()) delete op;
{- -------------------------------------------
(1.1) _cur_vm_operation を元の状態に戻しておく.
---------------------------------------- -}
_cur_vm_operation = prev_vm_operation;
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.