changeset 52833:0d1ec73b6d87 nestmates

VM support for classData Summary: store classData in an injected filed of the java.lang.Class instance Reviewed-by: lfoltan, mchung
author dholmes
date Wed, 14 Nov 2018 04:44:18 -0500
parents f38af7d9a194
children e500393dff99
files src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/classfile/classLoader.cpp src/hotspot/share/classfile/classLoaderExt.cpp src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/javaClasses.hpp src/hotspot/share/classfile/klassFactory.cpp src/hotspot/share/classfile/klassFactory.hpp src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp src/hotspot/share/oops/arrayKlass.cpp src/hotspot/share/oops/klass.cpp src/hotspot/share/prims/jvm.cpp src/hotspot/share/prims/methodHandles.cpp src/hotspot/share/prims/unsafe.cpp src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java src/java.base/share/classes/java/lang/invoke/MethodHandles.java
diffstat 19 files changed, 73 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/classFileParser.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -5512,6 +5512,7 @@
 
 InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
                                                       InstanceKlass* dynamic_nest_host,
+                                                      Handle classData,
                                                       TRAPS) {
   if (_klass != NULL) {
     return _klass;
@@ -5520,7 +5521,7 @@
   InstanceKlass* const ik =
     InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
 
-  fill_instance_klass(ik, changed_by_loadhook, dynamic_nest_host, CHECK_NULL);
+  fill_instance_klass(ik, changed_by_loadhook, dynamic_nest_host, classData, CHECK_NULL);
 
   assert(_klass == ik, "invariant");
 
@@ -5543,6 +5544,7 @@
 void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
                                           bool changed_by_loadhook,
                                           InstanceKlass* dynamic_nest_host,
+                                          Handle classData,
                                           TRAPS) {
   assert(ik != NULL, "invariant");
 
@@ -5701,6 +5703,7 @@
                                  Handle(THREAD, _loader_data->class_loader()),
                                  module_handle,
                                  _protection_domain,
+                                 classData,
                                  CHECK);
 
   assert(_all_mirandas != NULL, "invariant");
@@ -6149,7 +6152,7 @@
   if (_requested_name != NULL &&
       _requested_name != _class_name &&
       _is_nonfindable) {
-    _class_name = (Symbol*)_requested_name;
+      _class_name = (Symbol*)_requested_name;
     _class_name->increment_refcount();
     cp->symbol_at_put(cp->klass_name_index_at(_this_class_index), _class_name);
   }
--- a/src/hotspot/share/classfile/classFileParser.hpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Wed Nov 14 04:44:18 2018 -0500
@@ -179,7 +179,9 @@
   void fix_unsafe_anonymous_class_name(TRAPS);
 
   void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH,
-                           InstanceKlass* dynamic_nest_host, TRAPS);
+                           InstanceKlass* dynamic_nest_host,
+                           Handle classData, TRAPS);
+
   void set_klass(InstanceKlass* instance);
 
   void set_class_bad_constant_seen(short bad_constant);
@@ -513,7 +515,7 @@
 
   ~ClassFileParser();
 
-  InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, InstanceKlass* dynamic_nest_host, TRAPS);
+  InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, InstanceKlass* dynamic_nest_host, Handle classData, TRAPS);
 
   const ClassFileStream* clone_stream() const;
 
--- a/src/hotspot/share/classfile/classLoader.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/classLoader.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -1404,6 +1404,7 @@
                                                            false, // is_nonfindable
                                                            false, // can_access_vm_annotations
                                                            NULL,  // dynamic_nest_host
+                                                           Handle(), // classData
                                                            THREAD);
   if (HAS_PENDING_EXCEPTION) {
     if (DumpSharedSpaces) {
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -300,6 +300,7 @@
                                                            false, // is_nonfindable
                                                            false, // can_access_vm_annotations
                                                            NULL,  // dynamic_nest_host
+                                                           Handle(), // classData
                                                            THREAD);
 
   if (HAS_PENDING_EXCEPTION) {
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -799,12 +799,13 @@
       k->clear_has_raw_archived_mirror();
     }
   }
-  create_mirror(k, Handle(), Handle(), Handle(), CHECK);
+  create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK);
 }
 
 void java_lang_Class::initialize_mirror_fields(Klass* k,
                                                Handle mirror,
                                                Handle protection_domain,
+                                               Handle classData,
                                                TRAPS) {
   // Allocate a simple java object for a lock.
   // This needs to be a java object because during class initialization
@@ -817,6 +818,9 @@
 
   // Initialize static fields
   InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK);
