< prev index next >

src/hotspot/share/classfile/classFileParser.cpp

Print this page

        

@@ -53,10 +53,11 @@
 #include "oops/klassVtable.hpp"
 #include "oops/metadata.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/javaCalls.hpp"

@@ -120,10 +121,12 @@
 
 #define JAVA_12_VERSION                   56
 
 #define JAVA_13_VERSION                   57
 
+#define CONSTANT_CLASS_DESCRIPTORS        57
+
 void ClassFileParser::set_class_bad_constant_seen(short bad_constant) {
   assert((bad_constant == 19 || bad_constant == 20) && _major_version >= JAVA_9_VERSION,
          "Unexpected bad constant pool entry");
   if (_bad_constant_seen == 0) _bad_constant_seen = bad_constant;
 }

@@ -158,11 +161,11 @@
     // Each of the following case guarantees one more byte in the stream
     // for the following tag or the access_flags following constant pool,
     // so we don't need bounds-check for reading tag.
     const u1 tag = cfs->get_u1_fast();
     switch (tag) {
-      case JVM_CONSTANT_Class : {
+      case JVM_CONSTANT_Class: {
         cfs->guarantee_more(3, CHECK);  // name_index, tag/access_flags
         const u2 name_index = cfs->get_u2_fast();
         cp->klass_index_at_put(index, name_index);
         break;
       }

@@ -490,11 +493,18 @@
       case JVM_CONSTANT_ClassIndex: {
         const int class_index = cp->klass_index_at(index);
         check_property(valid_symbol_at(class_index),
           "Invalid constant pool index %u in class file %s",
           class_index, CHECK);
+
+        Symbol* const name = cp->symbol_at(class_index);
+        const unsigned int name_len = name->utf8_length();
+        if (name->is_Q_signature()) {
+          cp->unresolved_qdescriptor_at_put(index, class_index, num_klasses++);
+        } else {
         cp->unresolved_klass_at_put(index, class_index, num_klasses++);
+        }
         break;
       }
       case JVM_CONSTANT_StringIndex: {
         const int string_index = cp->string_index_at(index);
         check_property(valid_symbol_at(string_index),

@@ -1459,15 +1469,17 @@
   STATIC_OOP,           // Oops
   STATIC_BYTE,          // Boolean, Byte, char
   STATIC_SHORT,         // shorts
   STATIC_WORD,          // ints
   STATIC_DOUBLE,        // aligned long or double
+  STATIC_FLATTENABLE,   // flattenable field
   NONSTATIC_OOP,
   NONSTATIC_BYTE,
   NONSTATIC_SHORT,
   NONSTATIC_WORD,
   NONSTATIC_DOUBLE,
+  NONSTATIC_FLATTENABLE,
   MAX_FIELD_ALLOCATION_TYPE,
   BAD_ALLOCATION_TYPE = -1
 };
 
 static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = {

@@ -1483,16 +1495,17 @@
   NONSTATIC_SHORT,     // T_SHORT       =  9,
   NONSTATIC_WORD,      // T_INT         = 10,
   NONSTATIC_DOUBLE,    // T_LONG        = 11,
   NONSTATIC_OOP,       // T_OBJECT      = 12,
   NONSTATIC_OOP,       // T_ARRAY       = 13,
-  BAD_ALLOCATION_TYPE, // T_VOID        = 14,
-  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
-  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
-  BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
-  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
-  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
+  NONSTATIC_OOP,       // T_VALUETYPE   = 14,
+  BAD_ALLOCATION_TYPE, // T_VOID        = 15,
+  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 16,
+  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 17,
+  BAD_ALLOCATION_TYPE, // T_METADATA    = 18,
+  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 19,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 20,
   BAD_ALLOCATION_TYPE, // 0
   BAD_ALLOCATION_TYPE, // 1
   BAD_ALLOCATION_TYPE, // 2
   BAD_ALLOCATION_TYPE, // 3
   STATIC_BYTE ,        // T_BOOLEAN     =  4,

@@ -1503,22 +1516,26 @@
   STATIC_SHORT,        // T_SHORT       =  9,
   STATIC_WORD,         // T_INT         = 10,
   STATIC_DOUBLE,       // T_LONG        = 11,
   STATIC_OOP,          // T_OBJECT      = 12,
   STATIC_OOP,          // T_ARRAY       = 13,
-  BAD_ALLOCATION_TYPE, // T_VOID        = 14,
-  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
-  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
-  BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
-  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
-  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
+  STATIC_OOP,          // T_VALUETYPE   = 14,
+  BAD_ALLOCATION_TYPE, // T_VOID        = 15,
+  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 16,
+  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 17,
+  BAD_ALLOCATION_TYPE, // T_METADATA    = 18,
+  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 19,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 20
 };
 
-static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
+static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type, bool is_flattenable) {
   assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values");
   FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)];
   assert(result != BAD_ALLOCATION_TYPE, "bad type");
+  if (is_flattenable) {
+    result = is_static ? STATIC_FLATTENABLE : NONSTATIC_FLATTENABLE;
+  }
   return result;
 }
 
 class ClassFileParser::FieldAllocationCount : public ResourceObj {
  public:

@@ -1528,12 +1545,12 @@
     for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) {
       count[i] = 0;
     }
   }
 
