< 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 >