+
+ // Set classData
+  set_class_data(mirror(), classData());
 }
 
 // Set the java.lang.Module module field in the java_lang_Class mirror
@@ -870,7 +874,8 @@
 }
 
 void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
-                                    Handle module, Handle protection_domain, TRAPS) {
+                                    Handle module, Handle protection_domain,
+                                    Handle classData, TRAPS) {
   assert(k != NULL, "Use create_basic_type_mirror for primitive types");
   assert(k->java_mirror() == NULL, "should only assign mirror once");
 
@@ -917,7 +922,7 @@
     } else {
       assert(k->is_instance_klass(), "Must be");
 
-      initialize_mirror_fields(k, mirror, protection_domain, THREAD);
+      initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD);
       if (HAS_PENDING_EXCEPTION) {
         // If any of the fields throws an exception like OOM remove the klass field
         // from the mirror so GC doesn't follow it after the klass has been deallocated.
@@ -1322,6 +1327,15 @@
   java_class->obj_field_put(_signers_offset, (oop)signers);
 }
 
+oop java_lang_Class::class_data(oop java_class) {
+  assert(_classData_offset != 0, "must be set");
+  return java_class->obj_field(_classData_offset);
+}
+void java_lang_Class::set_class_data(oop java_class, oop class_data) {
+  assert(_classData_offset != 0, "must be set");
+  java_class->obj_field_put(_classData_offset, class_data);
+}
+
 
 void java_lang_Class::set_class_loader(oop java_class, oop loader) {
   // jdk7 runs Queens in bootstrapping and jdk8-9 has no coordinated pushes yet.
@@ -3992,6 +4006,7 @@
 int java_lang_Class::_component_mirror_offset;
 int java_lang_Class::_init_lock_offset;
 int java_lang_Class::_signers_offset;
+int java_lang_Class::_classData_offset;
 GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
 GrowableArray<Klass*>* java_lang_Class::_fixup_module_field_list = NULL;
 int java_lang_Throwable::backtrace_offset;
--- a/src/hotspot/share/classfile/javaClasses.hpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Wed Nov 14 04:44:18 2018 -0500
@@ -219,7 +219,8 @@
   macro(java_lang_Class, oop_size,               int_signature,     false) \
   macro(java_lang_Class, static_oop_field_count, int_signature,     false) \
   macro(java_lang_Class, protection_domain,      object_signature,  false) \
-  macro(java_lang_Class, signers,                object_signature,  false)
+  macro(java_lang_Class, signers,                object_signature,  false) \
+  macro(java_lang_Class, classData,              object_signature,  false)
 
 class java_lang_Class : AllStatic {
   friend class VMStructs;
@@ -240,6 +241,7 @@
   static int _class_loader_offset;
   static int _module_offset;
   static int _component_mirror_offset;
+  static int _classData_offset;
 
   static bool offsets_computed;
   static int classRedefinedCount_offset;
@@ -251,7 +253,8 @@
   static void set_protection_domain(oop java_class, oop protection_domain);
   static void set_class_loader(oop java_class, oop class_loader);
   static void set_component_mirror(oop java_class, oop comp_mirror);
-  static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, TRAPS);
+  static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain,
+                                       Handle classData, TRAPS);
   static void set_mirror_module_field(Klass* K, Handle mirror, Handle module, TRAPS);
  public:
   static void allocate_fixup_lists();
@@ -259,7 +262,7 @@
 
   // Instance creation
   static void create_mirror(Klass* k, Handle class_loader, Handle module,
-                            Handle protection_domain, TRAPS);
+                            Handle protection_domain, Handle classData, TRAPS);
   static void fixup_mirror(Klass* k, TRAPS);
   static oop  create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
 
@@ -305,6 +308,8 @@
   static oop  component_mirror(oop java_class);
   static objArrayOop  signers(oop java_class);
   static void set_signers(oop java_class, objArrayOop signers);
+  static oop  class_data(oop java_class);
+  static void set_class_data(oop java_class, oop classData);
 
   static oop class_loader(oop java_class);
   static void set_module(oop java_class, oop module);
--- a/src/hotspot/share/classfile/klassFactory.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/klassFactory.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -107,6 +107,7 @@
                              CHECK_NULL);
       InstanceKlass* new_ik = parser.create_instance_klass(true, // changed_by_loadhook
                                                            NULL,  // dynamic_nest_host
+                                                           Handle(), // classData
                                                            CHECK_NULL);
 
       if (cached_class_file != NULL) {
@@ -192,6 +193,7 @@
                                                 const bool is_nonfindable,
                                                 const bool can_access_vm_annotations,
                                                 InstanceKlass* dynamic_nest_host,
+                                                Handle classData,
                                                 TRAPS) {
   assert(stream != NULL, "invariant");
   assert(loader_data != NULL, "invariant");
@@ -228,8 +230,8 @@
                          ClassFileParser::BROADCAST, // publicity level
                          CHECK_NULL);
 