-  FieldAllocationType update(bool is_static, BasicType type) {
-    FieldAllocationType atype = basic_type_to_atype(is_static, type);
+  FieldAllocationType update(bool is_static, BasicType type, bool is_flattenable) {
+    FieldAllocationType atype = basic_type_to_atype(is_static, type, is_flattenable);
     if (atype != BAD_ALLOCATION_TYPE) {
       // Make sure there is no overflow with injected fields.
       assert(count[atype] < 0xFFFF, "More than 65535 fields");
       count[atype]++;
     }

@@ -1543,10 +1560,11 @@
 
 // Side-effects: populates the _fields, _fields_annotations,
 // _fields_type_annotations fields
 void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
                                    bool is_interface,
+                                   bool is_value_type,
                                    FieldAllocationCount* const fac,
                                    ConstantPool* cp,
                                    const int cp_size,
                                    u2* const java_fields_count_ptr,
                                    TRAPS) {

@@ -1565,11 +1583,12 @@
   *java_fields_count_ptr = length;
 
   int num_injected = 0;
   const InjectedField* const injected = JavaClasses::get_injected(_class_name,
                                                                   &num_injected);
-  const int total_fields = length + num_injected;
+
+  const int total_fields = length + num_injected + (is_value_type ? 1 : 0);
 
   // The field array starts with tuples of shorts
   // [access, name index, sig index, initial value index, byte offset].
   // A generic signature slot only exists for field with generic
   // signature attribute. And the access flag is set with

@@ -1599,13 +1618,15 @@
   int num_generic_signature = 0;
   for (int n = 0; n < length; n++) {
     // access_flags, name_index, descriptor_index, attributes_count
     cfs->guarantee_more(8, CHECK);
 
+    jint recognized_modifiers = JVM_RECOGNIZED_FIELD_MODIFIERS;
+
+    const jint flags = cfs->get_u2_fast() & recognized_modifiers;
+    verify_legal_field_modifiers(flags, is_interface, is_value_type, CHECK);
     AccessFlags access_flags;
-    const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
-    verify_legal_field_modifiers(flags, is_interface, CHECK);
     access_flags.set_flags(flags);
 
     const u2 name_index = cfs->get_u2_fast();
     check_property(valid_symbol_at(name_index),
       "Invalid constant pool index %u for field name in class file %s",

@@ -1617,10 +1638,26 @@
     check_property(valid_symbol_at(signature_index),
       "Invalid constant pool index %u for field signature in class file %s",
       signature_index, CHECK);
     const Symbol* const sig = cp->symbol_at(signature_index);
     verify_legal_field_signature(name, sig, CHECK);
+    assert(!access_flags.is_flattenable(), "ACC_FLATTENABLE should have been filtered out");
+    if (sig->is_Q_signature()) {
+      // assert(_major_version >= CONSTANT_CLASS_DESCRIPTORS, "Q-descriptors are only supported in recent classfiles");
+      access_flags.set_is_flattenable();
+    }
+    if (access_flags.is_flattenable()) {
+      // Array flattenability cannot be specified.  Arrays of value classes are
+      // are always flattenable.  Arrays of other classes are not flattenable.
+      if (sig->utf8_length() > 1 && sig->char_at(0) == '[') {
+        classfile_parse_error(
+            "Field \"%s\" with signature \"%s\" in class file %s is invalid."
+            " ACC_FLATTENABLE cannot be specified for an array",
+            name->as_C_string(), sig->as_klass_external_name(), CHECK);
+      }
+      _has_flattenable_fields = true;
+    }
 
     u2 constantvalue_index = 0;
     bool is_synthetic = false;
     u2 generic_signature_index = 0;
     const bool is_static = access_flags.is_static();

@@ -1676,11 +1713,11 @@
                       signature_index,
                       constantvalue_index);
     const BasicType type = cp->basic_type_for_signature_at(signature_index);
 
     // Remember how many oops we encountered and compute allocation type
-    const FieldAllocationType atype = fac->update(is_static, type);
+    const FieldAllocationType atype = fac->update(is_static, type, access_flags.is_flattenable());
     field->set_allocation_type(atype);
 
     // After field is initialized with type, we can augment it with aux info
     if (parsed_annotations.has_any_annotations())
       parsed_annotations.apply_to(field);

@@ -1717,16 +1754,29 @@
                         0);
 
       const BasicType type = FieldType::basic_type(injected[n].signature());
 
       // Remember how many oops we encountered and compute allocation type
-      const FieldAllocationType atype = fac->update(false, type);
+      const FieldAllocationType atype = fac->update(false, type, false);
       field->set_allocation_type(atype);
       index++;
     }
   }
 
+  if (is_value_type) {
+    index = length + num_injected;
+    FieldInfo* const field = FieldInfo::from_field_array(fa, index);
+    field->initialize(JVM_ACC_FIELD_INTERNAL | JVM_ACC_STATIC,
+                      vmSymbols::default_value_name_enum,
+                      vmSymbols::java_lang_Object_enum,
+                      0);
+    const BasicType type = FieldType::basic_type(vmSymbols::object_signature());
+    const FieldAllocationType atype = fac->update(true, type, false);
+    field->set_allocation_type(atype);
+    index++;
+  }
+
   assert(NULL == _fields, "invariant");
 
   _fields =
     MetadataFactory::new_array<u2>(_loader_data,
                                    index * FieldInfo::field_slots + num_generic_signature,

@@ -2346,10 +2396,11 @@
 // from the method back up to the containing klass. These flag values
 // are added to klass's access_flags.
 
 Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
                                       bool is_interface,
+                                      bool is_value_type,
                                       const ConstantPool* cp,
                                       AccessFlags* const promoted_flags,
                                       TRAPS) {
   assert(cfs != NULL, "invariant");
   assert(cp != NULL, "invariant");

@@ -2386,15 +2437,21 @@
       flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
     } else {
       classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_NULL);
     }
   } else {
-    verify_legal_method_modifiers(flags, is_interface, name, CHECK_NULL);
+    verify_legal_method_modifiers(flags, is_interface, is_value_type, name, CHECK_NULL);
   }
 
