changeset 53146:414c7fe66a7c lworld

8214489: [LW2] Q-mirror and method handle, and reflection initial support for Q-type Reviewed-by: fparain, thartmann
author mchung
date Thu, 29 Nov 2018 09:02:32 -0800
parents f5e1ce7c05bb
children 6982a88c661c
files src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/javaClasses.hpp src/hotspot/share/classfile/vmSymbols.cpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp src/hotspot/share/oops/valueKlass.hpp src/hotspot/share/runtime/javaCalls.cpp src/hotspot/share/runtime/reflection.cpp src/hotspot/share/runtime/signature.cpp src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java src/java.base/share/classes/java/lang/invoke/MemberName.java src/java.base/share/classes/java/lang/invoke/MethodHandleInfo.java src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java src/java.base/share/classes/java/lang/invoke/VarHandle.java src/java.base/share/classes/java/lang/reflect/Array.java src/java.base/share/classes/java/lang/reflect/Constructor.java src/java.base/share/classes/java/lang/reflect/Field.java src/java.base/share/classes/java/lang/reflect/Method.java src/java.base/share/classes/java/lang/reflect/Proxy.java src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java src/java.base/share/classes/jdk/internal/misc/Unsafe.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Method.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureReader.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java src/java.base/share/classes/sun/invoke/util/VerifyAccess.java src/java.base/share/native/libjava/Class.c src/java.base/share/native/libverify/check_code.c src/java.base/share/native/libverify/check_format.c test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java test/jdk/valhalla/valuetypes/MethodHandleTest.java test/jdk/valhalla/valuetypes/MixedValues.java test/jdk/valhalla/valuetypes/NonFlattenValue.java test/jdk/valhalla/valuetypes/QTypeDescriptorTest.java test/jdk/valhalla/valuetypes/Reflection.java test/jdk/valhalla/valuetypes/ValueArray.java test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java test/jdk/valhalla/valuetypes/ValueTypesAttributeTest.java
diffstat 55 files changed, 711 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/classFileParser.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -5447,11 +5447,12 @@
     case JVM_SIGNATURE_DOUBLE:
       return signature + 1;
     case JVM_SIGNATURE_VALUETYPE:
-      if (_major_version < CONSTANT_CLASS_DESCRIPTORS ) {
-        classfile_parse_error("Class name contains illegal Q-signature "
-                                          "in descriptor in class file %s",
-                                          CHECK_0);
-      }
+      // 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:
     {
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -918,7 +918,12 @@
     if (k->is_array_klass()) {
       if (k->is_valueArray_klass()) {
         Klass* element_klass = (Klass*) ValueArrayKlass::cast(k)->element_klass();
-        comp_mirror = Handle(THREAD, element_klass->java_mirror());
+        if (element_klass->is_value()) {
+          ValueKlass* vk = ValueKlass::cast(InstanceKlass::cast(element_klass));
+          comp_mirror = Handle(THREAD, vk->value_mirror());
+        } else {
+          comp_mirror = Handle(THREAD, element_klass->java_mirror());
+        }
       }
       else if (k->is_typeArray_klass()) {
         BasicType type = TypeArrayKlass::cast(k)->element_type();
@@ -927,7 +932,12 @@
         assert(k->is_objArray_klass(), "Must be");
         Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
         assert(element_klass != NULL, "Must have an element klass");
-        comp_mirror = Handle(THREAD, element_klass->java_mirror());
+        if (element_klass->is_value()) {
+          ValueKlass* vk = ValueKlass::cast(InstanceKlass::cast(element_klass));
+          comp_mirror = Handle(THREAD, vk->value_mirror());
+        } else {
+          comp_mirror = Handle(THREAD, element_klass->java_mirror());
+        }
       }
       assert(comp_mirror() != NULL, "must have a mirror");
 
@@ -967,12 +977,46 @@
       // concurrently doesn't expect a k to have a null java_mirror.
       release_set_array_klass(comp_mirror(), k);
     }
+
+    if (k->is_value()) {
+      // create the secondary mirror for value class
+      oop value_mirror_oop = create_value_mirror(k, mirror, CHECK);
+      set_box_mirror(mirror(), mirror());
+      set_value_mirror(mirror(), value_mirror_oop);
+    }
   } else {
     assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
     fixup_mirror_list()->push(k);
   }
 }
 
+// Create the secondary mirror for value type. Sets all the fields of this java.lang.Class
+// instance with the same value as the primary mirror except signers.
+// Class::setSigners and getSigners will use the primary mirror when passed to the JVM.
+oop java_lang_Class::create_value_mirror(Klass* k, Handle mirror, TRAPS) {
+    // Allocate mirror (java.lang.Class instance)
+    oop mirror_oop = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK_0);
+    Handle value_mirror(THREAD, mirror_oop);
+
+    java_lang_Class::set_klass(value_mirror(), k);
+    java_lang_Class::set_static_oop_field_count(value_mirror(), static_oop_field_count(mirror()));
+    // ## do we need to set init lock?
+    java_lang_Class::set_init_lock(value_mirror(), init_lock(mirror()));
+
+    if (k->is_array_klass()) {
+      assert(component_mirror(mirror()) != NULL, "must have a mirror");
+      set_component_mirror(value_mirror(), component_mirror(mirror()));
+    }
+
+    set_protection_domain(value_mirror(), protection_domain(mirror()));
+    set_class_loader(value_mirror(), class_loader(mirror()));
+    // ## handle if java.base is not yet defined
+    set_module(value_mirror(), module(mirror()));
+    set_box_mirror(value_mirror(), mirror());
+    set_value_mirror(value_mirror(), value_mirror());
+    return value_mirror();
+}                                              
+
 #if INCLUDE_CDS_JAVA_HEAP
 // Clears mirror fields. Static final fields with initial values are reloaded
 // from constant pool. The object identity hash is in the object header and is
@@ -1363,6 +1407,26 @@
   java_class->obj_field_put(_module_offset, module);
 }
 
+oop java_lang_Class::value_mirror(oop java_class) {
+  assert(_value_mirror_offset != 0, "must be set");
+  return java_class->obj_field(_value_mirror_offset);
+}
+
+void java_lang_Class::set_value_mirror(oop java_class, oop mirror) {
+  assert(_value_mirror_offset != 0, "must be set");
+  java_class->obj_field_put(_value_mirror_offset, mirror);
+}
+
+oop java_lang_Class::box_mirror(oop java_class) {
+  assert(_box_mirror_offset != 0, "must be set");
+  return java_class->obj_field(_box_mirror_offset);
+}
+
+void java_lang_Class::set_box_mirror(oop java_class, oop mirror) {
+  assert(_box_mirror_offset != 0, "must be set");
+  java_class->obj_field_put(_box_mirror_offset, mirror);
+}
+
 oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
   // This should be improved by adding a field at the Java level or by
   // introducing a new VM klass (see comment in ClassFileParser)
@@ -1447,8 +1511,14 @@
       name->increment_refcount();
     } else {
       ResourceMark rm;
-      const char* sigstr = k->signature_name();
-      int         siglen = (int) strlen(sigstr);
+      const char* sigstr;
+      if (k->is_value()) {
+        char c = (java_class == value_mirror(java_class)) ? 'Q' : 'L';
+        sigstr = InstanceKlass::cast(k)->signature_name_of(c);
+      } else {
+        sigstr = k->signature_name();
+      }
+      int siglen = (int) strlen(sigstr);
       if (!intern_if_not_found) {
         name = SymbolTable::probe(sigstr, siglen);
       } else {
@@ -1548,7 +1618,9 @@
   macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature,         false) ; \
   macro(_class_loader_offset,       k, "classLoader",         classloader_signature, false); \
   macro(_component_mirror_offset,   k, "componentType",       class_signature,       false); \
-  macro(_module_offset,             k, "module",              module_signature,      false)
+  macro(_module_offset,             k, "module",              module_signature,      false); \
+  macro(_box_mirror_offset,         k, "boxType",             class_signature,       false); \
+  macro(_value_mirror_offset,       k, "valueType",           class_signature,       false)
 
 void java_lang_Class::compute_offsets() {
   if (offsets_computed) {
@@ -4207,6 +4279,8 @@
 int java_lang_Class::_module_offset;
 int java_lang_Class::_protection_domain_offset;
 int java_lang_Class::_component_mirror_offset;
+int java_lang_Class::_box_mirror_offset;
+int java_lang_Class::_value_mirror_offset;
 int java_lang_Class::_init_lock_offset;
 int java_lang_Class::_signers_offset;
 GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
--- a/src/hotspot/share/classfile/javaClasses.hpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Thu Nov 29 09:02:32 2018 -0800
@@ -240,6 +240,8 @@
   static int _class_loader_offset;
   static int _module_offset;
   static int _component_mirror_offset;
+  static int _box_mirror_offset;
+  static int _value_mirror_offset;
 
   static bool offsets_computed;
   static int classRedefinedCount_offset;
@@ -262,6 +264,7 @@
                             Handle protection_domain, TRAPS);
   static void fixup_mirror(Klass* k, TRAPS);
   static oop  create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
+  static oop  create_value_mirror(Klass* k, Handle mirror, TRAPS);
 
   // Archiving
   static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
@@ -310,6 +313,11 @@
   static void set_module(oop java_class, oop module);
   static oop module(oop java_class);
 
+  static void set_box_mirror(oop java_class, oop mirror);
+  static oop box_mirror(oop java_class);
+  static void set_value_mirror(oop java_class, oop mirror);
+  static oop value_mirror(oop java_class);
+
   static int oop_size(oop java_class);
   static int oop_size_raw(oop java_class);
   static void set_oop_size(HeapWord* java_class, int size);
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -218,7 +218,7 @@
       return result;
     }
   }
-  return T_OBJECT;
+  return s->byte_at(0) == 'Q' ? T_VALUETYPE : T_OBJECT;
 }
 
 
