hotspot/src/share/vm/classfile/classFileParser.cpp
コメントによると, フットプリント削減のために methodOop 内にデータを詰め込んだ(データ構造をinline化した)(?)ため, method に関する情報を全部パースしないと methodOop のサイズが確定しない. そのため, ClassFileParser::parse_method() の処理も, メソッドに関する全ての部分の処理が全部入ってきていて「かなり見づらい」(big and clunky), とのこと.
(<= 関数でまとめるとかはできないもんだろうか. 難しいと書いてはあるが理由がいまいちわからない... #TODO)
なお, 結果は (返り値「だけ」ではなく) 引数で渡されたポインタにも書き込まれて返される.(#TODO) それぞれの引数に書き込まれる値は以下の通り.
AccessFlags *promoted_flags
method の flag のうち, class の flag にも影響するものが書き込まれる (最終的には class の flag にこれが足し込まれる)
typeArrayHandle* method_annotations
method の annotation 情報 (のうちの... #TODO)
typeArrayHandle* method_parameter_annotations
method の annotation 情報 (のうちの... #TODO)
typeArrayHandle* method_default_annotations
method の annotation 情報 (のうちの... #TODO)
#define MAX_ARGS_SIZE 255
#define MAX_CODE_SIZE 65535
#define INITIAL_MAX_LVT_NUMBER 256
// Note: the parse_method below is big and clunky because all parsing of the code and exceptions
// attribute is inlined. This is curbersome to avoid since we inline most of the parts in the
// methodOop to save footprint, so we only know the size of the resulting methodOop when the
// entire method attribute is parsed.
//
// The promoted_flags parameter is used to pass relevant access_flags
// from the method back up to the containing klass. These flag values
// are added to klass's access_flags.
methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interface,
AccessFlags *promoted_flags,
typeArrayHandle* method_annotations,
typeArrayHandle* method_parameter_annotations,
typeArrayHandle* method_default_annotations,
TRAPS) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
ClassFileStream* cfs = stream();
methodHandle nullHandle;
ResourceMark rm(THREAD);
{- -------------------------------------------
(1) まず, method_info 中の固定長のヘッダ部分を読み込み, 以下のように値の確認を行う
(access_flags, name_index, descriptor_index, attributes_count).
---------------------------------------- -}
// Parse fixed parts
cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count
{- -------------------------------------------
(1.1) flags (JVMS では access_flags) を読み込む
---------------------------------------- -}
int flags = cfs->get_u2_fast();
{- -------------------------------------------
(1.1) name_index を読み込み, その index 値が Constant Pool 内に収まっており,
utf8_info を指していることを確認する.
また, ClassFileParser::verify_legal_method_name() で
メソッド名として妥当な utf8 文字列かどうかも確認する.
---------------------------------------- -}
u2 name_index = cfs->get_u2_fast();
int cp_size = cp->length();
check_property(
valid_cp_range(name_index, cp_size) &&
cp->tag_at(name_index).is_utf8(),
"Illegal constant pool index %u for method name in class file %s",
name_index, CHECK_(nullHandle));
Symbol* name = cp->symbol_at(name_index);
verify_legal_method_name(name, CHECK_(nullHandle));
{- -------------------------------------------
(1.1) signature_index (JVMS では descriptor_index) を読み込み,
その index 値が Constant Pool 内に収まっており, utf8_info を指していることを確認する.
---------------------------------------- -}
u2 signature_index = cfs->get_u2_fast();
guarantee_property(
valid_cp_range(signature_index, cp_size) &&
cp->tag_at(signature_index).is_utf8(),
"Illegal constant pool index %u for method signature in class file %s",
signature_index, CHECK_(nullHandle));
Symbol* signature = cp->symbol_at(signature_index);
{- -------------------------------------------
(1.1) access_flags については, JVMS 4.6 に従い, <clinit> であれば無視している.
("Class and interface initialization methods (§2.9) are called
implicitly by the Java virtual machine. The value of their
access_flags item is ignored except for the setting of the ACC_STRICT flag.")
<clinit> でなければ, ClassFileParser::verify_legal_method_modifiers() で
おかしな設定ではないかどうか確認する.
---------------------------------------- -}
AccessFlags access_flags;
if (name == vmSymbols::class_initializer_name()) {
// We ignore the other access flags for a valid class initializer.
// (JVM Spec 2nd ed., chapter 4.6)
if (_major_version < 51) { // backward compatibility
flags = JVM_ACC_STATIC;
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
}
} else {
verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1) (_need_verify が立っていれば, signature_index が指す先の文字列について
ClassFileParser::verify_legal_method_signature() で
メソッドの型情報(メソッド・ディスクリプタ)として妥当な utf8 文字列かどうかも確認する.
また, メソッドの引数が 255 個(MAX_ARGS_SIZE)以下かどうかを確認する.)
---------------------------------------- -}
int args_size = -1; // only used when _need_verify is true
if (_need_verify) {
args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) +
verify_legal_method_signature(name, signature, CHECK_(nullHandle));
if (args_size > MAX_ARGS_SIZE) {
classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle));
}
}
access_flags.set_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);
{- -------------------------------------------
(1) (以下は メソッドの attributes 情報の読み込み処理.
フィールドのパース処理と違って, この処理が別関数ではなく ClassFileParser::parse_method() 内部に展開されており, 読みづらい)
---------------------------------------- -}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Default values for code and exceptions attribute elements
u2 max_stack = 0;
u2 max_locals = 0;
u4 code_length = 0;
u1* code_start = 0;
u2 exception_table_length = 0;
typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
u2 checked_exceptions_length = 0;
u2* checked_exceptions_start = NULL;
CompressedLineNumberWriteStream* linenumber_table = NULL;
int linenumber_table_length = 0;
int total_lvt_length = 0;
u2 lvt_cnt = 0;
u2 lvtt_cnt = 0;
bool lvt_allocated = false;
u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER;
u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER;
u2* localvariable_table_length;
u2** localvariable_table_start;
u2* localvariable_type_table_length;
u2** localvariable_type_table_start;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
// stackmap attribute - JDK1.5
typeArrayHandle stackmap_data;
u2 generic_signature_index = 0;
u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
u1* runtime_visible_parameter_annotations = NULL;
int runtime_visible_parameter_annotations_length = 0;
u1* runtime_invisible_parameter_annotations = NULL;
int runtime_invisible_parameter_annotations_length = 0;
u1* annotation_default = NULL;
int annotation_default_length = 0;
{- -------------------------------------------
(1) attribute の個数分だけループし, 以下のように値の読み込み処理を行う.
---------------------------------------- -}
// Parse code and exceptions attribute
u2 method_attributes_count = cfs->get_u2_fast();
while (method_attributes_count--) {
{- -------------------------------------------
(1.1) attribute_name_index と attribute_length を読み込む.
attribute_name_index については, その index 値が Constant Pool 内に収まっており,
utf8_info を指していることを確認する.
---------------------------------------- -}
cfs->guarantee_more(6, CHECK_(nullHandle)); // method_attribute_name_index, method_attribute_length
u2 method_attribute_name_index = cfs->get_u2_fast();
u4 method_attribute_length = cfs->get_u4_fast();
check_property(
valid_cp_range(method_attribute_name_index, cp_size) &&
cp->tag_at(method_attribute_name_index).is_utf8(),
"Invalid method attribute name index %u in class file %s",
method_attribute_name_index, CHECK_(nullHandle));
Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index);
{- -------------------------------------------
(1.1) 以下, 読み込んだ attribute_name に応じて, 適切に読み込み処理&内容の確認処理を行う.
---------------------------------------- -}
if (method_attribute_name == vmSymbols::tag_code()) {
{- -------------------------------------------
(1.1) * Code attribute の場合, (処理が長いので, このケースだけ小分けにして説明)
---------------------------------------- -}
// Parse Code attribute
{- -------------------------------------------
(1.1.1) * (_need_verify が立っていれば), access_flags 中の native や abstract が立っていないことを確認
---------------------------------------- -}
if (_need_verify) {
guarantee_property(!access_flags.is_native() && !access_flags.is_abstract(),
"Code attribute in native or abstract methods in class file %s",
CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1.1) * 既に, Code attribute を読み込んでいないかどうかを確認 (重複していたら ClassFormatError)
---------------------------------------- -}
if (parsed_code_attribute) {
classfile_parse_error("Multiple Code attributes in class file %s", CHECK_(nullHandle));
}
parsed_code_attribute = true;
{- -------------------------------------------
(1.1.1) * Stack size, locals size, および code size を読み込む.
(_need_verify が立っていれば), args_size <= max_locals であることと,
0 < code_length <= MAX_CODE_SIZE であることを確認.
---------------------------------------- -}
// Stack size, locals size, and code size
if (_major_version == 45 && _minor_version <= 2) {
cfs->guarantee_more(4, CHECK_(nullHandle));
max_stack = cfs->get_u1_fast();
max_locals = cfs->get_u1_fast();
code_length = cfs->get_u2_fast();
} else {
cfs->guarantee_more(8, CHECK_(nullHandle));
max_stack = cfs->get_u2_fast();
max_locals = cfs->get_u2_fast();
code_length = cfs->get_u4_fast();
}
if (_need_verify) {
guarantee_property(args_size <= max_locals,
"Arguments can't fit into locals in class file %s", CHECK_(nullHandle));
guarantee_property(code_length > 0 && code_length <= MAX_CODE_SIZE,
"Invalid method Code length %u in class file %s",
code_length, CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1.1) * 次に, byte code の先頭のアドレスを取得する.
(get_u1_buffer() は現在のポインタ値を返す. 現在のポインタの指す1byteを返す get_u1_fast() とは違うので注意)
---------------------------------------- -}
// Code pointer
code_start = cfs->get_u1_buffer();
assert(code_start != NULL, "null code start");
{- -------------------------------------------
(1.1.1) * byte code 自体はとりあえずスキップして次に進む
---------------------------------------- -}
cfs->guarantee_more(code_length, CHECK_(nullHandle));
cfs->skip_u1_fast(code_length);
{- -------------------------------------------
(1.1.1) * 次に, exception_table_length を読み込み,
exception_table_length が 0 より大きければ
ClassFileParser::parse_exception_table() で exception_table を読み込む.
---------------------------------------- -}
// Exception handler table
cfs->guarantee_more(2, CHECK_(nullHandle)); // exception_table_length
exception_table_length = cfs->get_u2_fast();
if (exception_table_length > 0) {
exception_handlers =
parse_exception_table(code_length, exception_table_length, cp, CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1.1) * 次に, Code attribute に付属する attribute を全て読み込む. (#TODO)
---------------------------------------- -}
// Parse additional attributes in code attribute
cfs->guarantee_more(2, CHECK_(nullHandle)); // code_attributes_count
u2 code_attributes_count = cfs->get_u2_fast();
unsigned int calculated_attribute_length = 0;
if (_major_version > 45 || (_major_version == 45 && _minor_version > 2)) {
calculated_attribute_length =
sizeof(max_stack) + sizeof(max_locals) + sizeof(code_length);
} else {
// max_stack, locals and length are smaller in pre-version 45.2 classes
calculated_attribute_length = sizeof(u1) + sizeof(u1) + sizeof(u2);
}
calculated_attribute_length +=
code_length +
sizeof(exception_table_length) +
sizeof(code_attributes_count) +
exception_table_length *
( sizeof(u2) + // start_pc
sizeof(u2) + // end_pc
sizeof(u2) + // handler_pc
sizeof(u2) ); // catch_type_index
while (code_attributes_count--) {
cfs->guarantee_more(6, CHECK_(nullHandle)); // code_attribute_name_index, code_attribute_length
u2 code_attribute_name_index = cfs->get_u2_fast();
u4 code_attribute_length = cfs->get_u4_fast();
calculated_attribute_length += code_attribute_length +
sizeof(code_attribute_name_index) +
sizeof(code_attribute_length);
check_property(valid_cp_range(code_attribute_name_index, cp_size) &&
cp->tag_at(code_attribute_name_index).is_utf8(),
"Invalid code attribute name index %u in class file %s",
code_attribute_name_index,
CHECK_(nullHandle));
if (LoadLineNumberTables &&
cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
// Parse and compress line number table
parse_linenumber_table(code_attribute_length, code_length,
&linenumber_table, CHECK_(nullHandle));
} else if (LoadLocalVariableTables &&
cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
// Parse local variable table
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
if (lvt_cnt == max_lvt_cnt) {
max_lvt_cnt <<= 1;
REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt);
REALLOC_RESOURCE_ARRAY(u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
}
localvariable_table_start[lvt_cnt] =
parse_localvariable_table(code_length,
max_locals,
code_attribute_length,
cp,
&localvariable_table_length[lvt_cnt],
false, // is not LVTT
CHECK_(nullHandle));
total_lvt_length += localvariable_table_length[lvt_cnt];
lvt_cnt++;
} else if (LoadLocalVariableTypeTables &&
_major_version >= JAVA_1_5_VERSION &&
cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
// Parse local variable type table
if (lvtt_cnt == max_lvtt_cnt) {
max_lvtt_cnt <<= 1;
REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt);
REALLOC_RESOURCE_ARRAY(u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
}
localvariable_type_table_start[lvtt_cnt] =
parse_localvariable_table(code_length,
max_locals,
code_attribute_length,
cp,
&localvariable_type_table_length[lvtt_cnt],
true, // is LVTT
CHECK_(nullHandle));
lvtt_cnt++;
} else if (UseSplitVerifier &&
_major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION &&
cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
// Stack map is only needed by the new verifier in JDK1.5.
if (parsed_stackmap_attribute) {
classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle));
}
typeArrayOop sm =
parse_stackmap_table(code_attribute_length, CHECK_(nullHandle));
stackmap_data = typeArrayHandle(THREAD, sm);
parsed_stackmap_attribute = true;
} else {
// Skip unknown attributes
cfs->skip_u1(code_attribute_length, CHECK_(nullHandle));
}
}
// check method attribute length
if (_need_verify) {
guarantee_property(method_attribute_length == calculated_attribute_length,
"Code segment has wrong length in class file %s", CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1) (ここまでが Code attribute の場合の処理)
---------------------------------------- -}
{- -------------------------------------------
(1.1) * Exceptions attribute の場合は, 1つのメソッドに複数の Exceptions attribute が指定されてはいけない.
以上のチェックが終わったら, ClassFileParser::parse_checked_exceptions() で
Exceptions attribute を読み込む.
---------------------------------------- -}
} else if (method_attribute_name == vmSymbols::tag_exceptions()) {
// Parse Exceptions attribute
if (parsed_checked_exceptions_attribute) {
classfile_parse_error("Multiple Exceptions attributes in class file %s", CHECK_(nullHandle));
}
parsed_checked_exceptions_attribute = true;
checked_exceptions_start =
parse_checked_exceptions(&checked_exceptions_length,
method_attribute_length,
cp, CHECK_(nullHandle));
{- -------------------------------------------
(1.1) * Synthetic attribute の場合は, attribute_length が 0 でないといけない.
(Synthetic attribute には他に情報は無いので単にこれだけ)
以上のチェックが終わったら, 読み込んだ access_flags 情報にこの情報を足し込む.
---------------------------------------- -}
} else if (method_attribute_name == vmSymbols::tag_synthetic()) {
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Synthetic method attribute length %u in class file %s",
method_attribute_length, CHECK_(nullHandle));
}
// Should we check that there hasn't already been a synthetic attribute?
access_flags.set_is_synthetic();
{- -------------------------------------------
(1.1) * Deprecated attribute の場合は, attribute_length が 0 でないといけない.
(Deprecated attribute には他に情報は無いので単にこれだけ)
(Deprecated attribute については, 呼び出し元には何の情報も返されない)
---------------------------------------- -}
} else if (method_attribute_name == vmSymbols::tag_deprecated()) { // 4276120
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Deprecated method attribute length %u in class file %s",
method_attribute_length, CHECK_(nullHandle));
}
{- -------------------------------------------
(1.1) * バージョンが Java 5 以降であれば, Java 5 で追加されたアノテーションの処理も行う. (#TODO)
---------------------------------------- -}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (method_attribute_name == vmSymbols::tag_signature()) {
if (method_attribute_length != 2) {
classfile_parse_error(
"Invalid Signature attribute length %u in class file %s",
method_attribute_length, CHECK_(nullHandle));
}
cfs->guarantee_more(2, CHECK_(nullHandle)); // generic_signature_index
generic_signature_index = cfs->get_u2_fast();
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
runtime_visible_annotations_length = method_attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
} else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
runtime_invisible_annotations_length = method_attribute_length;
runtime_invisible_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
cfs->skip_u1(runtime_invisible_annotations_length, CHECK_(nullHandle));
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
runtime_visible_parameter_annotations_length = method_attribute_length;
runtime_visible_parameter_annotations = cfs->get_u1_buffer();
assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations");
cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_(nullHandle));
} else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
runtime_invisible_parameter_annotations_length = method_attribute_length;
runtime_invisible_parameter_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_parameter_annotations != NULL, "null invisible parameter annotations");
cfs->skip_u1(runtime_invisible_parameter_annotations_length, CHECK_(nullHandle));
} else if (method_attribute_name == vmSymbols::tag_annotation_default()) {
annotation_default_length = method_attribute_length;
annotation_default = cfs->get_u1_buffer();
assert(annotation_default != NULL, "null annotation default");
cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));
{- -------------------------------------------
(1.1) もし認識できない attribute であれば, 単に読み飛ばすだけ.
(なお 2つあるのは, _major_version >= JAVA_1_5_VERSION の場合とそうでない場合に対応. どちらにせよ読み飛ばすだけだけど)
---------------------------------------- -}
} else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
}
} else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
}
}
{- -------------------------------------------
(1) ?? #TODO
---------------------------------------- -}
if (linenumber_table != NULL) {
linenumber_table->write_terminator();
linenumber_table_length = linenumber_table->position();
}
{- -------------------------------------------
(1) もしこの段階で (native や abstract ではないのに) Code attribute が1つもなければエラー
---------------------------------------- -}
// Make sure there's at least one Code attribute in non-native/non-abstract method
if (_need_verify) {
guarantee_property(access_flags.is_native() || access_flags.is_abstract() || parsed_code_attribute,
"Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle));
}
{- -------------------------------------------
(1) 次に, ここまでで読み込んだデータから methodOop を作成する.
---------------------------------------- -}
// All sizing information for a methodOop is finally available, now create it
methodOop m_oop = oopFactory::new_method(code_length, access_flags, linenumber_table_length,
total_lvt_length, checked_exceptions_length,
oopDesc::IsSafeConc, CHECK_(nullHandle));
methodHandle m (THREAD, m_oop);
{- -------------------------------------------
(1) (JMM のフック点)
---------------------------------------- -}
ClassLoadingService::add_class_method_size(m_oop->size()*HeapWordSize);
{- -------------------------------------------
(1) 次に, 作成した methodOop の中身を埋めていく.
まずは固定長の部分から埋めていき,
codes や line number table 等へと続き,
そして最後に local variable table (LVT) で完了. (詳細は見てない #TODO)
---------------------------------------- -}
// Fill in information from fixed part (access_flags already set)
m->set_constants(cp());
m->set_name_index(name_index);
m->set_signature_index(signature_index);
m->set_generic_signature_index(generic_signature_index);
#ifdef CC_INTERP
// hmm is there a gc issue here??
ResultTypeFinder rtf(cp->symbol_at(signature_index));
m->set_result_index(rtf.type());
#endif
if (args_size >= 0) {
m->set_size_of_parameters(args_size);
} else {
m->compute_size_of_parameters(THREAD);
}
#ifdef ASSERT
if (args_size >= 0) {
m->compute_size_of_parameters(THREAD);
assert(args_size == m->size_of_parameters(), "");
}
#endif
// Fill in code attribute information
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
m->constMethod()->set_stackmap_data(stackmap_data());
/**
* The exception_table field is the flag used to indicate
* that the methodOop and it's associated constMethodOop are partially
* initialized and thus are exempt from pre/post GC verification. Once
* the field is set, the oops are considered fully initialized so make
* sure that the oops can pass verification when this field is set.
*/
m->set_exception_table(exception_handlers());
// Copy byte codes
m->set_code(code_start);
// Copy line number table
if (linenumber_table != NULL) {
memcpy(m->compressed_linenumber_table(),
linenumber_table->buffer(), linenumber_table_length);
}
// Copy checked exceptions
if (checked_exceptions_length > 0) {
int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size);
}
/* Copy class file LVT's/LVTT's into the HotSpot internal LVT.
*
* Rules for LVT's and LVTT's are:
* - There can be any number of LVT's and LVTT's.
* - If there are n LVT's, it is the same as if there was just
* one LVT containing all the entries from the n LVT's.
* - There may be no more than one LVT entry per local variable.
* Two LVT entries are 'equal' if these fields are the same:
* start_pc, length, name, slot
* - There may be no more than one LVTT entry per each LVT entry.
* Each LVTT entry has to match some LVT entry.
* - HotSpot internal LVT keeps natural ordering of class file LVT entries.
*/
if (total_lvt_length > 0) {
int tbl_no, idx;
promoted_flags->set_has_localvariable_table();
LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE);
initialize_hashtable(lvt_Hash);
// To fill LocalVariableTable in
Classfile_LVT_Element* cf_lvt;
LocalVariableTableElement* lvt = m->localvariable_table_start();
for (tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) {
cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no];
for (idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) {
copy_lvt_element(&cf_lvt[idx], lvt);
// If no duplicates, add LVT elem in hashtable lvt_Hash.
if (LVT_put_after_lookup(lvt, lvt_Hash) == false
&& _need_verify
&& _major_version >= JAVA_1_5_VERSION ) {
clear_hashtable(lvt_Hash);
classfile_parse_error("Duplicated LocalVariableTable attribute "
"entry for '%s' in class file %s",
cp->symbol_at(lvt->name_cp_index)->as_utf8(),
CHECK_(nullHandle));
}
}
}
// To merge LocalVariableTable and LocalVariableTypeTable
Classfile_LVT_Element* cf_lvtt;
LocalVariableTableElement lvtt_elem;
for (tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) {
cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no];
for (idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) {
copy_lvt_element(&cf_lvtt[idx], &lvtt_elem);
int index = hash(&lvtt_elem);
LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash);
if (entry == NULL) {
if (_need_verify) {
clear_hashtable(lvt_Hash);
classfile_parse_error("LVTT entry for '%s' in class file %s "
"does not match any LVT entry",
cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(),
CHECK_(nullHandle));
}
} else if (entry->_elem->signature_cp_index != 0 && _need_verify) {
clear_hashtable(lvt_Hash);
classfile_parse_error("Duplicated LocalVariableTypeTable attribute "
"entry for '%s' in class file %s",
cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(),
CHECK_(nullHandle));
} else {
// to add generic signatures into LocalVariableTable
entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index;
}
}
}
clear_hashtable(lvt_Hash);
}
{- -------------------------------------------
(1) 次に, アノテーション情報を引数で渡されたポインタに格納する.
---------------------------------------- -}
*method_annotations = assemble_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
runtime_invisible_annotations,
runtime_invisible_annotations_length,
CHECK_(nullHandle));
*method_parameter_annotations = assemble_annotations(runtime_visible_parameter_annotations,
runtime_visible_parameter_annotations_length,
runtime_invisible_parameter_annotations,
runtime_invisible_parameter_annotations_length,
CHECK_(nullHandle));
*method_default_annotations = assemble_annotations(annotation_default,
annotation_default_length,
NULL,
0,
CHECK_(nullHandle));
{- -------------------------------------------
(1) finalizer や initializer であればフラグを立てる.
(このフラグは何のために使われている? #TODO)
---------------------------------------- -}
if (name == vmSymbols::finalize_method_name() &&
signature == vmSymbols::void_method_signature()) {
if (m->is_empty_method()) {
_has_empty_finalizer = true;
} else {
_has_finalizer = true;
}
}
if (name == vmSymbols::object_initializer_name() &&
signature == vmSymbols::void_method_signature() &&
m->is_vanilla_constructor()) {
_has_vanilla_constructor = true;
}
{- -------------------------------------------
(1) ?? #TODO
---------------------------------------- -}
if (EnableInvokeDynamic && (m->is_method_handle_invoke() ||
m->is_method_handle_adapter())) {
THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
"Method handle invokers must be defined internally to the VM", nullHandle);
}
{- -------------------------------------------
(1) 最後に, パース結果の methodOop をリターン.
---------------------------------------- -}
return m;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.