-  if (name == vmSymbols::object_initializer_name() && is_interface) {
+  if (name == vmSymbols::object_initializer_name()) {
+    if (is_interface) {
     classfile_parse_error("Interface cannot have a method named <init>, class file %s", CHECK_NULL);
+/* TBD: uncomment when javac stops generating <init>() for value types.
+    } else if (is_value_type) {
+      classfile_parse_error("Value Type cannot have a method named <init>, class file %s", CHECK_NULL);
+*/
+    }
   }
 
   int args_size = -1;  // only used when _need_verify is true
   if (_need_verify) {
     args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) +

@@ -2961,10 +3018,11 @@
 // from the methods back up to the containing klass. These flag values
 // are added to klass's access_flags.
 // Side-effects: populates the _methods field in the parser
 void ClassFileParser::parse_methods(const ClassFileStream* const cfs,
                                     bool is_interface,
+                                    bool is_value_type,
                                     AccessFlags* promoted_flags,
                                     bool* has_final_method,
                                     bool* declares_nonstatic_concrete_methods,
                                     TRAPS) {
   assert(cfs != NULL, "invariant");

@@ -2985,10 +3043,11 @@
                                                    CHECK);
 
     for (int index = 0; index < length; index++) {
       Method* method = parse_method(cfs,
                                     is_interface,
+                                    is_value_type,
                                     _cp,
                                     promoted_flags,
                                     CHECK);
 
       if (method->is_final()) {

@@ -3177,18 +3236,24 @@
       inner_name_index, CHECK_0);
     if (_need_verify) {
       guarantee_property(inner_class_info_index != outer_class_info_index,
                          "Class is both outer and inner class in class file %s", CHECK_0);
     }
-    // Access flags
-    jint flags;
+
+    jint recognized_modifiers = RECOGNIZED_INNER_CLASS_MODIFIERS;
     // JVM_ACC_MODULE is defined in JDK-9 and later.
     if (_major_version >= JAVA_9_VERSION) {
-      flags = cfs->get_u2_fast() & (RECOGNIZED_INNER_CLASS_MODIFIERS | JVM_ACC_MODULE);
-    } else {
-      flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
+      recognized_modifiers |= JVM_ACC_MODULE;
     }
+    // JVM_ACC_VALUE is defined for class file version 55 and later
+    if (supports_value_types()) {
+      recognized_modifiers |= JVM_ACC_VALUE;
+    }
+
+    // Access flags
+    jint flags = cfs->get_u2_fast() & recognized_modifiers;
+
     if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
       // Set abstract bit for old class files for backward compatibility
       flags |= JVM_ACC_ABSTRACT;
     }
     verify_legal_class_modifiers(flags, CHECK_0);

@@ -3387,10 +3452,12 @@
   bool runtime_invisible_type_annotations_exists = false;
   bool runtime_invisible_annotations_exists = false;
   bool parsed_source_debug_ext_annotations_exist = false;
   const u1* inner_classes_attribute_start = NULL;
   u4  inner_classes_attribute_length = 0;
+  const u1* value_types_attribute_start = NULL;
+  u4 value_types_attribute_length = 0;
   u2  enclosing_method_class_index = 0;
   u2  enclosing_method_method_index = 0;
   const u1* nest_members_attribute_start = NULL;
   u4  nest_members_attribute_length = 0;
 

@@ -3736,11 +3803,12 @@
                                                         TRAPS) {
   assert(cp != NULL, "invariant");
   const InstanceKlass* super_klass = NULL;
 
   if (super_class_index == 0) {
-    check_property(_class_name == vmSymbols::java_lang_Object(),
+    check_property(_class_name == vmSymbols::java_lang_Object()
+                   || (_access_flags.get_flags() & JVM_ACC_VALUE),
                    "Invalid superclass index %u in class file %s",
                    super_class_index,
                    CHECK_NULL);
   } else {
     check_property(valid_klass_reference_at(super_class_index),

@@ -3763,43 +3831,10 @@
     }
   }
   return super_klass;
 }
 
-static unsigned int compute_oop_map_count(const InstanceKlass* super,
-                                          unsigned int nonstatic_oop_map_count,
-                                          int first_nonstatic_oop_offset) {
-
-  unsigned int map_count =
-    NULL == super ? 0 : super->nonstatic_oop_map_count();
-  if (nonstatic_oop_map_count > 0) {
-    // We have oops to add to map
-    if (map_count == 0) {
-      map_count = nonstatic_oop_map_count;
-    }
-    else {
-      // Check whether we should add a new map block or whether the last one can
-      // be extended
-      const OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
-      const OopMapBlock* const last_map = first_map + map_count - 1;
-
-      const int next_offset = last_map->offset() + last_map->count() * heapOopSize;
-      if (next_offset == first_nonstatic_oop_offset) {
-        // There is no gap bettwen superklass's last oop field and first
-        // local oop field, merge maps.
-        nonstatic_oop_map_count -= 1;
-      }
-      else {
-        // Superklass didn't end with a oop field, add extra maps
-        assert(next_offset < first_nonstatic_oop_offset, "just checking");
-      }
-      map_count += nonstatic_oop_map_count;
-    }
-  }
-  return map_count;
-}
-
 #ifndef PRODUCT
 static void print_field_layout(const Symbol* name,
                                Array<u2>* fields,
                                const constantPoolHandle& cp,
                                int instance_size,

@@ -3836,20 +3871,162 @@
 #endif
 
 // Values needed for oopmap and InstanceKlass creation
 class ClassFileParser::FieldLayoutInfo : public ResourceObj {
  public:
-  int*          nonstatic_oop_offsets;
-  unsigned int* nonstatic_oop_counts;
-  unsigned int  nonstatic_oop_map_count;
-  unsigned int  total_oop_map_count;
+  OopMapBlocksBuilder* oop_map_blocks;
   int           instance_size;
   int           nonstatic_field_size;
   int           static_field_size;
   bool          has_nonstatic_fields;
 };
 
+// Utility to collect and compact oop maps during layout
+class ClassFileParser::OopMapBlocksBuilder : public ResourceObj {
+ public:
+  OopMapBlock*  nonstatic_oop_maps;
+  unsigned int  nonstatic_oop_map_count;
+  unsigned int  max_nonstatic_oop_maps;
+
+ public:
+  OopMapBlocksBuilder(unsigned int  max_blocks, TRAPS) {
+    max_nonstatic_oop_maps = max_blocks;
+    nonstatic_oop_map_count = 0;
+    if (max_blocks == 0) {
+      nonstatic_oop_maps = NULL;
+    } else {
+      nonstatic_oop_maps = NEW_RESOURCE_ARRAY_IN_THREAD(
+        THREAD, OopMapBlock, max_nonstatic_oop_maps);
+      memset(nonstatic_oop_maps, 0, sizeof(OopMapBlock) * max_blocks);
+    }
+  }
+
+  OopMapBlock* last_oop_map() const {
+    assert(nonstatic_oop_map_count > 0, "Has no oop maps");
+    return nonstatic_oop_maps + (nonstatic_oop_map_count - 1);
+  }
+
+  // addition of super oop maps
+  void initialize_inherited_blocks(OopMapBlock* blocks, unsigned int nof_blocks) {
+    assert(nof_blocks && nonstatic_oop_map_count == 0 &&
+        nof_blocks <= max_nonstatic_oop_maps, "invariant");
+
+    memcpy(nonstatic_oop_maps, blocks, sizeof(OopMapBlock) * nof_blocks);
+    nonstatic_oop_map_count += nof_blocks;
+  }
+
+  // collection of oops
+  void add(int offset, int count) {
+    if (nonstatic_oop_map_count == 0) {
+      nonstatic_oop_map_count++;
+    }
+    OopMapBlock*  nonstatic_oop_map = last_oop_map();
+    if (nonstatic_oop_map->count() == 0) {  // Unused map, set it up
+      nonstatic_oop_map->set_offset(offset);
+      nonstatic_oop_map->set_count(count);
+    } else if (nonstatic_oop_map->is_contiguous(offset)) { // contiguous, add
+      nonstatic_oop_map->increment_count(count);
+    } else { // Need a new one...
+      nonstatic_oop_map_count++;
+      assert(nonstatic_oop_map_count <= max_nonstatic_oop_maps, "range check");
+      nonstatic_oop_map = last_oop_map();
+      nonstatic_oop_map->set_offset(offset);
+      nonstatic_oop_map->set_count(count);
+    }
+  }
+
+  // general purpose copy, e.g. into allocated instanceKlass
+  void copy(OopMapBlock* dst) {
+    if (nonstatic_oop_map_count != 0) {
+      memcpy(dst, nonstatic_oop_maps, sizeof(OopMapBlock) * nonstatic_oop_map_count);
+    }
+  }
+
+  // Sort and compact adjacent blocks
+  void compact(TRAPS) {
+    if (nonstatic_oop_map_count <= 1) {
+      return;
+    }
+    /*
+     * Since field layout sneeks in oops before values, we will be able to condense
+     * blocks. There is potential to compact between super, own refs and values
+     * containing refs.
+     *
+     * Currently compaction is slightly limited due to values being 8 byte aligned.
+     * This may well change: FixMe if doesn't, the code below is fairly general purpose
+     * and maybe it doesn't need to be.
+     */
+    qsort(nonstatic_oop_maps, nonstatic_oop_map_count, sizeof(OopMapBlock),
+        (_sort_Fn)OopMapBlock::compare_offset);
+    if (nonstatic_oop_map_count < 2) {
+      return;
+    }
+
+     //Make a temp copy, and iterate through and copy back into the orig
+    ResourceMark rm(THREAD);
+    OopMapBlock* oop_maps_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, OopMapBlock,
+        nonstatic_oop_map_count);
+    OopMapBlock* oop_maps_copy_end = oop_maps_copy + nonstatic_oop_map_count;
+    copy(oop_maps_copy);
+    OopMapBlock*  nonstatic_oop_map = nonstatic_oop_maps;
+    unsigned int new_count = 1;
+    oop_maps_copy++;
+    while(oop_maps_copy < oop_maps_copy_end) {
+      assert(nonstatic_oop_map->offset() < oop_maps_copy->offset(), "invariant");
+      if (nonstatic_oop_map->is_contiguous(oop_maps_copy->offset())) {
+        nonstatic_oop_map->increment_count(oop_maps_copy->count());
+      } else {
+        nonstatic_oop_map++;
+        new_count++;
+        nonstatic_oop_map->set_offset(oop_maps_copy->offset());
+        nonstatic_oop_map->set_count(oop_maps_copy->count());
+      }
+      oop_maps_copy++;
+    }
+    assert(new_count <= nonstatic_oop_map_count, "end up with more maps after compact() ?");
+    nonstatic_oop_map_count = new_count;
+  }
+
+  void print_on(outputStream* st) const {
+    st->print_cr("  OopMapBlocks: %3d  /%3d", nonstatic_oop_map_count, max_nonstatic_oop_maps);
+    if (nonstatic_oop_map_count > 0) {
+      OopMapBlock* map = nonstatic_oop_maps;
+      OopMapBlock* last_map = last_oop_map();
+      assert(map <= last_map, "Last less than first");
+      while (map <= last_map) {
+        st->print_cr("    Offset: %3d  -%3d Count: %3d", map->offset(),
+            map->offset() + map->offset_span() - heapOopSize, map->count());
+        map++;
+      }
+    }
+  }
+
+  void print_value_on(outputStream* st) const {
+    print_on(st);
+  }
+
+};
+
+void ClassFileParser::throwValueTypeLimitation(THREAD_AND_LOCATION_DECL,
+                                               const char* msg,
+                                               const Symbol* name,
+                                               const Symbol* sig) const {
+
+  ResourceMark rm(THREAD);
+  if (name == NULL || sig == NULL) {
+    Exceptions::fthrow(THREAD_AND_LOCATION_ARGS,
+        vmSymbols::java_lang_ClassFormatError(),
+        "class: %s - %s", _class_name->as_C_string(), msg);
+  }
+  else {
+    Exceptions::fthrow(THREAD_AND_LOCATION_ARGS,
+        vmSymbols::java_lang_ClassFormatError(),
+        "\"%s\" sig: \"%s\" class: %s - %s", name->as_C_string(), sig->as_C_string(),
+        _class_name->as_C_string(), msg);
+  }
+}
+
 // Layout fields and fill in FieldLayoutInfo.  Could use more refactoring!
 void ClassFileParser::layout_fields(ConstantPool* cp,
                                     const FieldAllocationCount* fac,
                                     const ClassAnnotationCollector* parsed_annotations,
                                     FieldLayoutInfo* info,

@@ -3858,10 +4035,16 @@
   assert(cp != NULL, "invariant");
 
   // Field size and offset computation
   int nonstatic_field_size = _super_klass == NULL ? 0 :
                                _super_klass->nonstatic_field_size();
+  int next_nonstatic_valuetype_offset = 0;
+  int first_nonstatic_valuetype_offset = 0;
+
+  // Fields that are value types are handled differently depending if they are static or not:
+  // - static fields are oops
+  // - non-static fields are embedded
 
   // Count the contended fields by type.
   //
   // We ignore static fields, because @Contended is not supported for them.
   // The layout code below will also ignore the static fields.

@@ -3878,12 +4061,13 @@
   }
 
 
   // Calculate the starting byte offsets
   int next_static_oop_offset    = InstanceMirrorKlass::offset_of_static_fields();
+  // Value types in static fields are not embedded, they are handled with oops
   int next_static_double_offset = next_static_oop_offset +
-                                      ((fac->count[STATIC_OOP]) * heapOopSize);
+                                  ((fac->count[STATIC_OOP] + fac->count[STATIC_FLATTENABLE]) * heapOopSize);
   if (fac->count[STATIC_DOUBLE]) {
     next_static_double_offset = align_up(next_static_double_offset, BytesPerLong);
   }
 
   int next_static_word_offset   = next_static_double_offset +

@@ -3894,57 +4078,158 @@
                                   ((fac->count[STATIC_SHORT]) * BytesPerShort);
 
   int nonstatic_fields_start  = instanceOopDesc::base_offset_in_bytes() +
                                 nonstatic_field_size * heapOopSize;
 
+  // First field of value types is aligned on a long boundary in order to ease
+  // in-lining of value types (with header removal) in packed arrays and
+  // flatten value types
+  int initial_value_type_padding = 0;
+  if (is_value_type()) {
+    int old = nonstatic_fields_start;
+    nonstatic_fields_start = align_up(nonstatic_fields_start, BytesPerLong);
+    initial_value_type_padding = nonstatic_fields_start - old;
+  }
+
   int next_nonstatic_field_offset = nonstatic_fields_start;
 
   const bool is_contended_class     = parsed_annotations->is_contended();
 
   // Class is contended, pad before all the fields
   if (is_contended_class) {
     next_nonstatic_field_offset += ContendedPaddingWidth;
   }
 
+  // Temporary value types restrictions
+  if (is_value_type()) {
+    if (is_contended_class) {
+      throwValueTypeLimitation(THREAD_AND_LOCATION, "Value Types do not support @Contended annotation yet");
+      return;
+    }
+  }
+
   // Compute the non-contended fields count.
   // The packing code below relies on these counts to determine if some field
   // can be squeezed into the alignment gap. Contended fields are obviously
   // exempt from that.
   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];
 
+  int static_value_type_count = 0;
+  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 max_nonstatic_value_type = fac->count[NONSTATIC_FLATTENABLE] + 1;
+
+  nonstatic_value_type_indexes = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, int,
+                                                              max_nonstatic_value_type);
+  for (int i = 0; i < max_nonstatic_value_type; i++) {
+    nonstatic_value_type_indexes[i] = -1;
+  }
+  nonstatic_value_type_klasses = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, Klass*,
+                                                              max_nonstatic_value_type);
+
+  for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+    if (fs.allocation_type() == STATIC_FLATTENABLE) {
+      // Pre-resolve the flattenable field and check for value type circularity
+      // issues.  Note that super-class circularity checks are not needed here
+      // because flattenable fields can only be in value types and value types
+      // only have java.lang.Object as their super class.
+      // Also, note that super-interface circularity checks are not needed
+      // because interfaces cannot be value types.
+      ResourceMark rm;
+      if (!fs.signature()->is_Q_signature()) {
+        THROW(vmSymbols::java_lang_ClassFormatError());
+      }
+      Klass* klass =
+        SystemDictionary::resolve_flattenable_field_or_fail(&fs,
+                                                            Handle(THREAD, _loader_data->class_loader()),
+                                                            _protection_domain, true, CHECK);
+      assert(klass != NULL, "Sanity check");
+      if (!klass->access_flags().is_value_type()) {
+        THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
+      }
+      static_value_type_count++;
+    } else if (fs.allocation_type() == NONSTATIC_FLATTENABLE) {
+      // Pre-resolve the flattenable field and check for value type circularity issues.
+      ResourceMark rm;
+      if (!fs.signature()->is_Q_signature()) {
+        THROW(vmSymbols::java_lang_ClassFormatError());
+      }
+      Klass* klass =
+        SystemDictionary::resolve_flattenable_field_or_fail(&fs,
+                                                            Handle(THREAD, _loader_data->class_loader()),
+                                                            _protection_domain, true, CHECK);
+      assert(klass != NULL, "Sanity check");
+      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);
+      }
+    }
+  }
+
+  // Adjusting non_static_oop_count to take into account not flattened value types;
+  nonstatic_oop_count += not_flattened_value_types;
+
   // Total non-static fields count, including every contended field
   unsigned int nonstatic_fields_count = fac->count[NONSTATIC_DOUBLE] + fac->count[NONSTATIC_WORD] +
                                         fac->count[NONSTATIC_SHORT] + fac->count[NONSTATIC_BYTE] +