--- a/src/hotspot/share/oops/instanceKlass.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -2638,6 +2638,10 @@
 }
 
 const char* InstanceKlass::signature_name() const {
+  return signature_name_of(is_value() ? 'Q' : 'L');
+}
+
+const char* InstanceKlass::signature_name_of(char c) const {
   int hash_len = 0;
   char hash_buf[40];
 
@@ -2656,11 +2660,7 @@
 
   // Add L or Q as type indicator
   int dest_index = 0;
-  if (is_value()) {
-    dest[dest_index++] = 'Q';
-  } else {
-    dest[dest_index++] = 'L';
-  }
+  dest[dest_index++] = c;
 
   // Add the actual class name
   for (int src_index = 0; src_index < src_length; ) {
--- a/src/hotspot/share/oops/instanceKlass.hpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Thu Nov 29 09:02:32 2018 -0800
@@ -1310,6 +1310,7 @@
 
   // Naming
   const char* signature_name() const;
+  const char* signature_name_of(char c) const;
   static Symbol* package_from_name(const Symbol* name, TRAPS);
 
   // GC specific object visitors
--- a/src/hotspot/share/oops/valueKlass.hpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/oops/valueKlass.hpp	Thu Nov 29 09:02:32 2018 -0800
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_OOPS_VALUEKLASS_HPP
 #define SHARE_VM_OOPS_VALUEKLASS_HPP
 
+#include "classfile/javaClasses.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
@@ -127,6 +128,10 @@
   // Type testing
   bool is_value_slow() const        { return true; }
 
+  oop value_mirror() const {
+    return java_lang_Class::value_mirror(java_mirror());
+  }
+  
   // Casting from Klass*
   static ValueKlass* cast(Klass* k) {
     assert(k->is_value(), "cast to ValueKlass");
--- a/src/hotspot/share/runtime/javaCalls.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/runtime/javaCalls.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -159,22 +159,24 @@
 // Helper methods
 static BasicType runtime_type_from(JavaValue* result) {
   switch (result->get_type()) {
-    case T_BOOLEAN: // fall through
-    case T_CHAR   : // fall through
-    case T_SHORT  : // fall through
-    case T_INT    : // fall through
+    case T_BOOLEAN  : // fall through
+    case T_CHAR     : // fall through
+    case T_SHORT    : // fall through
+    case T_INT      : // fall through
 #ifndef _LP64
-    case T_OBJECT : // fall through
-    case T_ARRAY  : // fall through
+    case T_OBJECT   : // fall through
+    case T_ARRAY    : // fall through
+    case T_VALUETYPE: // fall through
 #endif
-    case T_BYTE   : // fall through
-    case T_VOID   : return T_INT;
-    case T_LONG   : return T_LONG;
-    case T_FLOAT  : return T_FLOAT;
-    case T_DOUBLE : return T_DOUBLE;
+    case T_BYTE     : // fall through
+    case T_VOID     : return T_INT;
+    case T_LONG     : return T_LONG;
+    case T_FLOAT    : return T_FLOAT;
+    case T_DOUBLE   : return T_DOUBLE;
 #ifdef _LP64
-    case T_ARRAY  : // fall through
-    case T_OBJECT:  return T_OBJECT;
+    case T_ARRAY    : // fall through
+    case T_OBJECT   : return T_OBJECT;
+    case T_VALUETYPE: return T_VALUETYPE;
 #endif
     default:
       ShouldNotReachHere();
--- a/src/hotspot/share/runtime/reflection.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/runtime/reflection.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -40,6 +40,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/arguments.hpp"
@@ -50,6 +51,7 @@
 #include "runtime/reflectionUtils.hpp"
 #include "runtime/signature.hpp"
 #include "runtime/vframe.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
 
 static void trace_class_resolution(const Klass* to_class) {
   ResourceMark rm;
@@ -782,13 +784,24 @@
   );
 }
 
+// Returns Q-mirror if qtype_if_value is true and k is a ValueKlass;
+// otherwise returns java_mirror or L-mirror for ValueKlass
+static oop java_mirror(Klass* k, jboolean qtype_if_value) {
+  if (qtype_if_value && k->is_value()) {
+    ValueKlass* vk = ValueKlass::cast(InstanceKlass::cast(k));
+    return vk->value_mirror();
+  } else {
+    return k->java_mirror();
+  }
+}
+
 // Utility method converting a single SignatureStream element into java.lang.Class instance
 static oop get_mirror_from_signature(const methodHandle& method,
                                      SignatureStream* ss,
                                      TRAPS) {
 
-
-  if (T_OBJECT == ss->type() || T_ARRAY == ss->type() || T_VALUETYPE == ss->type()) {
+  BasicType bt = ss->type();
+  if (T_OBJECT == bt || T_ARRAY == bt || T_VALUETYPE == bt) {
     Symbol* name = ss->as_symbol(CHECK_NULL);
     oop loader = method->method_holder()->class_loader();
     oop protection_domain = method->method_holder()->protection_domain();
@@ -800,13 +813,13 @@
     if (log_is_enabled(Debug, class, resolve)) {
       trace_class_resolution(k);
     }
-    return k->java_mirror();
+    return java_mirror((Klass*)k, bt == T_VALUETYPE);
   }
 
-  assert(ss->type() != T_VOID || ss->at_return_type(),
+  assert(bt != T_VOID || ss->at_return_type(),
     "T_VOID should only appear as return type");
 
-  return java_lang_Class::primitive_mirror(ss->type());
+  return java_lang_Class::primitive_mirror(bt);
 }
 
 static objArrayHandle get_parameter_types(const methodHandle& method,
@@ -855,8 +868,7 @@
   if (log_is_enabled(Debug, class, resolve)) {
     trace_class_resolution(result);
   }
-
-  oop nt = result->java_mirror();
+  oop nt = java_mirror(result, type == T_VALUETYPE);
   return Handle(THREAD, nt);
 }
 
@@ -1269,6 +1281,8 @@
   BasicType rtype;
   if (java_lang_Class::is_primitive(return_type_mirror)) {
     rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
+  } else if (java_lang_Class::value_mirror(return_type_mirror) == return_type_mirror) {
+    rtype = T_VALUETYPE;
   } else {
     rtype = T_OBJECT;
   }
--- a/src/hotspot/share/runtime/signature.cpp	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/hotspot/share/runtime/signature.cpp	Thu Nov 29 09:02:32 2018 -0800
@@ -31,6 +31,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
+#include "oops/valueKlass.hpp"
 #include "runtime/signature.hpp"
 
 // Implementation of SignatureIterator
@@ -403,7 +404,7 @@
     return Universe::java_mirror(type());
   Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL);
   if (klass == NULL)  return NULL;
-  return klass->java_mirror();
+  return _type == T_VALUETYPE ? ValueKlass::cast(InstanceKlass::cast(klass))->value_mirror() : klass->java_mirror();
 }
 
 Symbol* SignatureStream::as_symbol_or_null() {
--- a/src/java.base/share/classes/java/lang/Class.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/Class.java	Thu Nov 29 09:02:32 2018 -0800
@@ -58,7 +58,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.StringJoiner;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
@@ -189,8 +188,9 @@
      * @return a string representation of this class object.
      */
     public String toString() {
-        return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
-            + getName();
+        return (isValue() ? "value " : "")
+               + (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+               + getName();
     }
 
     /**
@@ -250,6 +250,10 @@
                 if (isAnnotation()) {
                     sb.append('@');
                 }
+                if (isValue()) {
+                    sb.append("value");
+                    sb.append(' ');
+                }
                 if (isInterface()) { // Note: all annotation types are interfaces
                     sb.append("interface");
                 } else {
@@ -338,6 +342,10 @@
      * <p> If {@code name} denotes an array class, the component type of
      * the array class is loaded but not initialized.
      *
+     * <p> If {@code name} denotes a value class, this method returns
+     * the {@code Class} object representing the
+     * {@linkplain #asBoxType() box value type}.
+     *
      * <p> For example, in an instance method the expression:
      *
      * <blockquote>
@@ -418,6 +426,10 @@
      * the given name is a class defined in a different module, this method
      * returns {@code null} after the class is loaded. </p>
      *
+     * <p> If {@code name} denotes a value class, this method returns
+     * the {@code Class} object representing the
+     * {@linkplain #asBoxType() box value type}. </p>
+     *
      * <p> This method does not check whether the requested class is
      * accessible to its caller. </p>
      *
@@ -499,6 +511,51 @@
     }
 
     /**
+     * Returns a {@code Class} object representing the <em>box type</em>
+     * of this class if this class is a {@linkplain #isValue() value class};
+     * otherwise, returns this class.
+     *
+     * <p> A value class has two {@code Class} representations,
+     * a null-free type or a nullable box type, that can be obtained
+     * by calling {@link #asValueType()} or {@link #asBoxType()} method
+     * for conversion.
+     *
+     * @return the box type of this class if this class is a value class;
+     *         otherwise, this class.
+     */
+    public Class<?> asBoxType() {
+        return isValue() ? boxType : this;
+    }
+
+    /**
+     * Returns a {@code Class} object representing the <em>null-free value type</em>
+     * of this class if this class is a {@linkplain #isValue() value class};
+     * otherwise, returns {@code null}.
+     *
+     * <p> A value class has two {@code Class} representations,
+     * a null-free type or a nullable box type, that can be obtained
+     * by calling {@link #asValueType()} or {@link #asBoxType()} method
+     * for conversion.
+     *
+     * @return the unbox value type of this class if this class is a value class;
+     *         otherwise, {@code null}.
+     */
+    public Class<?> asValueType() {
+        return isValue() ? valueType : null;
+    }
+
+    /*
+     * Returns true if this class is a non-value class or a box value class.
+     */
+    boolean isBoxType() {
+        return boxType == null || this == boxType;
+    }
+
+    // set by VM if this class is a value type
+    private transient Class<?> boxType;
+    private transient Class<?> valueType;
+
+    /**
      * Creates a new instance of the class represented by this {@code Class}
      * object.  The class is instantiated as if by a {@code new}
      * expression with an empty argument list.  The class is initialized if it
@@ -788,6 +845,8 @@
      * <tr><th scope="row"> char         <td style="text-align:center"> C
      * <tr><th scope="row"> class or interface
      *                                   <td style="text-align:center"> L<i>classname</i>;
+     * <tr><th scope="row"> {@linkplain #asValueType() regular value class}
+     *                                   <td style="text-align:center"> Q<i>classname</i>;
      * <tr><th scope="row"> double       <td style="text-align:center"> D
      * <tr><th scope="row"> float        <td style="text-align:center"> F
      * <tr><th scope="row"> int          <td style="text-align:center"> I
@@ -805,8 +864,12 @@
      *     returns "java.lang.String"
      * byte.class.getName()
      *     returns "byte"
+     * Point.class.getName()
+     *     returns "p.Point"
      * (new Object[3]).getClass().getName()
      *     returns "[Ljava.lang.Object;"
+     * (new Point[3]).getClass().getName()
+     *     returns "[QPoint;"
      * (new int[3][4][5][6][7][8][9]).getClass().getName()
      *     returns "[[[[[[[I"
      * </pre></blockquote>
@@ -816,8 +879,9 @@
      */
     public String getName() {
         String name = this.name;
-        if (name == null)
+        if (name == null) {
             this.name = name = getName0();
+        }
         return name;
     }
 
@@ -1217,7 +1281,6 @@
     @HotSpotIntrinsicCandidate
     public native int getModifiers();
 
-
     /**
      * Gets the signers of this class.
      *
@@ -1226,13 +1289,22 @@
      *          a primitive type or void.
      * @since   1.1
      */
-    public native Object[] getSigners();
-
+    public Object[] getSigners() {
+        Class<?> c = (isValue() && !isBoxType()) ? asBoxType() : this;
+        return c.getSigners0();
+    }
+
+    private native Object[] getSigners0();
 
     /**
      * Set the signers of this class.
      */
-    native void setSigners(Object[] signers);
+    void setSigners(Object[] signers) {
+        Class<?> c = (isValue() && !isBoxType()) ? asBoxType() : this;
+        c.setSigners0(signers);
+    }
+
+    native void setSigners0(Object[] signers);
 
 
     /**
@@ -1570,6 +1642,9 @@
      * component type with "[]" appended.  In particular the simple
      * name of an array whose component type is anonymous is "[]".
      *
+     * <p>The simple name of a value type is the simple name of
+     * this class with {@code ".box"} appended.
+     *
      * @return the simple name of the underlying class
      * @since 1.5
      */
@@ -1591,7 +1666,7 @@
             simpleName = getName();
             simpleName = simpleName.substring(simpleName.lastIndexOf('.') + 1); // strip the package name
         }
-        return simpleName;
+        return isValue() && isBoxType() ? simpleName + ".box" : simpleName;
     }
 
     /**
@@ -1610,14 +1685,15 @@
                     cl = cl.getComponentType();
                 } while (cl.isArray());
                 StringBuilder sb = new StringBuilder();
-                sb.append(cl.getName());
+                sb.append(cl.getTypeName());
                 for (int i = 0; i < dimensions; i++) {
                     sb.append("[]");
                 }
                 return sb.toString();
             } catch (Throwable e) { /*FALLTHRU*/ }
         }
-        return getName();
+        // ## append "/box" to box value type instead?
+        return isBoxType() ? getName() : getName() + "/val";
     }
 
     /**
@@ -3621,13 +3697,18 @@
      * @return the object after casting, or null if obj is null
      *
      * @throws ClassCastException if the object is not
-     * null and is not assignable to the type T.
+     * {@code null} and is not assignable to the type T.
+     * @throws NullPointerException if this class is a {@linkplain #asValueType()
+     * null-free value class} and the object is {@code null}
      *
      * @since 1.5
      */
     @SuppressWarnings("unchecked")
     @HotSpotIntrinsicCandidate
     public T cast(Object obj) {
+        if (isValue() && !isBoxType() && obj == null)
+            throw new NullPointerException(getName() + " is non-nullable value class");
+
         if (obj != null && !isInstance(obj))
             throw new ClassCastException(cannotCastMsg(obj));
         return (T) obj;
@@ -3896,7 +3977,7 @@
      * @since 1.8
      */
     public AnnotatedType[] getAnnotatedInterfaces() {
-         return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
+        return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
     }
 
     private native Class<?> getNestHost0();
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Thu Nov 29 09:02:32 2018 -0800
@@ -78,7 +78,7 @@
         if (!member.isStatic()) {
             if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor())
                 throw new InternalError(member.toString());
-            mtype = mtype.insertParameterTypes(0, refc);
+            mtype = mtype.insertParameterTypes(0, refc.isValue() ? refc.asValueType() : refc);
         }
         if (!member.isField()) {
             // refKind reflects the original type of lookup via findSpecial or
@@ -136,6 +136,8 @@
     private static DirectMethodHandle makeAllocator(MemberName ctor) {
         assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
         Class<?> instanceClass = ctor.getDeclaringClass();
+        if (instanceClass.isValue())
+            instanceClass = instanceClass.asValueType();  // convert to Q-Type
         ctor = ctor.asConstructor();
         assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
         MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Thu Nov 29 09:02:32 2018 -0800
@@ -191,10 +191,11 @@
      */
     public MethodType getInvocationType() {
         MethodType itype = getMethodOrFieldType();
+        Class<?> c = clazz.isValue() ? clazz.asValueType() : clazz;
         if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
-            return itype.changeReturnType(clazz);
+            return itype.changeReturnType(c);
         if (!isStatic())
-            return itype.insertParameterTypes(0, clazz);
+            return itype.insertParameterTypes(0, c);
         return itype;
     }
 
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleInfo.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleInfo.java	Thu Nov 29 09:02:32 2018 -0800
@@ -153,7 +153,8 @@
     public int getReferenceKind();
 
     /**
-     * Returns the class in which the cracked method handle's underlying member was defined.
+     * Returns the {@code Class} object representing {@linkplain Class#asBoxType() the box type}
+     * of the class in which the cracked method handle's underlying member was defined.
      * @return the declaring class of the underlying member
      */
     public Class<?> getDeclaringClass();
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Nov 29 09:02:32 2018 -0800
@@ -564,12 +564,12 @@
         sb.append(prefix);
         for (int i = 1; i < guardType.parameterCount() - 1; i++) {
             Class<?> pt = guardType.parameterType(i);
-            sb.append(getCharType(pt));
+            sb.append(getCharErasedType(pt));
         }
-        sb.append('_').append(getCharType(guardType.returnType()));
+        sb.append('_').append(getCharErasedType(guardType.returnType()));
         return sb.toString();
     }
-    static char getCharType(Class<?> pt) {
+    static char getCharErasedType(Class<?> pt) {
         return Wrapper.forBasicType(pt).basicTypeChar();
     }
     static NoSuchMethodError newNoSuchMethodErrorOnVarHandle(String name, MethodType mtype) {
--- a/src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java	Thu Nov 29 09:02:32 2018 -0800
@@ -233,7 +233,7 @@
             Object[] values = invoke(getters, obj);
             return Arrays.stream(values)
                          .map(Object::toString)
-                         .collect(Collectors.joining(", ", "[value ", "]"));
+                         .collect(Collectors.joining(", ", "[", "]"));
         } else {
             return obj.toString();
         }
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Thu Nov 29 09:02:32 2018 -0800
@@ -1544,6 +1544,11 @@
                                   Class<?>... intermediate) {
             Class<?>[] ps;
             int i;
+            // the field type (value) is mapped to the return type of MethodType
+            // the receiver type is mapped to a parameter type of MethodType
+            // So use the value type as receiver may be a box type.
+            if (receiver != null && receiver.isValue())
+                receiver = receiver.asValueType();
             switch (this) {
                 case GET:
                     ps = allocateParameters(0, receiver, intermediate);
--- a/src/java.base/share/classes/java/lang/reflect/Array.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/Array.java	Thu Nov 29 09:02:32 2018 -0800
@@ -330,11 +330,7 @@
         Class<?> componentType = array.getClass().getComponentType();
         if (componentType != null && !componentType.isPrimitive()) {
             Object[] objArray = (Object[]) array.getClass().cast(array);
-            if (componentType.isValue()) {
-                objArray[index] = componentType.cast(Objects.requireNonNull(value));
-            } else {
-                objArray[index] = componentType.cast(value);
-            }
+            objArray[index] = componentType.cast(value);
         } else {
             setReferenceOrPrimitive(array, index, value);
         }
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Nov 29 09:02:32 2018 -0800
@@ -210,7 +210,8 @@
     }
 
     /**
-     * Returns the {@code Class} object representing the class that
+     * Returns the {@code Class} object representing
+     * {@linkplain Class#asBoxType() the box type} of the class that
      * declares the constructor represented by this object.
      */
     @Override
--- a/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Nov 29 09:02:32 2018 -0800
@@ -185,7 +185,8 @@
     }
 
     /**
-     * Returns the {@code Class} object representing the class or interface
+     * Returns the {@code Class} object representing
+     * {@linkplain Class#asBoxType() the box type} of the class or interface
      * that declares the field represented by this {@code Field} object.
      */
     @Override
--- a/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Nov 29 09:02:32 2018 -0800
@@ -214,8 +214,10 @@
     }
 
     /**
-     * Returns the {@code Class} object representing the class or interface
+     * Returns the {@code Class} object representing
+     * {@linkplain Class#asBoxType() the box type} of the class or interface
      * that declares the method represented by this object.
+     *
      */
     @Override
     public Class<?> getDeclaringClass() {
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Nov 29 09:02:32 2018 -0800
@@ -854,7 +854,8 @@
                 type = Class.forName(c.getName(), false, ld);
             } catch (ClassNotFoundException e) {
             }
-            if (type != c) {
+            // use box type to do visibility check
+            if (type != c.asBoxType()) {
                 throw new IllegalArgumentException(c.getName() +
                         " referenced from a method is not visible from class loader");
             }
--- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java	Thu Nov 29 09:02:32 2018 -0800
@@ -30,8 +30,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -1412,9 +1410,11 @@
 
     /**
      * Generate code to invoke the Class.forName with the name of the given
-     * class to get its Class object at runtime.  The code is written to
-     * the supplied stream.  Note that the code generated by this method
-     * may caused the checked ClassNotFoundException to be thrown.
+     * class to get its Class object at runtime.  And also generate code
+     * to invoke Class.asValueBox if the class is regular value type.
+     *
+     * The code is written to the supplied stream.  Note that the code generated
+     * by this method may caused the checked ClassNotFoundException to be thrown.
      */
     private void codeClassForName(Class<?> cl, DataOutputStream out)
         throws IOException
@@ -1425,6 +1425,13 @@
         out.writeShort(cp.getMethodRef(
             "java/lang/Class",
             "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
+
+        if (cl.isValue() && cl == cl.asValueType()) {
+            out.writeByte(opc_invokevirtual);
+            out.writeShort(cp.getMethodRef(
+                "java/lang/Class",
+                "asValueType", "()Ljava/lang/Class;"));
+        }
     }
 
 
@@ -1488,7 +1495,8 @@
              */
             return type.getName().replace('.', '/');
         } else {
-            return "L" + dotToSlash(type.getName()) + ";";
+            char prefix = type.isValue() && type == type.asValueType() ? 'Q' : 'L';
+            return prefix + dotToSlash(type.getName()) + ";";
         }
     }
 
--- a/src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java	Thu Nov 29 09:02:32 2018 -0800
@@ -93,7 +93,7 @@
         IsolatedMethodBuilder isolatedMethodBuilder = new IsolatedMethodBuilder(className, lookup);
         isolatedMethodBuilder
                 .withSuperclass(Object.class)
-                .withMajorVersion(52)
+                .withMajorVersion(56)
                 .withMinorVersion(0)
                 .withFlags(Flag.ACC_PUBLIC)
                 .withMethod(methodName, type, M ->
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Thu Nov 29 09:02:32 2018 -0800
@@ -174,19 +174,32 @@
     @HotSpotIntrinsicCandidate
     public native void putInt(Object o, long offset, int x);
 
+    /**
+     * Returns true if the given class is a regular value type.
+     */
+    public boolean isValueType(Class<?> c) {
+        return c.isValue() && c == c.asValueType();
+    }
+
+    /**
+     * Returns true if the given class is a flattened array.
+     */
     public native boolean isFlattenedArray(Class<?> arrayClass);
 
     /**
      * Fetches a reference value from a given Java variable.
+     * This method can return a reference to either an object or value
+     * or a null reference.
+     *
      * @see #getInt(Object, long)
      */
     @HotSpotIntrinsicCandidate
     public native Object getObject(Object o, long offset);
 
-    public native Object getValue(Object base, long offset, Class<?> valueType);
-
     /**
      * Stores a reference value into a given Java variable.
+     * This method can store a reference to either an object or value
+     * or a null reference.
      * <p>
      * Unless the reference {@code x} being stored is either null
      * or matches the field type, the results are undefined.
@@ -198,7 +211,44 @@
     @HotSpotIntrinsicCandidate
     public native void putObject(Object o, long offset, Object x);
 
-    public native void putValue(Object base, long offset, Class<?> valueType, Object value);
+    /**
+     * Fetches a value of type {@code <V>} from a given Java variable.
+     * More specifically, fetches a field or array element within the given
+     * {@code o} object at the given offset, or (if {@code o} is null)
+     * from the memory address whose numerical value is the given offset.
+     *
+     * @param o Java heap object in which the variable resides, if any, else
+     *        null
+     * @param offset indication of where the variable resides in a Java heap
+     *        object, if any, else a memory address locating the variable
+     *        statically
+     * @param vc value class
+     * @param <V> the type of a value
+     * @return the value fetched from the indicated Java variable
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     */
+    public native <V> V getValue(Object o, long offset, Class<?> vc);
+
+    /**
+     * Stores the given value into a given Java variable.
+     *
+     * Unless the reference {@code o} being stored is either null
+     * or matches the field type and not in a value container,
+     * the results are undefined.
+     *
+     * @param o Java heap object in which the variable resides, if any, else
+     *        null
+     * @param offset indication of where the variable resides in a Java heap
+     *        object, if any, else a memory address locating the variable
+     *        statically
+     * @param vc value class
+     * @param v the value to store into the indicated Java variable
+     * @param <V> the type of a value
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     */
+    public native <V> void putValue(Object o, long offset, Class<?> vc, V v);
 
     /** @see #getInt(Object, long) */
     @HotSpotIntrinsicCandidate
@@ -1308,10 +1358,10 @@
                                                     Object x);
 
     @ForceInline
-    public final boolean compareAndSetValue(Object o, long offset,
-                                            Class<?> valueType,
-                                            Object expected,
-                                            Object x) {
+    public final <V> boolean compareAndSetValue(Object o, long offset,
+                                                Class<?> valueType,
+                                                V expected,
+                                                V x) {
         synchronized (valueLock) {
             Object witness = getValue(o, offset, valueType);
             if (witness.equals(expected)) {
@@ -1328,12 +1378,11 @@
     public final native Object compareAndExchangeObject(Object o, long offset,
                                                         Object expected,
                                                         Object x);
-
     @ForceInline
-    public final Object compareAndExchangeValue(Object o, long offset,
-                                                Class<?> valueType,
-                                                Object expected,
-                                                Object x) {
+    public final <V> Object compareAndExchangeValue(Object o, long offset,
+                                                    Class<?> valueType,
+                                                    V expected,
+                                                    V x) {
         synchronized (valueLock) {
             Object witness = getValue(o, offset, valueType);
             if (witness.equals(expected)) {
@@ -1345,31 +1394,31 @@
 
     @HotSpotIntrinsicCandidate
     public final Object compareAndExchangeObjectAcquire(Object o, long offset,
-                                                               Object expected,
-                                                               Object x) {
+                                                        Object expected,
+                                                        Object x) {
         return compareAndExchangeObject(o, offset, expected, x);
     }
 
     @ForceInline
-    public final Object compareAndExchangeValueAcquire(Object o, long offset,
-                                                       Class<?> valueType,
-                                                       Object expected,
-                                                       Object x) {
+    public final <V> Object compareAndExchangeValueAcquire(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
         return compareAndExchangeValue(o, offset, valueType, expected, x);
     }
 
     @HotSpotIntrinsicCandidate
     public final Object compareAndExchangeObjectRelease(Object o, long offset,
-                                                               Object expected,
-                                                               Object x) {
+                                                        Object expected,
+                                                        Object x) {
         return compareAndExchangeObject(o, offset, expected, x);
     }
 
     @ForceInline
-    public final Object compareAndExchangeValueRelease(Object o, long offset,
-                                                       Class<?> valueType,
-                                                       Object expected,
-                                                       Object x) {
+    public final <V> Object compareAndExchangeValueRelease(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
         return compareAndExchangeValue(o, offset, valueType, expected, x);
     }
 
@@ -1381,10 +1430,10 @@
     }
 
     @ForceInline
-    public final boolean weakCompareAndSetValuePlain(Object o, long offset,
-                                                     Class<?> valueType,
-                                                     Object expected,
-                                                     Object x) {
+    public final <V> boolean weakCompareAndSetValuePlain(Object o, long offset,
+                                                         Class<?> valueType,
+                                                         V expected,
+                                                         V x) {
         return compareAndSetValue(o, offset, valueType, expected, x);
     }
 
@@ -1396,10 +1445,10 @@
     }
 
     @ForceInline
-    public final boolean weakCompareAndSetValueAcquire(Object o, long offset,
-                                                       Class<?> valueType,
-                                                       Object expected,
-                                                       Object x) {
+    public final <V> boolean weakCompareAndSetValueAcquire(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
         return compareAndSetValue(o, offset, valueType, expected, x);
     }
 
@@ -1411,10 +1460,10 @@
     }
 
     @ForceInline
-    public final boolean weakCompareAndSetValueRelease(Object o, long offset,
-                                                       Class<?> valueType,
-                                                       Object expected,
-                                                       Object x) {
+    public final <V> boolean weakCompareAndSetValueRelease(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
         return compareAndSetValue(o, offset, valueType, expected, x);
     }
 
@@ -1426,10 +1475,10 @@
     }
 
     @ForceInline
-    public final boolean weakCompareAndSetValue(Object o, long offset,
-                                                Class<?> valueType,
-                                                Object expected,
-                                                Object x) {
+    public final <V> boolean weakCompareAndSetValue(Object o, long offset,
+                                                    Class<?> valueType,
+                                                    V expected,
+                                                    V x) {
         return compareAndSetValue(o, offset, valueType, expected, x);
     }
 
@@ -2055,7 +2104,7 @@
      */
     private static final Object valueLock = new Object();
 
-    public final Object getValueVolatile(Object base, long offset, Class<?> valueType) {
+    public final <V> Object getValueVolatile(Object base, long offset, Class<?> valueType) {
         synchronized (valueLock) {
             return getValue(base, offset, valueType);
         }
@@ -2068,7 +2117,7 @@
     @HotSpotIntrinsicCandidate
     public native void    putObjectVolatile(Object o, long offset, Object x);
 
-    public final void putValueVolatile(Object o, long offset, Class<?> valueType, Object x) {
+    public final <V> void putValueVolatile(Object o, long offset, Class<?> valueType, V x) {
         synchronized (valueLock) {
             putValue(o, offset, valueType, x);
         }
@@ -2146,7 +2195,7 @@
         return getObjectVolatile(o, offset);
     }
 
-    public final Object getValueAcquire(Object base, long offset, Class<?> valueType) {
+    public final <V> Object getValueAcquire(Object base, long offset, Class<?> valueType) {
         return getValueVolatile(base, offset, valueType);
     }
 
@@ -2214,7 +2263,7 @@
         putObjectVolatile(o, offset, x);
     }
 
-    public final void putValueRelease(Object o, long offset, Class<?> valueType, Object x) {
+    public final <V> void putValueRelease(Object o, long offset, Class<?> valueType, V x) {
         putValueVolatile(o, offset, valueType, x);
     }
 
@@ -2274,7 +2323,7 @@
         return getObjectVolatile(o, offset);
     }
 
-    public final Object getValueOpaque(Object base, long offset, Class<?> valueType) {
+    public final <V> Object getValueOpaque(Object base, long offset, Class<?> valueType) {
         return getValueVolatile(base, offset, valueType);
     }
 
@@ -2332,7 +2381,7 @@
         putObjectVolatile(o, offset, x);
     }
 
-    public final void putValueOpaque(Object o, long offset, Class<?> valueType, Object x) {
+    public final <V> void putValueOpaque(Object o, long offset, Class<?> valueType, V x) {
         putValueVolatile(o, offset, valueType, x);
     }
 
@@ -2770,7 +2819,8 @@
         return v;
     }
 
-    public final Object getAndSetValue(Object o, long offset, Class<?> valueType, Object newValue) {
+    @SuppressWarnings("unchecked")
+    public final <V> Object getAndSetValue(Object o, long offset, Class<?> valueType, V newValue) {
         synchronized (valueLock) {
             Object oldValue = getValue(o, offset, valueType);
             putValue(o, offset, valueType, newValue);
@@ -2788,7 +2838,7 @@
     }
 
     @ForceInline
-    public final Object getAndSetValueRelease(Object o, long offset, Class<?> valueType, Object newValue) {
+    public final <V> Object getAndSetValueRelease(Object o, long offset, Class<?> valueType, V newValue) {
         return getAndSetValue(o, offset, valueType, newValue);
     }
 
@@ -2802,7 +2852,7 @@
     }
 
     @ForceInline
-    public final Object getAndSetValueAcquire(Object o, long offset, Class<?> valueType, Object newValue) {
+    public final <V> Object getAndSetValueAcquire(Object o, long offset, Class<?> valueType, V newValue) {
         return getAndSetValue(o, offset, valueType, newValue);
     }
 
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Thu Nov 29 09:02:32 2018 -0800
@@ -2209,7 +2209,7 @@
                 while (desc.charAt(i) == '[') {
                     ++i;
                 }
-                if (desc.charAt(i) == 'L') {
+                if (desc.charAt(i) == 'L' || desc.charAt(i) == 'Q') {
                     ++i;
                     while (desc.charAt(i) != ';') {
                         ++i;
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java	Thu Nov 29 09:02:32 2018 -0800
@@ -773,6 +773,7 @@
         case 'D':
             return DOUBLE;
         case 'L':
+        case 'Q':
             // stores the internal name, not the descriptor!
             t = desc.substring(index + 1, desc.length() - 1);
             return OBJECT | cw.addType(t);
@@ -810,6 +811,7 @@
                 data = DOUBLE;
                 break;
             // case 'L':
+            // case 'Q':
             default:
                 // stores the internal name, not the descriptor
                 t = desc.substring(dims + 1, desc.length() - 1);
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java	Thu Nov 29 09:02:32 2018 -0800
@@ -1840,7 +1840,7 @@
                 while (descriptor.charAt(i) == '[') {
                     ++i;
                 }
-                if (descriptor.charAt(i) == 'L') {
+                if (descriptor.charAt(i) == 'L' || descriptor.charAt(i) == 'Q') {
                     ++i;
                     while (descriptor.charAt(i) != ';') {
                         ++i;
@@ -1849,6 +1849,7 @@
                 frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i));
                 break;
             case 'L':
+            case 'Q':
                 while (descriptor.charAt(i) != ';') {
                     ++i;
                 }
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java	Thu Nov 29 09:02:32 2018 -0800
@@ -451,7 +451,7 @@
                 car = desc.charAt(c);
                 return n << 2
                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
-            } else if (car == 'L') {
+            } else if (car == 'L' || car == 'Q') {
                 while (desc.charAt(c++) != ';') {
                 }
                 n += 1;
@@ -507,7 +507,7 @@
             while (buf[off + len] == '[') {
                 ++len;
             }
-            if (buf[off + len] == 'L') {
+            if (buf[off + len] == 'L' || buf[off + len] == 'Q') {
                 ++len;
                 while (buf[off + len] != ';') {
                     ++len;
@@ -515,6 +515,7 @@
             }
             return new Type(ARRAY, buf, off, len + 1);
         case 'L':
+        case 'Q':
             len = 1;
             while (buf[off + len] != ';') {
                 ++len;
@@ -817,8 +818,15 @@
                 buf.append('[');
                 d = d.getComponentType();
             } else {
-                buf.append('L');
                 String name = d.getName();
+                // Workarounds nasgen build that depends on ASM but compiled with
+                // the bootstrap JDK.  Can't use Class::isValue and Class::asValueType
+                int index = d.getTypeName().lastIndexOf("/val");
+                if (index > 0) {
+                    buf.append('Q');
+                } else {
+                    buf.append('L');
+                }
                 int len = name.length();
                 for (int i = 0; i < len; ++i) {
                     char car = name.charAt(i);
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java	Thu Nov 29 09:02:32 2018 -0800
@@ -568,6 +568,7 @@
             }
             break;
         // case 'L':
+        // case 'Q':
         default:
             if (index == 0) {
                 push(desc.substring(1, desc.length() - 1));
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Method.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Method.java	Thu Nov 29 09:02:32 2018 -0800
@@ -240,6 +240,7 @@
         if (desc != null) {
             sb.append(desc);
         } else {
+            // FIXME: support Q-type
             sb.append('L');
             if (t.indexOf('.') < 0) {
                 if (!defaultPackage) {
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java	Thu Nov 29 09:02:32 2018 -0800
@@ -89,6 +89,7 @@
             }
             return s;
         case Type.OBJECT:
+            // FIXME: support Q-type
             String newType = map(t.getInternalName());
             if (newType != null) {
                 return 'L' + newType + ';';
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureReader.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureReader.java	Thu Nov 29 09:02:32 2018 -0800
@@ -112,7 +112,7 @@
                 pos = end + 1;
 
                 c = signature.charAt(pos);
-                if (c == 'L' || c == '[' || c == 'T') {
+                if (c == 'L' || c == 'Q' || c == '[' || c == 'T') {
                     pos = parseType(signature, pos, v.visitClassBound());
                 }
 
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java	Thu Nov 29 09:02:32 2018 -0800
@@ -685,7 +685,7 @@
             pos = checkFormalTypeParameters(signature, pos);
         }
         pos = checkClassTypeSignature(signature, pos);
-        while (getChar(signature, pos) == 'L') {
+        while (getChar(signature, pos) == 'L' || getChar(signature, pos) == 'Q') {
             pos = checkClassTypeSignature(signature, pos);
         }
         if (pos != signature.length()) {
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java	Thu Nov 29 09:02:32 2018 -0800
@@ -1457,6 +1457,7 @@
                         + desc);
             }
         case 'L':
+        case 'Q':
             index = desc.indexOf(';', start);
             if (index == -1 || index - start < 2) {
                 throw new IllegalArgumentException("Invalid descriptor: "
--- a/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java	Thu Nov 29 09:02:32 2018 -0800
@@ -420,7 +420,11 @@
             return "[" + getClassName(c.getComponentType(), true);
         } else {
             if (addPrefixAndSuffixForNonPrimitiveTypes) {
-                return internalize("L" + c.getName() + ";");
+                if (unsafe.isValueType(c)) {
+                    return internalize('Q' + c.getName() + ";");
+                } else {
+                    return internalize('L' + c.getName() + ";");
+                }
             } else {
                 return internalize(c.getName());
             }
--- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java	Thu Nov 29 09:02:32 2018 -0800
@@ -90,9 +90,10 @@
             i[0] = endc+1;
             String name = str.substring(begc, endc).replace('/', '.');
             try {
-                return (loader == null)
-                    ? Class.forName(name, false, null)
-                    : loader.loadClass(name);
+                Class<?> clz = (loader == null)
+                                    ? Class.forName(name, false, null)
+                                    : loader.loadClass(name);
+                return c == 'Q' ? clz.asValueType() : clz.asBoxType();
             } catch (ClassNotFoundException ex) {
                 throw new TypeNotPresentException(name, ex);
             }
@@ -151,12 +152,14 @@
 
     private static void unparseSig(Class<?> t, StringBuilder sb) {
         char c = Wrapper.forBasicType(t).basicTypeChar();
-        if (c != 'L' && c != 'Q') {
+        if (c != 'L') {
             sb.append(c);
         } else if (t == Object.class) {
             sb.append("Ljava/lang/Object;");
         } else {
             boolean lsemi = (!t.isArray());
+            if (t == t.asValueType())
+                c = 'Q';
             if (lsemi)  sb.append(c);
             sb.append(t.getName().replace('.', '/'));
             if (lsemi)  sb.append(';');
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Thu Nov 29 09:02:32 2018 -0800
@@ -236,7 +236,7 @@
      * @param refc the class attempting to make the reference
      */
     public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
-        if (type == refc) {
+        if (type.asBoxType() == refc.asBoxType()) {
             return true;  // easy check
         }
         while (type.isArray())  type = type.getComponentType();
@@ -295,7 +295,7 @@
                         }
                     }
             });
-        return (type == res);
+        return (type.asBoxType() == res);
     }
 
     /**
--- a/src/java.base/share/native/libjava/Class.c	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/native/libjava/Class.c	Thu Nov 29 09:02:32 2018 -0800
@@ -56,8 +56,8 @@
     {"getSuperclass",    "()" CLS,          NULL},
     {"getInterfaces0",   "()[" CLS,         (void *)&JVM_GetClassInterfaces},
     {"isInterface",      "()Z",             (void *)&JVM_IsInterface},
-    {"getSigners",       "()[" OBJ,         (void *)&JVM_GetClassSigners},
-    {"setSigners",       "([" OBJ ")V",     (void *)&JVM_SetClassSigners},
+    {"getSigners0",      "()[" OBJ,         (void *)&JVM_GetClassSigners},
+    {"setSigners0",      "([" OBJ ")V",     (void *)&JVM_SetClassSigners},
     {"isArray",          "()Z",             (void *)&JVM_IsArrayClass},
     {"isPrimitive",      "()Z",             (void *)&JVM_IsPrimitiveClass},
     {"getModifiers",     "()I",             (void *)&JVM_GetClassModifiers},
--- a/src/java.base/share/native/libverify/check_code.c	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/native/libverify/check_code.c	Thu Nov 29 09:02:32 2018 -0800
@@ -3733,12 +3733,13 @@
           case JVM_SIGNATURE_FUNC:  /* ignore initial (, if given */
             break;
           case JVM_SIGNATURE_CLASS:
+          case JVM_SIGNATURE_VALUETYPE:
             while (*p != JVM_SIGNATURE_ENDCLASS) p++;
             break;
           case JVM_SIGNATURE_ARRAY:
             while (*p == JVM_SIGNATURE_ARRAY) p++;
             /* If an array of classes, skip over class name, too. */
-            if (*p == JVM_SIGNATURE_CLASS) {
+            if (*p == JVM_SIGNATURE_CLASS || *p == JVM_SIGNATURE_VALUETYPE) {
                 while (*p != JVM_SIGNATURE_ENDCLASS) p++;
             }
             break;
@@ -3817,7 +3818,8 @@
                 array_depth++;
                 continue;       /* only time we ever do the loop > 1 */
 
-            case JVM_SIGNATURE_CLASS: {
+            case JVM_SIGNATURE_CLASS:
+            case JVM_SIGNATURE_VALUETYPE: {
                 char buffer_space[256];
                 char *buffer = buffer_space;
                 char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS);
@@ -4199,6 +4201,7 @@
             args_size += 1;
             break;
           case JVM_SIGNATURE_CLASS:
+          case JVM_SIGNATURE_VALUETYPE:
             args_size += 1;
             while (*p != JVM_SIGNATURE_ENDCLASS) p++;
             break;
@@ -4206,7 +4209,7 @@
             args_size += 1;
             while ((*p == JVM_SIGNATURE_ARRAY)) p++;
             /* If an array of classes, skip over class name, too. */
-            if (*p == JVM_SIGNATURE_CLASS) {
+            if (*p == JVM_SIGNATURE_CLASS || *p == JVM_SIGNATURE_VALUETYPE) {
                 while (*p != JVM_SIGNATURE_ENDCLASS)
                   p++;
             }
--- a/src/java.base/share/native/libverify/check_format.c	Thu Nov 29 11:44:45 2018 -0500
+++ b/src/java.base/share/native/libverify/check_format.c	Thu Nov 29 09:02:32 2018 -0800
@@ -191,7 +191,8 @@
             case JVM_SIGNATURE_DOUBLE:
                 return name + 1;
 
-            case JVM_SIGNATURE_CLASS: {
+            case JVM_SIGNATURE_CLASS:
+            case JVM_SIGNATURE_VALUETYPE: {
                 /* Skip over the classname, if one is there. */
                 char *p =
                     skip_over_fieldname(name + 1, JNI_TRUE, --length);
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Thu Nov 29 09:02:32 2018 -0800
@@ -1289,7 +1289,7 @@
     // Tests writing an array element with a (statically known) incompatible type
     private static final MethodHandle setArrayElementIncompatible = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
         "setArrayElementIncompatible",
-        MethodType.methodType(void.class, TestLWorld.class, MyValue1[].class, int.class, MyValue2.class),
+        MethodType.methodType(void.class, TestLWorld.class, MyValue1[].class, int.class, MyValue2.class.asValueType()),
         CODE -> {
             CODE.
             aload_1().
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Thu Nov 29 09:02:32 2018 -0800
@@ -62,28 +62,28 @@
             ClassLoader loader = clazz.getClassLoader();
             MethodHandles.Lookup lookup = MethodHandles.lookup();
 
-            MethodType mt = MethodType.methodType(MyValue3.class);
+            MethodType mt = MethodType.methodType(MyValue3.class.asValueType());
             test1_mh = lookup.findVirtual(clazz, "test1_target", mt);
             test2_mh = lookup.findVirtual(clazz, "test2_target", mt);
             test3_mh = lookup.findVirtual(clazz, "test3_target", mt);
 
-            MethodType test4_mt1 = MethodType.methodType(int.class, MyValue1.class);
-            MethodType test4_mt2 = MethodType.methodType(MyValue1.class);
+            MethodType test4_mt1 = MethodType.methodType(int.class, MyValue1.class.asValueType());
+            MethodType test4_mt2 = MethodType.methodType(MyValue1.class.asValueType());
             MethodHandle test4_mh1 = lookup.findStatic(clazz, "test4_helper1", test4_mt1);
             MethodHandle test4_mh2 = lookup.findStatic(clazz, "test4_helper2", test4_mt2);
             test4_mh = MethodHandles.filterReturnValue(test4_mh2, test4_mh1);
 
-            MethodType test5_mt = MethodType.methodType(int.class, MyValue1.class);
+            MethodType test5_mt = MethodType.methodType(int.class, MyValue1.class.asValueType());
             test5_mh = lookup.findVirtual(clazz, "test5_target", test5_mt);
 
-            MethodType test6_mt = MethodType.methodType(MyValue3.class);
+            MethodType test6_mt = MethodType.methodType(MyValue3.class.asValueType());
             MethodHandle test6_mh1 = lookup.findVirtual(clazz, "test6_target1", test6_mt);
             MethodHandle test6_mh2 = lookup.findVirtual(clazz, "test6_target2", test6_mt);
             MethodType boolean_mt = MethodType.methodType(boolean.class);
             MethodHandle test6_mh_test = lookup.findVirtual(clazz, "test6_test", boolean_mt);
             test6_mh = MethodHandles.guardWithTest(test6_mh_test, test6_mh1, test6_mh2);
 
-            MethodType myvalue2_mt = MethodType.methodType(MyValue2.class);
+            MethodType myvalue2_mt = MethodType.methodType(MyValue2.class.asValueType());
             test7_mh1 = lookup.findStatic(clazz, "test7_target1", myvalue2_mt);
             MethodHandle test7_mh2 = lookup.findStatic(clazz, "test7_target2", myvalue2_mt);
             MethodHandle test7_mh_test = lookup.findStatic(clazz, "test7_test", boolean_mt);
@@ -98,7 +98,7 @@
                                                     MethodHandles.dropArguments(test8_mh1, 0, MethodHandle.class),
                                                     MethodHandles.invoker(myvalue2_mt));
 
-            MethodType test9_mt = MethodType.methodType(MyValue3.class);
+            MethodType test9_mt = MethodType.methodType(MyValue3.class.asValueType());
             MethodHandle test9_mh1 = lookup.findVirtual(clazz, "test9_target1", test9_mt);
             MethodHandle test9_mh2 = lookup.findVirtual(clazz, "test9_target2", test9_mt);
             MethodHandle test9_mh3 = lookup.findVirtual(clazz, "test9_target3", test9_mt);
@@ -109,12 +109,12 @@
                                                     test9_mh1,
                                                     MethodHandles.guardWithTest(test9_mh_test2, test9_mh2, test9_mh3));
 
-            MethodType test10_mt = MethodType.methodType(MyValue2.class);
+            MethodType test10_mt = MethodType.methodType(MyValue2.class.asValueType());
             MethodHandle test10_mh1 = lookup.findStatic(clazz, "test10_target1", test10_mt);
             test10_mh2 = lookup.findStatic(clazz, "test10_target2", test10_mt);
             test10_mh3 = lookup.findStatic(clazz, "test10_target3", test10_mt);
             MethodType test10_mt2 = MethodType.methodType(boolean.class);
-            MethodType test10_mt3 = MethodType.methodType(MyValue2.class);
+            MethodType test10_mt3 = MethodType.methodType(MyValue2.class.asValueType());
             MethodHandle test10_mh_test1 = lookup.findStatic(clazz, "test10_test1", test10_mt2);
             MethodHandle test10_mh_test2 = lookup.findStatic(clazz, "test10_test2", test10_mt2);
             test10_mh = MethodHandles.guardWithTest(test10_mh_test1,
@@ -138,7 +138,7 @@
 
     public static void main(String[] args) throws Throwable {
         TestMethodHandles test = new TestMethodHandles();
-        test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue3.class, MyValue3Inline.class);
+        test.run(args, MyValue1.class.asValueType(), MyValue2.class.asValueType(), MyValue2Inline.class.asValueType(), MyValue3.class.asValueType(), MyValue3Inline.class.asValueType());
     }
 
     // Everything inlined
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java	Thu Nov 29 09:02:32 2018 -0800
@@ -57,7 +57,7 @@
 
     private static final MethodHandle cloneValue = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
         "MyValue",
-        MethodType.methodType(Object.class, MyValue.class),
+        MethodType.methodType(Object.class, MyValue.class.asValueType()),
         CODE -> {
             CODE.
             aload_0().
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java	Thu Nov 29 09:02:32 2018 -0800
@@ -1398,7 +1398,7 @@
             if (args[i] != null && !parameterTypes[0].isInstance(args[i])) {
                 continue;
             }
-            if (args[i] == null && parameterTypes[0] == MyValue.class && !NullableValueTypes) {
+            if (args[i] == null && parameterTypes[0] == MyValue.class.asValueType() && !NullableValueTypes) {
                 continue;
             }
             if (parameterCount == 1) {
@@ -1420,7 +1420,7 @@
                     if (args[j] != null && !parameterTypes[1].isInstance(args[j])) {
                         continue;
                     }
-                    if (args[j] == null && parameterTypes[1] == MyValue.class && !NullableValueTypes) {
+                    if (args[j] == null && parameterTypes[1] == MyValue.class.asValueType() && !NullableValueTypes) {
                         continue;
                     }
                     System.out.print("Testing " + m.getName() + "(" + args[i] + ", " + args[j] + ")");
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java	Thu Nov 29 09:02:32 2018 -0800
@@ -460,7 +460,7 @@
     @Test
     @Warmup(10000) // Warmup to make sure 'test17_dontinline' is compiled
     public boolean test16(Object arg) throws Exception {
-        Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class);
+        Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class.asValueType());
         return (boolean)test16method.invoke(this, arg);
     }
 
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java	Thu Nov 29 09:02:32 2018 -0800
@@ -66,8 +66,11 @@
         try {
             Class<?> arrayCls = Class.forName(arrayClsName);
             assertTrue(arrayCls.isArray(), "Expected an array class");
-            assertTrue(arrayCls.getComponentType() == Point.class,
-                       "Expected component type of Point.class");
+            // array-of-L-type not supported yet
+            // the component type of a flattened value array is of the value type
+            // the component type of a non-flattened array is of the box type
+            assertTrue(arrayCls.getComponentType().asBoxType() == Point.class,
+                       "Expected component type of Point.class got: " + arrayCls.getComponentType());
 
             arrayClsName = "[" + arrayClsName;
             Class<?> mulArrayCls = Class.forName(arrayClsName);
--- a/test/jdk/valhalla/valuetypes/MethodHandleTest.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/MethodHandleTest.java	Thu Nov 29 09:02:32 2018 -0800
@@ -94,9 +94,7 @@
         test.setValueField("l", mv, l);
         test.setValueField("staticPoint", null, p);
         test.setValueField("staticLine", null, l);
-        // remove the following cases when javac and jvm make
-        // static value fields be flattenable
-        test.setValueField("staticPoint", null, null);
+        // staticLine is a nullable field
         test.setValueField("staticLine", null, null);
     }
 
--- a/test/jdk/valhalla/valuetypes/MixedValues.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/MixedValues.java	Thu Nov 29 09:02:32 2018 -0800
@@ -25,7 +25,7 @@
 
 public class MixedValues {
     static Point staticPoint = Point.makePoint(10, 10);
-    static Line staticLine;   // LW1 allows null static value field
+    static Line.box staticLine;   // null static value box field
     Point p;
     Line l;
     MutablePath mutablePath;
--- a/test/jdk/valhalla/valuetypes/NonFlattenValue.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/NonFlattenValue.java	Thu Nov 29 09:02:32 2018 -0800
@@ -24,12 +24,19 @@
 public value class NonFlattenValue {
     Point.box nfp;
 
-    NonFlattenValue(Point p) {
+    NonFlattenValue() {
+        Point p = Point.makePoint(0,0);
         this.nfp = p;
     }
     public Point.box point() {
         return nfp;
     }
+    public Point.val pointValue() {
+        return nfp;
+    }
+    public boolean has(Point.val p1, Point.box p2) {
+        return nfp.equals(p1) || nfp.equals(p2);
+    }
 
     public static NonFlattenValue make(int x, int y) {
         NonFlattenValue v = NonFlattenValue.default;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/valhalla/valuetypes/QTypeDescriptorTest.java	Thu Nov 29 09:02:32 2018 -0800
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test core reflection, dynamic proxy and lambdas that generates
+ *          classes dynamically that reference Q-type and L-type
+ * @compile -XDallowWithFieldOperator Point.java Line.java MutablePath.java
+ * @compile -XDallowWithFieldOperator NonFlattenValue.java
+ * @run testng/othervm -XX:+EnableValhalla -Dsun.reflect.noInflation=true QTypeDescriptorTest
+ */
+/* TODO: JVM_InvokeMethod does not support Q-Type yet
+ * @run testng/othervm -XX:+EnableValhalla -Dsun.reflect.inflationThreshold=0 QTypeDescriptorTest
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.*;
+import java.util.function.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class QTypeDescriptorTest {
+    static final Point P0 = Point.makePoint(10, 20);
+    static final Point P1 = Point.makePoint(30, 40);
+    static final NonFlattenValue NFV = NonFlattenValue.make(30, 40);
+
+    @Test
+    public static void testLambda() {
+        newArray(Point[]::new, 2);
+        newArray(Point[][]::new, 1);
+
+        newArray(NonFlattenValue[]::new, 3);
+        newArray(MutablePath[]::new, 4);
+
+        Function<Point[], T> f =
+            (points) -> { return new T(points); };
+        f.apply(new Point[] { P0, P1});
+    }
+
+    @Test
+    public static void testMethodInvoke() throws Exception {
+        Class<?> pointQType = Point.class.asValueType();
+        Class<?> nonFlattenValueQType = NonFlattenValue.class.asValueType();
+        Method m = QTypeDescriptorTest.class
+            .getDeclaredMethod("toLine", pointQType, nonFlattenValueQType);
+        makeLine(m, P0, NFV);
+
+        m = QTypeDescriptorTest.class
+                .getDeclaredMethod("toLine", Point[].class);
+        makeLine(m, (Object) new Point[] { P0, P1});
+    }
+
+    private static void makeLine(Method m, Object... args) throws Exception {
+        Line l = (Line) m.invoke(null, args);
+        assertEquals(l.p1, P0);
+        assertEquals(l.p2, NFV.pointValue());
+    }
+
+    @Test
+    public static void testStaticMethod() throws Throwable {
+        // static method in a value type with no parameter and void return type
+        Runnable r = () -> ValueTest.run();
+        r.run();
+
+        // via Method::invoke
+        Method m = ValueTest.class.getMethod("run");
+        m.invoke(null);
+
+        // via MethodHandle
+        MethodHandle mh = MethodHandles.lookup()
+            .findStatic(ValueTest.class, "run", MethodType.methodType(void.class));
+        mh.invokeExact();
+    }
+
+    @Test
+    public static void testConstructor() throws Exception {
+        Constructor<T> ctor = T.class.getDeclaredConstructor(Point[].class);
+        Point[] points = new Point[] { P0, P1 };
+        T test = (T) ctor.newInstance((Object)points);
+        assertEquals(test.points[0], P0);
+        assertEquals(test.points[1], P1);
+    }
+
+    @Test
+    public static void testProxy() throws Exception {
+        InvocationHandler handler = new InvocationHandler() {
+            @Override
+            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                if (method.getName().equals("toLine")) {
+                    return toLine((Point)args[0], (NonFlattenValue)args[1]);
+                }
+                throw new UnsupportedOperationException(method.toString());
+            }
+        };
+
+        Class<?>[] intfs = new Class<?>[] { I.class };
+        I intf = (I) Proxy.newProxyInstance(QTypeDescriptorTest.class.getClassLoader(), intfs, handler);
+        Line l = intf.toLine(P0, NFV);
+        assertEquals(l.p1, P0);
+        assertEquals(l.p2, NFV.pointValue());
+    }
+
+    private static <T> T[] newArray(IntFunction<T[]> arrayCreator, int size) {
+        return arrayCreator.apply(size);
+    }
+
+    private static Line toLine(Point p, NonFlattenValue nfv) {
+        return Line.makeLine(p, nfv.pointValue());
+    }
+
+    private static Line toLine(Point[] points) {
+        assertTrue(points.length == 2);
+        return Line.makeLine(points[0], points[1]);
+    }
+
+    static class T {
+        final Point[] points;
+        T(Point[] points) {
+            this.points = points;
+        }
+    }
+
+    interface I {
+        Line toLine(Point p, NonFlattenValue nfv);
+    }
+
+    static value class ValueTest {
+        private final int value;
+        public ValueTest() { this.value = 0; }
+
+        public static void run() {
+            Runnable r = () -> {
+                System.out.println("called ValueTest::run");
+            };
+            r.run();
+        }
+    }
+
+}
--- a/test/jdk/valhalla/valuetypes/Reflection.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/Reflection.java	Thu Nov 29 09:02:32 2018 -0800
@@ -25,21 +25,24 @@
 /*
  * @test
  * @summary test reflection on value types
- * @compile -XDallowWithFieldOperator Point.java Line.java
+ * @compile -XDallowWithFieldOperator Point.java Line.java NonFlattenValue.java
  * @run main/othervm -XX:+EnableValhalla Reflection
  */
 
 import java.lang.reflect.*;
+import java.util.Arrays;
+import java.util.stream.Collectors;
 
 public class Reflection {
     public static void main(String... args) throws Exception {
         testPointClass();
         testLineClass();
+        testNonFlattenValue();
     }
 
     static void testPointClass() throws Exception  {
         Point o = Point.makePoint(10, 20);
-        Reflection test = new Reflection("Point", o);
+        Reflection test = new Reflection(Point.class, "Point", o);
         test.newInstance();
         test.constructor();
         test.accessFieldX(o.x);
@@ -50,21 +53,69 @@
 
     static void testLineClass() throws Exception {
         Line l = Line.makeLine(10, 20, 30, 40);
-        Reflection test = new Reflection("Line", l);
-        test.getDeclaredFields();
+        Reflection test = new Reflection(Line.class, "Line", l);
+        test.checkField("p1", Point.class.asValueType());
+        test.checkField("p2", Point.class.asValueType());
+        test.checkMethod("p1", Point.class.asValueType());
+        test.checkMethod("p2", Point.class.asValueType());
+    }
+
+    static void testNonFlattenValue() throws Exception {
+        NonFlattenValue nfv = NonFlattenValue.make(10, 20);
+        Reflection test = new Reflection(NonFlattenValue.class, "NonFlattenValue", nfv);
+        test.checkField("nfp", Point.class.asBoxType());
+        test.checkMethod("point", Point.class.asBoxType());
+        test.checkMethod("pointValue", Point.class.asValueType());
+        test.checkMethod("has", void.class, Point.class.asValueType(), Point.class.asBoxType());
     }
 
     private final Class<?> c;
     private final Constructor<?> ctor;
     private final Object o;
-    Reflection(String cn, Object o) throws Exception {
+    Reflection(Class<?> type, String cn, Object o) throws Exception {
         this.c = Class.forName(cn);
-        if (!c.isValue()) {
+        if (!c.isValue() || c != type) {
             throw new RuntimeException(cn + " is not a value class");
         }
 
+        // the box type is the primary mirror
+        assertEquals(type, o.getClass());
+        assertEquals(type, c.asBoxType());
+
         this.ctor = c.getDeclaredConstructor();
         this.o = o;
+
+        // TODO: what should Object::getClass return?
+        // assertEquals(o.getClass(), c.asValueType());
+
+        // test the box type and value type
+        testBoxAndValueType(this.c);
+        // test array of Q-type
+        // TODO: array of L-type support
+        testArrayOfQType();
+    }
+
+    private static void testBoxAndValueType(Class<?> c) {
+        Class<?> box = c.asBoxType();
+        Class<?> val = c.asValueType();
+        assertTrue(val != null);
+        assertEquals(box.getTypeName(), c.getTypeName());
+        assertEquals(val.getTypeName(), c.getTypeName() + "/val");
+        assertEquals(box, c);
+        assertEquals(val.asBoxType(), box);
+        assertEquals(box.asValueType(), val);
+    }
+
+    void testArrayOfQType() {
+        Class<?> elementType = c.asValueType();
+        Object array = Array.newInstance(elementType, 1);
+        Class<?> arrayType = array.getClass();
+        assertTrue(arrayType.isArray());
+        Class<?> componentType = arrayType.getComponentType();
+        assertTrue(componentType.isValue());
+        assertEquals(componentType, elementType);
+        // Array is a reference type
+        assertEquals(arrayType.asBoxType(), arrayType);
     }
 
     void accessFieldX(int x) throws Exception {
@@ -126,9 +177,34 @@
         } catch (InaccessibleObjectException e) { }
     }
 
-    void getDeclaredFields() throws Exception {
-        for (Field f : c.getDeclaredFields()) {
-            System.out.println(f.getName() + " = " + f.get(o));
-        }
+    void checkField(String name, Class<?> type) throws Exception {
+        Field f = c.getDeclaredField(name);
+        System.out.format("Field %s::%s of type %s = %s%n",
+                          f.getDeclaringClass().getTypeName(), f.getName(),
+                          f.getType().getTypeName(), f.get(o));
+        assertEquals(f.getType(), type);
+    }
+
+    void checkMethod(String name, Class<?> returnType, Class<?>... params) throws Exception {
+        Method m = c.getDeclaredMethod(name, params);
+
+        String paramDesc = (params == null || params.length == 0) ? "" :
+            Arrays.stream(params).map(Class::getTypeName).collect(Collectors.joining(", "));
+        System.out.format("Method %s::%s(%s)%s%n",
+                          m.getDeclaringClass().getTypeName(), m.getName(),
+                          paramDesc, returnType.getTypeName());
+    }
+    
+    static void assertEquals(Object o1, Object o2) {
+        if (o1 == o2 || o1.equals(o2))
+            return;
+
+        throw new AssertionError(o1 + " != " + o2);
+    }
+
+    static void assertTrue(boolean value) {
+        if (!value)
+            throw new AssertionError("expected true");
+
     }
 }
--- a/test/jdk/valhalla/valuetypes/ValueArray.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/ValueArray.java	Thu Nov 29 09:02:32 2018 -0800
@@ -136,13 +136,17 @@
     }
 
     static value class PointArray {
-        public Point[] points;
+        public Point.box[] points;
         PointArray() {
-            points = new Point[0];
+            points = new Point.box[0];
         }
         public static PointArray makeArray(Point... points) {
             PointArray a = PointArray.default;
-            a = __WithField(a.points, points);
+            Point.box[] boxArray = new Point.box[points.length];
+            for (int i=0; i < points.length; i++) {
+                boxArray[i] = points[i];
+            }
+            a = __WithField(a.points, boxArray);
             return a;
         }
     }
--- a/test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java	Thu Nov 29 11:44:45 2018 -0500
+++ b/test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java	Thu Nov 29 09:02:32 2018 -0800
@@ -117,7 +117,7 @@
 
         public String toString() {
             System.out.println(l);
-            return String.format("[value %s, %s, %s, %s, %s]", Value.class,
+            return String.format("[%s, %s, %s, %s, %s]", Value.class,
                                  i, String.valueOf(d), s, l.toString());
         }
     }
@@ -215,54 +215,10 @@
         mv.visitMaxs(-1, -1);
         mv.visitEnd();
 
-        cw.visitAttribute(new ValueTypesAttribute(Set.of(Type.getInternalName(c))));
-
         cw.visitEnd();
 
         byte[] classBytes = cw.toByteArray();
         System.out.println("writing " + path);
         Files.write(path, classBytes);
     }
-
-    static class ValueTypesAttribute extends Attribute {
-        public static final String VALUE_TYPES = "ValueTypes";
-        private final Set<String> valueTypes;
-        public ValueTypesAttribute(Set<String> valueTypes) {
-            super(VALUE_TYPES);
-            this.valueTypes = valueTypes;
-        }
-        public ValueTypesAttribute() {
-            this(null);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-
-            int count = cr.readUnsignedShort(off);
-            off += 2;
-
-            Set<String> valueTypes = new HashSet<>();
-            for (int i=0; i<count; i++) {
-                String cn = cr.readClass(off, buf);
-                off += 2;
-            }
-            return new ValueTypesAttribute(valueTypes);
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
-            assert valueTypes != null;
-            ByteVector attr = new ByteVector();
-            attr.putShort(valueTypes.size());
-            valueTypes.stream().map(cn -> cn.replace('.', '/'))
-                      .forEach(cn -> attr.putShort(cw.newClass(cn)));
-            return attr;
-        }
-    }
 }
--- a/test/jdk/valhalla/valuetypes/ValueTypesAttributeTest.java	Thu Nov 29 11:44:45 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @summary Verify ValueTypes attribute generated by core reflection,
- *          dynamic proxy and lambda proxy classes
- * @compile -XDallowFlattenabilityModifiers -XDallowWithFieldOperator Point.java Line.java MutablePath.java
- * @compile -XDallowFlattenabilityModifiers -XDallowWithFieldOperator NonFlattenValue.java
- * @run testng/othervm -XX:+EnableValhalla -Dsun.reflect.inflationThreshold=0 ValueTypesAttributeTest
- */
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.*;
-import java.util.function.*;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-public class ValueTypesAttributeTest {
-    static final Point P0 = Point.makePoint(10, 20);
-    static final Point P1 = Point.makePoint(30, 40);
-    static final NonFlattenValue NFV = NonFlattenValue.make(30, 40);
-
-    @Test
-    public static void testLambda() {
-        newArray(Point[]::new, 2);
-        newArray(Point[][]::new, 1);
-
-        newArray(NonFlattenValue[]::new, 3);
-        newArray(MutablePath[]::new, 4);
-
-        Function<Point[], T> f =
-            (points) -> { return new T(points); };
-        f.apply(new Point[] { P0, P1});
-    }
-
-    @Test
-    public static void testMethodInvoke() throws Exception {
-        Method m = ValueTypesAttributeTest.class
-            .getDeclaredMethod("toLine", Point.class, NonFlattenValue.class);
-        makeLine(m, P0, NFV);
-
-        m = ValueTypesAttributeTest.class
-                .getDeclaredMethod("toLine", Point[].class);
-        makeLine(m, (Object) new Point[] { P0, P1});
-    }
-
-    private static void makeLine(Method m, Object... args) throws Exception {
-        Line l = (Line) m.invoke(null, args);
-        assertEquals(l.p1, P0);
-        assertEquals(l.p2, NFV.point());
-    }
-
-    @Test
-    public static void testStaticMethod() throws Throwable {
-        // static method in a value type with no parameter and void return type
-        Runnable r = () -> ValueTest.run();
-        r.run();
-
-        // via Method::invoke
-        Method m = ValueTest.class.getMethod("run");
-        m.invoke(null);
-
-        // via MethodHandle
-        MethodHandle mh = MethodHandles.lookup()
-            .findStatic(ValueTest.class, "run", MethodType.methodType(void.class));
-        mh.invokeExact();
-    }
-
-    @Test
-    public static void testConstructor() throws Exception {
-        Constructor<T> ctor = T.class.getDeclaredConstructor(Point[].class);
-        Point[] points = new Point[] { P0, P1 };
-        T test = (T) ctor.newInstance((Object)points);
-        assertEquals(test.points[0], P0);
-        assertEquals(test.points[1], P1);
-    }
-
-    @Test
-    public static void testProxy() throws Exception {
-        InvocationHandler handler = new InvocationHandler() {
-            @Override
-            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                if (method.getName().equals("toLine")) {
-                    return toLine((Point)args[0], (NonFlattenValue)args[1]);
-                }
-                throw new UnsupportedOperationException(method.toString());
-            }
-        };
-
-        Class<?>[] intfs = new Class<?>[] { I.class };
-        I intf = (I) Proxy.newProxyInstance(ValueTypesAttributeTest.class.getClassLoader(), intfs, handler);
-        Line l = intf.toLine(P0, NFV);
-        assertEquals(l.p1, P0);
-        assertEquals(l.p2, NFV.point());
-    }
-
-    private static <T> T[] newArray(IntFunction<T[]> arrayCreator, int size) {
-        return arrayCreator.apply(size);
-    }
-
-    private static Line toLine(Point p, NonFlattenValue nfv) {
-        return Line.makeLine(p, nfv.point());
-    }
-
-    private static Line toLine(Point[] points) {
-        assertTrue(points.length == 2);
-        return Line.makeLine(points[0], points[1]);
-    }
-
-    static class T {
-        final Point[] points;
-        T(Point[] points) {
-            this.points = points;
-        }
-    }
-
-    interface I {
-        Line toLine(Point p, NonFlattenValue nfv);
-    }
-
-    static value class ValueTest {
-        private final int value;
-        public ValueTest() { this.value = 0; }
-
-        public static void run() {
-            Runnable r = () -> {
-                System.out.println("called ValueTest::run");
-            };
-            r.run();
-        }
-    }
-
-}