-  InstanceKlass* result = parser.create_instance_klass(old_stream != stream, dynamic_nest_host, CHECK_NULL);
-  assert(result == parser.create_instance_klass(old_stream != stream, NULL, THREAD), "invariant");
+  InstanceKlass* result = parser.create_instance_klass(old_stream != stream, dynamic_nest_host, classData, CHECK_NULL);
+  assert(result == parser.create_instance_klass(old_stream != stream, NULL, classData, THREAD), "invariant");
 
   if (result == NULL) {
     return NULL;
--- a/src/hotspot/share/classfile/klassFactory.hpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/klassFactory.hpp	Wed Nov 14 04:44:18 2018 -0500
@@ -77,6 +77,7 @@
                                            const bool is_nonfindable,
                                            const bool can_access_vm_annotations,
                                            InstanceKlass* dynamic_nest_host,
+                                           Handle classData,
                                            TRAPS);
  public:
   static InstanceKlass* check_shared_class_file_load_hook(
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -999,6 +999,7 @@
                                               const bool is_weaknonfindable,
                                               const bool can_access_vm_annotations,
                                               InstanceKlass* dynamic_nest_host,
+                                              Handle classData,
                                               TRAPS) {
 
   EventClassLoad class_load_start_event;
@@ -1041,6 +1042,7 @@
                                                       is_nonfindable,
                                                       can_access_vm_annotations,
                                                       dynamic_nest_host,
+                                                      classData,
                                                       CHECK_NULL);
 
   if ((is_nonfindable || (unsafe_anonymous_host != NULL)) && k != NULL) {
@@ -1070,6 +1072,7 @@
     }
 
     // Initialize it now, since nobody else will.
+    // FIXME: why must we eager initialize? It should be initialized upon use.
     k->eager_initialize(CHECK_NULL);
 
     // notify jvmti
@@ -1146,6 +1149,7 @@
                                          false, // is_nonfindable
                                          false, // can_access_vm_annotations
                                          dynamic_nest_host,
+                                         Handle(), // classData
                                          CHECK_NULL);
   }
 
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Wed Nov 14 04:44:18 2018 -0500
@@ -289,6 +289,7 @@
                         false, // is_weaknonfindable
                         false, // can_access_vm_annotations
                         dynamic_nest_host,
+                        Handle(),  // classData
                         THREAD);
   }
   static InstanceKlass* parse_stream(Symbol* class_name,
@@ -301,6 +302,7 @@
                                      const bool is_weaknonfindable,
                                      const bool can_access_vm_annotations,
                                      InstanceKlass* dynamic_nest_host,
+                                     Handle classData,
                                      TRAPS);
 
   // Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Wed Nov 14 04:44:18 2018 -0500
@@ -421,6 +421,7 @@
   template(static_oop_field_count_name,               "static_oop_field_count")                   \
   template(protection_domain_name,                    "protection_domain")                        \
   template(signers_name,                              "signers_name")                             \
+  template(classData_name,                            "classData_name")                           \
   template(loader_data_name,                          "loader_data")                              \
   template(vmdependencies_name,                       "vmdependencies")                           \
   template(loader_name,                               "loader")                                   \
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -1474,7 +1474,8 @@
     CLEAR_PENDING_EXCEPTION;
     return NULL;
   }
-  InstanceKlass* const new_ik = new_parser.create_instance_klass(false, NULL, THREAD);
+  InstanceKlass* const new_ik = new_parser.create_instance_klass(false, NULL,
+                                                                 Handle(), THREAD);
   if (HAS_PENDING_EXCEPTION) {
     log_pending_exception(PENDING_EXCEPTION);
     CLEAR_PENDING_EXCEPTION;
--- a/src/hotspot/share/oops/arrayKlass.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/oops/arrayKlass.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -109,7 +109,7 @@
   assert((module_entry != NULL) || ((module_entry == NULL) && !ModuleEntryTable::javabase_defined()),
          "module entry not available post " JAVA_BASE_NAME " definition");
   oop module = (module_entry != NULL) ? module_entry->module() : (oop)NULL;
-  java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(), CHECK);
+  java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(), Handle(), CHECK);
 }
 
 GrowableArray<Klass*>* ArrayKlass::compute_secondary_supers(int num_extra_slots,
--- a/src/hotspot/share/oops/klass.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/oops/klass.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -562,7 +562,7 @@
   // gotten an OOM later but keep the mirror if it was created.
   if (java_mirror() == NULL) {
     log_trace(cds, mirror)("Recreate mirror for %s", external_name());
-    java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, CHECK);
+    java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, Handle(), CHECK);
   }
 }
 