-                                        fac->count[NONSTATIC_OOP];
+                                        fac->count[NONSTATIC_OOP] + fac->count[NONSTATIC_FLATTENABLE];
 
   const bool super_has_nonstatic_fields =
           (_super_klass != NULL && _super_klass->has_nonstatic_fields());
   const bool has_nonstatic_fields =
     super_has_nonstatic_fields || (nonstatic_fields_count != 0);
+  const bool has_nonstatic_value_fields = nonstatic_value_type_count > 0;
 
+  if (is_value_type() && (!has_nonstatic_fields)) {
+    // There are a number of fixes required throughout the type system and JIT
+    throwValueTypeLimitation(THREAD_AND_LOCATION, "Value Types do not support zero instance size yet");
+    return;
+  }
 
   // Prepare list of oops for oop map generation.
   //
   // "offset" and "count" lists are describing the set of contiguous oop
   // regions. offset[i] is the start of the i-th region, which then has
   // count[i] oops following. Before we know how many regions are required,
   // we pessimistically allocate the maps to fit all the oops into the
   // distinct regions.
   //
-  // TODO: We add +1 to always allocate non-zero resource arrays; we need
-  // to figure out if we still need to do this.
-  unsigned int nonstatic_oop_map_count = 0;
-  unsigned int max_nonstatic_oop_maps  = fac->count[NONSTATIC_OOP] + 1;
-
-  int* nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
-            THREAD, int, max_nonstatic_oop_maps);
-  unsigned int* const nonstatic_oop_counts  = NEW_RESOURCE_ARRAY_IN_THREAD(
-            THREAD, unsigned int, max_nonstatic_oop_maps);
+  int super_oop_map_count = (_super_klass == NULL) ? 0 :_super_klass->nonstatic_oop_map_count();
+  int max_oop_map_count =
+      super_oop_map_count +
+      fac->count[NONSTATIC_OOP] +
+      value_type_oop_map_count +
+      not_flattened_value_types;
+
+  OopMapBlocksBuilder* nonstatic_oop_maps = new OopMapBlocksBuilder(max_oop_map_count, THREAD);
+  if (super_oop_map_count > 0) {
+    nonstatic_oop_maps->initialize_inherited_blocks(_super_klass->start_of_nonstatic_oop_maps(),
+                                                    _super_klass->nonstatic_oop_map_count());
+  }
 
   int first_nonstatic_oop_offset = 0; // will be set for first oop field
 
   bool compact_fields   = CompactFields;
   int allocation_style = FieldsAllocationStyle;

@@ -3989,17 +4274,12 @@
   } 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 ) {
-      const unsigned int map_count = _super_klass->nonstatic_oop_map_count();
-      const OopMapBlock* const first_map = _super_klass->start_of_nonstatic_oop_maps();
-      const OopMapBlock* const last_map = first_map + map_count - 1;
-      const int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
-      if (next_offset == next_nonstatic_field_offset) {
+    if( nonstatic_field_size > 0 && super_oop_map_count > 0 ) {
+      if (next_nonstatic_field_offset == nonstatic_oop_maps->last_oop_map()->end_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);
       }

@@ -4078,10 +4358,20 @@
       next_nonstatic_oop_offset = align_up(next_nonstatic_oop_offset, heapOopSize);
     }
     next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
   }
 
+  // Aligning embedded value types
+  // bug below, the current algorithm to layout embedded value types always put them at the
+  // end of the layout, which doesn't match the different allocation policies the VM is
+  // supposed to provide => FixMe
+  // Note also that the current alignment policy is to make each value type starting on a
+  // 64 bits boundary. This could be optimized later. For instance, it could be nice to
+  // align value types according to their most constrained internal type.
+  next_nonstatic_valuetype_offset = align_up(next_nonstatic_padded_offset, BytesPerLong);
+  int next_value_type_index = 0;
+
   // 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()) {
 

@@ -4094,10 +4384,12 @@
     int real_offset = 0;
     const FieldAllocationType atype = (const FieldAllocationType) fs.allocation_type();
 
     // pack the rest of the fields
     switch (atype) {
+      // Value types in static fields are handled with oops
+      case STATIC_FLATTENABLE:   // Fallthrough
       case STATIC_OOP:
         real_offset = next_static_oop_offset;
         next_static_oop_offset += heapOopSize;
         break;
       case STATIC_BYTE:

@@ -4114,39 +4406,45 @@
         break;
       case STATIC_DOUBLE:
         real_offset = next_static_double_offset;
         next_static_double_offset += BytesPerLong;
         break;
+      case NONSTATIC_FLATTENABLE:
+        if (fs.is_flattened()) {
+          Klass* klass = nonstatic_value_type_klasses[next_value_type_index];
+          assert(klass != NULL, "Klass should have been loaded and resolved earlier");
+          assert(klass->access_flags().is_value_type(),"Must be a value type");
+          ValueKlass* vklass = ValueKlass::cast(klass);
+          real_offset = next_nonstatic_valuetype_offset;
+          next_nonstatic_valuetype_offset += (vklass->size_helper()) * wordSize - vklass->first_field_offset();
+          // aligning next value type on a 64 bits boundary
+          next_nonstatic_valuetype_offset = align_up(next_nonstatic_valuetype_offset, BytesPerLong);
+          next_value_type_index += 1;
+
+          if (vklass->contains_oops()) { // add flatten oop maps
+            int diff = real_offset - vklass->first_field_offset();
+            const OopMapBlock* map = vklass->start_of_nonstatic_oop_maps();
+            const OopMapBlock* const last_map = map + vklass->nonstatic_oop_map_count();
+            while (map < last_map) {
+              nonstatic_oop_maps->add(map->offset() + diff, map->count());
+              map++;
+            }
+          }
+          break;
+        } else {
+          // Fall through
+        }
       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;
         }
