hotspot/src/share/vm/classfile/classFileParser.cpp
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
Handle class_loader,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// So that JVMTI can cache class file in the state before retransformable agents
// have modified it
unsigned char *cached_class_file_bytes = NULL;
jint cached_class_file_length;
{- -------------------------------------------
(1) クラスファイルを読むための ClassFileStream を作成.
---------------------------------------- -}
ClassFileStream* cfs = stream();
{- -------------------------------------------
(1) PerfClassTraceTime のインスタンスを作成し, クラスローディングにかかった時間の計測を開始する
---------------------------------------- -}
// Timing
assert(THREAD->is_Java_thread(), "must be a JavaThread");
JavaThread* jt = (JavaThread*) THREAD;
PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(),
ClassLoader::perf_class_parse_selftime(),
NULL,
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::PARSE_CLASS);
{- -------------------------------------------
(1) (フィールドの初期化)
---------------------------------------- -}
_has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
_max_bootstrap_specifier_index = -1;
{- -------------------------------------------
(1) (JVMTI のフック点)
(なお, JVMTI agent によってクラスファイルの変更が行われた場合は, ClassFileStream をそちらに切り替える)
---------------------------------------- -}
if (JvmtiExport::should_post_class_file_load_hook()) {
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain,
&ptr, &end_ptr,
&cached_class_file_bytes,
&cached_class_file_length);
if (ptr != cfs->buffer()) {
// JVMTI agent has modified class file data.
// Set new class file stream using JVMTI agent modified
// class file data.
cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
set_stream(cfs);
}
}
{- -------------------------------------------
(1) (フィールドの初期化)
---------------------------------------- -}
_host_klass = host_klass;
_cp_patches = cp_patches;
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
instanceKlassHandle nullHandle;
{- -------------------------------------------
(1) 対象のクラスに対する verify が必要かどうかを確認しておく.
(デフォルトでは bootstrap class loader がロードしたものは verify は不要としている. -Xverify:all/none で設定を変更可能.)
---------------------------------------- -}
// Figure out whether we can skip format checking (matching classic VM behavior)
_need_verify = Verifier::should_verify_for(class_loader(), verify);
// Set the verify flag in stream
cfs->set_verify(_need_verify);
{- -------------------------------------------
(1) エラーメッセージの出力時に備えてクラス名を記憶しておく
---------------------------------------- -}
// Save the class file name for easier error message printing.
_class_name = (name != NULL) ? name : vmSymbols::unknown_class_name();
{- -------------------------------------------
(1) まず, magic number や version number を読み込み,
ClassFileParser::is_supported_version() で確認を行う.
(version number が合わなければ UnsupportedClassVersionError).
---------------------------------------- -}
cfs->guarantee_more(8, CHECK_(nullHandle)); // magic, major, minor
// Magic value
u4 magic = cfs->get_u4_fast();
guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
"Incompatible magic value %u in class file %s",
magic, CHECK_(nullHandle));
// Version numbers
u2 minor_version = cfs->get_u2_fast();
u2 major_version = cfs->get_u2_fast();
// Check version numbers - we check this even with verifier off
if (!is_supported_version(major_version, minor_version)) {
if (name == NULL) {
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_UnsupportedClassVersionError(),
"Unsupported major.minor version %u.%u",
major_version,
minor_version);
} else {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_UnsupportedClassVersionError(),
"%s : Unsupported major.minor version %u.%u",
name->as_C_string(),
major_version,
minor_version);
}
return nullHandle;
}
{- -------------------------------------------
(1) (フィールドの初期化)
(version number 番号情報を記録しておく)
---------------------------------------- -}
_major_version = major_version;
_minor_version = minor_version;
{- -------------------------------------------
(1) 「いくつかの broken な 1.1 API を 1.2 でも動かすために, verify を relaxed させるべきかどうか」を調べる
---------------------------------------- -}
// Check if verification needs to be relaxed for this class file
// Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
_relax_verify = Verifier::relax_verify_for(class_loader());
{- -------------------------------------------
(1) ClassFileParser::parse_constant_pool() を呼んで, コンスタントプール情報を読み込む.
---------------------------------------- -}
// Constant pool
constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up.
int cp_size = cp->length();
cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
{- -------------------------------------------
(1) 次に, access_flags の値を読み込む.
(<= Java 6 より前のバージョンでは, JVM_ACC_INTERFACE が立っているのに JVM_ACC_ABSTRACT が立っていなくてもいい??
古い Java 仮想マシン仕様でも立っていないと駄目だと書いているが... (#TODO))
---------------------------------------- -}
// Access flags
AccessFlags access_flags;
jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
}
verify_legal_class_modifiers(flags, CHECK_(nullHandle));
access_flags.set_flags(flags);
{- -------------------------------------------
(1) 次に, this_class を読み込み, 以下のようにチェックを行う.
---------------------------------------- -}
// This class and superclass
instanceKlassHandle super_klass;
u2 this_class_index = cfs->get_u2_fast();
{- -------------------------------------------
(1.1) this_class に入っていた index の値が, Constant Pool 内に収まっており,
unresolved な klass を指していることを確認.
---------------------------------------- -}
check_property(
valid_cp_range(this_class_index, cp_size) &&
cp->tag_at(this_class_index).is_unresolved_klass(),
"Invalid this class index %u in constant pool in class file %s",
this_class_index, CHECK_(nullHandle));
{- -------------------------------------------
(1.1) Constant Pool から this_class が指すクラス名を取得
(取得した Symbol は reference count を増加させて解放されないようにしておく)
---------------------------------------- -}
Symbol* class_name = cp->unresolved_klass_at(this_class_index);
assert(class_name != NULL, "class_name can't be null");
// It's important to set parsed_name *before* resolving the super class.
// (it's used for cleanup by the caller if parsing fails)
parsed_name = class_name;
// parsed_name is returned and can be used if there's an error, so add to
// its reference count. Caller will decrement the refcount.
parsed_name->increment_refcount();
{- -------------------------------------------
(1.1) 実際にクラスファイル中からクラス名が取得できたので, エラーメッセージ出力時用のクラス名を更新しておく.
(この時点までは NULL の可能性があった)
---------------------------------------- -}
// Update _class_name which could be null previously to be class_name
_class_name = class_name;
{- -------------------------------------------
(1.1) verify の必要があれば, this_class が array type になっていないことを確認.
---------------------------------------- -}
// Don't need to check whether this class name is legal or not.
// It has been checked when constant pool is parsed.
// However, make sure it is not an array type.
if (_need_verify) {
guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
"Bad class name in class file %s",
CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1) (変数宣言など)
(以下の block の末尾で, パース処理に使っていた handle は全て HandleMark によって回収されることになる.
ただし, this_klass に関する handle は返り値として返す必要があるので,
HandleMark 外で宣言した preserve_this_klass に退避させて HandleMark に回収されないようにしている.)
---------------------------------------- -}
klassOop preserve_this_klass; // for storing result across HandleMark
// release all handles when parsing is done
{ HandleMark hm(THREAD);
{- -------------------------------------------
(1.1) もし, this_class のクラス名が null だったり要求されていたクラス名と違っていたら
NoClassDefFoundError を投げて, ここでリターン.
---------------------------------------- -}
// Checks if name in class file matches requested name
if (name != NULL && class_name != name) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"%s (wrong name: %s)",
name->as_C_string(),
class_name->as_C_string()
);
return nullHandle;
}
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (TraceClassLoadingPreorder) {
tty->print("[Loading %s", name->as_klass_external_name());
if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
tty->print_cr("]");
}
{- -------------------------------------------
(1) 次に, super_class を読み込み, 以下のようにチェックを行う.
---------------------------------------- -}
u2 super_class_index = cfs->get_u2_fast();
{- -------------------------------------------
(1.1) super_class_index が 0 だった場合は, java_lang_Object かどうかを確認.
---------------------------------------- -}
if (super_class_index == 0) {
check_property(class_name == vmSymbols::java_lang_Object(),
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
{- -------------------------------------------
(1.1) super_class_index が 0 でなければ, その index 値が Constant Pool 内に収まっており,
class を指していること, また array ではないことを確認.
---------------------------------------- -}
} else {
check_property(valid_cp_range(super_class_index, cp_size) &&
is_klass_reference(cp, super_class_index),
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
bool is_array = false;
if (cp->tag_at(super_class_index).is_klass()) {
super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index));
if (_need_verify)
is_array = super_klass->oop_is_array();
} else if (_need_verify) {
is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
}
if (_need_verify) {
guarantee_property(!is_array,
"Bad superclass name in class file %s", CHECK_(nullHandle));
}
}
{- -------------------------------------------
(1) 次に, 実装しているインターフェースの情報を以下のように読み込む (インターフェースの個数, 及び実際のインターフェース情報).
---------------------------------------- -}
// Interfaces
{- -------------------------------------------
(1.1) まず, 実装したインターフェースの個数を読み込む.
---------------------------------------- -}
u2 itfs_len = cfs->get_u2_fast();
{- -------------------------------------------
(1.1) 次に, ClassFileParser::parse_interfaces() で
インターフェース情報(constant pool への index の配列)の読み込みと確認を行う.
(なお, 読み込んだ結果は objArrayOop として保持する)
---------------------------------------- -}
objArrayHandle local_interfaces;
if (itfs_len == 0) {
local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array());
} else {
local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, _class_name, CHECK_(nullHandle));
}
{- -------------------------------------------
(1) 次に, フィールドの情報を読み込む (フィールドの個数, 及び実際のフィールド情報).
(なお, ここで各フィールドに付属するアトリビュート情報も読み込む).
---------------------------------------- -}
// Fields (offsets are filled in later)
struct FieldAllocationCount fac = {0,0,0,0,0,0,0,0,0,0};
objArrayHandle fields_annotations;
typeArrayHandle fields = parse_fields(cp, access_flags.is_interface(), &fac, &fields_annotations, CHECK_(nullHandle));
{- -------------------------------------------
(1) 次に, メソッドの情報を読み込む (メソッドの個数, 及び実際のメソッド情報).
(なお, ここで各メソッドに付属するアトリビュート情報も読み込む).
---------------------------------------- -}
// Methods
bool has_final_method = false;
AccessFlags promoted_flags;
promoted_flags.set_flags(0);
// These need to be oop pointers because they are allocated lazily
// inside parse_methods inside a nested HandleMark
objArrayOop methods_annotations_oop = NULL;
objArrayOop methods_parameter_annotations_oop = NULL;
objArrayOop methods_default_annotations_oop = NULL;
objArrayHandle methods = parse_methods(cp, access_flags.is_interface(),
&promoted_flags,
&has_final_method,
&methods_annotations_oop,
&methods_parameter_annotations_oop,
&methods_default_annotations_oop,
CHECK_(nullHandle));
objArrayHandle methods_annotations(THREAD, methods_annotations_oop);
objArrayHandle methods_parameter_annotations(THREAD, methods_parameter_annotations_oop);
objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);
{- -------------------------------------------
(1) (この段階までで, クラスファイルの中を(ほぼ)全てパースし終わり, フォーマットチェックも完了)
---------------------------------------- -}
{- -------------------------------------------
(1) 次に, スーパークラスのチェックを以下のように行う.
---------------------------------------- -}
// We check super class after class file is parsed and format is checked
{- -------------------------------------------
(1.1) もしスーパークラスが存在し(= java/lang/Objectではなく), かつまだロードされてなければ,
SystemDictionary::resolve_super_or_fail() でロードする.
(ただし, パース対象のクラスがインターフェースの場合は
スーパークラスは java/lang/Object でなければいけないので,
その場合はここでエラーを出す)
---------------------------------------- -}
if (super_class_index > 0 && super_klass.is_null()) {
Symbol* sk = cp->klass_name_at(super_class_index);
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
// errors not checked yet.
guarantee_property(sk == vmSymbols::java_lang_Object(),
"Interfaces must have java.lang.Object as superclass in class file %s",
CHECK_(nullHandle));
}
klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
sk,
class_loader,
protection_domain,
true,
CHECK_(nullHandle));
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
{- -------------------------------------------
(1.1) ??
---------------------------------------- -}
if (LinkWellKnownClasses) // my super class is well known to me
cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve
}
{- -------------------------------------------
(1.1) super_klass が null でない(= java/lang/Object ではない?) 場合は,
super_klass がインターフェースではなく, final クラスでもないことを確認.
(もしインターフェースであれば IncompatibleClassChangeError, final クラスであれば VerifyError を出す)
---------------------------------------- -}
if (super_klass.not_null()) {
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"class %s has interface %s as super class",
class_name->as_klass_external_name(),
super_klass->external_name()
);
return nullHandle;
}
// Make sure super class is not final
if (super_klass->is_final()) {
THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle);
}
}
{- -------------------------------------------
(1) 実装しているインターフェースの推移的平方の数を計算し, その数にあった objArrayHandle を作成する.
---------------------------------------- -}
// Compute the transitive list of all unique interfaces implemented by this class
objArrayHandle transitive_interfaces = compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));
{- -------------------------------------------
(1) 全メソッドを名前順でソートし, vtable 中での index を割り振る.
---------------------------------------- -}
// sort methods
typeArrayHandle method_ordering = sort_methods(methods,
methods_annotations,
methods_parameter_annotations,
methods_default_annotations,
CHECK_(nullHandle));
{- -------------------------------------------
(1) ClassFileParser::parse_methods() の処理中で発見した「クラスのフラグに追加した方がいいフラグ」を access_flags に追加する.
---------------------------------------- -}
// promote flags from parse_methods() to the klass' flags
access_flags.add_promoted_flags(promoted_flags.as_int());
{- -------------------------------------------
(1) vtable, itable の大きさと miranda method の個数を計算する.
---------------------------------------- -}
// Size of Java vtable (in words)
int vtable_size = 0;
int itable_size = 0;
int num_miranda_methods = 0;
klassVtable::compute_vtable_size_and_num_mirandas(vtable_size,
num_miranda_methods,
super_klass(),
methods(),
access_flags,
class_loader,
class_name,
local_interfaces(),
CHECK_(nullHandle));
// Size of Java itable (in words)
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);
{- -------------------------------------------
(1) 各フィールドについて, オブジェクト内でのオフセットを決める. (#TODO)
型が同じものごとにまとめて配置している模様. まとめ方は FieldsAllocationStyle 等により変更できる模様 (#TODO)
(なお, ClassFileParser::parse_fields() に渡しておいた FieldAllocationCount 型の引数("fac")より, 各型のフィールド数は分かっている)
---------------------------------------- -}
// Field size and offset computation
int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size();
#ifndef PRODUCT
int orig_nonstatic_field_size = 0;
#endif
int static_field_size = 0;
int next_static_oop_offset;
int next_static_double_offset;
int next_static_word_offset;
int next_static_short_offset;
int next_static_byte_offset;
int next_static_type_offset;
int next_nonstatic_oop_offset;
int next_nonstatic_double_offset;
int next_nonstatic_word_offset;
int next_nonstatic_short_offset;
int next_nonstatic_byte_offset;
int next_nonstatic_type_offset;
int first_nonstatic_oop_offset;
int first_nonstatic_field_offset;
int next_nonstatic_field_offset;
// Calculate the starting byte offsets
next_static_oop_offset = instanceMirrorKlass::offset_of_static_fields();
next_static_double_offset = next_static_oop_offset +
(fac.static_oop_count * heapOopSize);
if ( fac.static_double_count &&
(Universe::field_type_should_be_aligned(T_DOUBLE) ||
Universe::field_type_should_be_aligned(T_LONG)) ) {
next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong);
}
next_static_word_offset = next_static_double_offset +
(fac.static_double_count * BytesPerLong);
next_static_short_offset = next_static_word_offset +
(fac.static_word_count * BytesPerInt);
next_static_byte_offset = next_static_short_offset +
(fac.static_short_count * BytesPerShort);
next_static_type_offset = align_size_up((next_static_byte_offset +
fac.static_byte_count ), wordSize );
static_field_size = (next_static_type_offset -
next_static_oop_offset) / wordSize;
// Add fake fields for java.lang.Class instances (also see below)
if (class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) {
java_lang_Class_fix_pre(&nonstatic_field_size, &fac);
}
first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() +
nonstatic_field_size * heapOopSize;
next_nonstatic_field_offset = first_nonstatic_field_offset;
// adjust the vmentry field declaration in java.lang.invoke.MethodHandle
if (EnableInvokeDynamic && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) {
java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
}
// Add a fake "discovered" field if it is not present
// for compatibility with earlier jdk's.
if (class_name == vmSymbols::java_lang_ref_Reference()
&& class_loader.is_null()) {
java_lang_ref_Reference_fix_pre(&fields, cp, &fac, CHECK_(nullHandle));
}
// end of "discovered" field compactibility fix
unsigned int nonstatic_double_count = fac.nonstatic_double_count;
unsigned int nonstatic_word_count = fac.nonstatic_word_count;
unsigned int nonstatic_short_count = fac.nonstatic_short_count;
unsigned int nonstatic_byte_count = fac.nonstatic_byte_count;
unsigned int nonstatic_oop_count = fac.nonstatic_oop_count;
bool super_has_nonstatic_fields =
(super_klass() != NULL && super_klass->has_nonstatic_fields());
bool has_nonstatic_fields = super_has_nonstatic_fields ||
((nonstatic_double_count + nonstatic_word_count +
nonstatic_short_count + nonstatic_byte_count +
nonstatic_oop_count) != 0);
// Prepare list of oops for oop map generation.
int* nonstatic_oop_offsets;
unsigned int* nonstatic_oop_counts;
unsigned int nonstatic_oop_map_count = 0;
nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, int, nonstatic_oop_count + 1);
nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, unsigned int, nonstatic_oop_count + 1);
// Add fake fields for java.lang.Class instances (also see above).
// FieldsAllocationStyle and CompactFields values will be reset to default.
if(class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) {
java_lang_Class_fix_post(&next_nonstatic_field_offset);
nonstatic_oop_offsets[0] = first_nonstatic_field_offset;
const uint fake_oop_count = (next_nonstatic_field_offset -
first_nonstatic_field_offset) / heapOopSize;
nonstatic_oop_counts[0] = fake_oop_count;
nonstatic_oop_map_count = 1;
nonstatic_oop_count -= fake_oop_count;
first_nonstatic_oop_offset = first_nonstatic_field_offset;
} else {
first_nonstatic_oop_offset = 0; // will be set for first oop field
}
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
next_nonstatic_double_offset = next_nonstatic_field_offset +
(nonstatic_oop_count * heapOopSize);
if ( nonstatic_double_count > 0 ) {
next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong);
}
next_nonstatic_word_offset = next_nonstatic_double_offset +
(nonstatic_double_count * BytesPerLong);
next_nonstatic_short_offset = next_nonstatic_word_offset +
(nonstatic_word_count * BytesPerInt);
next_nonstatic_byte_offset = next_nonstatic_short_offset +
(nonstatic_short_count * BytesPerShort);
next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset +
nonstatic_byte_count ), heapOopSize );
orig_nonstatic_field_size = nonstatic_field_size +
((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize);
}
#endif
bool compact_fields = CompactFields;
int allocation_style = FieldsAllocationStyle;
if( allocation_style < 0 || allocation_style > 2 ) { // Out of range?
assert(false, "0 <= FieldsAllocationStyle <= 2");
allocation_style = 1; // Optimistic
}
// The next classes have predefined hard-coded fields offsets
// (see in JavaClasses::compute_hard_coded_offsets()).
// Use default fields allocation order for them.
if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() &&
(class_name == vmSymbols::java_lang_AssertionStatusDirectives() ||
class_name == vmSymbols::java_lang_Class() ||
class_name == vmSymbols::java_lang_ClassLoader() ||
class_name == vmSymbols::java_lang_ref_Reference() ||
class_name == vmSymbols::java_lang_ref_SoftReference() ||
class_name == vmSymbols::java_lang_StackTraceElement() ||
class_name == vmSymbols::java_lang_String() ||
class_name == vmSymbols::java_lang_Throwable() ||
class_name == vmSymbols::java_lang_Boolean() ||
class_name == vmSymbols::java_lang_Character() ||
class_name == vmSymbols::java_lang_Float() ||
class_name == vmSymbols::java_lang_Double() ||
class_name == vmSymbols::java_lang_Byte() ||
class_name == vmSymbols::java_lang_Short() ||
class_name == vmSymbols::java_lang_Integer() ||
class_name == vmSymbols::java_lang_Long())) {
allocation_style = 0; // Allocate oops first
compact_fields = false; // Don't compact fields
}
if( allocation_style == 0 ) {
// Fields order: oops, longs/doubles, ints, shorts/chars, bytes
next_nonstatic_oop_offset = next_nonstatic_field_offset;
next_nonstatic_double_offset = next_nonstatic_oop_offset +
(nonstatic_oop_count * heapOopSize);
} else if( allocation_style == 1 ) {
// Fields order: longs/doubles, ints, shorts/chars, bytes, oops
next_nonstatic_double_offset = next_nonstatic_field_offset;
} else if( allocation_style == 2 ) {
// Fields allocation: oops fields in super and sub classes are together.
if( nonstatic_field_size > 0 && super_klass() != NULL &&
super_klass->nonstatic_oop_map_size() > 0 ) {
int map_size = super_klass->nonstatic_oop_map_size();
OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps();
OopMapBlock* last_map = first_map + map_size - 1;
int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
if (next_offset == next_nonstatic_field_offset) {
allocation_style = 0; // allocate oops first
next_nonstatic_oop_offset = next_nonstatic_field_offset;
next_nonstatic_double_offset = next_nonstatic_oop_offset +
(nonstatic_oop_count * heapOopSize);
}
}
if( allocation_style == 2 ) {
allocation_style = 1; // allocate oops last
next_nonstatic_double_offset = next_nonstatic_field_offset;
}
} else {
ShouldNotReachHere();
}
int nonstatic_oop_space_count = 0;
int nonstatic_word_space_count = 0;
int nonstatic_short_space_count = 0;
int nonstatic_byte_space_count = 0;
int nonstatic_oop_space_offset;
int nonstatic_word_space_offset;
int nonstatic_short_space_offset;
int nonstatic_byte_space_offset;
if( nonstatic_double_count > 0 ) {
int offset = next_nonstatic_double_offset;
next_nonstatic_double_offset = align_size_up(offset, BytesPerLong);
if( compact_fields && offset != next_nonstatic_double_offset ) {
// Allocate available fields into the gap before double field.
int length = next_nonstatic_double_offset - offset;
assert(length == BytesPerInt, "");
nonstatic_word_space_offset = offset;
if( nonstatic_word_count > 0 ) {
nonstatic_word_count -= 1;
nonstatic_word_space_count = 1; // Only one will fit
length -= BytesPerInt;
offset += BytesPerInt;
}
nonstatic_short_space_offset = offset;
while( length >= BytesPerShort && nonstatic_short_count > 0 ) {
nonstatic_short_count -= 1;
nonstatic_short_space_count += 1;
length -= BytesPerShort;
offset += BytesPerShort;
}
nonstatic_byte_space_offset = offset;
while( length > 0 && nonstatic_byte_count > 0 ) {
nonstatic_byte_count -= 1;
nonstatic_byte_space_count += 1;
length -= 1;
}
// Allocate oop field in the gap if there are no other fields for that.
nonstatic_oop_space_offset = offset;
if( length >= heapOopSize && nonstatic_oop_count > 0 &&
allocation_style != 0 ) { // when oop fields not first
nonstatic_oop_count -= 1;
nonstatic_oop_space_count = 1; // Only one will fit
length -= heapOopSize;
offset += heapOopSize;
}
}
}
next_nonstatic_word_offset = next_nonstatic_double_offset +
(nonstatic_double_count * BytesPerLong);
next_nonstatic_short_offset = next_nonstatic_word_offset +
(nonstatic_word_count * BytesPerInt);
next_nonstatic_byte_offset = next_nonstatic_short_offset +
(nonstatic_short_count * BytesPerShort);
int notaligned_offset;
if( allocation_style == 0 ) {
notaligned_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
} else { // allocation_style == 1
next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
if( nonstatic_oop_count > 0 ) {
next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize);
}
notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
}
next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize );
nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset
- first_nonstatic_field_offset)/heapOopSize);
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
// oop fields are located before non-oop fields (static and non-static).
int len = fields->length();
for (int i = 0; i < len; i += instanceKlass::next_offset) {
int real_offset;
FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset);
switch (atype) {
case STATIC_OOP:
real_offset = next_static_oop_offset;
next_static_oop_offset += heapOopSize;
break;
case STATIC_BYTE:
real_offset = next_static_byte_offset;
next_static_byte_offset += 1;
break;
case STATIC_SHORT:
real_offset = next_static_short_offset;
next_static_short_offset += BytesPerShort;
break;
case STATIC_WORD:
real_offset = next_static_word_offset;
next_static_word_offset += BytesPerInt;
break;
case STATIC_ALIGNED_DOUBLE:
case STATIC_DOUBLE:
real_offset = next_static_double_offset;
next_static_double_offset += BytesPerLong;
break;
case NONSTATIC_OOP:
if( nonstatic_oop_space_count > 0 ) {
real_offset = nonstatic_oop_space_offset;
nonstatic_oop_space_offset += heapOopSize;
nonstatic_oop_space_count -= 1;
} else {
real_offset = next_nonstatic_oop_offset;
next_nonstatic_oop_offset += heapOopSize;
}
// Update oop maps
if( nonstatic_oop_map_count > 0 &&
nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
real_offset -
int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
heapOopSize ) {
// Extend current oop map
nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
} else {
// Create new oop map
nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
nonstatic_oop_map_count += 1;
if( first_nonstatic_oop_offset == 0 ) { // Undefined
first_nonstatic_oop_offset = real_offset;
}
}
break;
case NONSTATIC_BYTE:
if( nonstatic_byte_space_count > 0 ) {
real_offset = nonstatic_byte_space_offset;
nonstatic_byte_space_offset += 1;
nonstatic_byte_space_count -= 1;
} else {
real_offset = next_nonstatic_byte_offset;
next_nonstatic_byte_offset += 1;
}
break;
case NONSTATIC_SHORT:
if( nonstatic_short_space_count > 0 ) {
real_offset = nonstatic_short_space_offset;
nonstatic_short_space_offset += BytesPerShort;
nonstatic_short_space_count -= 1;
} else {
real_offset = next_nonstatic_short_offset;
next_nonstatic_short_offset += BytesPerShort;
}
break;
case NONSTATIC_WORD:
if( nonstatic_word_space_count > 0 ) {
real_offset = nonstatic_word_space_offset;
nonstatic_word_space_offset += BytesPerInt;
nonstatic_word_space_count -= 1;
} else {
real_offset = next_nonstatic_word_offset;
next_nonstatic_word_offset += BytesPerInt;
}
break;
case NONSTATIC_ALIGNED_DOUBLE:
case NONSTATIC_DOUBLE:
real_offset = next_nonstatic_double_offset;
next_nonstatic_double_offset += BytesPerLong;
break;
default:
ShouldNotReachHere();
}
fields->short_at_put(i + instanceKlass::low_offset, extract_low_short_from_int(real_offset));
fields->short_at_put(i + instanceKlass::high_offset, extract_high_short_from_int(real_offset));
}
// Size of instances
int instance_size;
next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize );
instance_size = align_object_size(next_nonstatic_type_offset / wordSize);
assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value");
{- -------------------------------------------
(1) oopmap の大きさ(= OopMapBlock オブジェクトが占める大きさ)を計算する.
---------------------------------------- -}
// Number of non-static oop map blocks allocated at end of klass.
const unsigned int total_oop_map_count =
compute_oop_map_count(super_klass, nonstatic_oop_map_count,
first_nonstatic_oop_offset);
{- -------------------------------------------
(1) reference type かどうか (= java.lang.ref.Reference クラスのサブクラスかどうか) を調べる
---------------------------------------- -}
// Compute reference type
ReferenceType rt;
if (super_klass() == NULL) {
rt = REF_NONE;
} else {
rt = super_klass->reference_type();
}
{- -------------------------------------------
(1) パース結果を格納するための klassOop を確保する.
---------------------------------------- -}
// We can now create the basic klassOop for this klass
klassOop ik = oopFactory::new_instanceKlass(name, vtable_size, itable_size,
static_field_size,
total_oop_map_count,
rt, CHECK_(nullHandle));
instanceKlassHandle this_klass (THREAD, ik);
{- -------------------------------------------
(1) (assert 処理)
---------------------------------------- -}
assert(this_klass->static_field_size() == static_field_size, "sanity");
assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count,
"sanity");
{- -------------------------------------------
(1) 確保した klassOop 内にパース結果の情報を書き込んでいく.
(処理途中に, ClassFileParser::parse_classfile_attributes() による
クラスファイルのアトリビュートのパース処理が入っている模様.
処理はフィールドやメソッドのアトリビュートのパースとほぼ同様)
(また, oopmap 領域への書き込みは ClassFileParser::fill_oop_maps() で行われている)
---------------------------------------- -}
// Fill in information already parsed
this_klass->set_access_flags(access_flags);
this_klass->set_should_verify_class(verify);
jint lh = Klass::instance_layout_helper(instance_size, false);
this_klass->set_layout_helper(lh);
assert(this_klass->oop_is_instance(), "layout is correct");
assert(this_klass->size_helper() == instance_size, "correct size_helper");
// Not yet: supers are done below to support the new subtype-checking fields
//this_klass->set_super(super_klass());
this_klass->set_class_loader(class_loader());
this_klass->set_nonstatic_field_size(nonstatic_field_size);
this_klass->set_has_nonstatic_fields(has_nonstatic_fields);
this_klass->set_static_oop_field_count(fac.static_oop_count);
cp->set_pool_holder(this_klass());
error_handler.set_in_error(false); // turn off error handler for cp
this_klass->set_constants(cp());
this_klass->set_local_interfaces(local_interfaces());
this_klass->set_fields(fields());
this_klass->set_methods(methods());
if (has_final_method) {
this_klass->set_has_final_method();
}
this_klass->set_method_ordering(method_ordering());
// The instanceKlass::_methods_jmethod_ids cache and the
// instanceKlass::_methods_cached_itable_indices cache are
// both managed on the assumption that the initial cache
// size is equal to the number of methods in the class. If
// that changes, then instanceKlass::idnum_can_increment()
// has to be changed accordingly.
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
if (LinkWellKnownClasses || is_anonymous()) // I am well known to myself
cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
this_klass->set_protection_domain(protection_domain());
this_klass->set_fields_annotations(fields_annotations());
this_klass->set_methods_annotations(methods_annotations());
this_klass->set_methods_parameter_annotations(methods_parameter_annotations());
this_klass->set_methods_default_annotations(methods_default_annotations());
this_klass->set_minor_version(minor_version);
this_klass->set_major_version(major_version);
// Set up methodOop::intrinsic_id as soon as we know the names of methods.
// (We used to do this lazily, but now we query it in Rewriter,
// which is eagerly done for every method, so we might as well do it now,
// when everything is fresh in memory.)
if (methodOopDesc::klass_id_for_intrinsics(this_klass->as_klassOop()) != vmSymbols::NO_SID) {
for (int j = 0; j < methods->length(); j++) {
((methodOop)methods->obj_at(j))->init_intrinsic_id();
}
}
if (cached_class_file_bytes != NULL) {
// JVMTI: we have an instanceKlass now, tell it about the cached bytes
this_klass->set_cached_class_file(cached_class_file_bytes,
cached_class_file_length);
}
// Miranda methods
if ((num_miranda_methods > 0) ||
// if this class introduced new miranda methods or
(super_klass.not_null() && (super_klass->has_miranda_methods()))
// super class exists and this class inherited miranda methods
) {
this_klass->set_has_miranda_methods(); // then set a flag
}
// Additional attributes
parse_classfile_attributes(cp, this_klass, CHECK_(nullHandle));
// Make sure this is the end of class file stream
guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
// VerifyOops believes that once this has been set, the object is completely loaded.
// Compute transitive closure of interfaces this class implements
this_klass->set_transitive_interfaces(transitive_interfaces());
// Fill in information needed to compute superclasses.
this_klass->initialize_supers(super_klass(), CHECK_(nullHandle));
// Initialize itable offset tables
klassItable::setup_itable_offset_table(this_klass);
// Do final class setup
fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts);
set_precomputed_flags(this_klass);
// reinitialize modifiers, using the InnerClasses attribute
int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
this_klass->set_modifier_flags(computed_modifiers);
{- -------------------------------------------
(1) 正しいクラスになっていることをチェックする.
---------------------------------------- -}
// check if this class can access its super class
check_super_class_access(this_klass, CHECK_(nullHandle));
// check if this class can access its superinterfaces
check_super_interface_access(this_klass, CHECK_(nullHandle));
// check if this class overrides any final method
check_final_method_override(this_klass, CHECK_(nullHandle));
// check that if this class is an interface then it doesn't have static methods
if (this_klass->is_interface()) {
check_illegal_static_method(this_klass, CHECK_(nullHandle));
}
{- -------------------------------------------
(1) java_lang_Class::create_mirror() を呼んで mirror を生成する.
---------------------------------------- -}
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle));
{- -------------------------------------------
(1) (JMM のフック点)
(DTrace のフック点)にもなっているが... (See: ClassLoadingService::notify_class_loaded())
---------------------------------------- -}
ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()),
false /* not shared class */);
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (TraceClassLoading) {
// print in a single call to reduce interleaving of output
if (cfs->source() != NULL) {
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
cfs->source());
} else if (class_loader.is_null()) {
if (THREAD->is_Java_thread()) {
klassOop caller = ((JavaThread*)THREAD)->security_get_caller_class(1);
tty->print("[Loaded %s by instance of %s]\n",
this_klass->external_name(),
instanceKlass::cast(caller)->external_name());
} else {
tty->print("[Loaded %s]\n", this_klass->external_name());
}
} else {
ResourceMark rm;
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
instanceKlass::cast(class_loader->klass())->external_name());
}
}
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (TraceClassResolution) {
// print out the superclass.
const char * from = Klass::cast(this_klass())->external_name();
if (this_klass->java_super() != NULL) {
tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name());
}
// print out each of the interface classes referred to by this class.
objArrayHandle local_interfaces(THREAD, this_klass->local_interfaces());
if (!local_interfaces.is_null()) {
int length = local_interfaces->length();
for (int i = 0; i < length; i++) {
klassOop k = klassOop(local_interfaces->obj_at(i));
instanceKlass* to_class = instanceKlass::cast(k);
const char * to = to_class->external_name();
tty->print("RESOLVE %s %s (interface)\n", from, to);
}
}
}
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
if( nonstatic_field_size < orig_nonstatic_field_size ) {
tty->print("[Saved %d of %d bytes in %s]\n",
(orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize,
orig_nonstatic_field_size*heapOopSize,
this_klass->external_name());
} else if( nonstatic_field_size > orig_nonstatic_field_size ) {
tty->print("[Wasted %d over %d bytes in %s]\n",
(nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize,
orig_nonstatic_field_size*heapOopSize,
this_klass->external_name());
}
}
#endif
{- -------------------------------------------
(1) パース結果である this_klass Handle の中身を HandleMark 外に待避.
---------------------------------------- -}
// preserve result across HandleMark
preserve_this_klass = this_klass();
}
{- -------------------------------------------
(1) パース結果を再度 Handle に包み直して, 呼び出し元にリターン.
---------------------------------------- -}
// Create new handle outside HandleMark
instanceKlassHandle this_klass (THREAD, preserve_this_klass);
debug_only(this_klass->as_klassOop()->verify();)
return this_klass;
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.