hotspot/src/share/vm/classfile/verifier.cpp
bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool should_verify_class, TRAPS) {
{- -------------------------------------------
(1) (HandleMark), (ResourceMark)
---------------------------------------- -}
HandleMark hm;
ResourceMark rm(THREAD);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Symbol* exception_name = NULL;
const size_t message_buffer_len = klass->name()->utf8_length() + 1024;
char* message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len);
const char* klassName = klass->external_name();
{- -------------------------------------------
(1) (コメントによると,
verify が必要な場合には, まず split verifier が使用できるかどうかを確認する.
使用できない場合や
verification が FailOverToOldVerifier で失敗した場合は,
inference verifier での verification を行う,
とのこと)
---------------------------------------- -}
// If the class should be verified, first see if we can use the split
// verifier. If not, or if verification fails and FailOverToOldVerifier
// is set, then call the inference verifier.
{- -------------------------------------------
(1) 以下の if ブロック内で verification 処理を行う.
(クラスファイルのバージョン及びコマンドラインオプションに応じて
type check verifier と type inference verifier のどちらかを使用)
ただし, verify が不要なクラスの場合には
(= Verifier::is_eligible_for_verification() が false の場合には)
この処理は行わない.
---------------------------------------- -}
if (is_eligible_for_verification(klass, should_verify_class)) {
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (TraceClassInitialization) {
tty->print_cr("Start class verification for: %s", klassName);
}
{- -------------------------------------------
(1.1) verification 処理を行う.
以下の条件がどちらも成り立つ場合は, type checking verifier を使用する.
そうでない場合は, type inference verifier を使用する.
* UseSplitVerifier オプションが指定されている
* クラスファイルのバージョンが 1.6 以降
(なお, type checking verifier で失敗した場合は,
FailOverToOldVerifier オプションが指定されていれば,
type inference verifier で再度検証する)
---------------------------------------- -}
{- -------------------------------------------
(1.1.1) (以下は type checking verifier を使用する場合)
---------------------------------------- -}
if (UseSplitVerifier &&
klass->major_version() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) {
{- -------------------------------------------
(1.1.1) (変数宣言など)
---------------------------------------- -}
ClassVerifier split_verifier(
klass, message_buffer, message_buffer_len, THREAD);
{- -------------------------------------------
(1.1.1) ClassVerifier::verify_class() を呼んで, verification を行う.
---------------------------------------- -}
split_verifier.verify_class(THREAD);
{- -------------------------------------------
(1.1.1) verification が失敗した場合,
以下の条件が全て成り立てば
Verifier::inference_verify() を呼んで
type inference による verification を行う.
* クラスファイルのバージョンが NOFAILOVER_MAJOR_VERSION 未満
(なお, 現状では値は 51 で固定.
type checking が使われるのはバージョン 50(JDK6) 以上なので, 対象となるのはバージョン50のみ)
* FailOverToOldVerifier オプションが指定されている.
*
---------------------------------------- -}
exception_name = split_verifier.result();
if (klass->major_version() < NOFAILOVER_MAJOR_VERSION &&
FailOverToOldVerifier && !HAS_PENDING_EXCEPTION &&
(exception_name == vmSymbols::java_lang_VerifyError() ||
exception_name == vmSymbols::java_lang_ClassFormatError())) {
if (TraceClassInitialization) {
tty->print_cr(
"Fail over class verification to old verifier for: %s", klassName);
}
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
}
{- -------------------------------------------
(1.1.1) (以下は type inference verifier を使用する場合)
---------------------------------------- -}
} else {
{- -------------------------------------------
(1.1.1) Verifier::inference_verify() を呼んで
type inference による verification を行う.
---------------------------------------- -}
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
}
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (TraceClassInitialization) {
if (HAS_PENDING_EXCEPTION) {
tty->print("Verification for %s has", klassName);
tty->print_cr(" exception pending %s ",
instanceKlass::cast(PENDING_EXCEPTION->klass())->external_name());
} else if (exception_name != NULL) {
tty->print_cr("Verification for %s failed", klassName);
}
tty->print_cr("End class verification for: %s", klassName);
}
}
{- -------------------------------------------
(1) 以下で, verification 結果に応じて結果をリターンする (あるいは例外を発生させる)
* 何らかの例外が発生している場合:
false をリターン (この場合は, 発生した例外がそのまま持ち上がる)
* verification 処理の返値が NULL だった場合 (= 検証が成功した場合)
true をリターン
* verification 処理の返値が 非NULL の場合 (= 投げるべき例外が返された場合)
指定された例外を投げる.
(ただし, 指定された例外のクラス(あるいはその祖先のクラスのどれか)が
検証対象のクラス自身だった場合, クラス階層がおかしいので,
その例外を投げると例外クラスの初期化で無限に再帰してしまって酷いことになる.
そのため, この場合には代わりに VirtualMachineError を投げる)
---------------------------------------- -}
if (HAS_PENDING_EXCEPTION) {
return false; // use the existing exception
} else if (exception_name == NULL) {
return true; // verifcation succeeded
} else { // VerifyError or ClassFormatError to be created and thrown
ResourceMark rm(THREAD);
instanceKlassHandle kls =
SystemDictionary::resolve_or_fail(exception_name, true, CHECK_false);
while (!kls.is_null()) {
if (kls == klass) {
// If the class being verified is the exception we're creating
// or one of it's superclasses, we're in trouble and are going
// to infinitely recurse when we try to initialize the exception.
// So bail out here by throwing the preallocated VM error.
THROW_OOP_(Universe::virtual_machine_error_instance(), false);
}
kls = kls->super();
}
message_buffer[message_buffer_len - 1] = '\0'; // just to be sure
THROW_MSG_(exception_name, message_buffer, false);
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.