-
-        // Record this oop in the 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 ) {
-          // This oop is adjacent to the previous one, add to current oop map
-          assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
-          nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
-        } else {
-          // This oop is not adjacent to the previous one, create new oop map
-          assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
-          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;
-          }
-        }
+        nonstatic_oop_maps->add(real_offset, 1);
         break;
       case NONSTATIC_BYTE:
         if( nonstatic_byte_space_count > 0 ) {
           real_offset = nonstatic_byte_space_offset;
           nonstatic_byte_space_offset += 1;

@@ -4251,34 +4549,21 @@
             next_nonstatic_padded_offset = align_up(next_nonstatic_padded_offset, BytesPerLong);
             real_offset = next_nonstatic_padded_offset;
             next_nonstatic_padded_offset += BytesPerLong;
             break;
 
+            // Value types in static fields are handled with oops
+          case NONSTATIC_FLATTENABLE:
+            throwValueTypeLimitation(THREAD_AND_LOCATION,
+                                     "@Contended annotation not supported for value types yet", fs.name(), fs.signature());
+            return;
+
           case NONSTATIC_OOP:
             next_nonstatic_padded_offset = align_up(next_nonstatic_padded_offset, heapOopSize);
             real_offset = next_nonstatic_padded_offset;
             next_nonstatic_padded_offset += heapOopSize;
-
-            // Record this oop in the 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 ) {
-              // This oop is adjacent to the previous one, add to current oop map
-              assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
-              nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
-            } else {
-              // This oop is not adjacent to the previous one, create new oop map
-              assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
-              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;
-              }
-            }
+            nonstatic_oop_maps->add(real_offset, 1);
             break;
 
           default:
             ShouldNotReachHere();
         }

@@ -4309,16 +4594,28 @@
 
   // Entire class is contended, pad in the back.
   // This helps to alleviate memory contention effects for subclass fields
   // and/or adjacent object.
   if (is_contended_class) {
+    assert(!is_value_type(), "@Contended not supported for value types yet");
     next_nonstatic_padded_offset += ContendedPaddingWidth;
   }
 
-  int notaligned_nonstatic_fields_end = next_nonstatic_padded_offset;
+  int notaligned_nonstatic_fields_end;
+  if (nonstatic_value_type_count != 0) {
+    notaligned_nonstatic_fields_end = next_nonstatic_valuetype_offset;
+  } else {
+    notaligned_nonstatic_fields_end = next_nonstatic_padded_offset;
+  }
 
-  int nonstatic_fields_end      = align_up(notaligned_nonstatic_fields_end, heapOopSize);
+  int nonstatic_field_sz_align = heapOopSize;
+  if (is_value_type()) {
+    if ((notaligned_nonstatic_fields_end - nonstatic_fields_start) > heapOopSize) {
+      nonstatic_field_sz_align = BytesPerLong; // value copy of fields only uses jlong copy
+    }
+  }
+  int nonstatic_fields_end      = align_up(notaligned_nonstatic_fields_end, nonstatic_field_sz_align);
   int instance_end              = align_up(notaligned_nonstatic_fields_end, wordSize);
   int static_fields_end         = align_up(next_static_byte_offset, wordSize);
 
   int static_field_size         = (static_fields_end -
                                    InstanceMirrorKlass::offset_of_static_fields()) / wordSize;

@@ -4326,92 +4623,49 @@
                                   (nonstatic_fields_end - nonstatic_fields_start) / heapOopSize;
 
   int instance_size             = align_object_size(instance_end / wordSize);
 
   assert(instance_size == align_object_size(align_up(
-         (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize),
-          wordSize) / wordSize), "consistent layout helper value");
+         (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize)
+         + initial_value_type_padding, wordSize) / wordSize), "consistent layout helper value");
+
 
   // Invariant: nonstatic_field end/start should only change if there are
   // nonstatic fields in the class, or if the class is contended. We compare
   // against the non-aligned value, so that end alignment will not fail the
   // assert without actually having the fields.
   assert((notaligned_nonstatic_fields_end == nonstatic_fields_start) ||
          is_contended_class ||
          (nonstatic_fields_count > 0), "double-check nonstatic start/end");
 
   // 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);
+  nonstatic_oop_maps->compact(THREAD);
 
 #ifndef PRODUCT
-  if (PrintFieldLayout) {
+  if ((PrintFieldLayout && !is_value_type()) ||
+      (PrintValueLayout && (is_value_type() || has_nonstatic_value_fields))) {
     print_field_layout(_class_name,
           _fields,
           cp,
           instance_size,
           nonstatic_fields_start,
           nonstatic_fields_end,
           static_fields_end);
+    nonstatic_oop_maps->print_on(tty);
+    tty->print("\n");
   }
 
 #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->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;
 }
 
-static void fill_oop_maps(const InstanceKlass* k,
-                          unsigned int nonstatic_oop_map_count,
-                          const int* nonstatic_oop_offsets,
-                          const unsigned int* nonstatic_oop_counts) {
-
-  assert(k != NULL, "invariant");
-
-  OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps();
-  const InstanceKlass* const super = k->superklass();
-  const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0;
-  if (super_count > 0) {
-    // Copy maps from superklass
-    OopMapBlock* super_oop_map = super->start_of_nonstatic_oop_maps();
-    for (unsigned int i = 0; i < super_count; ++i) {
-      *this_oop_map++ = *super_oop_map++;
-    }
-  }
-
-  if (nonstatic_oop_map_count > 0) {
-    if (super_count + nonstatic_oop_map_count > k->nonstatic_oop_map_count()) {
-      // The counts differ because there is no gap between superklass's last oop
-      // field and the first local oop field.  Extend the last oop map copied
-      // from the superklass instead of creating new one.
-      nonstatic_oop_map_count--;
-      nonstatic_oop_offsets++;
-      this_oop_map--;
-      this_oop_map->set_count(this_oop_map->count() + *nonstatic_oop_counts++);
-      this_oop_map++;
-    }
-
-    // Add new map blocks, fill them
-    while (nonstatic_oop_map_count-- > 0) {
-      this_oop_map->set_offset(*nonstatic_oop_offsets++);
-      this_oop_map->set_count(*nonstatic_oop_counts++);
-      this_oop_map++;
-    }
-    assert(k->start_of_nonstatic_oop_maps() + k->nonstatic_oop_map_count() ==
-           this_oop_map, "sanity");
-  }
-}
-
-
-void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
+void ClassFileParser::set_precomputed_flags(InstanceKlass* ik, TRAPS) {
   assert(ik != NULL, "invariant");
 
   const Klass* const super = ik->super();
 
   // Check if this klass has an empty finalize method (i.e. one with return bytecode only),

@@ -4440,10 +4694,14 @@
 #endif
 
   // Check if this klass supports the java.lang.Cloneable interface
   if (SystemDictionary::Cloneable_klass_loaded()) {
     if (ik->is_subtype_of(SystemDictionary::Cloneable_klass())) {
+      if (ik->is_value()) {
+        throwValueTypeLimitation(THREAD_AND_LOCATION, "Value Types do not support Cloneable");
+        return;
+      }
       ik->set_is_cloneable();
     }
   }
 
   // Check if this klass has a vanilla default constructor

@@ -4480,10 +4738,15 @@
     const jint lh = Klass::instance_layout_helper(ik->size_helper(), true);
     ik->set_layout_helper(lh);
   }
 }
 