--- a/src/hotspot/share/prims/jvm.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/prims/jvm.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -1039,6 +1039,7 @@
       trace_class_resolution(k);
     }
   } else { //nonfindable
+    Handle classData_h(THREAD, JNIHandles::resolve(classData));
     k = SystemDictionary::parse_stream(class_name,
                                        class_loader,
                                        protection_domain,
@@ -1049,6 +1050,7 @@
                                        is_weak,
                                        vm_annotations,
                                        host_class,
+                                       classData_h,
                                        CHECK_NULL);
     if (k == NULL) {
       THROW_MSG_0(vmSymbols::java_lang_Error(), "Failure to define a nonfindable class");
--- a/src/hotspot/share/prims/methodHandles.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/prims/methodHandles.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -1517,6 +1517,17 @@
 }
 JVM_END
 
+/*
+ * Return the class data from the injected classData field of the given lookup class
+ */
+JVM_ENTRY(jobject, MHN_classData(JNIEnv *env, jobject igcls, jclass lookup))
+  if (lookup == NULL) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
+  }
+  oop mirror = JNIHandles::resolve_non_null(lookup);
+  return (jobject) JNIHandles::make_local(env, java_lang_Class::class_data(mirror));
+JVM_END
+
 /**
  * Throws a java/lang/UnsupportedOperationException unconditionally.
  * This is required by the specification of MethodHandle.invoke if
@@ -1575,7 +1586,8 @@
   {CC "clearCallSiteContext",      CC "(" CTX ")V",                          FN_PTR(MHN_clearCallSiteContext)},
   {CC "staticFieldOffset",         CC "(" MEM ")J",                          FN_PTR(MHN_staticFieldOffset)},
   {CC "staticFieldBase",           CC "(" MEM ")" OBJ,                        FN_PTR(MHN_staticFieldBase)},
-  {CC "getMemberVMInfo",           CC "(" MEM ")" OBJ,                        FN_PTR(MHN_getMemberVMInfo)}
+  {CC "getMemberVMInfo",           CC "(" MEM ")" OBJ,                       FN_PTR(MHN_getMemberVMInfo)},
+  {CC "classData",                 CC "(" CLS ")" OBJ,                       FN_PTR(MHN_classData)}
 };
 
 static JNINativeMethod MH_methods[] = {
--- a/src/hotspot/share/prims/unsafe.cpp	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/hotspot/share/prims/unsafe.cpp	Wed Nov 14 04:44:18 2018 -0500
@@ -823,6 +823,7 @@
                                                 false, // is_weak
                                                 false, // can_access_vm_annotations
                                                 NULL,  // dynamic_nest_host 
+                                                Handle(), // classData
                                                 CHECK_NULL);
   if (anonk == NULL) {
     return NULL;
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Nov 14 04:44:18 2018 -0500
@@ -72,6 +72,9 @@
                                                  boolean resolve,
                                                  Object ifNotAvailable);
 
+    /// ClassData support
+    static native Object classData(Class<?> lookupClass);
+
     /** Represents a context to track nmethod dependencies on CallSite instance target. */
     static class CallSiteContext implements Runnable {
         //@Injected JVM_nmethodBucket* vmdependencies;
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Nov 08 16:23:52 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Nov 14 04:44:18 2018 -0500
@@ -1212,7 +1212,7 @@
             }
 
             // should we allow clearing?  getAndClearClassData
-            return CLASS_DATA_MAP.get(lookupClass);
+            return MethodHandleNatives.classData(lookupClass);
         }
 
         // package-private
@@ -1265,11 +1265,6 @@
             assert clazz.getClassLoader() == lookupClass.getClassLoader()
                    && clazz.getPackageName().equals(lookupClass.getPackageName());
 
-            // ## TBD what if multiple threads defining this same class??
-            // may need VM to inject the classData in a Class itself at define class time
-            if (classData != null) {
-                CLASS_DATA_MAP.putIfAbsent(clazz, classData);
-            }
             return clazz;
         }
 
@@ -1286,9 +1281,6 @@
         // cached protection domain
         private volatile ProtectionDomain cachedProtectionDomain;
 
-        // don't see the need to use ClassValue
-        private static final WeakHashMap<Class<?>, Object> CLASS_DATA_MAP = new WeakHashMap<>();
-
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }