< prev index next >

src/hotspot/share/classfile/classFileParser.cpp

Print this page

        

*** 1747,1756 **** --- 1747,1757 ---- for (int j = total_fields * FieldInfo::field_slots; j < generic_signature_slot; j++) { _fields->at_put(i++, fa[j]); } assert(_fields->length() == i, ""); + //tty->print_cr("length of the _fields array %d for class %s", i, _class_name->as_klass_external_name()); } if (_need_verify && length > 1) { // Check duplicated fields ResourceMark rm(THREAD);
*** 3221,3230 **** --- 3222,3322 ---- cfs->set_current(current_mark); return length; } + u2 ClassFileParser::parse_classfile_permitted_subtypes_attribute(const ClassFileStream* const cfs, + const u1* const permitted_subtypes_attribute_start, + TRAPS) { + const u1* const current_mark = cfs->current(); + u2 length = 0; + if (permitted_subtypes_attribute_start != NULL) { + cfs->set_current(permitted_subtypes_attribute_start); + cfs->guarantee_more(2, CHECK_0); // length + length = cfs->get_u2_fast(); + } + const int size = length; + Array<u2>* const permitted_subtypes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0); + _permitted_subtypes = permitted_subtypes; + + int index = 0; + cfs->guarantee_more(2 * length, CHECK_0); + for (int n = 0; n < length; n++) { + const u2 class_info_index = cfs->get_u2_fast(); + check_property( + valid_klass_reference_at(class_info_index), + "Permitted subtype class_info_index %u has bad constant type in class file %s", + class_info_index, CHECK_0); + permitted_subtypes->at_put(index++, class_info_index); + } + assert(index == size, "wrong size"); + + // Restore buffer's current position. + cfs->set_current(current_mark); + + return length; + } + + void ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* const cfs, + const u1* const record_attribute_start, + ConstantPool* cp, + int* const record_params_count_ptr, + TRAPS) { + assert(NULL == _record_params, "invariant"); + + const u1* const current_mark = cfs->current(); + int num_of_params = 0; + if (record_attribute_start != NULL) { + cfs->set_current(record_attribute_start); + cfs->guarantee_more(2, CHECK); // length + num_of_params = (int)cfs->get_u2_fast(); + // DEBUG + // tty->print_cr("this record has %d parameters", num_of_params); + } + + *record_params_count_ptr = num_of_params; + + ResourceMark rm(THREAD); + u2* const record_params_array = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, + u2, + num_of_params * (RecordParamInfo::param_slots + 1)); + for (int n = 0; n < num_of_params; n++) { + cfs->guarantee_more(RecordParamInfo::param_slots, CHECK); + + const u2 method_ref_index = cfs->get_u2_fast(); + //check_property(valid_symbol_at(method_ref_index), + // "Invalid constant pool index %u for record parameter name in class file %s", + // method_ref_index, CHECK); + //const Symbol* const method_ref = cp->symbol_at(method_ref_index); + // we will need a way to verify that the symbol is correct + // verify_legal_field_name(name, CHECK); + // DEBUG + // tty->print_cr("name read %s", name->as_klass_external_name()); + + RecordParamInfo* const record_param_info = RecordParamInfo::from_record_params_array(record_params_array, n); + record_param_info->initialize(method_ref_index); + } + + assert(NULL == _record_params, "invariant"); + + _record_params = MetadataFactory::new_array<u2>(_loader_data, + num_of_params * RecordParamInfo::param_slots, + CHECK); + { + int i = 0; + for (; i < num_of_params * RecordParamInfo::param_slots; i++) { + _record_params->at_put(i, record_params_array[i]); + } + assert(_record_params->length() == i, ""); + // DEBUG + // tty->print_cr("length of the _record_params array %d for class %s", i, _class_name->as_klass_external_name()); + } + + // Restore buffer's current position. + cfs->set_current(current_mark); + } + void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) { set_class_synthetic_flag(true); } void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream* const cfs, TRAPS) {
*** 3330,3345 **** --- 3422,3443 ---- // Set inner classes attribute to default sentinel _inner_classes = Universe::the_empty_short_array(); // Set nest members attribute to default sentinel _nest_members = Universe::the_empty_short_array(); + // Set _permitted_subtypes attribute to default sentinel + _permitted_subtypes = Universe::the_empty_short_array(); + // Set record params to default sentinel + _record_params = Universe::the_empty_short_array(); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); bool parsed_sourcefile_attribute = false; bool parsed_innerclasses_attribute = false; bool parsed_nest_members_attribute = false; + bool parsed_permitted_subtypes_attribute = false; bool parsed_nest_host_attribute = false; + bool parsed_record_attribute = false; bool parsed_enclosingmethod_attribute = false; bool parsed_bootstrap_methods_attribute = false; const u1* runtime_visible_annotations = NULL; int runtime_visible_annotations_length = 0; const u1* runtime_invisible_annotations = NULL;
*** 3355,3364 **** --- 3453,3466 ---- u4 inner_classes_attribute_length = 0; u2 enclosing_method_class_index = 0; u2 enclosing_method_method_index = 0; const u1* nest_members_attribute_start = NULL; u4 nest_members_attribute_length = 0; + const u1* record_attribute_start = NULL; + u4 record_attribute_length = 0; + const u1* permitted_subtypes_attribute_start = NULL; + u4 permitted_subtypes_attribute_length = 0; // Iterate over attributes while (attributes_count--) { cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast();
*** 3537,3546 **** --- 3639,3670 ---- check_property( valid_klass_reference_at(class_info_index), "Nest-host class_info_index %u has bad constant type in class file %s", class_info_index, CHECK); _nest_host = class_info_index; + } else if (tag == vmSymbols::tag_permitted_subtypes()) { + // Check for PermittedSubtypes tag + if (!_access_flags.is_final()) { + classfile_parse_error("PermittedSubtypes attribute in non-final class file %s", CHECK); + } + if (parsed_permitted_subtypes_attribute) { + classfile_parse_error("Multiple PermittedSubtypes attributes in class file %s", CHECK); + } else { + parsed_permitted_subtypes_attribute = true; + } + permitted_subtypes_attribute_start = cfs->current(); + permitted_subtypes_attribute_length = attribute_length; + cfs->skip_u1(permitted_subtypes_attribute_length, CHECK); + } else if (tag == vmSymbols::tag_record()) { + if (parsed_record_attribute) { + classfile_parse_error("Multiple Record attributes in class file %s", CHECK); + } else { + parsed_record_attribute = true; + } + record_attribute_start = cfs->current(); + record_attribute_length = attribute_length; + cfs->skip_u1(record_attribute_length, CHECK); } else { // Unknown attribute cfs->skip_u1(attribute_length, CHECK); } } else {
*** 3588,3597 **** --- 3712,3742 ---- nest_members_attribute_length == sizeof(num_of_classes) + sizeof(u2) * num_of_classes, "Wrong NestMembers attribute length in class file %s", CHECK); } } + if (parsed_record_attribute) { + parse_classfile_record_attribute( + cfs, + record_attribute_start, + cp, + &_record_params_count, + CHECK); + } + + if (parsed_permitted_subtypes_attribute) { + const u2 num_of_subtypes = parse_classfile_permitted_subtypes_attribute( + cfs, + permitted_subtypes_attribute_start, + CHECK); + if (_need_verify) { + guarantee_property( + permitted_subtypes_attribute_length == sizeof(num_of_subtypes) + sizeof(u2) * num_of_subtypes, + "Wrong PermittedSubtypes attribute length in class file %s", CHECK); + } + } + if (_max_bootstrap_specifier_index >= 0) { guarantee_property(parsed_bootstrap_methods_attribute, "Missing BootstrapMethods attribute in class file %s", CHECK); } }
*** 3642,3652 **** } // Transfer ownership of metadata allocated to the InstanceKlass. void ClassFileParser::apply_parsed_class_metadata( InstanceKlass* this_klass, ! int java_fields_count, TRAPS) { assert(this_klass != NULL, "invariant"); _cp->set_pool_holder(this_klass); this_klass->set_constants(_cp); this_klass->set_fields(_fields, java_fields_count); --- 3787,3798 ---- } // Transfer ownership of metadata allocated to the InstanceKlass. void ClassFileParser::apply_parsed_class_metadata( InstanceKlass* this_klass, ! int java_fields_count, ! int record_params_count, TRAPS) { assert(this_klass != NULL, "invariant"); _cp->set_pool_holder(this_klass); this_klass->set_constants(_cp); this_klass->set_fields(_fields, java_fields_count);
*** 3654,3663 **** --- 3800,3811 ---- this_klass->set_inner_classes(_inner_classes); this_klass->set_nest_members(_nest_members); this_klass->set_nest_host_index(_nest_host); this_klass->set_local_interfaces(_local_interfaces); this_klass->set_annotations(_combined_annotations); + this_klass->set_record_params(_record_params, record_params_count); + this_klass->set_permitted_subtypes(_permitted_subtypes); // Delay the setting of _transitive_interfaces until after initialize_supers() in // fill_instance_klass(). It is because the _transitive_interfaces may be shared with // its _super. If an OOM occurs while loading the current klass, its _super field // may not have been set. When GC tries to free the klass, the _transitive_interfaces // may be deallocated mistakenly in InstanceKlass::deallocate_interfaces(). Subsequent
*** 4725,4740 **** const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; ! const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; ! if ((is_abstract && is_final) || ! (is_interface && !is_abstract) || ! (is_interface && major_gte_15 && (is_super || is_enum)) || ! (!is_interface && major_gte_15 && is_annotation)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal class modifiers in class %s: 0x%X", --- 4873,4889 ---- const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; ! const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION; ! const bool major_gte_12 = _major_version >= JAVA_12_VERSION; ! if ((is_abstract && is_final && !major_gte_12) || ! (is_interface && !is_abstract && !major_gte_12) || ! (is_interface && major_gte_1_5 && (is_super || is_enum)) || ! (!is_interface && major_gte_1_5 && is_annotation)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal class modifiers in class %s: 0x%X",
*** 5494,5513 **** assert(_fac != NULL, "invariant"); ik->set_static_oop_field_count(_fac->count[STATIC_OOP]); // this transfers ownership of a lot of arrays from // the parser onto the InstanceKlass* ! apply_parsed_class_metadata(ik, _java_fields_count, CHECK); // note that is not safe to use the fields in the parser from this point on assert(NULL == _cp, "invariant"); assert(NULL == _fields, "invariant"); assert(NULL == _methods, "invariant"); assert(NULL == _inner_classes, "invariant"); assert(NULL == _nest_members, "invariant"); assert(NULL == _local_interfaces, "invariant"); assert(NULL == _combined_annotations, "invariant"); if (_has_final_method) { ik->set_has_final_method(); } --- 5643,5664 ---- assert(_fac != NULL, "invariant"); ik->set_static_oop_field_count(_fac->count[STATIC_OOP]); // this transfers ownership of a lot of arrays from // the parser onto the InstanceKlass* ! apply_parsed_class_metadata(ik, _java_fields_count, _record_params_count, CHECK); // note that is not safe to use the fields in the parser from this point on assert(NULL == _cp, "invariant"); assert(NULL == _fields, "invariant"); assert(NULL == _methods, "invariant"); assert(NULL == _inner_classes, "invariant"); assert(NULL == _nest_members, "invariant"); assert(NULL == _local_interfaces, "invariant"); assert(NULL == _combined_annotations, "invariant"); + assert(NULL == _record_params, "invariant"); + assert(NULL == _permitted_subtypes, "invariant"); if (_has_final_method) { ik->set_has_final_method(); }
*** 5683,5692 **** --- 5834,5845 ---- set_klass_to_deallocate(NULL); // it's official set_klass(ik); + check_subtyping(CHECK); + debug_only(ik->verify();) } void ClassFileParser::update_class_name(Symbol* new_class_name) { // Decrement the refcount in the old name, since we're clobbering it.
*** 5785,5794 **** --- 5938,5949 ---- _fields(NULL), _methods(NULL), _inner_classes(NULL), _nest_members(NULL), _nest_host(0), + _record_params(NULL), + _permitted_subtypes(NULL), _local_interfaces(NULL), _transitive_interfaces(NULL), _combined_annotations(NULL), _annotations(NULL), _type_annotations(NULL),
*** 5818,5827 **** --- 5973,5983 ---- _minor_version(0), _this_class_index(0), _super_class_index(0), _itfs_len(0), _java_fields_count(0), + _record_params_count(-1), _need_verify(false), _relax_verify(false), _has_nonstatic_concrete_methods(false), _declares_nonstatic_concrete_methods(false), _has_final_method(false),
*** 5891,5904 **** --- 6047,6062 ---- _cp = NULL; _fields = NULL; _methods = NULL; _inner_classes = NULL; _nest_members = NULL; + _permitted_subtypes = NULL; _local_interfaces = NULL; _combined_annotations = NULL; _annotations = _type_annotations = NULL; _fields_annotations = _fields_type_annotations = NULL; + _record_params = NULL; } // Destructor to clean up ClassFileParser::~ClassFileParser() { _class_name->decrement_refcount();
*** 5922,5931 **** --- 6080,6097 ---- if (_nest_members != NULL && _nest_members != Universe::the_empty_short_array()) { MetadataFactory::free_array<u2>(_loader_data, _nest_members); } + if (_record_params != NULL && _record_params != Universe::the_empty_short_array()) { + MetadataFactory::free_array<u2>(_loader_data, _record_params); + } + + if (_permitted_subtypes != NULL && _permitted_subtypes != Universe::the_empty_short_array()) { + MetadataFactory::free_array<u2>(_loader_data, _permitted_subtypes); + } + // Free interfaces InstanceKlass::deallocate_interfaces(_loader_data, _super_klass, _local_interfaces, _transitive_interfaces); if (_combined_annotations != NULL) {
*** 6254,6267 **** _class_name->as_klass_external_name(), _super_klass->external_name() ); return; } - // Make sure super class is not final - if (_super_klass->is_final()) { - THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class"); - } } // Compute the transitive list of all unique interfaces implemented by this class _transitive_interfaces = compute_transitive_interfaces(_super_klass, --- 6420,6429 ----
*** 6275,6290 **** --- 6437,6457 ---- _method_ordering = sort_methods(_methods); _all_mirandas = new GrowableArray<Method*>(20); Handle loader(THREAD, _loader_data->class_loader()); + bool is_sealed = _access_flags.is_final() && + _permitted_subtypes != NULL && + _permitted_subtypes != Universe::the_empty_short_array() && + _permitted_subtypes->length() > 0; klassVtable::compute_vtable_size_and_num_mirandas(&_vtable_size, &_num_miranda_methods, _all_mirandas, _super_klass, _methods, _access_flags, + is_sealed, _major_version, loader, _class_name, _local_interfaces, CHECK);
*** 6302,6311 **** --- 6469,6502 ---- // Compute reference typ _rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type(); } + void ClassFileParser::check_subtyping(TRAPS) { + assert(NULL != _klass, "_klass should have been resolved before calling this method"); + if (_super_klass != NULL) { + if (_super_klass->is_final()) { + bool isPermittedSubtype = _super_klass->has_as_permitted_subtype(_klass, CHECK); + if (!isPermittedSubtype) { + THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class"); + } + } + } + Array<InstanceKlass*>* local_interfaces = _klass->local_interfaces(); + if (local_interfaces != NULL && local_interfaces != Universe::the_empty_instance_klass_array()) { + for (int i = 0; i < local_interfaces->length(); i++) { + InstanceKlass* intf = local_interfaces->at(i); + if (intf->is_final()) { + bool isPermittedSubtype = intf->has_as_permitted_subtype(_klass, CHECK); + if (!isPermittedSubtype) { + THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final interface"); + } + } + } + } + } + void ClassFileParser::set_klass(InstanceKlass* klass) { #ifdef ASSERT if (klass != NULL) { assert(NULL == _klass, "leaking?");
< prev index next >