hotspot/src/share/vm/classfile/systemDictionary.cpp
changeset 13391 30245956af37
parent 13286 b8b0898d5f3a
child 13728 882756847a04
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Mon Jul 23 13:04:59 2012 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Tue Jul 24 10:51:00 2012 -0700
@@ -30,6 +30,7 @@
 #include "classfile/resolutionErrors.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "compiler/compileBroker.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
 #include "memory/gcLocker.hpp"
@@ -193,7 +194,10 @@
 // Forwards to resolve_instance_class_or_null
 
 klassOop SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
-  assert(!THREAD->is_Compiler_thread(), "Can not load classes with the Compiler thread");
+  assert(!THREAD->is_Compiler_thread(),
+         err_msg("can not load classes with compiler thread: class=%s, classloader=%s",
+                 class_name->as_C_string(),
+                 class_loader.is_null() ? "null" : class_loader->klass()->klass_part()->name()->as_C_string()));
   if (FieldType::is_array(class_name)) {
     return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
   } else if (FieldType::is_obj(class_name)) {
@@ -2358,72 +2362,134 @@
 }
 
 
-methodOop SystemDictionary::find_method_handle_invoke(Symbol* name,
-                                                      Symbol* signature,
-                                                      KlassHandle accessing_klass,
-                                                      TRAPS) {
-  if (!EnableInvokeDynamic)  return NULL;
-  vmSymbols::SID name_id = vmSymbols::find_sid(name);
-  assert(name_id != vmSymbols::NO_SID, "must be a known name");
-  unsigned int hash  = invoke_method_table()->compute_hash(signature, name_id);
+methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid,
+                                                            Symbol* signature,
+                                                            TRAPS) {
+  methodHandle empty;
+  assert(EnableInvokeDynamic, "");
+  assert(MethodHandles::is_signature_polymorphic(iid) &&
+         MethodHandles::is_signature_polymorphic_intrinsic(iid) &&
+         iid != vmIntrinsics::_invokeGeneric,
+         err_msg("must be a known MH intrinsic iid=%d: %s", iid, vmIntrinsics::name_at(iid)));
+
+  unsigned int hash  = invoke_method_table()->compute_hash(signature, iid);
   int          index = invoke_method_table()->hash_to_index(hash);
-  SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature, name_id);
-  methodHandle non_cached_result;
+  SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature, iid);
+  methodHandle m;
   if (spe == NULL || spe->property_oop() == NULL) {
     spe = NULL;
     // Must create lots of stuff here, but outside of the SystemDictionary lock.
-    if (THREAD->is_Compiler_thread())
-      return NULL;              // do not attempt from within compiler
-    bool for_invokeGeneric = (name_id != vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name));
-    bool found_on_bcp = false;
-    Handle mt = find_method_handle_type(signature, accessing_klass,
-                                        for_invokeGeneric,
-                                        found_on_bcp, CHECK_NULL);
-    KlassHandle  mh_klass = SystemDictionaryHandles::MethodHandle_klass();
-    methodHandle m = methodOopDesc::make_invoke_method(mh_klass, name, signature,
-                                                       mt, CHECK_NULL);
+    m = methodOopDesc::make_method_handle_intrinsic(iid, signature, CHECK_(empty));
+    CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier,
+                                  methodHandle(), CompileThreshold, "MH", CHECK_(empty));
+
     // Now grab the lock.  We might have to throw away the new method,
     // if a racing thread has managed to install one at the same time.
