##构造方法ClassFileParser,parse_stream解析文件流
ClassFileParser::ClassFileParser(ClassFileStream* stream,Symbol* name,ClassLoaderData* loader_data,const ClassLoadInfo* cl_info,Publicity pub_level,TRAPS) :_stream(stream),_class_name(NULL),_loader_data(loader_data),_is_hidden(cl_info->is_hidden()),_can_access_vm_annotations(cl_info->can_access_vm_annotations()),_orig_cp_size(0),_super_klass(),_cp(NULL),_fields(NULL),_methods(NULL),_inner_classes(NULL),_nest_members(NULL),_nest_host(0),_permitted_subclasses(NULL),_record_components(NULL),_local_interfaces(NULL),_transitive_interfaces(NULL),_combined_annotations(NULL),_class_annotations(NULL),_class_type_annotations(NULL),_fields_annotations(NULL),_fields_type_annotations(NULL),_klass(NULL),_klass_to_deallocate(NULL),_parsed_annotations(NULL),_fac(NULL),_field_info(NULL),_method_ordering(NULL),_all_mirandas(NULL),_vtable_size(0),_itable_size(0),_num_miranda_methods(0),_rt(REF_NONE),_protection_domain(cl_info->protection_domain()),_access_flags(),_pub_level(pub_level),_bad_constant_seen(0),_synthetic_flag(false),_sde_length(false),_sde_buffer(NULL),_sourcefile_index(0),_generic_signature_index(0),_major_version(0),_minor_version(0),_this_class_index(0),_super_class_index(0),_itfs_len(0),_java_fields_count(0),_need_verify(false),_relax_verify(false),_has_nonstatic_concrete_methods(false),_declares_nonstatic_concrete_methods(false),_has_final_method(false),_has_contended_fields(false),_has_finalizer(false),_has_empty_finalizer(false),_has_vanilla_constructor(false),_max_bootstrap_specifier_index(-1) {_class_name = name != NULL ? name : vmSymbols::unknown_class_name();_class_name->increment_refcount();assert(_loader_data != NULL, "invariant");assert(stream != NULL, "invariant");assert(_stream != NULL, "invariant");assert(_stream->buffer() == _stream->current(), "invariant");assert(_class_name != NULL, "invariant");assert(0 == _access_flags.as_int(), "invariant");// Figure out whether we can skip format checking (matching classic VM behavior)if (DumpSharedSpaces) {// verify == true means it's a 'remote' class (i.e., non-boot class)// Verification decision is based on BytecodeVerificationRemote flag// for those classes._need_verify = (stream->need_verify()) ? BytecodeVerificationRemote :BytecodeVerificationLocal;}else {_need_verify = Verifier::should_verify_for(_loader_data->class_loader(),stream->need_verify());}// synch back verification state to streamstream->set_verify(_need_verify);// 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 = relax_format_check_for(_loader_data);parse_stream(stream, CHECK);post_process_parsed_stream(stream, _cp, CHECK);
}
##parse_stream方法
void ClassFileParser::parse_stream(const ClassFileStream* const stream,TRAPS) {assert(stream != NULL, "invariant");assert(_class_name != NULL, "invariant");// BEGIN STREAM PARSINGstream->guarantee_more(8, CHECK); // magic, major, minor// Magic valueconst u4 magic = stream->get_u4_fast();guarantee_property(magic == JAVA_CLASSFILE_MAGIC,"Incompatible magic value %u in class file %s",magic, CHECK);// Version numbers_minor_version = stream->get_u2_fast();_major_version = stream->get_u2_fast();// Check version numbers - we check this even with verifier offverify_class_version(_major_version, _minor_version, _class_name, CHECK);stream->guarantee_more(3, CHECK); // length, first cp tagu2 cp_size = stream->get_u2_fast();guarantee_property(cp_size >= 1, "Illegal constant pool size %u in class file %s",cp_size, CHECK);_orig_cp_size = cp_size;if (is_hidden()) { // Add a slot for hidden class name.cp_size++;}_cp = ConstantPool::allocate(_loader_data,cp_size,CHECK);ConstantPool* const cp = _cp;parse_constant_pool(stream, cp, _orig_cp_size, CHECK);assert(cp_size == (const u2)cp->length(), "invariant");// ACCESS FLAGSstream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len// Access flagsjint flags;// JVM_ACC_MODULE is defined in JDK-9 and later.if (_major_version >= JAVA_9_VERSION) {flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);} else {flags = stream->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 compatibilityflags |= JVM_ACC_ABSTRACT;}verify_legal_class_modifiers(flags, CHECK);short bad_constant = class_bad_constant_seen();if (bad_constant != 0) {// Do not throw CFE until after the access_flags are checked because if// ACC_MODULE is set in the access flags, then NCDFE must be thrown, not CFE.classfile_parse_error("Unknown constant tag %u in class file %s", bad_constant, THREAD);return;}_access_flags.set_flags(flags);// This class and superclass_this_class_index = stream->get_u2_fast();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);Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);assert(class_name_in_cp != NULL, "class_name can't be null");// 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_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY,"Bad class name in class file %s",CHECK);}#ifdef ASSERT// Basic sanity checksif (_is_hidden) {assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");}
#endif// Update the _class_name as needed depending on whether this is a named, un-named, or hidden class.if (_is_hidden) {assert(_class_name != NULL, "Unexpected null _class_name");
#ifdef ASSERTif (_need_verify) {verify_legal_class_name(_class_name, CHECK);}
#endif} else {// Check if name in class file matches given nameif (_class_name != class_name_in_cp) {if (_class_name != vmSymbols::unknown_class_name()) {ResourceMark rm(THREAD);Exceptions::fthrow(THREAD_AND_LOCATION,vmSymbols::java_lang_NoClassDefFoundError(),"%s (wrong name: %s)",class_name_in_cp->as_C_string(),_class_name->as_C_string());return;} else {// The class name was not known by the caller so we set it from// the value in the CP.update_class_name(class_name_in_cp);}// else nothing to do: the expected class name matches what is in the CP}}// Verification prevents us from creating names with dots in them, this// asserts that that's the case.assert(is_internal_format(_class_name), "external class name format used internally");if (!is_internal()) {LogTarget(Debug, class, preorder) lt;if (lt.is_enabled()){ResourceMark rm(THREAD);LogStream ls(lt);ls.print("%s", _class_name->as_klass_external_name());if (stream->source() != NULL) {ls.print(" source: %s", stream->source());}ls.cr();}}// SUPERKLASS_super_class_index = stream->get_u2_fast();_super_klass = parse_super_class(cp,_super_class_index,_need_verify,CHECK);// Interfaces_itfs_len = stream->get_u2_fast();parse_interfaces(stream,_itfs_len,cp,&_has_nonstatic_concrete_methods,CHECK);assert(_local_interfaces != NULL, "invariant");// Fields (offsets are filled in later)_fac = new FieldAllocationCount();parse_fields(stream,_access_flags.is_interface(),_fac,cp,cp_size,&_java_fields_count,CHECK);assert(_fields != NULL, "invariant");// MethodsAccessFlags promoted_flags;parse_methods(stream,_access_flags.is_interface(),&promoted_flags,&_has_final_method,&_declares_nonstatic_concrete_methods,CHECK);assert(_methods != NULL, "invariant");// promote flags from parse_methods() to the klass' flags_access_flags.add_promoted_flags(promoted_flags.as_int());if (_declares_nonstatic_concrete_methods) {_has_nonstatic_concrete_methods = true;}// Additional attributes/annotations_parsed_annotations = new ClassAnnotationCollector();parse_classfile_attributes(stream, cp, _parsed_annotations, CHECK);assert(_inner_classes != NULL, "invariant");// Finalize the Annotations metadata object,// now that all annotation arrays have been created.create_combined_annotations(CHECK);// Make sure this is the end of class file streamguarantee_property(stream->at_eos(),"Extra bytes at the end of class file %s",CHECK);// all bytes in stream read and parsed
}
##parse_fields解析class文件字段
// Side-effects: populates the _fields, _fields_annotations,
// _fields_type_annotations fields
void ClassFileParser::parse_fields(const ClassFileStream* const cfs,bool is_interface,FieldAllocationCount* const fac,ConstantPool* cp,const int cp_size,u2* const java_fields_count_ptr,TRAPS) {assert(cfs != NULL, "invariant");assert(fac != NULL, "invariant");assert(cp != NULL, "invariant");assert(java_fields_count_ptr != NULL, "invariant");assert(NULL == _fields, "invariant");assert(NULL == _fields_annotations, "invariant");assert(NULL == _fields_type_annotations, "invariant");cfs->guarantee_more(2, CHECK); // lengthconst u2 length = cfs->get_u2_fast();*java_fields_count_ptr = length;int num_injected = 0;const InjectedField* const injected = JavaClasses::get_injected(_class_name,&num_injected);const int total_fields = length + num_injected;// The field array starts with tuples of shorts// [access, name index, sig index, initial value index, byte offset].// A generic signature slot only exists for field with generic// signature attribute. And the access flag is set with// JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic// signature slots are at the end of the field array and after all// other fields data.//// f1: [access, name index, sig index, initial value index, low_offset, high_offset]// f2: [access, name index, sig index, initial value index, low_offset, high_offset]// ...// fn: [access, name index, sig index, initial value index, low_offset, high_offset]// [generic signature index]// [generic signature index]// ...//// Allocate a temporary resource array for field data. For each field,// a slot is reserved in the temporary array for the generic signature// index. After parsing all fields, the data are copied to a permanent// array and any unused slots will be discarded.ResourceMark rm(THREAD);u2* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,u2,total_fields * (FieldInfo::field_slots + 1));// The generic signature slots start after all other fields' data.int generic_signature_slot = total_fields * FieldInfo::field_slots;int num_generic_signature = 0;for (int n = 0; n < length; n++) {// access_flags, name_index, descriptor_index, attributes_countcfs->guarantee_more(8, CHECK);AccessFlags access_flags;const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;verify_legal_field_modifiers(flags, is_interface, CHECK);access_flags.set_flags(flags);const u2 name_index = cfs->get_u2_fast();check_property(valid_symbol_at(name_index),"Invalid constant pool index %u for field name in class file %s",name_index, CHECK);const Symbol* const name = cp->symbol_at(name_index);verify_legal_field_name(name, CHECK);const u2 signature_index = cfs->get_u2_fast();check_property(valid_symbol_at(signature_index),"Invalid constant pool index %u for field signature in class file %s",signature_index, CHECK);const Symbol* const sig = cp->symbol_at(signature_index);verify_legal_field_signature(name, sig, CHECK);u2 constantvalue_index = 0;bool is_synthetic = false;u2 generic_signature_index = 0;const bool is_static = access_flags.is_static();FieldAnnotationCollector parsed_annotations(_loader_data);const u2 attributes_count = cfs->get_u2_fast();if (attributes_count > 0) {parse_field_attributes(cfs,attributes_count,is_static,signature_index,&constantvalue_index,&is_synthetic,&generic_signature_index,&parsed_annotations,CHECK);if (parsed_annotations.field_annotations() != NULL) {if (_fields_annotations == NULL) {_fields_annotations = MetadataFactory::new_array<AnnotationArray*>(_loader_data, length, NULL,CHECK);}_fields_annotations->at_put(n, parsed_annotations.field_annotations());parsed_annotations.set_field_annotations(NULL);}if (parsed_annotations.field_type_annotations() != NULL) {if (_fields_type_annotations == NULL) {_fields_type_annotations =MetadataFactory::new_array<AnnotationArray*>(_loader_data,length,NULL,CHECK);}_fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations());parsed_annotations.set_field_type_annotations(NULL);}if (is_synthetic) {access_flags.set_is_synthetic();}if (generic_signature_index != 0) {access_flags.set_field_has_generic_signature();fa[generic_signature_slot] = generic_signature_index;generic_signature_slot ++;num_generic_signature ++;}}FieldInfo* const field = FieldInfo::from_field_array(fa, n);field->initialize(access_flags.as_short(),name_index,signature_index,constantvalue_index);const BasicType type = cp->basic_type_for_signature_at(signature_index);// Update FieldAllocationCount for this kind of fieldfac->update(is_static, type);// After field is initialized with type, we can augment it with aux infoif (parsed_annotations.has_any_annotations()) {parsed_annotations.apply_to(field);if (field->is_contended()) {_has_contended_fields = true;}}}int index = length;if (num_injected != 0) {for (int n = 0; n < num_injected; n++) {// Check for duplicatesif (injected[n].may_be_java) {const Symbol* const name = injected[n].name();const Symbol* const signature = injected[n].signature();bool duplicate = false;for (int i = 0; i < length; i++) {const FieldInfo* const f = FieldInfo::from_field_array(fa, i);if (name == cp->symbol_at(f->name_index()) &&signature == cp->symbol_at(f->signature_index())) {// Symbol is desclared in Java so skip this oneduplicate = true;break;}}if (duplicate) {// These will be removed from the field array at the endcontinue;}}// Injected fieldFieldInfo* const field = FieldInfo::from_field_array(fa, index);field->initialize((u2)JVM_ACC_FIELD_INTERNAL,(u2)(injected[n].name_index),(u2)(injected[n].signature_index),0);const BasicType type = Signature::basic_type(injected[n].signature());// Update FieldAllocationCount for this kind of fieldfac->update(false, type);index++;}}assert(NULL == _fields, "invariant");_fields =MetadataFactory::new_array<u2>(_loader_data,index * FieldInfo::field_slots + num_generic_signature,CHECK);// Sometimes injected fields already exist in the Java source so// the fields array could be too long. In that case the// fields array is trimed. Also unused slots that were reserved// for generic signature indexes are discarded.{int i = 0;for (; i < index * FieldInfo::field_slots; i++) {_fields->at_put(i, fa[i]);}for (int j = total_fields * FieldInfo::field_slots;j < generic_signature_slot; j++) {_fields->at_put(i++, fa[j]);}assert(_fields->length() == i, "");}if (_need_verify && length > 1) {// Check duplicated fieldsResourceMark rm(THREAD);NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, NameSigHash*, HASH_ROW_SIZE);initialize_hashtable(names_and_sigs);bool dup = false;const Symbol* name = NULL;const Symbol* sig = NULL;{debug_only(NoSafepointVerifier nsv;)for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {name = fs.name();sig = fs.signature();// If no duplicates, add name/signature in hashtable names_and_sigs.if (!put_after_lookup(name, sig, names_and_sigs)) {dup = true;break;}}}if (dup) {classfile_parse_error("Duplicate field name \"%s\" with signature \"%s\" in class file %s",name->as_C_string(), sig->as_klass_external_name(), THREAD);}}
}
##parse_methods解析class文件方法
// The promoted_flags parameter is used to pass relevant access_flags
// from the methods back up to the containing klass. These flag values
// are added to klass's access_flags.
// Side-effects: populates the _methods field in the parser
void ClassFileParser::parse_methods(const ClassFileStream* const cfs,bool is_interface,AccessFlags* promoted_flags,bool* has_final_method,bool* declares_nonstatic_concrete_methods,TRAPS) {assert(cfs != NULL, "invariant");assert(promoted_flags != NULL, "invariant");assert(has_final_method != NULL, "invariant");assert(declares_nonstatic_concrete_methods != NULL, "invariant");assert(NULL == _methods, "invariant");cfs->guarantee_more(2, CHECK); // lengthconst u2 length = cfs->get_u2_fast();if (length == 0) {_methods = Universe::the_empty_method_array();} else {_methods = MetadataFactory::new_array<Method*>(_loader_data,length,NULL,CHECK);for (int index = 0; index < length; index++) {Method* method = parse_method(cfs,is_interface,_cp,promoted_flags,CHECK);if (method->is_final()) {*has_final_method = true;}// declares_nonstatic_concrete_methods: declares concrete instance methods, any access flags// used for interface initialization, and default method inheritance analysisif (is_interface && !(*declares_nonstatic_concrete_methods)&& !method->is_abstract() && !method->is_static()) {*declares_nonstatic_concrete_methods = true;}_methods->at_put(index, method);}if (_need_verify && length > 1) {// Check duplicated methodsResourceMark rm(THREAD);NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, NameSigHash*, HASH_ROW_SIZE);initialize_hashtable(names_and_sigs);bool dup = false;const Symbol* name = NULL;const Symbol* sig = NULL;{debug_only(NoSafepointVerifier nsv;)for (int i = 0; i < length; i++) {const Method* const m = _methods->at(i);name = m->name();sig = m->signature();// If no duplicates, add name/signature in hashtable names_and_sigs.if (!put_after_lookup(name, sig, names_and_sigs)) {dup = true;break;}}}if (dup) {classfile_parse_error("Duplicate method name \"%s\" with signature \"%s\" in class file %s",name->as_C_string(), sig->as_klass_external_name(), THREAD);}}}
}