hotspot/src/share/vm/runtime/sharedRuntime.cpp
address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
address pc,
SharedRuntime::ImplicitExceptionKind exception_kind)
{
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
address target_pc = NULL;
{- -------------------------------------------
(1) 例外が発生したアドレスがインタープリタ内を指している場合は,
発生した例外に応じて, 以下の適切なハンドラをリターン.
* NullPointerException の場合
Interpreter::throw_NullPointerException_entry()
* ArithmeticException の場合
Interpreter::throw_ArithmeticException_entry()
* StackOverflowError の場合
Interpreter::throw_StackOverflowError_entry())
(なお, C++ interpreter の場合は, ここに来ることはない)
---------------------------------------- -}
if (Interpreter::contains(pc)) {
#ifdef CC_INTERP
// C++ interpreter doesn't throw implicit exceptions
ShouldNotReachHere();
#else
switch (exception_kind) {
case IMPLICIT_NULL: return Interpreter::throw_NullPointerException_entry();
case IMPLICIT_DIVIDE_BY_ZERO: return Interpreter::throw_ArithmeticException_entry();
case STACK_OVERFLOW: return Interpreter::throw_StackOverflowError_entry();
default: ShouldNotReachHere();
}
#endif // !CC_INTERP
{- -------------------------------------------
(1) 例外が発生したアドレスがインタープリタ内ではない場合,
発生した例外に応じて, 以下の適切なハンドラをリターン.
* StackOverflowError の場合
StubRoutines::throw_StackOverflowError_entry()
(なおこの場合, Deoptimization::cleanup_deopt_info() による...#TODO)
* NullPointerException の場合
#TODO (nmethod::continuation_for_implicit_exception()?? それ以外にもある??)
* ArithmeticException の場合
例外を起こした nmethod に対して
nmethod::continuation_for_implicit_exception() を呼ぶことで
ハンドラを取得.
---------------------------------------- -}
} else {
switch (exception_kind) {
case STACK_OVERFLOW: {
// Stack overflow only occurs upon frame setup; the callee is
// going to be unwound. Dispatch to a shared runtime stub
// which will cause the StackOverflowError to be fabricated
// and processed.
// For stack overflow in deoptimization blob, cleanup thread.
if (thread->deopt_mark() != NULL) {
Deoptimization::cleanup_deopt_info(thread, NULL);
}
return StubRoutines::throw_StackOverflowError_entry();
}
case IMPLICIT_NULL: {
if (VtableStubs::contains(pc)) {
// We haven't yet entered the callee frame. Fabricate an
// exception and begin dispatching it in the caller. Since
// the caller was at a call site, it's safe to destroy all
// caller-saved registers, as these entry points do.
VtableStub* vt_stub = VtableStubs::stub_containing(pc);
// If vt_stub is NULL, then return NULL to signal handler to report the SEGV error.
if (vt_stub == NULL) return NULL;
if (vt_stub->is_abstract_method_error(pc)) {
assert(!vt_stub->is_vtable_stub(), "should never see AbstractMethodErrors from vtable-type VtableStubs");
return StubRoutines::throw_AbstractMethodError_entry();
} else {
return StubRoutines::throw_NullPointerException_at_call_entry();
}
} else {
CodeBlob* cb = CodeCache::find_blob(pc);
// If code blob is NULL, then return NULL to signal handler to report the SEGV error.
if (cb == NULL) return NULL;
// Exception happened in CodeCache. Must be either:
// 1. Inline-cache check in C2I handler blob,
// 2. Inline-cache check in nmethod, or
// 3. Implict null exception in nmethod
if (!cb->is_nmethod()) {
guarantee(cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(),
"exception happened outside interpreter, nmethods and vtable stubs (1)");
// There is no handler here, so we will simply unwind.
return StubRoutines::throw_NullPointerException_at_call_entry();
}
// Otherwise, it's an nmethod. Consult its exception handlers.
nmethod* nm = (nmethod*)cb;
if (nm->inlinecache_check_contains(pc)) {
// exception happened inside inline-cache check code
// => the nmethod is not yet active (i.e., the frame
// is not set up yet) => use return address pushed by
// caller => don't push another return address
return StubRoutines::throw_NullPointerException_at_call_entry();
}
#ifndef PRODUCT
_implicit_null_throws++;
#endif
target_pc = nm->continuation_for_implicit_exception(pc);
// If there's an unexpected fault, target_pc might be NULL,
// in which case we want to fall through into the normal
// error handling code.
}
break; // fall through
}
case IMPLICIT_DIVIDE_BY_ZERO: {
nmethod* nm = CodeCache::find_nmethod(pc);
guarantee(nm != NULL, "must have containing nmethod for implicit division-by-zero exceptions");
#ifndef PRODUCT
_implicit_div0_throws++;
#endif
target_pc = nm->continuation_for_implicit_exception(pc);
// If there's an unexpected fault, target_pc might be NULL,
// in which case we want to fall through into the normal
// error handling code.
break; // fall through
}
default: ShouldNotReachHere();
}
{- -------------------------------------------
(1.1) (assert)
---------------------------------------- -}
assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind");
{- -------------------------------------------
(1.1) (デバッグ用の処理)
---------------------------------------- -}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException"));
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (exception_kind == IMPLICIT_NULL) {
Events::log("Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
} else {
Events::log("Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
}
{- -------------------------------------------
(1.1) 結果をリターン.
---------------------------------------- -}
return target_pc;
}
{- -------------------------------------------
(1) (以下は決して到達しないパス)
---------------------------------------- -}
ShouldNotReachHere();
return NULL;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.