-    if (found_on_bcp) {
-      MutexLocker ml(SystemDictionary_lock, Thread::current());
-      spe = invoke_method_table()->find_entry(index, hash, signature, name_id);
+    {
+      MutexLocker ml(SystemDictionary_lock, THREAD);
+      spe = invoke_method_table()->find_entry(index, hash, signature, iid);
       if (spe == NULL)
-        spe = invoke_method_table()->add_entry(index, hash, signature, name_id);
-      if (spe->property_oop() == NULL) {
+        spe = invoke_method_table()->add_entry(index, hash, signature, iid);
+      if (spe->property_oop() == NULL)
         spe->set_property_oop(m());
-        // Link m to his method type, if it is suitably generic.
-        oop mtform = java_lang_invoke_MethodType::form(mt());
-        if (mtform != NULL && mt() == java_lang_invoke_MethodTypeForm::erasedType(mtform)
-            // vmlayout must be an invokeExact:
-            && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name)
-            && java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
-          java_lang_invoke_MethodTypeForm::init_vmlayout(mtform, m());
-        }
+    }
+  }
+
+  assert(spe != NULL && spe->property_oop() != NULL, "");
+  m = methodOop(spe->property_oop());
+  assert(m->is_method(), "");
+
+  return m;
+}
+
+// Helper for unpacking the return value from linkMethod and linkCallSite.
+static methodHandle unpack_method_and_appendix(Handle mname,
+                                               objArrayHandle appendix_box,
+                                               Handle* appendix_result,
+                                               TRAPS) {
+  methodHandle empty;
+  if (mname.not_null()) {
+    oop vmtarget = java_lang_invoke_MemberName::vmtarget(mname());
+    if (vmtarget != NULL && vmtarget->is_method()) {
+      methodOop m = methodOop(vmtarget);
+      oop appendix = appendix_box->obj_at(0);
+      if (TraceMethodHandles) {
+    #ifndef PRODUCT
+        tty->print("Linked method="INTPTR_FORMAT": ", m);
+        m->print();
+        if (appendix != NULL) { tty->print("appendix = "); appendix->print(); }
+        tty->cr();
+    #endif //PRODUCT
       }
-    } else {
-      non_cached_result = m;
+      (*appendix_result) = Handle(THREAD, appendix);
+      return methodHandle(THREAD, m);
     }
   }
-  if (spe != NULL && spe->property_oop() != NULL) {
-    assert(spe->property_oop()->is_method(), "");
-    return (methodOop) spe->property_oop();
-  } else {
-    return non_cached_result();
+  THROW_MSG_(vmSymbols::java_lang_LinkageError(), "bad value from MethodHandleNatives", empty);
+  return empty;
+}
+
+methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
+                                                          Symbol* signature,
+                                                          KlassHandle accessing_klass,
+                                                          Handle* appendix_result,
+                                                          TRAPS) {
+  methodHandle empty;
+  assert(EnableInvokeDynamic, "");
+  assert(!THREAD->is_Compiler_thread(), "");
+  Handle method_type =
+    SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty));
+  if (false) {  // FIXME: Decide if the Java upcall should resolve signatures.
+    method_type = java_lang_String::create_from_symbol(signature, CHECK_(empty));
   }
+
+  KlassHandle  mh_klass = SystemDictionaryHandles::MethodHandle_klass();
+  int ref_kind = JVM_REF_invokeVirtual;
+  Handle name_str = StringTable::intern(name, CHECK_(empty));
+  objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty));
+  assert(appendix_box->obj_at(0) == NULL, "");
+
+  // call java.lang.invoke.MethodHandleNatives::linkMethod(... String, MethodType) -> MemberName
+  JavaCallArguments args;
+  args.push_oop(accessing_klass()->java_mirror());
+  args.push_int(ref_kind);
+  args.push_oop(mh_klass()->java_mirror());
+  args.push_oop(name_str());
+  args.push_oop(method_type());
+  args.push_oop(appendix_box());
+  JavaValue result(T_OBJECT);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::MethodHandleNatives_klass(),
+                         vmSymbols::linkMethod_name(),
+                         vmSymbols::linkMethod_signature(),
+                         &args, CHECK_(empty));
+  Handle mname(THREAD, (oop) result.get_jobject());
+  return unpack_method_and_appendix(mname, appendix_box, appendix_result, THREAD);
 }
 
+
 // Ask Java code to find or construct a java.lang.invoke.MethodType for the given
 // signature, as interpreted relative to the given class loader.
 // Because of class loader constraints, all method handle usage must be
 // consistent with this loader.
 Handle SystemDictionary::find_method_handle_type(Symbol* signature,
                                                  KlassHandle accessing_klass,
-                                                 bool for_invokeGeneric,
-                                                 bool& return_bcp_flag,
                                                  TRAPS) {
+  Handle empty;
+  vmIntrinsics::ID null_iid = vmIntrinsics::_none;  // distinct from all method handle invoker intrinsics
+  unsigned int hash  = invoke_method_table()->compute_hash(signature, null_iid);
+  int          index = invoke_method_table()->hash_to_index(hash);
+  SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature, null_iid);
+  if (spe != NULL && spe->property_oop() != NULL) {
+    assert(java_lang_invoke_MethodType::is_instance(spe->property_oop()), "");
+    return Handle(THREAD, spe->property_oop());
+  } else if (THREAD->is_Compiler_thread()) {
+    warning("SystemDictionary::find_method_handle_type called from compiler thread");  // FIXME
+    return Handle();  // do not attempt from within compiler, unless it was cached
+  }
+
   Handle class_loader, protection_domain;
   bool is_on_bcp = true;  // keep this true as long as we can materialize from the boot classloader
-  Handle empty;
   int npts = ArgumentCount(signature).size();
   objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::Class_klass(), npts, CHECK_(empty));
   int arg = 0;