+bool ClassFileParser::supports_value_types() const {
+  // Value types are only supported by class file version 55 and later
+  return _major_version >= JAVA_11_VERSION;
+}
+
 // utility methods for appending an array with check for duplicates
 
 static void append_interfaces(GrowableArray<InstanceKlass*>* result,
                               const Array<InstanceKlass*>* const ifs) {
   // iterate over new interfaces

@@ -4742,21 +5005,33 @@
 
 // utility methods for format checking
 
 void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
   const bool is_module = (flags & JVM_ACC_MODULE) != 0;
+  const bool is_value_type = (flags & JVM_ACC_VALUE) != 0;
   assert(_major_version >= JAVA_9_VERSION || !is_module, "JVM_ACC_MODULE should not be set");
+  assert(supports_value_types() || !is_value_type, "JVM_ACC_VALUE should not be set");
   if (is_module) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
       vmSymbols::java_lang_NoClassDefFoundError(),
       "%s is not a class because access_flag ACC_MODULE is set",
       _class_name->as_C_string());
     return;
   }
 
+  if (is_value_type && !EnableValhalla) {
+    ResourceMark rm(THREAD);
+    Exceptions::fthrow(
+      THREAD_AND_LOCATION,
+      vmSymbols::java_lang_ClassFormatError(),
+      "Class modifier ACC_VALUE in class %s requires option -XX:+EnableValhalla",
+      _class_name->as_C_string()
+    );
+  }
+
   if (!_need_verify) { return; }
 
   const bool is_interface  = (flags & JVM_ACC_INTERFACE)  != 0;
   const bool is_abstract   = (flags & JVM_ACC_ABSTRACT)   != 0;
   const bool is_final      = (flags & JVM_ACC_FINAL)      != 0;

@@ -4766,11 +5041,12 @@
   const bool major_gte_15  = _major_version >= JAVA_1_5_VERSION;
 
   if ((is_abstract && is_final) ||
       (is_interface && !is_abstract) ||
       (is_interface && major_gte_15 && (is_super || is_enum)) ||
-      (!is_interface && major_gte_15 && is_annotation)) {
+      (!is_interface && major_gte_15 && is_annotation) ||
+      (is_value_type && (is_interface || is_abstract || is_enum || !is_final))) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
       vmSymbols::java_lang_ClassFormatError(),
       "Illegal class modifiers in class %s: 0x%X",

@@ -4849,10 +5125,11 @@
   }
 }
 
 void ClassFileParser::verify_legal_field_modifiers(jint flags,
                                                    bool is_interface,
+                                                   bool is_value_type,
                                                    TRAPS) const {
   if (!_need_verify) { return; }
 
   const bool is_public    = (flags & JVM_ACC_PUBLIC)    != 0;
   const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;

@@ -4873,10 +5150,14 @@
       is_illegal = true;
     }
   } else { // not interface
     if (has_illegal_visibility(flags) || (is_final && is_volatile)) {
       is_illegal = true;
+    } else {
+      if (is_value_type && !is_static && !is_final) {
+        is_illegal = true;
+      }
     }
   }
 
   if (is_illegal) {
     ResourceMark rm(THREAD);

@@ -4889,10 +5170,11 @@
   }
 }
 
 void ClassFileParser::verify_legal_method_modifiers(jint flags,
                                                     bool is_interface,
+                                                    bool is_value_type,
                                                     const Symbol* name,
                                                     TRAPS) const {
   if (!_need_verify) { return; }
 
   const bool is_public       = (flags & JVM_ACC_PUBLIC)       != 0;

@@ -4948,19 +5230,23 @@
         if (is_static || is_final || is_synchronized || is_native ||
             is_abstract || (major_gte_15 && is_bridge)) {
           is_illegal = true;
         }
       } else { // not initializer
+        if (is_value_type && is_synchronized && !is_static) {
+          is_illegal = true;
+        } else {
         if (is_abstract) {
           if ((is_final || is_native || is_private || is_static ||
               (major_gte_15 && (is_synchronized || is_strict)))) {
             is_illegal = true;
           }
         }
       }
     }
   }
+  }
 
   if (is_illegal) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,

@@ -5120,22 +5406,31 @@
     case JVM_SIGNATURE_INT:
     case JVM_SIGNATURE_FLOAT:
     case JVM_SIGNATURE_LONG:
     case JVM_SIGNATURE_DOUBLE:
       return signature + 1;
-    case JVM_SIGNATURE_CLASS: {
+    case JVM_SIGNATURE_VALUETYPE:
+      // Can't enable this check until JDK upgrades the bytecode generators
+      // if (_major_version < CONSTANT_CLASS_DESCRIPTORS ) {
+      //   classfile_parse_error("Class name contains illegal Q-signature "
+      //                                    "in descriptor in class file %s",
+      //                                    CHECK_0);
+      // }
+      // fall through
+    case JVM_SIGNATURE_CLASS:
+    {
       if (_major_version < JAVA_1_5_VERSION) {
         // Skip over the class name if one is there
         const char* const p = skip_over_field_name(signature + 1, true, --length);
 
         // The next character better be a semicolon
         if (p && (p - signature) > 1 && p[0] == ';') {
           return p + 1;
         }
       }
       else {
-        // Skip leading 'L' and ignore first appearance of ';'
+        // Skip leading 'L' or 'Q' and ignore first appearance of ';'
         signature++;
         const char* c = (const char*) memchr(signature, ';', length - 1);
         // Format check signature
         if (c != NULL) {
           int newlen = c - (char*) signature;

@@ -5186,10 +5481,13 @@
     } else if (_major_version < JAVA_1_5_VERSION) {
       if (bytes[0] != '<') {
         p = skip_over_field_name(bytes, true, length);
         legal = (p != NULL) && ((p - bytes) == (int)length);
       }
+    } else if (_major_version >= CONSTANT_CLASS_DESCRIPTORS && bytes[length - 1] == ';' ) {
+      // Support for L...; and Q...; descriptors
+      legal = verify_unqualified_name(bytes + 1, length - 2, LegalClass);
     } else {
       // 4900761: relax the constraints based on JSR202 spec
       // Class names may be drawn from the entire Unicode character set.
       // Identifiers between '/' must be unqualified names.
       // The utf8 string has been verified when parsing cpool entries.

@@ -5360,11 +5658,11 @@
   return _field_info->static_field_size;
 }
 
 int ClassFileParser::total_oop_map_count() const {
   assert(_field_info != NULL, "invariant");
-  return _field_info->total_oop_map_count;
+  return _field_info->oop_map_blocks->nonstatic_oop_map_count;
 }
 
 jint ClassFileParser::layout_size() const {
   assert(_field_info != NULL, "invariant");
   return _field_info->instance_size;

@@ -5490,10 +5788,16 @@
       log_info(class, fingerprint)("%s :  expected = " PTR64_FORMAT " actual = " PTR64_FORMAT,
                                  ik->external_name(), aot_fp, _stream->compute_fingerprint());
     }
   }
 
+  if (ik->is_value()) {
+    ValueKlass* vk = ValueKlass::cast(ik);
+    oop val = ik->allocate_instance(CHECK_NULL);
+    vk->set_default_value(val);
+  }
+
   return ik;
 }
 
 void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
   assert(ik != NULL, "invariant");

@@ -5510,11 +5814,11 @@
 
   set_klass_to_deallocate(ik);
 
   assert(_field_info != NULL, "invariant");
   assert(ik->static_field_size() == _field_info->static_field_size, "sanity");
-  assert(ik->nonstatic_oop_map_count() == _field_info->total_oop_map_count,
+  assert(ik->nonstatic_oop_map_count() == _field_info->oop_map_blocks->nonstatic_oop_map_count,
     "sanity");
 
   assert(ik->is_instance_klass(), "sanity");
   assert(ik->size_helper() == _field_info->instance_size, "sanity");
 

@@ -5523,11 +5827,11 @@
 
   // 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);
   assert(_fac != NULL, "invariant");
-  ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+  ik->set_static_oop_field_count(_fac->count[STATIC_OOP] + _fac->count[STATIC_FLATTENABLE]);
 
   // this transfers ownership of a lot of arrays from
   // the parser onto the InstanceKlass*
   apply_parsed_class_metadata(ik, _java_fields_count, CHECK);
 

@@ -5611,17 +5915,17 @@
   // Initialize itable offset tables
   klassItable::setup_itable_offset_table(ik);
 
   // Compute transitive closure of interfaces this class implements
   // Do final class setup
-  fill_oop_maps(ik,
-                _field_info->nonstatic_oop_map_count,
-                _field_info->nonstatic_oop_offsets,
-                _field_info->nonstatic_oop_counts);
+  OopMapBlocksBuilder* oop_map_blocks = _field_info->oop_map_blocks;
+  if (oop_map_blocks->nonstatic_oop_map_count > 0) {
+    oop_map_blocks->copy(ik->start_of_nonstatic_oop_maps());
+  }
 
   // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
-  set_precomputed_flags(ik);
+  set_precomputed_flags(ik, CHECK);
 
   // check if this class can access its super class
   check_super_class_access(ik, CHECK);
 
   // check if this class can access its superinterfaces

@@ -5667,10 +5971,33 @@
       // We won a potential race
       JvmtiExport::add_default_read_edges(module_handle, THREAD);
     }
   }
 
+  int nfields = ik->java_fields_count();
+  if (ik->is_value()) nfields++;
+  for (int i = 0; i < nfields; i++) {
+    if (ik->field_access_flags(i) & JVM_ACC_FLATTENABLE) {
+      Symbol* klass_name = ik->field_signature(i)->fundamental_name(CHECK);
+      // Value classes must have been pre-loaded
+      Klass* klass = SystemDictionary::find(klass_name,
+          Handle(THREAD, ik->class_loader()),
+          Handle(THREAD, ik->protection_domain()), CHECK);
+      assert(klass != NULL, "Sanity check");
+      assert(klass->access_flags().is_value_type(), "Value type expected");
+      ik->set_value_field_klass(i, klass);
+      klass_name->decrement_refcount();
+    } else if (is_value_type() && ((ik->field_access_flags(i) & JVM_ACC_FIELD_INTERNAL) != 0)
+        && ((ik->field_access_flags(i) & JVM_ACC_STATIC) != 0)) {
+      ValueKlass::cast(ik)->set_default_value_offset(ik->field_offset(i));
+    }
+  }
+
+  if (is_value_type()) {
+    ValueKlass::cast(ik)->initialize_calling_convention(CHECK);
+  }
+
   ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
 
   if (!is_internal()) {
     if (log_is_enabled(Info, class, load)) {
       ResourceMark rm;

@@ -5856,10 +6183,11 @@
   _need_verify(false),
   _relax_verify(false),
   _has_nonstatic_concrete_methods(false),
   _declares_nonstatic_concrete_methods(false),
   _has_final_method(false),
+  _has_flattenable_fields(false),
   _has_finalizer(false),
   _has_empty_finalizer(false),
   _has_vanilla_constructor(false),
   _max_bootstrap_specifier_index(-1) {
 

@@ -6051,19 +6379,23 @@
   assert(cp_size == (const u2)cp->length(), "invariant");
 
   // ACCESS FLAGS
   stream->guarantee_more(8, CHECK);  // flags, this_class, super_class, infs_len
 
-  // Access flags
-  jint flags;
+  jint recognized_modifiers = JVM_RECOGNIZED_CLASS_MODIFIERS;
   // JVM_ACC_MODULE is defined in JDK-9 and later.
   if (_major_version >= JAVA_9_VERSION) {
-    flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);
-  } else {
-    flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
+    recognized_modifiers |= JVM_ACC_MODULE;
+  }
+  // JVM_ACC_VALUE is defined for class file version 55 and later
+  if (supports_value_types()) {
+    recognized_modifiers |= JVM_ACC_VALUE;
   }
 
+  // Access flags
+  jint flags = stream->get_u2_fast() & recognized_modifiers;
+
   if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
     // Set abstract bit for old class files for backward compatibility
     flags |= JVM_ACC_ABSTRACT;
   }
 

@@ -6194,10 +6526,11 @@
 
   // 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);

@@ -6206,10 +6539,11 @@
 
   // 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);
 

@@ -6287,10 +6621,18 @@
         _class_name->as_klass_external_name(),
         _super_klass->external_name()
       );
       return;
     }
+
+    // For a value class, only java/lang/Object is an acceptable super class
+    if (_access_flags.get_flags() & JVM_ACC_VALUE) {
+      guarantee_property(_super_klass->name() == vmSymbols::java_lang_Object(),
+        "Value type must have java.lang.Object as superclass in class file %s",
+        CHECK);
+    }
+
     // Make sure super class is not final
     if (_super_klass->is_final()) {
       THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
     }
   }

@@ -6327,10 +6669,23 @@
     klassItable::compute_itable_size(_transitive_interfaces);
 
   assert(_fac != NULL, "invariant");
   assert(_parsed_annotations != NULL, "invariant");
 
+
+  for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
+    if (fs.is_flattenable()) {
+      // Pre-load value class
+      Klass* klass = SystemDictionary::resolve_flattenable_field_or_fail(&fs,
+          Handle(THREAD, _loader_data->class_loader()),
+          _protection_domain, true, CHECK);
+      assert(klass != NULL, "Sanity check");
+      assert(klass->access_flags().is_value_type(), "Value type expected");
+      _has_flattenable_fields = true;
+    }
+  }
+
   _field_info = new FieldLayoutInfo();
   layout_fields(cp, _fac, _parsed_annotations, _field_info, CHECK);
 
   // Compute reference typ
   _rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type();

@@ -6364,10 +6719,11 @@
 const ClassFileStream* ClassFileParser::clone_stream() const {
   assert(_stream != NULL, "invariant");
 
   return _stream->clone();
 }
+
 // ----------------------------------------------------------------------------
 // debugging
 
 #ifdef ASSERT
 
< prev index next >