< prev index next >

src/hotspot/share/classfile/systemDictionary.cpp

Print this page

        

@@ -66,10 +66,11 @@
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
 #include "prims/jvmtiExport.hpp"
+#include "prims/resolvedMethodTable.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/biasedLocking.hpp"
 #include "runtime/fieldType.hpp"
 #include "runtime/handles.inline.hpp"

@@ -84,10 +85,13 @@
 #include "services/threadService.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_CDS
 #include "classfile/systemDictionaryShared.hpp"
 #endif
+#if INCLUDE_JVMCI
+#include "jvmci/jvmciRuntime.hpp"
+#endif
 #if INCLUDE_JFR
 #include "jfr/jfr.hpp"
 #endif
 
 PlaceholderTable*      SystemDictionary::_placeholders        = NULL;

@@ -986,28 +990,44 @@
   return k;
 }
 
 // Note: this method is much like resolve_from_stream, but
 // does not publish the classes via the SystemDictionary.
-// Handles unsafe_DefineAnonymousClass and redefineclasses
-// RedefinedClasses do not add to the class hierarchy
+// Handles Lookup.defineClass nonfindable, unsafe_DefineAnonymousClass
+// and redefineclasses. RedefinedClasses do not add to the class hierarchy.
 InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
                                               Handle class_loader,
                                               Handle protection_domain,
                                               ClassFileStream* st,
                                               const InstanceKlass* unsafe_anonymous_host,
                                               GrowableArray<Handle>* cp_patches,
+                                              const bool is_nonfindable,
+                                              const bool is_weaknonfindable,
+                                              const bool can_access_vm_annotations,
+                                              InstanceKlass* dynamic_nest_host,
+                                              Handle classData,
                                               TRAPS) {
 
   EventClassLoad class_load_start_event;
 
   ClassLoaderData* loader_data;
+
   if (unsafe_anonymous_host != NULL) {
-    // Create a new CLD for an unsafe anonymous class, that uses the same class loader
-    // as the unsafe_anonymous_host
+    // - for unsafe anonymous class: create a new short-lived CLD that uses the same
+    //                               class loader as the unsafe_anonymous_host.
     guarantee(oopDesc::equals(unsafe_anonymous_host->class_loader(), class_loader()), "should be the same");
-    loader_data = ClassLoaderData::unsafe_anonymous_class_loader_data(class_loader);
+    loader_data = ClassLoaderData::shortlived_class_loader_data(class_loader);
+  } else if (is_nonfindable) {
+    // - for weak nonfindable class: create a new short-lived CLD whose loader is
+    //                               the Lookup class' loader.
+    // - for nonfindable class: add the class to the Lookup class' loader's CLD.
+    if (is_weaknonfindable) {
+      loader_data = ClassLoaderData::shortlived_class_loader_data(class_loader);
+    } else {
+      // This nonfindable class goes into the regular CLD pool for this loader.
+      loader_data = register_loader(class_loader);
+    }
   } else {
     loader_data = ClassLoaderData::class_loader_data(class_loader());
   }
 
   assert(st != NULL, "invariant");

@@ -1022,16 +1042,22 @@
                                                       class_name,
                                                       loader_data,
                                                       protection_domain,
                                                       unsafe_anonymous_host,
                                                       cp_patches,
+                                                      is_nonfindable,
+                                                      can_access_vm_annotations,
+                                                      dynamic_nest_host,
+                                                      classData,
                                                       CHECK_NULL);
 
-  if (unsafe_anonymous_host != NULL && k != NULL) {
-    // Unsafe anonymous classes must update ClassLoaderData holder (was unsafe_anonymous_host loader)
+  if ((is_nonfindable || (unsafe_anonymous_host != NULL)) && k != NULL) {
+    // Weak nonfindable and unsafe anonymous classes must update ClassLoaderData holder
     // so that they can be unloaded when the mirror is no longer referenced.
-    k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
+    if (is_weaknonfindable || (unsafe_anonymous_host != NULL)) {
+      k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
+    }
 
     {
       MutexLocker mu_r(Compile_lock, THREAD);
 
       // Add to class hierarchy, initialize vtables, and do possible

@@ -1048,11 +1074,12 @@
     k->link_class(CHECK_NULL);
     if (cp_patches != NULL) {
       k->constants()->patch_resolved_references(cp_patches);
     }
 
-    // If it's anonymous, initialize it now, since nobody else will.
+    // 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
     if (JvmtiExport::should_post_class_load()) {
         assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");

@@ -1075,10 +1102,11 @@
 
 InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
                                                      Handle class_loader,
                                                      Handle protection_domain,
                                                      ClassFileStream* st,
+                                                     InstanceKlass* dynamic_nest_host,
                                                      TRAPS) {
 
   HandleMark hm(THREAD);
 
   // Classloaders that support parallelism, e.g. bootstrap classloader,

@@ -1119,12 +1147,16 @@
     }
     k = KlassFactory::create_from_stream(st,
                                          class_name,
                                          loader_data,
                                          protection_domain,
-                                         NULL, // unsafe_anonymous_host
-                                         NULL, // cp_patches
+                                         NULL,  // unsafe_anonymous_host
+                                         NULL,  // cp_patches
+                                         false, // is_nonfindable
+                                         false, // can_access_vm_annotations
+                                         dynamic_nest_host,
+                                         Handle(), // classData
                                          CHECK_NULL);
   }
 
   assert(k != NULL, "no klass created");
   Symbol* h_name = k->name();

@@ -1819,21 +1851,23 @@
     GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
     assert_locked_or_safepoint(ClassLoaderDataGraph_lock);  // caller locks.
     // First, mark for unload all ClassLoaderData referencing a dead class loader.
     unloading_occurred = ClassLoaderDataGraph::do_unloading();
     if (unloading_occurred) {
-      MutexLocker ml2(is_concurrent ? Module_lock : NULL);
+      MutexLockerEx ml2(is_concurrent ? Module_lock : NULL);
       JFR_ONLY(Jfr::on_unloading_classes();)
 
-      MutexLocker ml1(is_concurrent ? SystemDictionary_lock : NULL);
+      MutexLockerEx ml1(is_concurrent ? SystemDictionary_lock : NULL);
       ClassLoaderDataGraph::clean_module_and_package_info();
       constraints()->purge_loader_constraints();
       resolution_errors()->purge_resolution_errors();
     }
   }
 
   GCTraceTime(Debug, gc, phases) t("Trigger cleanups", gc_timer);
+  // Trigger cleaning the ResolvedMethodTable even if no unloading occurred.
+  ResolvedMethodTable::trigger_cleanup();
 
   if (unloading_occurred) {
     SymbolTable::trigger_cleanup();
 
     // Oops referenced by the protection domain cache table may get unreachable independently

@@ -1917,10 +1951,17 @@
   assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
   int sid = wk_init_info[id - FIRST_WKID];
   Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
   InstanceKlass** klassp = &_well_known_klasses[id];
 
+
+#if INCLUDE_JVMCI
+  if (id >= FIRST_JVMCI_WKID) {
+    assert(EnableJVMCI, "resolve JVMCI classes only when EnableJVMCI is true");
+  }
+#endif
+
   if ((*klassp) == NULL) {
     Klass* k = resolve_or_fail(symbol, true, CHECK_0);
     (*klassp) = InstanceKlass::cast(k);
   }
   return ((*klassp) != NULL);

@@ -2005,11 +2046,11 @@
   // JSR 292 classes
   WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
   WKID jsr292_group_end   = WK_KLASS_ENUM_NAME(VolatileCallSite_klass);
   resolve_wk_klasses_until(jsr292_group_start, scan, CHECK);
   resolve_wk_klasses_through(jsr292_group_end, scan, CHECK);
-  WKID last = WKID_LIMIT;
+  WKID last = NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID);
   resolve_wk_klasses_until(last, scan, CHECK);
 
   _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass);
   _box_klasses[T_CHAR]    = WK_KLASS(Character_klass);
   _box_klasses[T_FLOAT]   = WK_KLASS(Float_klass);

@@ -2738,65 +2779,110 @@
                          vmSymbols::linkMethodHandleConstant_signature(),
                          &args, CHECK_(empty));
   return Handle(THREAD, (oop) result.get_jobject());
 }
 
-// Ask Java to run a bootstrap method, in order to create a dynamic call site
-// while linking an invokedynamic op, or compute a constant for Dynamic_info CP entry
-// with linkage results being stored back into the bootstrap specifier.
-void SystemDictionary::invoke_bootstrap_method(BootstrapInfo& bootstrap_specifier, TRAPS) {
-  // Resolve the bootstrap specifier, its name, type, and static arguments
-  bootstrap_specifier.resolve_bsm(CHECK);
+// Ask Java to compute a constant by invoking a BSM given a Dynamic_info CP entry
+Handle SystemDictionary::link_dynamic_constant(Klass* caller,
+                                               int condy_index,
+                                               Handle bootstrap_specifier,
+                                               Symbol* name,
+                                               Symbol* type,
+                                               TRAPS) {
+  Handle empty;
+  Handle bsm, info;
+  if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
+    bsm = bootstrap_specifier;
+  } else {
+    assert(bootstrap_specifier->is_objArray(), "");
+    objArrayOop args = (objArrayOop) bootstrap_specifier();
+    assert(args->length() == 2, "");
+    bsm  = Handle(THREAD, args->obj_at(0));
+    info = Handle(THREAD, args->obj_at(1));
+  }
+  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
+            "caller must supply a valid BSM");
 
   // This should not happen.  JDK code should take care of that.
-  if (bootstrap_specifier.caller() == NULL || bootstrap_specifier.type_arg().is_null()) {
-    THROW_MSG(vmSymbols::java_lang_InternalError(), "Invalid bootstrap method invocation with no caller or type argument");
+  if (caller == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad dynamic constant", empty);
   }
 
-  bool is_indy = bootstrap_specifier.is_method_call();
-  objArrayHandle appendix_box;
-  if (is_indy) {
-    // Some method calls may require an appendix argument.  Arrange to receive it.
-    appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK);
-    assert(appendix_box->obj_at(0) == NULL, "");
-  }
+  Handle constant_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
+
+  // Resolve the constant type in the context of the caller class
+  Handle type_mirror = find_java_mirror_for_type(type, caller, SignatureStream::NCDFError,
+                                                 CHECK_(empty));
 
-  // call condy: java.lang.invoke.MethodHandleNatives::linkDynamicConstant(caller, condy_index, bsm, type, info)
-  //       indy: java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
+  // call java.lang.invoke.MethodHandleNatives::linkConstantDyanmic(caller, condy_index, bsm, type, info)
   JavaCallArguments args;
-  args.push_oop(Handle(THREAD, bootstrap_specifier.caller_mirror()));
-  args.push_int(bootstrap_specifier.bss_index());
-  args.push_oop(bootstrap_specifier.bsm());
-  args.push_oop(bootstrap_specifier.name_arg());
-  args.push_oop(bootstrap_specifier.type_arg());
-  args.push_oop(bootstrap_specifier.arg_values());
-  if (is_indy) {
-    args.push_oop(appendix_box);
-  }
+  args.push_oop(Handle(THREAD, caller->java_mirror()));
+  args.push_int(condy_index);
+  args.push_oop(bsm);
+  args.push_oop(constant_name);
+  args.push_oop(type_mirror);
+  args.push_oop(info);
   JavaValue result(T_OBJECT);
   JavaCalls::call_static(&result,
                          SystemDictionary::MethodHandleNatives_klass(),
-                         is_indy ? vmSymbols::linkCallSite_name() : vmSymbols::linkDynamicConstant_name(),
-                         is_indy ? vmSymbols::linkCallSite_signature() : vmSymbols::linkDynamicConstant_signature(),
-                         &args, CHECK);
-
-  Handle value(THREAD, (oop) result.get_jobject());
-  if (is_indy) {
-    Handle appendix;
-    methodHandle method = unpack_method_and_appendix(value,
-                                                     bootstrap_specifier.caller(),
-                                                     appendix_box,
-                                                     &appendix, CHECK);
-    bootstrap_specifier.set_resolved_method(method, appendix);
+                         vmSymbols::linkDynamicConstant_name(),
+                         vmSymbols::linkDynamicConstant_signature(),
+                         &args, CHECK_(empty));
+
+  return Handle(THREAD, (oop) result.get_jobject());
+}
+
+// Ask Java code to find or construct a java.lang.invoke.CallSite for the given
+// name and signature, as interpreted relative to the given class loader.
+methodHandle SystemDictionary::find_dynamic_call_site_invoker(Klass* caller,
+                                                              int indy_index,
+                                                              Handle bootstrap_specifier,
+                                                              Symbol* name,
+                                                              Symbol* type,
+                                                              Handle *appendix_result,
+                                                              TRAPS) {
+  methodHandle empty;
+  Handle bsm, info;
+  if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
+    bsm = bootstrap_specifier;
   } else {
-    bootstrap_specifier.set_resolved_value(value);
+    objArrayOop args = (objArrayOop) bootstrap_specifier();
+    assert(args->length() == 2, "");
+    bsm  = Handle(THREAD, args->obj_at(0));
+    info = Handle(THREAD, args->obj_at(1));
+  }
+  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
+            "caller must supply a valid BSM");
+
+  Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
+  Handle method_type = find_method_handle_type(type, caller, CHECK_(empty));
+
+  // This should not happen.  JDK code should take care of that.
+  if (caller == NULL || method_type.is_null()) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokedynamic", empty);
   }
 
-  // sanity check
-  assert(bootstrap_specifier.is_resolved() ||
-         (bootstrap_specifier.is_method_call() &&
-          bootstrap_specifier.resolved_method().not_null()), "bootstrap method call failed");
+  objArrayHandle appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK_(empty));
+  assert(appendix_box->obj_at(0) == NULL, "");
+
+  // call java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
+  JavaCallArguments args;
+  args.push_oop(Handle(THREAD, caller->java_mirror()));
+  args.push_int(indy_index);
+  args.push_oop(bsm);
+  args.push_oop(method_name);
+  args.push_oop(method_type);
+  args.push_oop(info);
+  args.push_oop(appendix_box);
+  JavaValue result(T_OBJECT);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::MethodHandleNatives_klass(),
+                         vmSymbols::linkCallSite_name(),
+                         vmSymbols::linkCallSite_signature(),
+                         &args, CHECK_(empty));
+  Handle mname(THREAD, (oop) result.get_jobject());
+  return unpack_method_and_appendix(mname, caller, appendix_box, appendix_result, THREAD);
 }
 
 // Protection domain cache table handling
 
 ProtectionDomainCacheEntry* SystemDictionary::cache_get(Handle protection_domain) {

@@ -2847,29 +2933,17 @@
   assert_locked_or_safepoint(SystemDictionary_lock);
   if (verbose) {
     print_on(st);
   } else {
     CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
-    ClassLoaderDataGraph::print_table_statistics(st);
+    ClassLoaderDataGraph::print_dictionary_statistics(st);
     placeholders()->print_table_statistics(st, "Placeholder Table");
     constraints()->print_table_statistics(st, "LoaderConstraints Table");
-    pd_cache_table()->print_table_statistics(st, "ProtectionDomainCache Table");
+    _pd_cache_table->print_table_statistics(st, "ProtectionDomainCache Table");
   }
 }
 
-TableStatistics SystemDictionary::placeholders_statistics() {
-  return placeholders()->statistics_calculate();
-}
-
-TableStatistics SystemDictionary::loader_constraints_statistics() {
-  return constraints()->statistics_calculate();
-}
-
-TableStatistics SystemDictionary::protection_domain_cache_statistics() {
-  return pd_cache_table()->statistics_calculate();
-}
-
 // Utility for dumping dictionaries.
 SystemDictionaryDCmd::SystemDictionaryDCmd(outputStream* output, bool heap) :
                                  DCmdWithParser(output, heap),
   _verbose("-verbose", "Dump the content of each dictionary entry for all class loaders",
            "BOOLEAN", false, "false") {
< prev index next >