@@ -2432,6 +2498,7 @@
   for (SignatureStream ss(signature); !ss.is_done(); ss.next()) {
     oop mirror = NULL;
     if (is_on_bcp) {
+      // Note:  class_loader & protection_domain are both null at this point.
       mirror = ss.as_java_mirror(class_loader, protection_domain,
                                  SignatureStream::ReturnNull, CHECK_(empty));
       if (mirror == NULL) {
@@ -2452,9 +2519,11 @@
       rt = Handle(THREAD, mirror);
     else
       pts->obj_at_put(arg++, mirror);
+
     // Check accessibility.
     if (ss.is_object() && accessing_klass.not_null()) {
       klassOop sel_klass = java_lang_Class::as_klassOop(mirror);
+      mirror = NULL;  // safety
       // Emulate constantPoolOopDesc::verify_constant_pool_resolve.
       if (Klass::cast(sel_klass)->oop_is_objArray())
         sel_klass = objArrayKlass::cast(sel_klass)->bottom_klass();
@@ -2477,23 +2546,18 @@
                          &args, CHECK_(empty));
   Handle method_type(THREAD, (oop) result.get_jobject());
 
-  if (for_invokeGeneric) {
-    // call java.lang.invoke.MethodHandleNatives::notifyGenericMethodType(MethodType) -> void
-    JavaCallArguments args(Handle(THREAD, method_type()));
-    JavaValue no_result(T_VOID);
-    JavaCalls::call_static(&no_result,
-                           SystemDictionary::MethodHandleNatives_klass(),
-                           vmSymbols::notifyGenericMethodType_name(),
-                           vmSymbols::notifyGenericMethodType_signature(),
-                           &args, THREAD);
-    if (HAS_PENDING_EXCEPTION) {
-      // If the notification fails, just kill it.
-      CLEAR_PENDING_EXCEPTION;
+  if (is_on_bcp) {
+    // We can cache this MethodType inside the JVM.
+    MutexLocker ml(SystemDictionary_lock, THREAD);
+    spe = invoke_method_table()->find_entry(index, hash, signature, null_iid);
+    if (spe == NULL)
+      spe = invoke_method_table()->add_entry(index, hash, signature, null_iid);
+    if (spe->property_oop() == NULL) {
+      spe->set_property_oop(method_type());
     }
   }
 
-  // report back to the caller with the MethodType and the "on_bcp" flag
-  return_bcp_flag = is_on_bcp;
+  // report back to the caller with the MethodType
   return method_type;
 }
 
@@ -2508,8 +2572,7 @@
   Handle name = java_lang_String::create_from_symbol(name_sym, CHECK_(empty));
   Handle type;
   if (signature->utf8_length() > 0 && signature->byte_at(0) == '(') {
-    bool ignore_is_on_bcp = false;
-    type = find_method_handle_type(signature, caller, false, ignore_is_on_bcp, CHECK_(empty));
+    type = find_method_handle_type(signature, caller, CHECK_(empty));
   } else {
     ResourceMark rm(THREAD);
     SignatureStream ss(signature, false);
@@ -2543,119 +2606,54 @@
 
 // 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.
-Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method,
-                                                Symbol* name,
-                                                methodHandle signature_invoker,
-                                                Handle info,
-                                                methodHandle caller_method,
-                                                int caller_bci,
-                                                TRAPS) {
-  Handle empty;
-  guarantee(bootstrap_method.not_null() &&
-            java_lang_invoke_MethodHandle::is_instance(bootstrap_method()),
+methodHandle SystemDictionary::find_dynamic_call_site_invoker(KlassHandle caller,
+                                                              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 {
+    assert(bootstrap_specifier->is_objArray(), "");
+    objArrayHandle args(THREAD, (objArrayOop) bootstrap_specifier());
+    int len = args->length();
+    assert(len >= 1, "");
+    bsm = Handle(THREAD, args->obj_at(0));
+    if (len > 1) {
+      objArrayOop args1 = oopFactory::new_objArray(SystemDictionary::Object_klass(), len-1, CHECK_(empty));
+      for (int i = 1; i < len; i++)
+        args1->obj_at_put(i-1, args->obj_at(i));
+      info = Handle(THREAD, args1);
+    }
+  }
+  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
             "caller must supply a valid BSM");
 
-  Handle caller_mname = MethodHandles::new_MemberName(CHECK_(empty));
-  MethodHandles::init_MemberName(caller_mname(), caller_method());
-
-  // call java.lang.invoke.MethodHandleNatives::makeDynamicCallSite(bootm, name, mtype, info, caller_mname, caller_pos)
-  oop name_str_oop = StringTable::intern(name, CHECK_(empty)); // not a handle!
-  JavaCallArguments args(Handle(THREAD, bootstrap_method()));
-  args.push_oop(name_str_oop);
-  args.push_oop(signature_invoker->method_handle_type());
+  Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
+  Handle method_type = find_method_handle_type(type, caller, CHECK_(empty));
+
+  objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty));
+  assert(appendix_box->obj_at(0) == NULL, "");
+
+  // call java.lang.invoke.MethodHandleNatives::linkCallSite(caller, bsm, name, mtype, info, &appendix)
+  JavaCallArguments args;
+  args.push_oop(caller->java_mirror());
+  args.push_oop(bsm());
+  args.push_oop(method_name());
+  args.push_oop(method_type());
   args.push_oop(info());
-  args.push_oop(caller_mname());
-  args.push_int(caller_bci);
+  args.push_oop(appendix_box);
   JavaValue result(T_OBJECT);
   JavaCalls::call_static(&result,
                          SystemDictionary::MethodHandleNatives_klass(),
-                         vmSymbols::makeDynamicCallSite_name(),
-                         vmSymbols::makeDynamicCallSite_signature(),
+                         vmSymbols::linkCallSite_name(),
+                         vmSymbols::linkCallSite_signature(),
                          &args, CHECK_(empty));
-  oop call_site_oop = (oop) result.get_jobject();
-  assert(call_site_oop->is_oop()
-         /*&& java_lang_invoke_CallSite::is_instance(call_site_oop)*/, "must be sane");
-  if (TraceMethodHandles) {
-#ifndef PRODUCT
-    tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop);
-    call_site_oop->print();
-    tty->cr();
-#endif //PRODUCT
-  }
-  return call_site_oop;
-}
-
-Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci,
-                                               int cache_index,
-                                               Handle& argument_info_result,
-                                               TRAPS) {
-  Handle empty;
-
-  constantPoolHandle pool;
-  {
-    klassOop caller = caller_method->method_holder();
-    if (!Klass::cast(caller)->oop_is_instance())  return empty;
-    pool = constantPoolHandle(THREAD, instanceKlass::cast(caller)->constants());
-  }
-
-  int constant_pool_index = pool->cache()->entry_at(cache_index)->constant_pool_index();
-  constantTag tag = pool->tag_at(constant_pool_index);
-
-  if (tag.is_invoke_dynamic()) {
-    // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments
-    // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
-    int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index);
-    if (bsm_index != 0) {
-      int bsm_index_in_cache = pool->cache()->entry_at(cache_index)->bootstrap_method_index_in_cache();
-      DEBUG_ONLY(int bsm_index_2 = pool->cache()->entry_at(bsm_index_in_cache)->constant_pool_index());
-      assert(bsm_index == bsm_index_2, "BSM constant lifted to cache");
-      if (TraceMethodHandles) {
-        tty->print_cr("resolving bootstrap method for "PTR_FORMAT" at %d at cache[%d]CP[%d]...",
-                      (intptr_t) caller_method(), caller_bci, cache_index, constant_pool_index);
-      }
-      oop bsm_oop = pool->resolve_cached_constant_at(bsm_index_in_cache, CHECK_(empty));
-      if (TraceMethodHandles) {
-        tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":",
-                      (intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop);
-      }
-      assert(bsm_oop->is_oop(), "must be sane");
-      // caller must verify that it is of type MethodHandle
-      Handle bsm(THREAD, bsm_oop);
-      bsm_oop = NULL;  // safety
-
-      // Extract the optional static arguments.
-      Handle argument_info;  // either null, or one arg, or Object[]{arg...}
-      int argc = pool->invoke_dynamic_argument_count_at(constant_pool_index);
-      if (TraceInvokeDynamic) {
-        tty->print_cr("find_bootstrap_method: [%d/%d] CONSTANT_InvokeDynamic: %d[%d]",
-                      constant_pool_index, cache_index, bsm_index, argc);
-      }
-      if (argc > 0) {
-        objArrayHandle arg_array;
-        if (argc > 1) {
-          objArrayOop arg_array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), argc, CHECK_(empty));
-          arg_array = objArrayHandle(THREAD, arg_array_oop);
-          argument_info = arg_array;
-        }
-        for (int arg_i = 0; arg_i < argc; arg_i++) {
-          int arg_index = pool->invoke_dynamic_argument_index_at(constant_pool_index, arg_i);
-          oop arg_oop = pool->resolve_possibly_cached_constant_at(arg_index, CHECK_(empty));
-          if (arg_array.is_null()) {
-            argument_info = Handle(THREAD, arg_oop);
-          } else {
-            arg_array->obj_at_put(arg_i, arg_oop);
-          }
-        }
-      }
-
-      argument_info_result = argument_info;  // return argument_info to caller
-      return bsm;
-    }
-  } else {
-    ShouldNotReachHere();  // verifier does not allow this
-  }
-
-  return empty;
+  Handle mname(THREAD, (oop) result.get_jobject());
+  return unpack_method_and_appendix(mname, appendix_box, appendix_result, THREAD);
 }
 
 // Since the identity hash code for symbols changes when the symbols are