< prev index next >

src/hotspot/share/classfile/classFileParser.cpp

Print this page
rev 59083 : DRAFT 8236522: NonTearable marker interface for inline classes to enforce atomicity

*** 81,90 **** --- 81,91 ---- #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/resourceHash.hpp" + #include "utilities/stringUtils.hpp" #include "utilities/utf8.hpp" #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" #endif
*** 941,954 **** return true; } // Side-effects: populates the _local_interfaces field ! void ClassFileParser::parse_interfaces(const ClassFileStream* const stream, ! const int itfs_len, ! ConstantPool* const cp, bool* const has_nonstatic_concrete_methods, TRAPS) { assert(stream != NULL, "invariant"); assert(cp != NULL, "invariant"); assert(has_nonstatic_concrete_methods != NULL, "invariant"); --- 942,962 ---- return true; } // Side-effects: populates the _local_interfaces field ! void ClassFileParser::parse_interfaces(const ClassFileStream* stream, ! int itfs_len, ! ConstantPool* cp, bool* const has_nonstatic_concrete_methods, + // FIXME: lots of these functions + // declare their parameters as const, + // which adds only noise to the code. + // Remove the spurious const modifiers. + // Many are of the form "const int x" + // or "T* const x". + bool* const is_declared_atomic, TRAPS) { assert(stream != NULL, "invariant"); assert(cp != NULL, "invariant"); assert(has_nonstatic_concrete_methods != NULL, "invariant");
*** 992,1005 **** _class_name->as_klass_external_name(), interf->external_name(), interf->class_in_module_of_loader())); } ! if (InstanceKlass::cast(interf)->has_nonstatic_concrete_methods()) { *has_nonstatic_concrete_methods = true; } ! _local_interfaces->at_put(index, InstanceKlass::cast(interf)); } if (!_need_verify || itfs_len <= 1) { return; } --- 1000,1017 ---- _class_name->as_klass_external_name(), interf->external_name(), interf->class_in_module_of_loader())); } ! InstanceKlass* ik = InstanceKlass::cast(interf); ! if (ik->has_nonstatic_concrete_methods()) { *has_nonstatic_concrete_methods = true; } ! if (ik->is_declared_atomic()) { ! *is_declared_atomic = true; ! } ! _local_interfaces->at_put(index, ik); } if (!_need_verify || itfs_len <= 1) { return; }
*** 4344,4353 **** --- 4356,4366 ---- int nonstatic_value_type_count = 0; int* nonstatic_value_type_indexes = NULL; Klass** nonstatic_value_type_klasses = NULL; unsigned int value_type_oop_map_count = 0; int not_flattened_value_types = 0; + int not_atomic_value_types = 0; int max_nonstatic_value_type = fac->count[NONSTATIC_FLATTENABLE] + 1; nonstatic_value_type_indexes = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, int, max_nonstatic_value_type);
*** 4378,4397 **** if (!klass->access_flags().is_value_type()) { THROW(vmSymbols::java_lang_IncompatibleClassChangeError()); } ValueKlass* vk = ValueKlass::cast(klass); // Conditions to apply flattening or not should be defined in a single place ! if ((ValueFieldMaxFlatSize < 0) || (vk->size_helper() * HeapWordSize) <= ValueFieldMaxFlatSize) { nonstatic_value_type_indexes[nonstatic_value_type_count] = fs.index(); nonstatic_value_type_klasses[nonstatic_value_type_count] = klass; nonstatic_value_type_count++; ValueKlass* vklass = ValueKlass::cast(klass); if (vklass->contains_oops()) { value_type_oop_map_count += vklass->nonstatic_oop_map_count(); } fs.set_flattened(true); } else { not_flattened_value_types++; fs.set_flattened(false); } } --- 4391,4422 ---- if (!klass->access_flags().is_value_type()) { THROW(vmSymbols::java_lang_IncompatibleClassChangeError()); } ValueKlass* vk = ValueKlass::cast(klass); // Conditions to apply flattening or not should be defined in a single place ! bool too_big_to_flatten = (ValueFieldMaxFlatSize >= 0 && ! (vk->size_helper() * HeapWordSize) > ValueFieldMaxFlatSize); ! bool too_atomic_to_flatten = vk->is_declared_atomic(); ! bool too_volatile_to_flatten = fs.access_flags().is_volatile(); ! if (vk->is_naturally_atomic()) { ! too_atomic_to_flatten = false; ! //too_volatile_to_flatten = false; //FIXME ! // volatile fields are currently never flattened, this could change in the future ! } ! if (!(too_big_to_flatten | too_atomic_to_flatten | too_volatile_to_flatten)) { nonstatic_value_type_indexes[nonstatic_value_type_count] = fs.index(); nonstatic_value_type_klasses[nonstatic_value_type_count] = klass; nonstatic_value_type_count++; ValueKlass* vklass = ValueKlass::cast(klass); if (vklass->contains_oops()) { value_type_oop_map_count += vklass->nonstatic_oop_map_count(); } fs.set_flattened(true); + if (!vk->is_atomic()) { // flat and non-atomic: take note + not_atomic_value_types++; + } } else { not_flattened_value_types++; fs.set_flattened(false); } }
*** 4846,4855 **** --- 4871,4893 ---- info->oop_map_blocks = nonstatic_oop_maps; 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; + + // A value type is naturally atomic if it has just one field, and + // that field is simple enough. + info->_is_naturally_atomic = (is_value_type() && + !super_has_nonstatic_fields && + (nonstatic_fields_count <= 1) && + (not_atomic_value_types == 0) && + (nonstatic_contended_count == 0)); + // This may be too restrictive, since if all the fields fit in 64 + // bits we could make the decision to align instances of this class + // to 64-bit boundaries, and load and store them as single words. + // And on machines which supported larger atomics we could similarly + // allow larger values to be atomic, if properly aligned. } void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { assert(ik != NULL, "invariant");
*** 5981,5990 **** --- 6019,6029 ---- } // CheckIntrinsics #endif // ASSERT } } + // Called from a factory method in KlassFactory, not from this file. InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) { if (_klass != NULL) { return _klass; }
*** 6050,6059 **** --- 6089,6101 ---- ik->set_should_verify_class(_need_verify); // Not yet: supers are done below to support the new subtype-checking fields ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size); ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields); + if (_field_info->_is_naturally_atomic && ik->is_value()) { + ik->set_is_naturally_atomic(); + } if (_is_empty_value) { ik->set_is_empty_value(); } assert(_fac != NULL, "invariant"); ik->set_static_oop_field_count(_fac->count[STATIC_OOP] + _fac->count[STATIC_FLATTENABLE]);
*** 6099,6108 **** --- 6141,6153 ---- ik->set_minor_version(_minor_version); ik->set_major_version(_major_version); ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods); ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods); + if (_is_declared_atomic) { + ik->set_is_declared_atomic(); + } if (_unsafe_anonymous_host != NULL) { assert (ik->is_unsafe_anonymous(), "should be the same"); ik->set_unsafe_anonymous_host(_unsafe_anonymous_host); }
*** 6431,6440 **** --- 6476,6487 ---- _declares_nonstatic_concrete_methods(false), _has_final_method(false), _has_contended_fields(false), _has_flattenable_fields(false), _is_empty_value(false), + _is_naturally_atomic(false), + _is_declared_atomic(false), _has_finalizer(false), _has_empty_finalizer(false), _has_vanilla_constructor(false), _max_bootstrap_specifier_index(-1) {
*** 6770,6788 **** _itfs_len = stream->get_u2_fast(); parse_interfaces(stream, _itfs_len, cp, &_has_nonstatic_concrete_methods, CHECK); assert(_local_interfaces != NULL, "invariant"); // Fields (offsets are filled in later) _fac = new FieldAllocationCount(); parse_fields(stream, ! _access_flags.is_interface(), ! _access_flags.is_value_type(), _fac, cp, cp_size, &_java_fields_count, CHECK); --- 6817,6836 ---- _itfs_len = stream->get_u2_fast(); parse_interfaces(stream, _itfs_len, cp, &_has_nonstatic_concrete_methods, + &_is_declared_atomic, CHECK); assert(_local_interfaces != NULL, "invariant"); // Fields (offsets are filled in later) _fac = new FieldAllocationCount(); parse_fields(stream, ! is_interface(), ! is_value_type(), _fac, cp, cp_size, &_java_fields_count, CHECK);
*** 6790,6801 **** assert(_fields != NULL, "invariant"); // Methods AccessFlags promoted_flags; parse_methods(stream, ! _access_flags.is_interface(), ! _access_flags.is_value_type(), &promoted_flags, &_has_final_method, &_declares_nonstatic_concrete_methods, CHECK); --- 6838,6849 ---- assert(_fields != NULL, "invariant"); // Methods AccessFlags promoted_flags; parse_methods(stream, ! is_interface(), ! is_value_type(), &promoted_flags, &_has_final_method, &_declares_nonstatic_concrete_methods, CHECK);
*** 6840,6850 **** CHECK); } // We check super class after class file is parsed and format is checked if (_super_class_index > 0 && NULL ==_super_klass) { Symbol* const super_class_name = cp->klass_name_at(_super_class_index); ! if (_access_flags.is_interface()) { // Before attempting to resolve the superclass, check for class format // errors not checked yet. guarantee_property(super_class_name == vmSymbols::java_lang_Object(), "Interfaces must have java.lang.Object as superclass in class file %s", CHECK); --- 6888,6898 ---- CHECK); } // We check super class after class file is parsed and format is checked if (_super_class_index > 0 && NULL ==_super_klass) { Symbol* const super_class_name = cp->klass_name_at(_super_class_index); ! if (is_interface()) { // Before attempting to resolve the superclass, check for class format // errors not checked yet. guarantee_property(super_class_name == vmSymbols::java_lang_Object(), "Interfaces must have java.lang.Object as superclass in class file %s", CHECK);
*** 6861,6870 **** --- 6909,6921 ---- if (_super_klass != NULL) { if (_super_klass->has_nonstatic_concrete_methods()) { _has_nonstatic_concrete_methods = true; } + if (_super_klass->is_declared_atomic()) { + _is_declared_atomic = true; + } if (_super_klass->is_interface()) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION,
*** 6887,6896 **** --- 6938,6959 ---- if (_super_klass->is_final()) { THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class"); } } + if (_class_name == vmSymbols::java_lang_NonTearable() && _loader_data->class_loader() == NULL) { + // This is the original source of this condition. + // It propagates by inheritance, as if testing "instanceof NonTearable". + _is_declared_atomic = true; + } else if (*ForceNonTearable != '\0') { + // Allow a command line switch to force the same atomicity property: + const char* class_name_str = _class_name->as_C_string(); + if (StringUtils::class_list_match(ForceNonTearable, class_name_str)) { + _is_declared_atomic = true; + } + } + // Compute the transitive list of all unique interfaces implemented by this class _transitive_interfaces = compute_transitive_interfaces(_super_klass, _local_interfaces, _loader_data,
*** 6915,6925 **** _class_name, _local_interfaces, CHECK); // Size of Java itable (in words) ! _itable_size = _access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); assert(_fac != NULL, "invariant"); assert(_parsed_annotations != NULL, "invariant"); --- 6978,6988 ---- _class_name, _local_interfaces, CHECK); // Size of Java itable (in words) ! _itable_size = is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); assert(_fac != NULL, "invariant"); assert(_parsed_annotations != NULL, "invariant");
< prev index next >