< 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,10 +81,11 @@
#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,14 +942,21 @@
return true;
}
// Side-effects: populates the _local_interfaces field
-void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
- const int itfs_len,
- ConstantPool* const cp,
+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,14 +1000,18 @@
_class_name->as_klass_external_name(),
interf->external_name(),
interf->class_in_module_of_loader()));
}
- if (InstanceKlass::cast(interf)->has_nonstatic_concrete_methods()) {
+ InstanceKlass* ik = InstanceKlass::cast(interf);
+ if (ik->has_nonstatic_concrete_methods()) {
*has_nonstatic_concrete_methods = true;
}
- _local_interfaces->at_put(index, InstanceKlass::cast(interf));
+ if (ik->is_declared_atomic()) {
+ *is_declared_atomic = true;
+ }
+ _local_interfaces->at_put(index, ik);
}
if (!_need_verify || itfs_len <= 1) {
return;
}
@@ -4344,10 +4356,11 @@
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,20 +4391,32 @@
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) {
+ 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,10 +4871,23 @@
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,10 +6019,11 @@
} // 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,10 +6089,13 @@
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,10 +6141,13 @@
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,10 +6476,12 @@
_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,19 +6817,20 @@
_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,
- _access_flags.is_interface(),
- _access_flags.is_value_type(),
+ is_interface(),
+ is_value_type(),
_fac,
cp,
cp_size,
&_java_fields_count,
CHECK);
@@ -6790,12 +6838,12 @@
assert(_fields != NULL, "invariant");
// Methods
AccessFlags promoted_flags;
parse_methods(stream,
- _access_flags.is_interface(),
- _access_flags.is_value_type(),
+ is_interface(),
+ is_value_type(),
&promoted_flags,
&_has_final_method,
&_declares_nonstatic_concrete_methods,
CHECK);
@@ -6840,11 +6888,11 @@
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()) {
+ 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,10 +6909,13 @@
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,10 +6938,22 @@
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,11 +6978,11 @@
_class_name,
_local_interfaces,
CHECK);
// Size of Java itable (in words)
- _itable_size = _access_flags.is_interface() ? 0 :
+ _itable_size = is_interface() ? 0 :
klassItable::compute_itable_size(_transitive_interfaces);
assert(_fac != NULL, "invariant");
assert(_parsed_annotations != NULL, "invariant");
< prev index next >