From cdc18c13221aa2f5a9ac61c7ec76b6c6305b578a Mon Sep 17 00:00:00 2001 From: coleenp Date: Wed, 13 Mar 2013 17:34:29 -0400 Subject: [PATCH] 8003419: NPG: Clean up metadata created during class loading if failure Summary: Store metadata on ClassFileParser instance to be cleaned up by destructor. This enabled some refactoring of the enormous parseClassFile function. Reviewed-by: jmasa, acorn --- src/share/vm/classfile/classFileParser.cpp | 1956 ++++++++++---------- src/share/vm/classfile/classFileParser.hpp | 164 +- src/share/vm/oops/constMethod.cpp | 6 + src/share/vm/oops/constMethod.hpp | 1 + src/share/vm/oops/instanceKlass.cpp | 110 +- src/share/vm/oops/instanceKlass.hpp | 21 +- 6 files changed, 1154 insertions(+), 1104 deletions(-) diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp index 005bda61b..9f2a9f419 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp @@ -90,8 +90,7 @@ // Extension method support. #define JAVA_8_VERSION 52 - -void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) { +void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -104,7 +103,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif - Handle class_loader(THREAD, loader_data->class_loader()); + Handle class_loader(THREAD, _loader_data->class_loader()); // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -124,7 +123,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); - cp->klass_index_at_put(index, name_index); + _cp->klass_index_at_put(index, name_index); } break; case JVM_CONSTANT_Fieldref : @@ -132,7 +131,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->field_at_put(index, class_index, name_and_type_index); + _cp->field_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_Methodref : @@ -140,7 +139,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->method_at_put(index, class_index, name_and_type_index); + _cp->method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_InterfaceMethodref : @@ -148,14 +147,14 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->interface_method_at_put(index, class_index, name_and_type_index); + _cp->interface_method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_String : { cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags u2 string_index = cfs->get_u2_fast(); - cp->string_index_at_put(index, string_index); + _cp->string_index_at_put(index, string_index); } break; case JVM_CONSTANT_MethodHandle : @@ -174,11 +173,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags u1 ref_kind = cfs->get_u1_fast(); u2 method_index = cfs->get_u2_fast(); - cp->method_handle_index_at_put(index, ref_kind, method_index); + _cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags u2 signature_index = cfs->get_u2_fast(); - cp->method_type_index_at_put(index, signature_index); + _cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); } @@ -200,21 +199,21 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later - cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); + _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); } break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->int_at_put(index, (jint) bytes); + _cp->int_at_put(index, (jint) bytes); } break; case JVM_CONSTANT_Float : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->float_at_put(index, *(jfloat*)&bytes); + _cp->float_at_put(index, *(jfloat*)&bytes); } break; case JVM_CONSTANT_Long : @@ -225,7 +224,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->long_at_put(index, bytes); + _cp->long_at_put(index, bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -237,7 +236,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->double_at_put(index, *(jdouble*)&bytes); + _cp->double_at_put(index, *(jdouble*)&bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -246,7 +245,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); u2 signature_index = cfs->get_u2_fast(); - cp->name_and_type_at_put(index, name_index, signature_index); + _cp->name_and_type_at_put(index, name_index, signature_index); } break; case JVM_CONSTANT_Utf8 : @@ -283,11 +282,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, indices[names_count] = index; hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { - cp->symbol_at_put(index, result); + _cp->symbol_at_put(index, result); } } break; @@ -300,7 +299,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, // Allocate the remaining symbols if (names_count > 0) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). @@ -310,23 +309,6 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs0->set_current(cfs1.current()); } -// This class unreferences constant pool symbols if an error has occurred -// while parsing the class before it is assigned into the class. -// If it gets an error after that it is unloaded and the constant pool will -// be cleaned up then. -class ConstantPoolCleaner : public StackObj { - constantPoolHandle _cphandle; - bool _in_error; - public: - ConstantPoolCleaner(constantPoolHandle cp) : _cphandle(cp), _in_error(true) {} - ~ConstantPoolCleaner() { - if (_in_error && _cphandle.not_null()) { - _cphandle->unreference_symbols(); - } - } - void set_in_error(bool clean) { _in_error = clean; } -}; - bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { @@ -336,7 +318,7 @@ inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { return NULL; } -constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_data, TRAPS) { +constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; @@ -345,16 +327,13 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ guarantee_property( length >= 1, "Illegal constant pool size %u in class file %s", length, CHECK_(nullHandle)); - ConstantPool* constant_pool = - ConstantPool::allocate(loader_data, - length, - CHECK_(nullHandle)); + ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length, + CHECK_(nullHandle)); + _cp = constant_pool; // save in case of errors constantPoolHandle cp (THREAD, constant_pool); - ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. - // parsing constant pool entries - parse_constant_pool_entries(loader_data, cp, length, CHECK_(nullHandle)); + parse_constant_pool_entries(length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability @@ -373,8 +352,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); - check_property(valid_cp_range(klass_ref_index, length) && - is_klass_reference(cp, klass_ref_index), + check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK_(nullHandle)); @@ -404,16 +382,12 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int name_ref_index = cp->name_ref_index_at(index); int signature_ref_index = cp->signature_ref_index_at(index); - check_property( - valid_cp_range(name_ref_index, length) && - cp->tag_at(name_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - name_ref_index, CHECK_(nullHandle)); - check_property( - valid_cp_range(signature_ref_index, length) && - cp->tag_at(signature_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - signature_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(name_ref_index), + "Invalid constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(signature_ref_index), + "Invalid constant pool index %u in class file %s", + signature_ref_index, CHECK_(nullHandle)); break; } case JVM_CONSTANT_Utf8 : @@ -425,22 +399,18 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_ClassIndex : { int class_index = cp->klass_index_at(index); - check_property( - valid_cp_range(class_index, length) && - cp->tag_at(class_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - class_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(class_index), + "Invalid constant pool index %u in class file %s", + class_index, CHECK_(nullHandle)); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); } break; case JVM_CONSTANT_StringIndex : { int string_index = cp->string_index_at(index); - check_property( - valid_cp_range(string_index, length) && - cp->tag_at(string_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - string_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(string_index), + "Invalid constant pool index %u in class file %s", + string_index, CHECK_(nullHandle)); Symbol* sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); } @@ -491,12 +461,9 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_MethodType : { int ref_index = cp->method_type_index_at(index); - check_property( - valid_cp_range(ref_index, length) && - cp->tag_at(ref_index).is_utf8() && - EnableInvokeDynamic, - "Invalid constant pool index %u in class file %s", - ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(ref_index) && EnableInvokeDynamic, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); } break; case JVM_CONSTANT_InvokeDynamic : @@ -541,7 +508,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } if (!_need_verify) { - cp_in_error.set_in_error(false); return cp; } @@ -664,7 +630,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } // end of switch } // end of for - cp_in_error.set_in_error(false); return cp; } @@ -786,93 +751,92 @@ bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) { } -Array* ClassFileParser::parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, +Array* ClassFileParser::parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS) { - ClassFileStream* cfs = stream(); - assert(length > 0, "only called for length>0"); - // FIXME: Leak at later OOM. - Array* interfaces = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - - int index; - for (index = 0; index < length; index++) { - u2 interface_index = cfs->get_u2(CHECK_NULL); - KlassHandle interf; - check_property( - valid_cp_range(interface_index, cp->length()) && - is_klass_reference(cp, interface_index), - "Interface name has bad constant pool index %u in class file %s", - interface_index, CHECK_NULL); - if (cp->tag_at(interface_index).is_klass()) { - interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); - } else { - Symbol* unresolved_klass = cp->klass_name_at(interface_index); - - // Don't need to check legal name because it's checked when parsing constant pool. - // But need to make sure it's not an array type. - guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, - "Bad interface name in class file %s", CHECK_NULL); - Handle class_loader(THREAD, loader_data->class_loader()); - - // Call resolve_super so classcircularity is checked - Klass* k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_NULL); - interf = KlassHandle(THREAD, k); - } + if (length == 0) { + _local_interfaces = Universe::the_empty_klass_array(); + } else { + ClassFileStream* cfs = stream(); + assert(length > 0, "only called for length>0"); + _local_interfaces = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); - if (!interf()->is_interface()) { - THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); - } - if (InstanceKlass::cast(interf())->has_default_methods()) { - *has_default_methods = true; + int index; + for (index = 0; index < length; index++) { + u2 interface_index = cfs->get_u2(CHECK_NULL); + KlassHandle interf; + check_property( + valid_klass_reference_at(interface_index), + "Interface name has bad constant pool index %u in class file %s", + interface_index, CHECK_NULL); + if (_cp->tag_at(interface_index).is_klass()) { + interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index)); + } else { + Symbol* unresolved_klass = _cp->klass_name_at(interface_index); + + // Don't need to check legal name because it's checked when parsing constant pool. + // But need to make sure it's not an array type. + guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, + "Bad interface name in class file %s", CHECK_NULL); + Handle class_loader(THREAD, _loader_data->class_loader()); + + // Call resolve_super so classcircularity is checked + Klass* k = SystemDictionary::resolve_super_or_fail(class_name, + unresolved_klass, class_loader, protection_domain, + false, CHECK_NULL); + interf = KlassHandle(THREAD, k); + } + + if (!interf()->is_interface()) { + THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); + } + if (InstanceKlass::cast(interf())->has_default_methods()) { + *has_default_methods = true; + } + _local_interfaces->at_put(index, interf()); } - interfaces->at_put(index, interf()); - } - if (!_need_verify || length <= 1) { - return interfaces; - } + if (!_need_verify || length <= 1) { + return _local_interfaces; + } - // Check if there's any duplicates in interfaces - ResourceMark rm(THREAD); - NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, NameSigHash*, HASH_ROW_SIZE); - initialize_hashtable(interface_names); - bool dup = false; - { - debug_only(No_Safepoint_Verifier nsv;) - for (index = 0; index < length; index++) { - Klass* k = interfaces->at(index); - Symbol* name = InstanceKlass::cast(k)->name(); - // If no duplicates, add (name, NULL) in hashtable interface_names. - if (!put_after_lookup(name, NULL, interface_names)) { - dup = true; - break; + // Check if there's any duplicates in interfaces + ResourceMark rm(THREAD); + NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, NameSigHash*, HASH_ROW_SIZE); + initialize_hashtable(interface_names); + bool dup = false; + { + debug_only(No_Safepoint_Verifier nsv;) + for (index = 0; index < length; index++) { + Klass* k = _local_interfaces->at(index); + Symbol* name = InstanceKlass::cast(k)->name(); + // If no duplicates, add (name, NULL) in hashtable interface_names. + if (!put_after_lookup(name, NULL, interface_names)) { + dup = true; + break; + } } } + if (dup) { + classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + } } - if (dup) { - classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); - } - - return interfaces; + return _local_interfaces; } -void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) { +void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) { // Make sure the constant pool entry is of a type appropriate to this field guarantee_property( (constantvalue_index > 0 && - constantvalue_index < cp->length()), + constantvalue_index < _cp->length()), "Bad initial value index %u in ConstantValue attribute in class file %s", constantvalue_index, CHECK); - constantTag value_type = cp->tag_at(constantvalue_index); - switch ( cp->basic_type_for_signature_at(signature_index) ) { + constantTag value_type = _cp->tag_at(constantvalue_index); + switch ( _cp->basic_type_for_signature_at(signature_index) ) { case T_LONG: guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK); break; @@ -886,7 +850,7 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK); break; case T_OBJECT: - guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;") + guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;") && value_type.is_string()), "Bad string initial value in class file %s", CHECK); break; @@ -899,15 +863,11 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur // Parse attributes for a field. -void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - u2 attributes_count, +void ClassFileParser::parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); @@ -927,12 +887,11 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + check_property(valid_symbol_at(attribute_name_index), "Invalid field attribute index %u in class file %s", attribute_name_index, CHECK); - Symbol* attribute_name = cp->symbol_at(attribute_name_index); + Symbol* attribute_name = _cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { // ignore if non-static if (constantvalue_index != 0) { @@ -944,7 +903,7 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, attribute_length, CHECK); constantvalue_index = cfs->get_u2(CHECK); if (_need_verify) { - verify_constantvalue(constantvalue_index, signature_index, cp, CHECK); + verify_constantvalue(constantvalue_index, signature_index, CHECK); } } else if (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) { @@ -971,10 +930,8 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -1004,18 +961,18 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; - *field_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, + AnnotationArray* a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); - *field_type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); + parsed_annotations->set_field_annotations(a); + a = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + parsed_annotations->set_field_type_annotations(a); return; } @@ -1106,13 +1063,9 @@ class FieldAllocationCount: public ResourceObj { } }; -Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, +Array* ClassFileParser::parse_fields(Symbol* class_name, bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length @@ -1147,8 +1100,6 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); - AnnotationArray* field_annotations = NULL; - AnnotationArray* field_type_annotations = NULL; // The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; @@ -1161,53 +1112,52 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, access_flags.set_flags(flags); 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(), + int cp_size = _cp->length(); + check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", - name_index, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); + name_index, + CHECK_NULL); + Symbol* name = _cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); - check_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); - Symbol* sig = cp->symbol_at(signature_index); + Symbol* sig = _cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); - FieldAnnotationCollector parsed_annotations; + FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { - parse_field_attributes(loader_data, - cp, attributes_count, is_static, signature_index, + parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, - &generic_signature_index, &field_annotations, - &field_type_annotations, &parsed_annotations, + &generic_signature_index, &parsed_annotations, CHECK_NULL); - if (field_annotations != NULL) { - if (*fields_annotations == NULL) { - *fields_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_annotations() != NULL) { + if (_fields_annotations == NULL) { + _fields_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_annotations)->at_put(n, field_annotations); + _fields_annotations->at_put(n, parsed_annotations.field_annotations()); + parsed_annotations.set_field_annotations(NULL); } - if (field_type_annotations != NULL) { - if (*fields_type_annotations == NULL) { - *fields_type_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_type_annotations() != NULL) { + if (_fields_type_annotations == NULL) { + _fields_type_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_type_annotations)->at_put(n, field_type_annotations); + _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(); } @@ -1224,7 +1174,7 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, name_index, signature_index, constantvalue_index); - BasicType type = cp->basic_type_for_signature_at(signature_index); + BasicType type = _cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); @@ -1245,8 +1195,8 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool duplicate = false; for (int i = 0; i < length; i++) { FieldInfo* f = FieldInfo::from_field_array(fa, i); - if (name == cp->symbol_at(f->name_index()) && - signature == cp->symbol_at(f->signature_index())) { + if (name == _cp->symbol_at(f->name_index()) && + signature == _cp->symbol_at(f->signature_index())) { // Symbol is desclared in Java so skip this one duplicate = true; break; @@ -1280,8 +1230,9 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, // fields array is trimed. Also unused slots that were reserved // for generic signature indexes are discarded. Array* fields = MetadataFactory::new_array( - loader_data, index * FieldInfo::field_slots + num_generic_signature, + _loader_data, index * FieldInfo::field_slots + num_generic_signature, CHECK_NULL); + _fields = fields; // save in case of error { int i = 0; for (; i < index * FieldInfo::field_slots; i++) { @@ -1303,7 +1254,7 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) { Symbol* name = fs.name(); Symbol* sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. @@ -1330,10 +1281,8 @@ static void copy_u2_with_conversion(u2* dest, u2* src, int length) { } -u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, +u2* ClassFileParser::parse_exception_table(u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); @@ -1354,8 +1303,7 @@ u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, "Illegal exception table handler in class file %s", CHECK_NULL); if (catch_type_index != 0) { - guarantee_property(valid_cp_range(catch_type_index, cp->length()) && - is_klass_reference(cp, catch_type_index), + guarantee_property(valid_klass_reference_at(catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_NULL); } } @@ -1506,7 +1454,6 @@ void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt u2* ClassFileParser::parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, bool isLVTT, TRAPS) { @@ -1544,20 +1491,16 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, "Invalid length %u in %s in class file %s", length, tbl_name, CHECK_NULL); } - int cp_size = cp->length(); - guarantee_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + guarantee_property(valid_symbol_at(name_index), "Name index %u in %s has bad constant type in class file %s", name_index, tbl_name, CHECK_NULL); - guarantee_property( - valid_cp_range(descriptor_index, cp_size) && - cp->tag_at(descriptor_index).is_utf8(), + guarantee_property(valid_symbol_at(descriptor_index), "Signature index %u in %s has bad constant type in class file %s", descriptor_index, tbl_name, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); - Symbol* sig = cp->symbol_at(descriptor_index); + Symbol* name = _cp->symbol_at(name_index); + Symbol* sig = _cp->symbol_at(descriptor_index); verify_legal_field_name(name, CHECK_NULL); u2 extra_slot = 0; if (!isLVTT) { @@ -1579,7 +1522,7 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS) { + u1* u1_array, u2* u2_array, TRAPS) { ClassFileStream* cfs = stream(); u2 index = 0; // index in the array with long/double occupying two slots u4 i1 = *u1_index; @@ -1591,8 +1534,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i index++; } else if (tag == ITEM_Object) { u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); - guarantee_property(valid_cp_range(class_index, cp->length()) && - is_klass_reference(cp, class_index), + guarantee_property(valid_klass_reference_at(class_index), "Bad class index %u in StackMap in class file %s", class_index, CHECK); } else if (tag == ITEM_Uninitialized) { @@ -1613,8 +1555,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i *u2_index = i2; } -Array* ClassFileParser::parse_stackmap_table( - ClassLoaderData* loader_data, +u1* ClassFileParser::parse_stackmap_table( u4 code_attribute_length, TRAPS) { if (code_attribute_length == 0) return NULL; @@ -1629,18 +1570,12 @@ Array* ClassFileParser::parse_stackmap_table( if (!_need_verify && !DumpSharedSpaces) { return NULL; } - - Array* stackmap_data = - MetadataFactory::new_array(loader_data, code_attribute_length, 0, CHECK_NULL); - - memcpy((void*)stackmap_data->adr_at(0), - (void*)stackmap_table_start, code_attribute_length); - return stackmap_data; + return stackmap_table_start; } u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS) { + TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length *checked_exceptions_length = cfs->get_u2_fast(); @@ -1657,8 +1592,7 @@ u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); check_property( - valid_cp_range(checked_exception, cp->length()) && - is_klass_reference(cp, checked_exception), + valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } @@ -1735,9 +1669,7 @@ int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) { } // Sift through annotations, looking for those significant to the VM: -void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, - constantPoolHandle cp, +void ClassFileParser::parse_annotations(u1* buffer, int limit, ClassFileParser::AnnotationCollector* coll, TRAPS) { // annotations := do(nann:u2) {annotation} @@ -1767,17 +1699,17 @@ void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, u1* abase = buffer + index0; int atype = Bytes::get_Java_u2(abase + atype_off); int count = Bytes::get_Java_u2(abase + count_off); - Symbol* aname = check_symbol_at(cp, atype); + Symbol* aname = check_symbol_at(_cp, atype); if (aname == NULL) break; // invalid annotation name Symbol* member = NULL; if (count >= 1) { int member_index = Bytes::get_Java_u2(abase + member_off); - member = check_symbol_at(cp, member_index); + member = check_symbol_at(_cp, member_index); if (member == NULL) break; // invalid member name } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); + AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); @@ -1836,6 +1768,12 @@ void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { f->set_contended_group(contended_group()); } +ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() { + // If there's an error deallocate metadata for field annotations + MetadataFactory::free_array(_loader_data, _field_annotations); + MetadataFactory::free_array(_loader_data, _field_type_annotations); +} + void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { if (has_annotation(_method_ForceInline)) m->set_force_inline(true); @@ -1894,10 +1832,9 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, && _need_verify && _major_version >= JAVA_1_5_VERSION) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), + _cp->symbol_at(lvt->name_cp_index)->as_utf8(), CHECK); } } @@ -1916,18 +1853,16 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, if (entry == NULL) { if (_need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); 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(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTypeTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } else { // to add generic signatures into LocalVariableTable @@ -1939,8 +1874,7 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, } -void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, +void ClassFileParser::copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -1961,8 +1895,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_annotations_length + runtime_invisible_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_annotations, + a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, @@ -1972,8 +1905,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_parameter_annotations_length + runtime_invisible_parameter_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, + a = assemble_annotations(runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, runtime_invisible_parameter_annotations, runtime_invisible_parameter_annotations_length, @@ -1982,8 +1914,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, } if (annotation_default_length > 0) { - a = assemble_annotations(loader_data, - annotation_default, + a = assemble_annotations(annotation_default, annotation_default_length, NULL, 0, @@ -1993,8 +1924,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_type_annotations_length + runtime_invisible_type_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_type_annotations, + a = assemble_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, runtime_invisible_type_annotations, runtime_invisible_type_annotations_length, @@ -2013,9 +1943,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, // from the method back up to the containing klass. These flag values // are added to klass's access_flags. -methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +methodHandle ClassFileParser::parse_method(bool is_interface, AccessFlags *promoted_flags, TRAPS) { ClassFileStream* cfs = stream(); @@ -2026,22 +1954,20 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, int flags = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); + int cp_size = _cp->length(); check_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_(nullHandle)); - Symbol* name = cp->symbol_at(name_index); + Symbol* name = _cp->symbol_at(name_index); verify_legal_method_name(name, CHECK_(nullHandle)); u2 signature_index = cfs->get_u2_fast(); guarantee_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Illegal constant pool index %u for method signature in class file %s", signature_index, CHECK_(nullHandle)); - Symbol* signature = cp->symbol_at(signature_index); + Symbol* signature = _cp->symbol_at(signature_index); AccessFlags access_flags; if (name == vmSymbols::class_initializer_name()) { @@ -2097,7 +2023,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; // stackmap attribute - JDK1.5 - Array* stackmap_data = NULL; + u1* stackmap_data = NULL; + int stackmap_data_length = 0; u2 generic_signature_index = 0; MethodAnnotationCollector parsed_annotations; u1* runtime_visible_annotations = NULL; @@ -2122,12 +2049,11 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 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(), + valid_symbol_at(method_attribute_name_index), "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); + Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index); if (method_attribute_name == vmSymbols::tag_code()) { // Parse Code attribute if (_need_verify) { @@ -2171,7 +2097,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, exception_table_length = cfs->get_u2_fast(); if (exception_table_length > 0) { exception_table_start = - parse_exception_table(loader_data, code_length, exception_table_length, cp, CHECK_(nullHandle)); + parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle)); } // Parse additional attributes in code attribute @@ -2204,19 +2130,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 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(), + check_property(valid_symbol_at(code_attribute_name_index), "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()) { + _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()) { + _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( @@ -2238,7 +2163,6 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_table_length[lvt_cnt], false, // is not LVTT CHECK_(nullHandle)); @@ -2246,7 +2170,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, lvt_cnt++; } else if (LoadLocalVariableTypeTables && _major_version >= JAVA_1_5_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { + _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); @@ -2268,19 +2192,19 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 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()) { + _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)); } - stackmap_data = parse_stackmap_table(loader_data, code_attribute_length, CHECK_(nullHandle)); + stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle)); + stackmap_data_length = code_attribute_length; parsed_stackmap_attribute = true; } else { // Skip unknown attributes @@ -2301,7 +2225,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, checked_exceptions_start = parse_checked_exceptions(&checked_exceptions_length, method_attribute_length, - cp, CHECK_(nullHandle)); + CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { // reject multiple method parameters if (method_parameters_seen) { @@ -2359,9 +2283,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, cp, &parsed_annotations, + parse_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2434,18 +2357,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 0); Method* m = Method::allocate( - loader_data, code_length, access_flags, &sizes, + _loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); // Fill in information from fixed part (access_flags already set) - m->set_constants(cp()); + m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); #ifdef CC_INTERP // hmm is there a gc issue here?? - ResultTypeFinder rtf(cp->symbol_at(signature_index)); + ResultTypeFinder rtf(_cp->symbol_at(signature_index)); m->set_result_index(rtf.type()); #endif @@ -2464,7 +2387,10 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); - m->constMethod()->set_stackmap_data(stackmap_data); + if (stackmap_data != NULL) { + m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data, + stackmap_data_length, CHECK_NULL); + } // Copy byte codes m->set_code(code_start); @@ -2520,7 +2446,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parsed_annotations.apply_to(m); // Copy annotations - copy_method_annotations(loader_data, m->constMethod(), + copy_method_annotations(m->constMethod(), runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, @@ -2560,9 +2486,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // from the methods back up to the containing klass. These flag values // are added to klass's access_flags. -Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +Array* ClassFileParser::parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_methods, @@ -2571,15 +2495,13 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { - return Universe::the_empty_method_array(); + _methods = Universe::the_empty_method_array(); } else { - // FIXME: Handle leaks at later failures. - Array* methods = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + _methods = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); HandleMark hm(THREAD); for (int index = 0; index < length; index++) { - methodHandle method = parse_method(loader_data, - cp, is_interface, + methodHandle method = parse_method(is_interface, promoted_flags, CHECK_NULL); @@ -2590,7 +2512,7 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, // default method *has_default_methods = true; } - methods->at_put(index, method()); + _methods->at_put(index, method()); } if (_need_verify && length > 1) { @@ -2603,7 +2525,7 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { - Method* m = methods->at(i); + Method* m = _methods->at(i); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { dup = true; @@ -2616,14 +2538,12 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, CHECK_NULL); } } - return methods; } + return _methods; } -Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS) { +intArray* ClassFileParser::sort_methods(Array* methods) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2641,10 +2561,11 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, // Note that the ordering is not alphabetical, see Symbol::fast_compare Method::sort_methods(methods); + intArray* method_ordering = NULL; // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { - Array* method_ordering = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + method_ordering = new intArray(length); for (int index = 0; index < length; index++) { Method* m = methods->at(index); int old_index = m->vtable_index(); @@ -2652,29 +2573,25 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, method_ordering->at_put(index, old_index); m->set_vtable_index(Method::invalid_vtable_index); } - return method_ordering; - } else { - return Universe::the_empty_int_array(); } + return method_ordering; } -void ClassFileParser::parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK); // sourcefile_index u2 sourcefile_index = cfs->get_u2_fast(); check_property( - valid_cp_range(sourcefile_index, cp->length()) && - cp->tag_at(sourcefile_index).is_utf8(), + valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); - set_class_sourcefile(cp->symbol_at(sourcefile_index)); + set_class_sourcefile(_cp->symbol_at(sourcefile_index)); } -void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS) { +void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) { ClassFileStream* cfs = stream(); u1* sde_buffer = cfs->get_u1_buffer(); assert(sde_buffer != NULL, "null sde buffer"); @@ -2698,12 +2615,10 @@ void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantP #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) // Return number of classes in the inner classes attribute table -u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, +u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u1* current_mark = cfs->current(); @@ -2724,33 +2639,31 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa // enclosing_method_class_index, // enclosing_method_method_index] int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); - // FIXME: Will leak on exceptions. - Array* inner_classes = MetadataFactory::new_array(loader_data, size, CHECK_0); + Array* inner_classes = MetadataFactory::new_array(_loader_data, size, CHECK_0); + _inner_classes = inner_classes; + int index = 0; - int cp_size = cp->length(); + int cp_size = _cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 for (int n = 0; n < length; n++) { // Inner class index u2 inner_class_info_index = cfs->get_u2_fast(); check_property( inner_class_info_index == 0 || - (valid_cp_range(inner_class_info_index, cp_size) && - is_klass_reference(cp, inner_class_info_index)), + valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index u2 outer_class_info_index = cfs->get_u2_fast(); check_property( outer_class_info_index == 0 || - (valid_cp_range(outer_class_info_index, cp_size) && - is_klass_reference(cp, outer_class_info_index)), + valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name u2 inner_name_index = cfs->get_u2_fast(); check_property( - inner_name_index == 0 || (valid_cp_range(inner_name_index, cp_size) && - cp->tag_at(inner_name_index).is_utf8()), + inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); if (_need_verify) { @@ -2794,33 +2707,27 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa } assert(index == size, "wrong size"); - // Update InstanceKlass with inner class info. - set_class_inner_classes(inner_classes); - // Restore buffer's current position. cfs->set_current(current_mark); return length; } -void ClassFileParser::parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) { set_class_synthetic_flag(true); } -void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_signature_attribute(TRAPS) { ClassFileStream* cfs = stream(); u2 signature_index = cfs->get_u2(CHECK); check_property( - valid_cp_range(signature_index, cp->length()) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); - set_class_generic_signature(cp->symbol_at(signature_index)); + set_class_generic_signature(_cp->symbol_at(signature_index)); } -void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, - constantPoolHandle cp, - u4 attribute_byte_length, TRAPS) { +void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) { ClassFileStream* cfs = stream(); u1* current_start = cfs->current(); @@ -2841,10 +2748,14 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat // The array begins with a series of short[2] pairs, one for each tuple. int index_size = (attribute_array_length * 2); - Array* operands = MetadataFactory::new_array(loader_data, index_size + operand_count, CHECK); + Array* operands = MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK); + + // Eagerly assign operands so they will be deallocated with the constant + // pool if there is an error. + _cp->set_operands(operands); int operand_fill_index = index_size; - int cp_size = cp->length(); + int cp_size = _cp->length(); for (int n = 0; n < attribute_array_length; n++) { // Store a 32-bit offset into the header of the operand array. @@ -2856,7 +2767,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_count = cfs->get_u2_fast(); check_property( valid_cp_range(bootstrap_method_index, cp_size) && - cp->tag_at(bootstrap_method_index).is_method_handle(), + _cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", bootstrap_method_index, CHECK); @@ -2868,7 +2779,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_index = cfs->get_u2_fast(); check_property( valid_cp_range(argument_index, cp_size) && - cp->tag_at(argument_index).is_loadable_constant(), + _cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", argument_index, CHECK); @@ -2883,17 +2794,13 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat guarantee_property(current_end == current_start + attribute_byte_length, "Bad length on BootstrapMethods in class file %s", CHECK); - - cp->set_operands(operands); } -void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassFileParser::ClassAnnotationCollector* parsed_annotations, +void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel - set_class_inner_classes(Universe::the_empty_short_array()); + _inner_classes = Universe::the_empty_short_array(); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); bool parsed_sourcefile_attribute = false; @@ -2918,11 +2825,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); - Symbol* tag = cp->symbol_at(attribute_name_index); + Symbol* tag = _cp->symbol_at(attribute_name_index); if (tag == vmSymbols::tag_source_file()) { // Check for SourceFile tag if (_need_verify) { @@ -2933,10 +2839,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, } else { parsed_sourcefile_attribute = true; } - parse_classfile_sourcefile_attribute(cp, CHECK); + parse_classfile_sourcefile_attribute(CHECK); } else if (tag == vmSymbols::tag_source_debug_extension()) { // Check for SourceDebugExtension tag - parse_classfile_source_debug_extension_attribute(cp, (int)attribute_length, CHECK); + parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK); } else if (tag == vmSymbols::tag_inner_classes()) { // Check for InnerClasses tag if (parsed_innerclasses_attribute) { @@ -2955,7 +2861,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Invalid Synthetic classfile attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_synthetic_attribute(cp, CHECK); + parse_classfile_synthetic_attribute(CHECK); } else if (tag == vmSymbols::tag_deprecated()) { // Check for Deprecatd tag - 4276120 if (attribute_length != 0) { @@ -2970,15 +2876,13 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Wrong Signature attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_signature_attribute(cp, CHECK); + parse_classfile_signature_attribute(CHECK); } else if (tag == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -3000,13 +2904,11 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, classfile_parse_error("Invalid class index in EnclosingMethod attribute in class file %s", CHECK); } // Validate the constant pool indices and types - if (!cp->is_within_bounds(enclosing_method_class_index) || - !is_klass_reference(cp, enclosing_method_class_index)) { - classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); - } + check_property(valid_klass_reference_at(enclosing_method_class_index), + "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && - (!cp->is_within_bounds(enclosing_method_method_index) || - !cp->tag_at(enclosing_method_method_index).is_name_and_type())) { + (!_cp->is_within_bounds(enclosing_method_method_index) || + !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) { classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } } else if (tag == vmSymbols::tag_bootstrap_methods() && @@ -3014,7 +2916,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, if (parsed_bootstrap_methods_attribute) classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); parsed_bootstrap_methods_attribute = true; - parse_classfile_bootstrap_methods_attribute(loader_data, cp, attribute_length, CHECK); + parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK); } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) { runtime_visible_type_annotations_length = attribute_length; runtime_visible_type_annotations = cfs->get_u1_buffer(); @@ -3035,29 +2937,24 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, cfs->skip_u1(attribute_length, CHECK); } } - AnnotationArray* annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK); - set_class_annotations(annotations); - AnnotationArray* type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); - set_class_type_annotations(type_annotations); + _annotations = assemble_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + _type_annotations = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( - loader_data, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, enclosing_method_method_index, - cp, CHECK); + CHECK); if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) { guarantee_property( inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes, @@ -3085,18 +2982,43 @@ void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) { if (_sde_buffer != NULL) { k->set_source_debug_extension(_sde_buffer, _sde_length); } - k->set_inner_classes(_inner_classes); } -AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, +// Transfer ownership of metadata allocated to the InstanceKlass. +void ClassFileParser::apply_parsed_class_metadata( + instanceKlassHandle this_klass, + int java_fields_count, TRAPS) { + // Assign annotations if needed + if (_annotations != NULL || _type_annotations != NULL || + _fields_annotations != NULL || _fields_type_annotations != NULL) { + Annotations* annotations = Annotations::allocate(_loader_data, CHECK); + annotations->set_class_annotations(_annotations); + annotations->set_class_type_annotations(_type_annotations); + annotations->set_fields_annotations(_fields_annotations); + annotations->set_fields_type_annotations(_fields_type_annotations); + this_klass->set_annotations(annotations); + } + + _cp->set_pool_holder(this_klass()); + this_klass->set_constants(_cp); + this_klass->set_fields(_fields, java_fields_count); + this_klass->set_methods(_methods); + this_klass->set_inner_classes(_inner_classes); + this_klass->set_local_interfaces(_local_interfaces); + this_klass->set_transitive_interfaces(_transitive_interfaces); + + // Clear out these fields so they don't get deallocated by the destructor + clear_class_metadata(); +} + +AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS) { AnnotationArray* annotations = NULL; if (runtime_visible_annotations != NULL || runtime_invisible_annotations != NULL) { - annotations = MetadataFactory::new_array(loader_data, + annotations = MetadataFactory::new_array(_loader_data, runtime_visible_annotations_length + runtime_invisible_annotations_length, CHECK_(annotations)); @@ -3144,6 +3066,581 @@ static void parseAndPrintGenericSignatures( #endif // ndef PRODUCT +instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index, + TRAPS) { + instanceKlassHandle super_klass; + 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_NULL); + } else { + check_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + // 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_NULL); + } + } + return super_klass; +} + + +// Values needed for oopmap and InstanceKlass creation +class FieldLayoutInfo : public StackObj { + public: + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count; + unsigned int total_oop_map_count; + int instance_size; + int nonstatic_field_size; + int static_field_size; + bool has_nonstatic_fields; +}; + +// Layout fields and fill in FieldLayoutInfo. Could use more refactoring! +void ClassFileParser::layout_fields(Handle class_loader, + FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, + TRAPS) { + + // get the padding width from the option + // TODO: Ask VM about specific CPU we are running on + int pad_size = ContendedPaddingWidth; + + // 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 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_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; + int next_nonstatic_padded_offset; + + // Count the contended fields by type. + int nonstatic_contended_count = 0; + FieldAllocationCount fac_contended; + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + if (fs.is_contended()) { + fac_contended.count[atype]++; + if (!fs.access_flags().is_static()) { + nonstatic_contended_count++; + } + } + } + int contended_count = nonstatic_contended_count; + + + // Calculate the starting byte offsets + next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); + next_static_double_offset = next_static_oop_offset + + ((fac->count[STATIC_OOP]) * heapOopSize); + if ( fac->count[STATIC_DOUBLE] && + (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->count[STATIC_DOUBLE]) * BytesPerLong); + next_static_short_offset = next_static_word_offset + + ((fac->count[STATIC_WORD]) * BytesPerInt); + next_static_byte_offset = next_static_short_offset + + ((fac->count[STATIC_SHORT]) * BytesPerShort); + + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + + // class is contended, pad before all the fields + if (parsed_annotations->is_contended()) { + first_nonstatic_field_offset += pad_size; + } + + next_nonstatic_field_offset = first_nonstatic_field_offset; + + unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; + unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; + unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; + unsigned int nonstatic_byte_count = fac->count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; + unsigned int nonstatic_oop_count = fac->count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; + + 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); + + 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, padded fields + 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, padded fields + 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 ) { + unsigned int map_count = _super_klass->nonstatic_oop_map_count(); + OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps(); + OopMapBlock* last_map = first_map + map_count - 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); + next_nonstatic_padded_offset = next_nonstatic_byte_offset + + nonstatic_byte_count; + + // let oops jump before padding with this allocation style + if( allocation_style == 1 ) { + next_nonstatic_oop_offset = next_nonstatic_padded_offset; + if( nonstatic_oop_count > 0 ) { + next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); + } + next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * 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). + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // contended instance fields are handled below + if (fs.is_contended() && !fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + // pack the rest of the fields + 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_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_DOUBLE: + real_offset = next_nonstatic_double_offset; + next_nonstatic_double_offset += BytesPerLong; + break; + default: + ShouldNotReachHere(); + } + fs.set_offset(real_offset); + } + + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contended_count > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + if (nonstatic_contended_count > 0) { + next_nonstatic_padded_offset += pad_size; + } + + // collect all contended groups + BitMap bm(_cp->size()); + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + // skip already laid out fields + if (fs.is_offset_set()) continue; + + if (fs.is_contended()) { + bm.set_bit(fs.contended_group()); + } + } + + int current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // handle statics below + if (fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + case NONSTATIC_BYTE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += 1; + break; + + case NONSTATIC_SHORT: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerShort; + break; + + case NONSTATIC_WORD: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerInt; + break; + + case NONSTATIC_DOUBLE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerLong; + break; + + case NONSTATIC_OOP: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += heapOopSize; + + // 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; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_nonstatic_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_nonstatic_padded_offset += pad_size; + } + } + + // handle static fields + } + + // Size of instances + int notaligned_offset = next_nonstatic_padded_offset; + + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (parsed_annotations->is_contended()) { + notaligned_offset += pad_size; + } + + int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); + int static_field_size = (next_static_type_offset - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + + 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); + + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); + int 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 + ((parsed_annotations->is_contended()) ? pad_size : 0)), + wordSize) / wordSize), "consistent layout helper value"); + + // 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); + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + ResourceMark rm; + 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, + _class_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, + _class_name); + } + } + + if (PrintFieldLayout) { + print_field_layout(_class_name, + _fields, + _cp, + instance_size, + first_nonstatic_field_offset, + next_nonstatic_field_offset, + next_static_type_offset); + } + +#endif + // Pass back information needed for InstanceKlass creation + info->nonstatic_oop_offsets = nonstatic_oop_offsets; + info->nonstatic_oop_counts = nonstatic_oop_counts; + info->nonstatic_oop_map_count = nonstatic_oop_map_count; + info->total_oop_map_count = total_oop_map_count; + info->instance_size = instance_size; + info->static_field_size = static_field_size; + info->nonstatic_field_size = nonstatic_field_size; + info->has_nonstatic_fields = has_nonstatic_fields; +} + + instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, @@ -3176,7 +3673,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::PARSE_CLASS); - init_parsed_class_attributes(); + init_parsed_class_attributes(loader_data); if (JvmtiExport::should_post_class_file_load_hook()) { // Get the cached class file bytes (if any) from the class that @@ -3271,8 +3768,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool - constantPoolHandle cp = parse_constant_pool(loader_data, CHECK_(nullHandle)); - ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. + constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); int cp_size = cp->length(); @@ -3290,7 +3786,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, access_flags.set_flags(flags); // This class and superclass - instanceKlassHandle super_klass; u2 this_class_index = cfs->get_u2_fast(); check_property( valid_cp_range(this_class_index, cp_size) && @@ -3345,59 +3840,27 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } u2 super_class_index = cfs->get_u2_fast(); - 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)); - } 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)); - } - } + instanceKlassHandle super_klass = parse_super_class(super_class_index, + CHECK_NULL); // Interfaces u2 itfs_len = cfs->get_u2_fast(); - Array* local_interfaces; - if (itfs_len == 0) { - local_interfaces = Universe::the_empty_klass_array(); - } else { - local_interfaces = parse_interfaces( - cp, itfs_len, loader_data, protection_domain, _class_name, - &has_default_methods, CHECK_(nullHandle)); - } + Array* local_interfaces = + parse_interfaces(itfs_len, protection_domain, _class_name, + &has_default_methods, CHECK_(nullHandle)); u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; - Array* fields_annotations = NULL; - Array* fields_type_annotations = NULL; - Array* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations, - &fields_type_annotations, - &java_fields_count, - CHECK_(nullHandle)); + Array* fields = parse_fields(class_name, + access_flags.is_interface(), + &fac, &java_fields_count, + CHECK_(nullHandle)); // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - Array* methods = parse_methods(loader_data, - cp, access_flags.is_interface(), + Array* methods = parse_methods(access_flags.is_interface(), &promoted_flags, &has_final_method, &has_default_methods, @@ -3405,7 +3868,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Additional attributes ClassAnnotationCollector parsed_annotations; - parse_classfile_attributes(loader_data, cp, &parsed_annotations, CHECK_(nullHandle)); + parse_classfile_attributes(&parsed_annotations, 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)); @@ -3452,13 +3915,15 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } + // save super klass for error handling. + _super_klass = super_klass; + // Compute the transitive list of all unique interfaces implemented by this class - Array* transitive_interfaces = compute_transitive_interfaces(loader_data, super_klass, local_interfaces, CHECK_(nullHandle)); + _transitive_interfaces = + compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle)); // sort methods - Array* method_ordering = sort_methods(loader_data, - methods, - CHECK_(nullHandle)); + intArray* method_ordering = sort_methods(methods); // promote flags from parse_methods() to the klass' flags access_flags.add_promoted_flags(promoted_flags.as_int()); @@ -3476,495 +3941,14 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, CHECK_(nullHandle)); // Size of Java itable (in words) - itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); - - // get the padding width from the option - // TODO: Ask VM about specific CPU we are running on - int pad_size = ContendedPaddingWidth; - - // 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 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_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; - int next_nonstatic_padded_offset; - - // Count the contended fields by type. - int nonstatic_contended_count = 0; - FieldAllocationCount fac_contended; - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - if (fs.is_contended()) { - fac_contended.count[atype]++; - if (!fs.access_flags().is_static()) { - nonstatic_contended_count++; - } - } - } - int contended_count = nonstatic_contended_count; - - - // Calculate the starting byte offsets - next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); - - next_static_double_offset = next_static_oop_offset + - ((fac.count[STATIC_OOP]) * heapOopSize); - if ( fac.count[STATIC_DOUBLE] && - (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.count[STATIC_DOUBLE]) * BytesPerLong); - next_static_short_offset = next_static_word_offset + - ((fac.count[STATIC_WORD]) * BytesPerInt); - next_static_byte_offset = next_static_short_offset + - ((fac.count[STATIC_SHORT]) * BytesPerShort); - - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - first_nonstatic_field_offset += pad_size; - } - - next_nonstatic_field_offset = first_nonstatic_field_offset; - - unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; - unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; - unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; - unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; - unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; - - 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); - - 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 - } + itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); - if( allocation_style == 0 ) { - // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields - 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, padded fields - 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_count = super_klass->nonstatic_oop_map_count(); - OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); - OopMapBlock* last_map = first_map + map_count - 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(); - } + FieldLayoutInfo info; + layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL); - 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); - next_nonstatic_padded_offset = next_nonstatic_byte_offset + - nonstatic_byte_count; - - // let oops jump before padding with this allocation style - if( allocation_style == 1 ) { - next_nonstatic_oop_offset = next_nonstatic_padded_offset; - if( nonstatic_oop_count > 0 ) { - next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); - } - next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * 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). - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // contended instance fields are handled below - if (fs.is_contended() && !fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - // pack the rest of the fields - 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_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_DOUBLE: - real_offset = next_nonstatic_double_offset; - next_nonstatic_double_offset += BytesPerLong; - break; - default: - ShouldNotReachHere(); - } - fs.set_offset(real_offset); - } - - - // Handle the contended cases. - // - // Each contended field should not intersect the cache line with another contended field. - // In the absence of alignment information, we end up with pessimistically separating - // the fields with full-width padding. - // - // Additionally, this should not break alignment for the fields, so we round the alignment up - // for each field. - if (contended_count > 0) { - - // if there is at least one contended field, we need to have pre-padding for them - if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += pad_size; - } - - // collect all contended groups - BitMap bm(cp->size()); - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - // skip already laid out fields - if (fs.is_offset_set()) continue; - - if (fs.is_contended()) { - bm.set_bit(fs.contended_group()); - } - } - - int current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // handle statics below - if (fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - case NONSTATIC_BYTE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += 1; - break; - - case NONSTATIC_SHORT: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerShort; - break; - - case NONSTATIC_WORD: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerInt; - break; - - case NONSTATIC_DOUBLE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerLong; - break; - - case NONSTATIC_OOP: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += heapOopSize; - - // 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; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_nonstatic_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_nonstatic_padded_offset += pad_size; - } - } - - // handle static fields - - } // handle contended - - // Size of instances - int instance_size; - - int notaligned_offset = next_nonstatic_padded_offset; - - // Entire class is contended, pad in the back. - // This helps to alleviate memory contention effects for subclass fields - // and/or adjacent object. - if (parsed_annotations.is_contended()) { - notaligned_offset += pad_size; - } - - int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); - int static_field_size = (next_static_type_offset - - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; - - 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); - - 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 + ((parsed_annotations.is_contended()) ? pad_size : 0)), - wordSize) / wordSize), "consistent layout helper value"); + int total_oop_map_size2 = + InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count); - // 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); // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -3974,53 +3958,42 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } // We can now create the basic Klass* for this klass - int total_oop_map_size2 = - InstanceKlass::nonstatic_oop_map_size(total_oop_map_count); - - Klass* ik = InstanceKlass::allocate_instance_klass(loader_data, - vtable_size, - itable_size, - static_field_size, - total_oop_map_size2, - rt, - access_flags, - name, - super_klass(), - !host_klass.is_null(), - CHECK_(nullHandle)); - - // Add all classes to our internal class loader list here, - // including classes in the bootstrap (NULL) class loader. - loader_data->add_class(ik); - - instanceKlassHandle this_klass (THREAD, ik); - - assert(this_klass->static_field_size() == static_field_size, "sanity"); - assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count, + _klass = InstanceKlass::allocate_instance_klass(loader_data, + vtable_size, + itable_size, + info.static_field_size, + total_oop_map_size2, + rt, + access_flags, + name, + super_klass(), + !host_klass.is_null(), + CHECK_(nullHandle)); + instanceKlassHandle this_klass (THREAD, _klass); + + assert(this_klass->static_field_size() == info.static_field_size, "sanity"); + assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count, "sanity"); // Fill in information already parsed this_klass->set_should_verify_class(verify); - jint lh = Klass::instance_layout_helper(instance_size, false); + jint lh = Klass::instance_layout_helper(info.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"); + assert(this_klass->size_helper() == info.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_data(loader_data); - this_klass->set_nonstatic_field_size(nonstatic_field_size); - this_klass->set_has_nonstatic_fields(has_nonstatic_fields); + this_klass->set_nonstatic_field_size(info.nonstatic_field_size); + this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); - 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, java_fields_count); - this_klass->set_methods(methods); + + apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL); + if (has_final_method) { this_klass->set_has_final_method(); } - this_klass->set_method_ordering(method_ordering); + this_klass->copy_method_ordering(method_ordering, CHECK_NULL); // The InstanceKlass::_methods_jmethod_ids cache and the // InstanceKlass::_methods_cached_itable_indices cache are // both managed on the assumption that the initial cache @@ -4032,17 +4005,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Assign allocations if needed - if (_annotations != NULL || _type_annotations != NULL || - fields_annotations != NULL || fields_type_annotations != NULL) { - Annotations* annotations = Annotations::allocate(loader_data, CHECK_NULL); - annotations->set_class_annotations(_annotations); - annotations->set_class_type_annotations(_type_annotations); - annotations->set_fields_annotations(fields_annotations); - annotations->set_fields_type_annotations(fields_type_annotations); - this_klass->set_annotations(annotations); - } - this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); @@ -4077,8 +4039,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, this_klass->set_has_miranda_methods(); // then set a flag } - this_klass->set_transitive_interfaces(transitive_interfaces); - // Fill in information needed to compute superclasses. this_klass->initialize_supers(super_klass(), CHECK_(nullHandle)); @@ -4087,7 +4047,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Compute transitive closure of interfaces this class implements // Do final class setup - fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); + fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper set_precomputed_flags(this_klass); @@ -4186,35 +4146,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - ResourceMark rm; - 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 - -#ifndef PRODUCT - if (PrintFieldLayout) { - print_field_layout(name, - fields, - cp, - instance_size, - first_nonstatic_field_offset, - next_nonstatic_field_offset, - next_static_type_offset); - } -#endif - // preserve result across HandleMark preserve_this_klass = this_klass(); } @@ -4224,9 +4155,40 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, instanceKlassHandle this_klass (THREAD, preserve_this_klass); debug_only(this_klass->verify();) + // Clear class if no error has occurred so destructor doesn't deallocate it + _klass = NULL; return this_klass; } +// Destructor to clean up if there's an error +ClassFileParser::~ClassFileParser() { + MetadataFactory::free_metadata(_loader_data, _cp); + MetadataFactory::free_array(_loader_data, _fields); + + // Free methods + InstanceKlass::deallocate_methods(_loader_data, _methods); + + // beware of the Universe::empty_blah_array!! + if (_inner_classes != Universe::the_empty_short_array()) { + MetadataFactory::free_array(_loader_data, _inner_classes); + } + + // Free interfaces + InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(), + _local_interfaces, _transitive_interfaces); + + MetadataFactory::free_array(_loader_data, _annotations); + MetadataFactory::free_array(_loader_data, _type_annotations); + Annotations::free_contents(_loader_data, _fields_annotations); + Annotations::free_contents(_loader_data, _fields_type_annotations); + + clear_class_metadata(); + + // deallocate the klass if already created. + MetadataFactory::free_metadata(_loader_data, _klass); + _klass = NULL; +} + void ClassFileParser::print_field_layout(Symbol* name, Array* fields, constantPoolHandle cp, @@ -4418,7 +4380,7 @@ void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defi } } -// utility method for appending and array with check for duplicates +// utility methods for appending an array with check for duplicates void append_interfaces(GrowableArray* result, Array* ifs) { // iterate over new interfaces @@ -4430,8 +4392,9 @@ void append_interfaces(GrowableArray* result, Array* ifs) { } } - -Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* loader_data, instanceKlassHandle super, Array* local_ifs, TRAPS) { +Array* ClassFileParser::compute_transitive_interfaces( + instanceKlassHandle super, + Array* local_ifs, TRAPS) { // Compute maximum size for transitive interfaces int max_transitive_size = 0; int super_size = 0; @@ -4478,7 +4441,7 @@ Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l // length will be less than the max_transitive_size if duplicates were removed int length = result->length(); assert(length <= max_transitive_size, "just checking"); - Array* new_result = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + Array* new_result = MetadataFactory::new_array(_loader_data, length, CHECK_NULL); for (int i = 0; i < length; i++) { Klass* e = result->at(i); assert(e != NULL, "just checking"); @@ -4488,7 +4451,6 @@ Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l } } - void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); if ((super != NULL) && diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp index 7cedcefb3..0fd883046 100644 --- a/src/share/vm/classfile/classFileParser.hpp +++ b/src/share/vm/classfile/classFileParser.hpp @@ -34,6 +34,7 @@ #include "classfile/symbolTable.hpp" class FieldAllocationCount; +class FieldLayoutInfo; // Parser for for .class files @@ -47,6 +48,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2 _major_version; u2 _minor_version; Symbol* _class_name; + ClassLoaderData* _loader_data; KlassHandle _host_klass; GrowableArray* _cp_patches; // overrides for CP entries @@ -58,33 +60,59 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // class attributes parsed before the instance klass is created: bool _synthetic_flag; + int _sde_length; + char* _sde_buffer; Symbol* _sourcefile; Symbol* _generic_signature; - char* _sde_buffer; - int _sde_length; - Array* _inner_classes; + + // Metadata created before the instance klass is created. Must be deallocated + // if not transferred to the InstanceKlass upon successful class loading + // in which case these pointers have been set to NULL. + instanceKlassHandle _super_klass; + ConstantPool* _cp; + Array* _fields; + Array* _methods; + Array* _inner_classes; + Array* _local_interfaces; + Array* _transitive_interfaces; AnnotationArray* _annotations; AnnotationArray* _type_annotations; + Array* _fields_annotations; + Array* _fields_type_annotations; + InstanceKlass* _klass; // InstanceKlass once created. void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } void set_class_sourcefile(Symbol* x) { _sourcefile = x; } void set_class_generic_signature(Symbol* x) { _generic_signature = x; } void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } - void set_class_inner_classes(Array* x) { _inner_classes = x; } - void set_class_annotations(AnnotationArray* x) { _annotations = x; } - void set_class_type_annotations(AnnotationArray* x) { _type_annotations = x; } - void init_parsed_class_attributes() { + + void init_parsed_class_attributes(ClassLoaderData* loader_data) { + _loader_data = loader_data; _synthetic_flag = false; _sourcefile = NULL; _generic_signature = NULL; _sde_buffer = NULL; _sde_length = 0; - _annotations = _type_annotations = NULL; // initialize the other flags too: _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; _max_bootstrap_specifier_index = -1; + clear_class_metadata(); + _klass = NULL; } void apply_parsed_class_attributes(instanceKlassHandle k); // update k + void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS); + void clear_class_metadata() { + // metadata created before the instance klass is created. Must be + // deallocated if classfile parsing returns an error. + _cp = NULL; + _fields = NULL; + _methods = NULL; + _inner_classes = NULL; + _local_interfaces = NULL; + _transitive_interfaces = NULL; + _annotations = _type_annotations = NULL; + _fields_annotations = _fields_type_annotations = NULL; + } class AnnotationCollector { public: @@ -124,11 +152,27 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } bool is_contended() { return has_annotation(_sun_misc_Contended); } }; + + // This class also doubles as a holder for metadata cleanup. class FieldAnnotationCollector: public AnnotationCollector { + ClassLoaderData* _loader_data; + AnnotationArray* _field_annotations; + AnnotationArray* _field_type_annotations; public: - FieldAnnotationCollector() : AnnotationCollector(_in_field) { } + FieldAnnotationCollector(ClassLoaderData* loader_data) : + AnnotationCollector(_in_field), + _loader_data(loader_data), + _field_annotations(NULL), + _field_type_annotations(NULL) {} void apply_to(FieldInfo* f); + ~FieldAnnotationCollector(); + AnnotationArray* field_annotations() { return _field_annotations; } + AnnotationArray* field_type_annotations() { return _field_type_annotations; } + + void set_field_annotations(AnnotationArray* a) { _field_annotations = a; } + void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; } }; + class MethodAnnotationCollector: public AnnotationCollector { public: MethodAnnotationCollector() : AnnotationCollector(_in_method) { } @@ -152,38 +196,30 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_stream(ClassFileStream* st) { _stream = st; } // Constant pool parsing - void parse_constant_pool_entries(ClassLoaderData* loader_data, - constantPoolHandle cp, int length, TRAPS); + void parse_constant_pool_entries(int length, TRAPS); - constantPoolHandle parse_constant_pool(ClassLoaderData* loader_data, TRAPS); + constantPoolHandle parse_constant_pool(TRAPS); // Interface parsing - Array* parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, + Array* parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS); void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); + instanceKlassHandle parse_super_class(int super_class_index, TRAPS); // Field parsing - void parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, u2 attributes_count, + void parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, FieldAnnotationCollector* parsed_annotations, TRAPS); - Array* parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, bool is_interface, + Array* parse_fields(Symbol* class_name, + bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS); void print_field_layout(Symbol* name, @@ -195,65 +231,52 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int static_fields_end); // Method parsing - methodHandle parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + methodHandle parse_method(bool is_interface, AccessFlags* promoted_flags, TRAPS); - Array* parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + Array* parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_method, TRAPS); - Array* sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS); - u2* parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS); + intArray* sort_methods(Array* methods); + + u2* parse_exception_table(u4 code_length, u4 exception_table_length, + TRAPS); void parse_linenumber_table( u4 code_attribute_length, u4 code_length, CompressedLineNumberWriteStream** write_stream, TRAPS); u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, + u2* localvariable_table_length, bool isLVTT, TRAPS); u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS); + TRAPS); void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS); - Array* parse_stackmap_table(ClassLoaderData* loader_data, u4 code_attribute_length, TRAPS); + u1* u1_array, u2* u2_array, TRAPS); + u1* parse_stackmap_table(u4 code_attribute_length, TRAPS); // Classfile attribute parsing - void parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS); - u2 parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, + void parse_classfile_sourcefile_attribute(TRAPS); + void parse_classfile_source_debug_extension_attribute(int length, TRAPS); + u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS); - void parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassAnnotationCollector* parsed_annotations, + void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations, TRAPS); - void parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, constantPoolHandle cp, u4 attribute_length, TRAPS); + void parse_classfile_synthetic_attribute(TRAPS); + void parse_classfile_signature_attribute(TRAPS); + void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS); // Annotations handling - AnnotationArray* assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, + AnnotationArray* assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS); int skip_annotation(u1* buffer, int limit, int index); int skip_annotation_value(u1* buffer, int limit, int index); - void parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, constantPoolHandle cp, + void parse_annotations(u1* buffer, int limit, /* Results (currently, only one result is supported): */ AnnotationCollector* result, TRAPS); @@ -267,8 +290,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); void set_precomputed_flags(instanceKlassHandle k); - Array* compute_transitive_interfaces(ClassLoaderData* loader_data, - instanceKlassHandle super, + Array* compute_transitive_interfaces(instanceKlassHandle super, Array* local_ifs, TRAPS); // Format checker methods @@ -318,7 +340,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { bool is_supported_version(u2 major, u2 minor); bool has_illegal_visibility(jint flags); - void verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS); + void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS); void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS); void verify_legal_class_name(Symbol* name, TRAPS); void verify_legal_field_name(Symbol* name, TRAPS); @@ -359,10 +381,17 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // In older versions of the VM, Klass*s cannot sneak into early phases of // constant pool construction, but in later versions they can. // %%% Let's phase out the old is_klass_reference. - bool is_klass_reference(constantPoolHandle cp, int index) { - return (EnableInvokeDynamic - ? cp->tag_at(index).is_klass_or_reference() - : cp->tag_at(index).is_klass_reference()); + bool valid_klass_reference_at(int index) { + return _cp->is_within_bounds(index) && + (EnableInvokeDynamic + ? _cp->tag_at(index).is_klass_or_reference() + : _cp->tag_at(index).is_klass_reference()); + } + + // Checks that the cpool index is in range and is a utf8 + bool valid_symbol_at(int cpool_index) { + return (_cp->is_within_bounds(cpool_index) && + _cp->tag_at(cpool_index).is_utf8()); } void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, @@ -373,8 +402,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2** localvariable_type_table_start, TRAPS); - void copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, + void copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -391,9 +419,15 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int annotation_default_length, TRAPS); + // lays out fields in class and returns the total oopmap count + void layout_fields(Handle class_loader, FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } + ~ClassFileParser(); // Parse .class file and return new Klass*. The Klass* is not hooked up // to the system dictionary or any other structures, so a .class file can diff --git a/src/share/vm/oops/constMethod.cpp b/src/share/vm/oops/constMethod.cpp index dfee42449..98a29a2e1 100644 --- a/src/share/vm/oops/constMethod.cpp +++ b/src/share/vm/oops/constMethod.cpp @@ -67,6 +67,12 @@ ConstMethod::ConstMethod(int byte_code_size, set_size_of_parameters(0); } +// Accessor that copies to metadata. +void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data, + u1* sd, int length, TRAPS) { + _stackmap_data = MetadataFactory::new_array(loader_data, length, CHECK); + memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length); +} // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { diff --git a/src/share/vm/oops/constMethod.hpp b/src/share/vm/oops/constMethod.hpp index 21fa344bc..0c4212564 100644 --- a/src/share/vm/oops/constMethod.hpp +++ b/src/share/vm/oops/constMethod.hpp @@ -280,6 +280,7 @@ public: // stackmap table data Array* stackmap_data() const { return _stackmap_data; } void set_stackmap_data(Array* sd) { _stackmap_data = sd; } + void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); bool has_stackmap_table() const { return _stackmap_data != NULL; } void init_fingerprint() { diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp index 89cf23a35..e296c501c 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp @@ -165,7 +165,8 @@ HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__end, volatile int InstanceKlass::_total_instanceKlass_count = 0; -Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, +InstanceKlass* InstanceKlass::allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -207,10 +208,35 @@ Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, access_flags, is_anonymous); } + // Check for pending exception before adding to the loader data and incrementing + // class count. Can get OOM here. + if (HAS_PENDING_EXCEPTION) { + return NULL; + } + + // Add all classes to our internal class loader list here, + // including classes in the bootstrap (NULL) class loader. + loader_data->add_class(ik); + Atomic::inc(&_total_instanceKlass_count); return ik; } + +// copy method ordering from resource area to Metaspace +void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) { + if (m != NULL) { + // allocate a new array and copy contents (memcpy?) + _method_ordering = MetadataFactory::new_array(class_loader_data(), m->length(), CHECK); + for (int i = 0; i < m->length(); i++) { + _method_ordering->at_put(i, m->at(i)); + } + } else { + _method_ordering = Universe::the_empty_int_array(); + } +} + + InstanceKlass::InstanceKlass(int vtable_len, int itable_len, int static_field_size, @@ -223,9 +249,6 @@ InstanceKlass::InstanceKlass(int vtable_len, int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, access_flags.is_interface(), is_anonymous); - // The sizes of these these three variables are used for determining the - // size of the instanceKlassOop. It is critical that these are set to the right - // sizes before the first GC, i.e., when we allocate the mirror. set_vtable_length(vtable_len); set_itable_length(itable_len); set_static_field_size(static_field_size); @@ -288,12 +311,51 @@ InstanceKlass::InstanceKlass(int vtable_len, } +void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, + Array* methods) { + if (methods != NULL && methods != Universe::the_empty_method_array()) { + for (int i = 0; i < methods->length(); i++) { + Method* method = methods->at(i); + if (method == NULL) continue; // maybe null if error processing + // Only want to delete methods that are not executing for RedefineClasses. + // The previous version will point to them so they're not totally dangling + assert (!method->on_stack(), "shouldn't be called with methods on stack"); + MetadataFactory::free_metadata(loader_data, method); + } + MetadataFactory::free_array(loader_data, methods); + } +} + +void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces) { + // Only deallocate transitive interfaces if not empty, same as super class + // or same as local interfaces. See code in parseClassFile. + Array* ti = transitive_interfaces; + if (ti != Universe::the_empty_klass_array() && ti != local_interfaces) { + // check that the interfaces don't come from super class + Array* sti = (super_klass == NULL) ? NULL : + InstanceKlass::cast(super_klass)->transitive_interfaces(); + if (ti != sti) { + MetadataFactory::free_array(loader_data, ti); + } + } + + // local interfaces can be empty + if (local_interfaces != Universe::the_empty_klass_array()) { + MetadataFactory::free_array(loader_data, local_interfaces); + } +} + // This function deallocates the metadata and C heap pointers that the // InstanceKlass points to. void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // Orphan the mirror first, CMS thinks it's still live. - java_lang_Class::set_klass(java_mirror(), NULL); + if (java_mirror() != NULL) { + java_lang_Class::set_klass(java_mirror(), NULL); + } // Need to take this class off the class loader data list. loader_data->remove_class(this); @@ -308,17 +370,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // reference counting symbol names. release_C_heap_structures(); - Array* ms = methods(); - if (ms != Universe::the_empty_method_array()) { - for (int i = 0; i <= methods()->length() -1 ; i++) { - Method* method = methods()->at(i); - // Only want to delete methods that are not executing for RedefineClasses. - // The previous version will point to them so they're not totally dangling - assert (!method->on_stack(), "shouldn't be called with methods on stack"); - MetadataFactory::free_metadata(loader_data, method); - } - MetadataFactory::free_array(loader_data, methods()); - } + deallocate_methods(loader_data, methods()); set_methods(NULL); if (method_ordering() != Universe::the_empty_int_array()) { @@ -335,24 +387,8 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(NULL); - // Only deallocate transitive interfaces if not empty, same as super class - // or same as local interfaces. See code in parseClassFile. - Array* ti = transitive_interfaces(); - if (ti != Universe::the_empty_klass_array() && ti != local_interfaces()) { - // check that the interfaces don't come from super class - Array* sti = (super() == NULL) ? NULL : - InstanceKlass::cast(super())->transitive_interfaces(); - if (ti != sti) { - MetadataFactory::free_array(loader_data, ti); - } - } + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(NULL); - - // local interfaces can be empty - Array* li = local_interfaces(); - if (li != Universe::the_empty_klass_array()) { - MetadataFactory::free_array(loader_data, li); - } set_local_interfaces(NULL); MetadataFactory::free_array(loader_data, fields()); @@ -360,9 +396,11 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. - assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - MetadataFactory::free_metadata(loader_data, constants()); - set_constants(NULL); + if (constants() != NULL) { + assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); + MetadataFactory::free_metadata(loader_data, constants()); + set_constants(NULL); + } if (inner_classes() != Universe::the_empty_short_array()) { MetadataFactory::free_array(loader_data, inner_classes()); diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp index c4dffdcb6..9d94b2436 100644 --- a/src/share/vm/oops/instanceKlass.hpp +++ b/src/share/vm/oops/instanceKlass.hpp @@ -147,7 +147,8 @@ class InstanceKlass: public Klass { AccessFlags access_flags, bool is_anonymous); public: - static Klass* allocate_instance_klass(ClassLoaderData* loader_data, + static InstanceKlass* allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -266,7 +267,6 @@ class InstanceKlass: public Klass { u1 _init_state; // state of class u1 _reference_type; // reference type - JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies @@ -358,16 +358,19 @@ class InstanceKlass: public Klass { // method ordering Array* method_ordering() const { return _method_ordering; } void set_method_ordering(Array* m) { _method_ordering = m; } + void copy_method_ordering(intArray* m, TRAPS); // interfaces Array* local_interfaces() const { return _local_interfaces; } void set_local_interfaces(Array* a) { guarantee(_local_interfaces == NULL || a == NULL, "Just checking"); _local_interfaces = a; } + Array* transitive_interfaces() const { return _transitive_interfaces; } void set_transitive_interfaces(Array* a) { guarantee(_transitive_interfaces == NULL || a == NULL, "Just checking"); - _transitive_interfaces = a; } + _transitive_interfaces = a; + } private: friend class fieldDescriptor; @@ -383,10 +386,9 @@ class InstanceKlass: public Klass { int java_fields_count() const { return (int)_java_fields_count; } Array* fields() const { return _fields; } - void set_fields(Array* f, u2 java_fields_count) { guarantee(_fields == NULL || f == NULL, "Just checking"); - _fields = f; + _fields = f; _java_fields_count = java_fields_count; } @@ -916,8 +918,15 @@ class InstanceKlass: public Klass { void clean_method_data(BoolObjectClosure* is_alive); // Explicit metaspace deallocation of fields - // For RedefineClasses, we need to deallocate instanceKlasses + // For RedefineClasses and class file parsing errors, we need to deallocate + // instanceKlasses and the metadata they point to. void deallocate_contents(ClassLoaderData* loader_data); + static void deallocate_methods(ClassLoaderData* loader_data, + Array* methods); + void static deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces); // The constant pool is on stack if any of the methods are executing or // referenced by handles. -- GitLab