7056328: JSR 292 invocation sometimes fails in adapters for types not on boot class path
authorjrose
Thu, 23 Jun 2011 17:14:06 -0700
changeset 10008 d84de97ad847
parent 10007 43d4a6542551
child 10009 9fa7d67d09fe
7056328: JSR 292 invocation sometimes fails in adapters for types not on boot class path Reviewed-by: never
hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp
hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
hotspot/src/share/vm/ci/ciEnv.cpp
hotspot/src/share/vm/ci/ciEnv.hpp
hotspot/src/share/vm/ci/ciField.cpp
hotspot/src/share/vm/ci/ciMethod.cpp
hotspot/src/share/vm/ci/ciMethodHandle.cpp
hotspot/src/share/vm/ci/ciObjArrayKlass.cpp
hotspot/src/share/vm/ci/ciSignature.cpp
hotspot/src/share/vm/ci/ciSignature.hpp
hotspot/src/share/vm/classfile/javaClasses.cpp
hotspot/src/share/vm/classfile/javaClasses.hpp
hotspot/src/share/vm/classfile/systemDictionary.cpp
hotspot/src/share/vm/interpreter/linkResolver.cpp
hotspot/src/share/vm/oops/constantPoolKlass.cpp
hotspot/src/share/vm/oops/constantPoolOop.cpp
hotspot/src/share/vm/oops/constantPoolOop.hpp
hotspot/src/share/vm/oops/cpCacheOop.cpp
hotspot/src/share/vm/oops/cpCacheOop.hpp
hotspot/src/share/vm/oops/methodOop.cpp
hotspot/src/share/vm/oops/methodOop.hpp
hotspot/src/share/vm/prims/methodHandleWalk.cpp
hotspot/src/share/vm/prims/methodHandleWalk.hpp
hotspot/src/share/vm/prims/methodHandles.cpp
hotspot/src/share/vm/prims/methodHandles.hpp
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -266,7 +266,7 @@
 
 void TemplateTable::ldc(bool wide) {
   transition(vtos, vtos);
-  Label call_ldc, notInt, notString, notClass, exit;
+  Label call_ldc, notInt, isString, notString, notClass, exit;
 
   if (wide) {
     __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned);
@@ -317,8 +317,11 @@
 
   __ bind(notInt);
  // __ cmp(O2, JVM_CONSTANT_String);
+  __ brx(Assembler::equal, true, Assembler::pt, isString);
+  __ delayed()->cmp(O2, JVM_CONSTANT_Object);
   __ brx(Assembler::notEqual, true, Assembler::pt, notString);
   __ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f);
+  __ bind(isString);
   __ ld_ptr(O0, O1, Otos_i);
   __ verify_oop(Otos_i);
   __ push(atos);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -373,15 +373,17 @@
     __ jcc(Assembler::equal, L);
     __ cmpl(rdx, JVM_CONSTANT_String);
     __ jcc(Assembler::equal, L);
+    __ cmpl(rdx, JVM_CONSTANT_Object);
+    __ jcc(Assembler::equal, L);
     __ stop("unexpected tag type in ldc");
     __ bind(L);
   }
 #endif
   Label isOop;
   // atos and itos
-  // String is only oop type we will see here
-  __ cmpl(rdx, JVM_CONSTANT_String);
-  __ jccb(Assembler::equal, isOop);
+  // Integer is only non-oop type we will see here
+  __ cmpl(rdx, JVM_CONSTANT_Integer);
+  __ jccb(Assembler::notEqual, isOop);
   __ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset));
   __ push(itos);
   __ jmp(Done);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -385,6 +385,8 @@
     __ jcc(Assembler::equal, L);
     __ cmpl(rdx, JVM_CONSTANT_String);
     __ jcc(Assembler::equal, L);
+    __ cmpl(rdx, JVM_CONSTANT_Object);
+    __ jcc(Assembler::equal, L);
     __ stop("unexpected tag type in ldc");
     __ bind(L);
   }
--- a/hotspot/src/share/vm/ci/ciEnv.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -50,6 +50,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/oop.inline2.hpp"
 #include "prims/jvmtiExport.hpp"
+#include "prims/methodHandleWalk.hpp"
 #include "runtime/init.hpp"
 #include "runtime/reflection.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -371,6 +372,7 @@
 // ------------------------------------------------------------------
 // ciEnv::get_klass_by_name_impl
 ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
+                                       constantPoolHandle cpool,
                                        ciSymbol* name,
                                        bool require_local) {
   ASSERT_IN_VM;
@@ -386,7 +388,7 @@
                     sym->utf8_length()-2,
                     KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass));
     ciSymbol* strippedname = get_symbol(strippedsym);
-    return get_klass_by_name_impl(accessing_klass, strippedname, require_local);
+    return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local);
   }
 
   // Check for prior unloaded klass.  The SystemDictionary's answers
@@ -443,6 +445,7 @@
     // Get element ciKlass recursively.
     ciKlass* elem_klass =
       get_klass_by_name_impl(accessing_klass,
+                             cpool,
                              get_symbol(elem_sym),
                              require_local);
     if (elem_klass != NULL && elem_klass->is_loaded()) {
@@ -451,6 +454,19 @@
     }
   }
 
+  if (found_klass() == NULL && !cpool.is_null() && cpool->has_preresolution()) {
+    // Look inside the constant pool for pre-resolved class entries.
+    for (int i = cpool->length() - 1; i >= 1; i--) {
+      if (cpool->tag_at(i).is_klass()) {
+        klassOop kls = cpool->resolved_klass_at(i);
+        if (Klass::cast(kls)->name() == sym) {
+          found_klass = KlassHandle(THREAD, kls);
+          break;
+        }
+      }
+    }
+  }
+
   if (found_klass() != NULL) {
     // Found it.  Build a CI handle.
     return get_object(found_klass())->as_klass();
@@ -468,6 +484,7 @@
                                   ciSymbol* klass_name,
                                   bool require_local) {
   GUARDED_VM_ENTRY(return get_klass_by_name_impl(accessing_klass,
+                                                 constantPoolHandle(),
                                                  klass_name,
                                                  require_local);)
 }
@@ -508,13 +525,14 @@
   if (klass.is_null()) {
     // Not found in constant pool.  Use the name to do the lookup.
     ciKlass* k = get_klass_by_name_impl(accessor,
+                                        cpool,
                                         get_symbol(klass_name),
                                         false);
     // Calculate accessibility the hard way.
     if (!k->is_loaded()) {
       is_accessible = false;
     } else if (k->loader() != accessor->loader() &&
-               get_klass_by_name_impl(accessor, k->name(), true) == NULL) {
+               get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) {
       // Loaded only remotely.  Not linked yet.
       is_accessible = false;
     } else {
@@ -565,7 +583,7 @@
     index = cpc_entry->constant_pool_index();
     oop obj = cpc_entry->f1();
     if (obj != NULL) {
-      assert(obj->is_instance(), "must be an instance");
+      assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
       ciObject* ciobj = get_object(obj);
       return ciConstant(T_OBJECT, ciobj);
     }
@@ -607,7 +625,7 @@
     return ciConstant(T_OBJECT, klass->java_mirror());
   } else if (tag.is_object()) {
     oop obj = cpool->object_at(index);
-    assert(obj->is_instance(), "must be an instance");
+    assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
     ciObject* ciobj = get_object(obj);
     return ciConstant(T_OBJECT, ciobj);
   } else if (tag.is_method_type()) {
@@ -729,9 +747,35 @@
   Symbol* name_sym = cpool->name_ref_at(index);
   Symbol* sig_sym  = cpool->signature_ref_at(index);
 
+  if (cpool->has_preresolution()
+      || (holder == ciEnv::MethodHandle_klass() &&
+          methodOopDesc::is_method_handle_invoke_name(name_sym))) {
+    // Short-circuit lookups for JSR 292-related call sites.
+    // That is, do not rely only on name-based lookups, because they may fail
+    // if the names are not resolvable in the boot class loader (7056328).
+    switch (bc) {
+    case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokeinterface:
+    case Bytecodes::_invokespecial:
+    case Bytecodes::_invokestatic:
+      {
+        methodOop m = constantPoolOopDesc::method_at_if_loaded(cpool, index, bc);
+        if (m != NULL) {
+          return get_object(m)->as_method();
+        }
+      }
+    }
+  }
+
   if (holder_is_accessible) { // Our declared holder is loaded.
     instanceKlass* lookup = declared_holder->get_instanceKlass();
     methodOop m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
+    if (m != NULL &&
+        (bc == Bytecodes::_invokestatic
+         ?  instanceKlass::cast(m->method_holder())->is_not_initialized()
+         : !instanceKlass::cast(m->method_holder())->is_loaded())) {
+      m = NULL;
+    }
     if (m != NULL) {
       // We found the method.
       return get_object(m)->as_method();
@@ -1046,7 +1090,7 @@
 // ciEnv::find_system_klass
 ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) {
   VM_ENTRY_MARK;
-  return get_klass_by_name_impl(NULL, klass_name, false);
+  return get_klass_by_name_impl(NULL, constantPoolHandle(), klass_name, false);
 }
 
 // ------------------------------------------------------------------
--- a/hotspot/src/share/vm/ci/ciEnv.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -137,6 +137,7 @@
 
   // Implementation methods for loading and constant pool access.
   ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
+                                  constantPoolHandle cpool,
                                   ciSymbol* klass_name,
                                   bool require_local);
   ciKlass*   get_klass_by_index_impl(constantPoolHandle cpool,
--- a/hotspot/src/share/vm/ci/ciField.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciField.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -287,7 +287,7 @@
 }
 
 ciType* ciField::compute_type_impl() {
-  ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, _signature, false);
+  ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false);
   if (!type->is_primitive_type() && is_shared()) {
     // We must not cache a pointer to an unshared type, in a shared field.
     bool type_is_also_shared = false;
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -125,7 +125,8 @@
   _name = env->get_symbol(h_m()->name());
   _holder = env->get_object(h_m()->method_holder())->as_instance_klass();
   ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
-  _signature = new (env->arena()) ciSignature(_holder, sig_symbol);
+  constantPoolHandle cpool = h_m()->constants();
+  _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
   _method_data = NULL;
   // Take a snapshot of these values, so they will be commensurate with the MDO.
   if (ProfileInterpreter || TieredCompilation) {
@@ -152,7 +153,7 @@
   // These fields are always filled in.
   _name = name;
   _holder = holder;
-  _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, signature);
+  _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, constantPoolHandle(), signature);
   _intrinsic_id = vmIntrinsics::_none;
   _liveness = NULL;
   _can_be_statically_bound = false;
--- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -41,6 +41,16 @@
   VM_ENTRY_MARK;
   Handle h(get_oop());
   methodHandle callee(_callee->get_methodOop());
+  assert(callee->is_method_handle_invoke(), "");
+  oop mt1 = callee->method_handle_type();
+  oop mt2 = java_lang_invoke_MethodHandle::type(h());
+  if (!java_lang_invoke_MethodType::equals(mt1, mt2)) {
+    if (PrintMiscellaneous && (Verbose || WizardMode)) {
+      tty->print_cr("ciMethodHandle::get_adapter: types not equal");
+      mt1->print(); mt2->print();
+    }
+    return NULL;
+  }
   // We catch all exceptions here that could happen in the method
   // handle compiler and stop the VM.
   MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD);
@@ -53,7 +63,7 @@
   if (PrintMiscellaneous && (Verbose || WizardMode)) {
     tty->print("*** ciMethodHandle::get_adapter => ");
     PENDING_EXCEPTION->print();
-    tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@
+    tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print();
   }
   CLEAR_PENDING_EXCEPTION;
   return NULL;
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -93,6 +93,7 @@
       // element klass by name.
       _element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl(
                           this,
+                          constantPoolHandle(),
                           construct_array_name(base_element_klass()->name(),
                                                dimension() - 1),
                           false);
--- a/hotspot/src/share/vm/ci/ciSignature.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciSignature.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -35,7 +35,7 @@
 
 // ------------------------------------------------------------------
 // ciSignature::ciSignature
-ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) {
+ciSignature::ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* symbol) {
   ASSERT_IN_VM;
   EXCEPTION_CONTEXT;
   _accessing_klass = accessing_klass;
@@ -64,7 +64,7 @@
         CLEAR_PENDING_EXCEPTION;
       } else {
         ciSymbol* klass_name = env->get_symbol(name);
-        type = env->get_klass_by_name_impl(_accessing_klass, klass_name, false);
+        type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
       }
     }
     _types->append(type);
--- a/hotspot/src/share/vm/ci/ciSignature.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciSignature.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -44,7 +44,7 @@
 
   friend class ciMethod;
 
-  ciSignature(ciKlass* accessing_klass, ciSymbol* signature);
+  ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature);
 
   void get_all_klasses();
 
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -2574,6 +2574,18 @@
   return name;
 }
 
+bool java_lang_invoke_MethodType::equals(oop mt1, oop mt2) {
+  if (rtype(mt1) != rtype(mt2))
+    return false;
+  if (ptype_count(mt1) != ptype_count(mt2))
+    return false;
+  for (int i = ptype_count(mt1) - 1; i >= 0; i--) {
+    if (ptype(mt1, i) != ptype(mt2, i))
+      return false;
+  }
+  return true;
+}
+
 oop java_lang_invoke_MethodType::rtype(oop mt) {
   assert(is_instance(mt), "must be a MethodType");
   return mt->obj_field(_rtype_offset);
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -1079,6 +1079,8 @@
     return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
   }
 
+  static bool equals(oop mt1, oop mt2);
+
   // Accessors for code generation:
   static int rtype_offset_in_bytes()            { return _rtype_offset; }
   static int ptypes_offset_in_bytes()           { return _ptypes_offset; }
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -2367,6 +2367,8 @@
         // 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());
         }
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -294,6 +294,16 @@
   Symbol*  method_signature  = pool->signature_ref_at(index);
   KlassHandle  current_klass(THREAD, pool->pool_holder());
 
+  if (pool->has_preresolution()
+      || (resolved_klass() == SystemDictionary::MethodHandle_klass() &&
+          methodOopDesc::is_method_handle_invoke_name(method_name))) {
+    methodOop result_oop = constantPoolOopDesc::method_at_if_loaded(pool, index);
+    if (result_oop != NULL) {
+      resolved_method = methodHandle(THREAD, result_oop);
+      return;
+    }
+  }
+
   resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
 }
 
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -310,10 +310,14 @@
     st->print(" - flags: 0x%x", cp->flags());
     if (cp->has_pseudo_string()) st->print(" has_pseudo_string");
     if (cp->has_invokedynamic()) st->print(" has_invokedynamic");
+    if (cp->has_preresolution()) st->print(" has_preresolution");
     st->cr();
   }
+  if (cp->pool_holder() != NULL) {
+    bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp);
+    st->print_cr(" - holder: " INTPTR_FORMAT "%s", cp->pool_holder(), (extra? " (extra)" : ""));
+  }
   st->print_cr(" - cache: " INTPTR_FORMAT, cp->cache());
-
   for (int index = 1; index < cp->length(); index++) {      // Index 0 is unused
     st->print(" - %3d : ", index);
     cp->tag_at(index).print_on(st);
@@ -414,10 +418,15 @@
   st->print("constant pool [%d]", cp->length());
   if (cp->has_pseudo_string()) st->print("/pseudo_string");
   if (cp->has_invokedynamic()) st->print("/invokedynamic");
+  if (cp->has_preresolution()) st->print("/preresolution");
   if (cp->operands() != NULL)  st->print("/operands[%d]", cp->operands()->length());
   cp->print_address_on(st);
   st->print(" for ");
   cp->pool_holder()->print_value_on(st);
+  if (cp->pool_holder() != NULL) {
+    bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp);
+    if (extra)  st->print(" (extra)");
+  }
   if (cp->cache() != NULL) {
     st->print(" cache=" PTR_FORMAT, cp->cache());
   }
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -266,6 +266,29 @@
 }
 
 
+methodOop constantPoolOopDesc::method_at_if_loaded(constantPoolHandle cpool,
+                                                   int which, Bytecodes::Code invoke_code) {
+  assert(!constantPoolCacheOopDesc::is_secondary_index(which), "no indy instruction here");
+  if (cpool->cache() == NULL)  return false;  // nothing to load yet
+  int cache_index = which - CPCACHE_INDEX_TAG;
+  if (!(cache_index >= 0 && cache_index < cpool->cache()->length())) {
+    if (PrintMiscellaneous && (Verbose||WizardMode)) {
+      tty->print_cr("bad operand %d for %d in:", which, invoke_code); cpool->print();
+    }
+    return NULL;
+  }
+  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
+  if (invoke_code != Bytecodes::_illegal)
+    return e->get_method_if_resolved(invoke_code, cpool);
+  Bytecodes::Code bc;
+  if ((bc = e->bytecode_1()) != (Bytecodes::Code)0)
+    return e->get_method_if_resolved(bc, cpool);
+  if ((bc = e->bytecode_2()) != (Bytecodes::Code)0)
+    return e->get_method_if_resolved(bc, cpool);
+  return NULL;
+}
+
+
 Symbol* constantPoolOopDesc::impl_name_ref_at(int which, bool uncached) {
   int name_index = name_ref_index_at(impl_name_and_type_ref_index_at(which, uncached));
   return symbol_at(name_index);
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -103,7 +103,8 @@
 
   enum FlagBit {
     FB_has_invokedynamic = 1,
-    FB_has_pseudo_string = 2
+    FB_has_pseudo_string = 2,
+    FB_has_preresolution = 3
   };
 
   int flags() const                         { return _flags; }
@@ -179,8 +180,10 @@
 
   bool has_pseudo_string() const            { return flag_at(FB_has_pseudo_string); }
   bool has_invokedynamic() const            { return flag_at(FB_has_invokedynamic); }
+  bool has_preresolution() const            { return flag_at(FB_has_preresolution); }
   void set_pseudo_string()                  {    set_flag_at(FB_has_pseudo_string); }
   void set_invokedynamic()                  {    set_flag_at(FB_has_invokedynamic); }
+  void set_preresolution()                  {    set_flag_at(FB_has_preresolution); }
 
   // Klass holding pool
   klassOop pool_holder() const              { return _pool_holder; }
@@ -663,6 +666,8 @@
   friend class SystemDictionary;
 
   // Used by compiler to prevent classloading.
+  static methodOop method_at_if_loaded        (constantPoolHandle this_oop, int which,
+                                               Bytecodes::Code bc = Bytecodes::_illegal);
   static klassOop klass_at_if_loaded          (constantPoolHandle this_oop, int which);
   static klassOop klass_ref_at_if_loaded      (constantPoolHandle this_oop, int which);
   // Same as above - but does LinkResolving.
--- a/hotspot/src/share/vm/oops/cpCacheOop.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -295,6 +295,50 @@
 }
 
 
+methodOop ConstantPoolCacheEntry::get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool) {
+  assert(invoke_code > (Bytecodes::Code)0, "bad query");
+  if (is_secondary_entry()) {
+    return cpool->cache()->entry_at(main_entry_index())->get_method_if_resolved(invoke_code, cpool);
+  }
+  // Decode the action of set_method and set_interface_call
+  if (bytecode_1() == invoke_code) {
+    oop f1 = _f1;
+    if (f1 != NULL) {
+      switch (invoke_code) {
+      case Bytecodes::_invokeinterface:
+        assert(f1->is_klass(), "");
+        return klassItable::method_for_itable_index(klassOop(f1), (int) f2());
+      case Bytecodes::_invokestatic:
+      case Bytecodes::_invokespecial:
+        assert(f1->is_method(), "");
+        return methodOop(f1);
+      }
+    }
+  }
+  if (bytecode_2() == invoke_code) {
+    switch (invoke_code) {
+    case Bytecodes::_invokevirtual:
+      if (is_vfinal()) {
+        // invokevirtual
+        methodOop m = methodOop((intptr_t) f2());
+        assert(m->is_method(), "");
+        return m;
+      } else {
+        int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index());
+        if (cpool->tag_at(holder_index).is_klass()) {
+          klassOop klass = cpool->resolved_klass_at(holder_index);
+          if (!Klass::cast(klass)->oop_is_instance())
+            klass = SystemDictionary::Object_klass();
+          return instanceKlass::cast(klass)->method_at_vtable((int) f2());
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+
+
 class LocalOopClosure: public OopClosure {
  private:
   void (*_f)(oop*);
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -194,6 +194,8 @@
     methodHandle signature_invoker               // determines signature information
   );
 
+  methodOop get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool);
+
   // For JVM_CONSTANT_InvokeDynamic cache entries:
   void initialize_bootstrap_method_index_in_cache(int bsm_cache_index);
   int  bootstrap_method_index_in_cache();
--- a/hotspot/src/share/vm/oops/methodOop.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/methodOop.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -928,14 +928,40 @@
   name->increment_refcount();
   signature->increment_refcount();
 
+  // record non-BCP method types in the constant pool
+  GrowableArray<KlassHandle>* extra_klasses = NULL;
+  for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) {
+    oop ptype = (i == -1
+                 ? java_lang_invoke_MethodType::rtype(method_type())
+                 : java_lang_invoke_MethodType::ptype(method_type(), i));
+    klassOop klass = check_non_bcp_klass(java_lang_Class::as_klassOop(ptype));
+    if (klass != NULL) {
+      if (extra_klasses == NULL)
+        extra_klasses = new GrowableArray<KlassHandle>(len+1);
+      bool dup = false;
+      for (int j = 0; j < extra_klasses->length(); j++) {
+        if (extra_klasses->at(j) == klass) { dup = true; break; }
+      }
+      if (!dup)
+        extra_klasses->append(KlassHandle(THREAD, klass));
+    }
+  }
+
+  int extra_klass_count = (extra_klasses == NULL ? 0 : extra_klasses->length());
+  int cp_length = _imcp_limit + extra_klass_count;
   constantPoolHandle cp;
   {
-    constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
+    constantPoolOop cp_oop = oopFactory::new_constantPool(cp_length, IsSafeConc, CHECK_(empty));
     cp = constantPoolHandle(THREAD, cp_oop);
   }
   cp->symbol_at_put(_imcp_invoke_name,       name);
   cp->symbol_at_put(_imcp_invoke_signature,  signature);
   cp->string_at_put(_imcp_method_type_value, Universe::the_null_string());
+  for (int j = 0; j < extra_klass_count; j++) {
+    KlassHandle klass = extra_klasses->at(j);
+    cp->klass_at_put(_imcp_limit + j, klass());
+  }
+  cp->set_preresolution();
   cp->set_pool_holder(holder());
 
   // set up the fancy stuff:
@@ -984,6 +1010,14 @@
   return m;
 }
 
+klassOop methodOopDesc::check_non_bcp_klass(klassOop klass) {
+  if (klass != NULL && Klass::cast(klass)->class_loader() != NULL) {
+    if (Klass::cast(klass)->oop_is_objArray())
+      klass = objArrayKlass::cast(klass)->bottom_klass();
+    return klass;
+  }
+  return NULL;
+}
 
 
 methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
--- a/hotspot/src/share/vm/oops/methodOop.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/methodOop.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -600,6 +600,7 @@
                                          Symbol* signature, //anything at all
                                          Handle method_type,
                                          TRAPS);
+  static klassOop check_non_bcp_klass(klassOop klass);
   // these operate only on invoke methods:
   oop method_handle_type() const;
   static jint* method_type_offsets_chain();  // series of pointer-offsets, terminated by -1
--- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -425,6 +425,8 @@
         ArgToken arg = _outgoing.at(arg_slot);
         assert(dest == arg.basic_type(), "");
         arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty));
+        // replace the object by the result of the cast, to make the compiler happy:
+        change_argument(T_OBJECT, arg_slot, T_OBJECT, arg);
         debug_only(dest_klass = (klassOop)badOop);
         break;
       }
@@ -467,7 +469,7 @@
         ArgToken arglist[2];
         arglist[0] = arg;         // outgoing 'this'
         arglist[1] = ArgToken();  // sentinel
-        arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty));
+        arg = make_invoke(methodHandle(), unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty));
         change_argument(T_OBJECT, arg_slot, dest, arg);
         break;
       }
@@ -483,7 +485,7 @@
         ArgToken arglist[2];
         arglist[0] = arg;         // outgoing value
         arglist[1] = ArgToken();  // sentinel
-        arg = make_invoke(NULL, boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty));
+        arg = make_invoke(methodHandle(), boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty));
         change_argument(src, arg_slot, T_OBJECT, arg);
         break;
       }
@@ -599,8 +601,9 @@
           lose("bad vmlayout slot", CHECK_(empty));
         }
         // FIXME: consider inlining the invokee at the bytecode level
-        ArgToken ret = make_invoke(methodOop(invoker), vmIntrinsics::_none,
+        ArgToken ret = make_invoke(methodHandle(THREAD, methodOop(invoker)), vmIntrinsics::_invokeGeneric,
                                    Bytecodes::_invokevirtual, false, 1+argc, &arglist[0], CHECK_(empty));
+        // The iid = _invokeGeneric really means to adjust reference types as needed.
         DEBUG_ONLY(invoker = NULL);
         if (rtype == T_OBJECT) {
           klassOop rklass = java_lang_Class::as_klassOop( java_lang_invoke_MethodType::rtype(recursive_mtype()) );
@@ -657,7 +660,7 @@
         arglist[0] = array_arg;   // value to check
         arglist[1] = length_arg;  // length to check
         arglist[2] = ArgToken();  // sentinel
-        make_invoke(NULL, vmIntrinsics::_checkSpreadArgument,
+        make_invoke(methodHandle(), vmIntrinsics::_checkSpreadArgument,
                     Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty));
 
         // Spread out the array elements.
@@ -680,7 +683,7 @@
           ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_(empty));
           ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_(empty));
           change_argument(T_VOID, ap, element_type, element_arg);
-          ap += type2size[element_type];
+          //ap += type2size[element_type];  // don't do this; insert next arg to *right* of previous
         }
         break;
       }
@@ -731,7 +734,7 @@
   }
   assert(ap == _outgoing_argc, "");
   arglist[ap] = ArgToken();  // add a sentinel, for the sake of asserts
-  return make_invoke(chain().last_method_oop(),
+  return make_invoke(chain().last_method(),
                      vmIntrinsics::_none,
                      chain().last_invoke_code(), true,
                      ap, arglist, THREAD);
@@ -853,7 +856,6 @@
   if (src != dst) {
     if (MethodHandles::same_basic_type_for_returns(src, dst, /*raw*/ true)) {
       if (MethodHandles::is_float_fixed_reinterpretation_cast(src, dst)) {
-        if (for_return)  Untested("MHW return raw conversion");  // still untested
         vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(src, dst);
         if (iid == vmIntrinsics::_none) {
           lose("no raw conversion method", CHECK);
@@ -865,18 +867,24 @@
           assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity");
           arglist[0] = arg;         // outgoing 'this'
           arglist[1] = ArgToken();  // sentinel
-          arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
+          arg = make_invoke(methodHandle(), iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
           change_argument(src, slot, dst, arg);
         } else {
           // return type conversion
-          klassOop arg_klass = NULL;
-          arglist[0] = make_parameter(src, arg_klass, -1, CHECK);  // return value
-          arglist[1] = ArgToken();                                 // sentinel
-          (void) make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
+          if (_return_conv == vmIntrinsics::_none) {
+            _return_conv = iid;
+          } else if (_return_conv == vmIntrinsics::for_raw_conversion(dst, src)) {
+            _return_conv = vmIntrinsics::_none;
+          } else if (_return_conv != zero_return_conv()) {
+            lose(err_msg("requested raw return conversion not allowed: %s -> %s (before %s)", type2name(src), type2name(dst), vmIntrinsics::name_at(_return_conv)), CHECK);
+          }
         }
       } else {
         // Nothing to do.
       }
+    } else if (for_return && (!is_subword_type(src) || !is_subword_type(dst))) {
+      // This can occur in exception-throwing MHs, which have a fictitious return value encoded as Void or Empty.
+      _return_conv = zero_return_conv();
     } else if (src == T_OBJECT && is_java_primitive(dst)) {
       // ref-to-prim: discard ref, push zero
       lose("requested ref-to-prim conversion not expected", CHECK);
@@ -896,6 +904,7 @@
     _thread(THREAD),
     _bytecode(THREAD, 50),
     _constants(THREAD, 10),
+    _non_bcp_klasses(THREAD, 5),
     _cur_stack(0),
     _max_stack(0),
     _rtype(T_ILLEGAL)
@@ -908,6 +917,15 @@
   _name_index      = cpool_symbol_put(name);
   _signature_index = cpool_symbol_put(signature);
 
+  // To make the resulting methods more recognizable by
+  // stack walkers and compiler heuristics,
+  // we put them in holder class MethodHandle.
+  // See klass_is_method_handle_adapter_holder
+  // and methodOopDesc::is_method_handle_adapter.
+  _target_klass = SystemDictionaryHandles::MethodHandle_klass();
+
+  check_non_bcp_klasses(java_lang_invoke_MethodHandle::type(root()), CHECK);
+
   // Get return type klass.
   Handle first_mtype(THREAD, chain().method_type_oop());
   // _rklass is NULL for primitives.
@@ -929,6 +947,7 @@
   assert(_thread == THREAD, "must be same thread");
   methodHandle nullHandle;
   (void) walk(CHECK_(nullHandle));
+  record_non_bcp_klasses();
   return get_method_oop(CHECK_(nullHandle));
 }
 
@@ -1197,10 +1216,18 @@
   }
   case T_OBJECT: {
     Handle value = arg.object();
-    if (value.is_null())
+    if (value.is_null()) {
       emit_bc(Bytecodes::_aconst_null);
-    else
-      emit_bc(Bytecodes::_ldc, cpool_object_put(value));
+      break;
+    }
+    if (java_lang_Class::is_instance(value())) {
+      klassOop k = java_lang_Class::as_klassOop(value());
+      if (k != NULL) {
+        emit_bc(Bytecodes::_ldc, cpool_klass_put(k));
+        break;
+      }
+    }
+    emit_bc(Bytecodes::_ldc, cpool_object_put(value));
     break;
   }
   default:
@@ -1260,6 +1287,7 @@
       index = src.index();
     }
     emit_bc(op, cpool_klass_put(tk));
+    check_non_bcp_klass(tk, CHECK_(src));
     // Allocate a new local for the type so that we don't hide the
     // previous type from the verifier.
     index = new_local_index(type);
@@ -1292,15 +1320,15 @@
 
 // Emit bytecodes for the given invoke instruction.
 MethodHandleWalker::ArgToken
-MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
+MethodHandleCompiler::make_invoke(methodHandle m, vmIntrinsics::ID iid,
                                   Bytecodes::Code op, bool tailcall,
                                   int argc, MethodHandleWalker::ArgToken* argv,
                                   TRAPS) {
   ArgToken zero;
-  if (m == NULL) {
+  if (m.is_null()) {
     // Get the intrinsic methodOop.
-    m = vmIntrinsics::method_for(iid);
-    if (m == NULL) {
+    m = methodHandle(THREAD, vmIntrinsics::method_for(iid));
+    if (m.is_null()) {
       lose(vmIntrinsics::name_at(iid), CHECK_(zero));
     }
   }
@@ -1309,18 +1337,46 @@
   Symbol*  name      = m->name();
   Symbol*  signature = m->signature();
 
+  if (iid == vmIntrinsics::_invokeGeneric &&
+      argc >= 1 && argv[0].token_type() == tt_constant) {
+    assert(m->intrinsic_id() == vmIntrinsics::_invokeExact, "");
+    Handle receiver = argv[0].object();
+    Handle rtype(THREAD, java_lang_invoke_MethodHandle::type(receiver()));
+    Handle mtype(THREAD, m->method_handle_type());
+    if (rtype() != mtype()) {
+      assert(java_lang_invoke_MethodType::form(rtype()) ==
+             java_lang_invoke_MethodType::form(mtype()),
+             "must be the same shape");
+      // customize m to the exact required rtype
+      bool has_non_bcp_klass = check_non_bcp_klasses(rtype(), CHECK_(zero));
+      TempNewSymbol sig2 = java_lang_invoke_MethodType::as_signature(rtype(), true, CHECK_(zero));
+      methodHandle m2;
+      if (!has_non_bcp_klass) {
+        methodOop m2_oop = SystemDictionary::find_method_handle_invoke(m->name(), sig2,
+                                                                       KlassHandle(), CHECK_(zero));
+        m2 = methodHandle(THREAD, m2_oop);
+      }
+      if (m2.is_null()) {
+        // just build it fresh
+        m2 = methodOopDesc::make_invoke_method(klass, m->name(), sig2, rtype, CHECK_(zero));
+        if (m2.is_null())
+          lose(err_msg("no customized invoker %s", sig2->as_utf8()), CHECK_(zero));
+      }
+      m = m2;
+      signature = m->signature();
+    }
+  }
+
+  check_non_bcp_klass(klass, CHECK_(zero));
+  if (m->is_method_handle_invoke()) {
+    check_non_bcp_klasses(m->method_handle_type(), CHECK_(zero));
+  }
+
   // Count the number of arguments, not the size
   ArgumentCount asc(signature);
   assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1),
          "argc mismatch");
 
-  if (tailcall) {
-    // Actually, in order to make these methods more recognizable,
-    // let's put them in holder class MethodHandle.  That way stack
-    // walkers and compiler heuristics can recognize them.
-    _target_klass = SystemDictionary::MethodHandle_klass();
-  }
-
   // Inline the method.
   InvocationCounter* ic = m->invocation_counter();
   ic->set_carry_flag();
@@ -1353,7 +1409,7 @@
   int signature_index     = cpool_symbol_put(signature);
   int name_and_type_index = cpool_name_and_type_put(name_index, signature_index);
   int klass_index         = cpool_klass_put(klass);
-  int methodref_index     = cpool_methodref_put(klass_index, name_and_type_index);
+  int methodref_index     = cpool_methodref_put(op, klass_index, name_and_type_index, m);
 
   // Generate invoke.
   switch (op) {
@@ -1380,6 +1436,20 @@
   stack_push(rbt);  // The return value is already pushed onto the stack.
   ArgToken ret;
   if (tailcall) {
+    if (return_conv() == zero_return_conv()) {
+      rbt = T_VOID;  // discard value
+    } else if (return_conv() != vmIntrinsics::_none) {
+      // return value conversion
+      int index = new_local_index(rbt);
+      emit_store(rbt, index);
+      ArgToken arglist[2];
+      arglist[0] = ArgToken(tt_temporary, rbt, index);
+      arglist[1] = ArgToken();  // sentinel
+      ret = make_invoke(methodHandle(), return_conv(), Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(zero));
+      set_return_conv(vmIntrinsics::_none);
+      rbt = ret.basic_type();
+      emit_load(rbt, ret.index());
+    }
     if (rbt != _rtype) {
       if (rbt == T_VOID) {
         // push a zero of the right sort
@@ -1425,6 +1495,7 @@
     case T_OBJECT:
       if (_rklass.not_null() && _rklass() != SystemDictionary::Object_klass() && !Klass::cast(_rklass())->is_interface()) {
         emit_bc(Bytecodes::_checkcast, cpool_klass_put(_rklass()));
+        check_non_bcp_klass(_rklass(), CHECK_(zero));
       }
       emit_bc(Bytecodes::_areturn);
       break;
@@ -1525,6 +1596,52 @@
   return index;
 }
 
+bool MethodHandleCompiler::check_non_bcp_klasses(Handle method_type, TRAPS) {
+  bool res = false;
+  for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) {
+    oop ptype = (i == -1
+                 ? java_lang_invoke_MethodType::rtype(method_type())
+                 : java_lang_invoke_MethodType::ptype(method_type(), i));
+    res |= check_non_bcp_klass(java_lang_Class::as_klassOop(ptype), CHECK_(false));
+  }
+  return res;
+}
+
+bool MethodHandleCompiler::check_non_bcp_klass(klassOop klass, TRAPS) {
+  klass = methodOopDesc::check_non_bcp_klass(klass);
+  if (klass != NULL) {
+    Symbol* name = Klass::cast(klass)->name();
+    for (int i = _non_bcp_klasses.length() - 1; i >= 0; i--) {
+      klassOop k2 = _non_bcp_klasses.at(i)();
+      if (Klass::cast(k2)->name() == name) {
+        if (k2 != klass) {
+          lose(err_msg("unsupported klass name alias %s", name->as_utf8()), THREAD);
+        }
+        return true;
+      }
+    }
+    _non_bcp_klasses.append(KlassHandle(THREAD, klass));
+    return true;
+  }
+  return false;
+}
+
+void MethodHandleCompiler::record_non_bcp_klasses() {
+  // Append extra klasses to constant pool, to guide klass lookup.
+  for (int k = 0; k < _non_bcp_klasses.length(); k++) {
+    klassOop non_bcp_klass = _non_bcp_klasses.at(k)();
+    bool add_to_cp = true;
+    for (int j = 1; j < _constants.length(); j++) {
+      ConstantValue* cv = _constants.at(j);
+      if (cv != NULL && cv->tag() == JVM_CONSTANT_Class
+          && cv->klass_oop() == non_bcp_klass) {
+        add_to_cp = false;
+        break;
+      }
+    }
+    if (add_to_cp)  cpool_klass_put(non_bcp_klass);
+  }
+}
 
 constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
   constantPoolHandle nullHandle;
@@ -1544,6 +1661,8 @@
     case JVM_CONSTANT_Double:      cpool->double_at_put(       i, cv->get_jdouble()                    ); break;
     case JVM_CONSTANT_Class:       cpool->klass_at_put(        i, cv->klass_oop()                      ); break;
     case JVM_CONSTANT_Methodref:   cpool->method_at_put(       i, cv->first_index(), cv->second_index()); break;
+    case JVM_CONSTANT_InterfaceMethodref:
+                                cpool->interface_method_at_put(i, cv->first_index(), cv->second_index()); break;
     case JVM_CONSTANT_NameAndType: cpool->name_and_type_at_put(i, cv->first_index(), cv->second_index()); break;
     case JVM_CONSTANT_Object:      cpool->object_at_put(       i, cv->object_oop()                     ); break;
     default: ShouldNotReachHere();
@@ -1558,6 +1677,8 @@
     }
   }
 
+  cpool->set_preresolution();
+
   // Set the constant pool holder to the target method's class.
   cpool->set_pool_holder(_target_klass());
 
@@ -1606,6 +1727,33 @@
   Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty));  // Use fake class.
   Rewriter::relocate_and_link(_target_klass(), methods, CHECK_(empty));  // Use fake class.
 
+  // Pre-resolve selected CP cache entries, to avoid problems with class loader scoping.
+  constantPoolCacheHandle cpc(THREAD, cpool->cache());
+  for (int i = 0; i < cpc->length(); i++) {
+    ConstantPoolCacheEntry* e = cpc->entry_at(i);
+    assert(!e->is_secondary_entry(), "no indy instructions in here, yet");
+    int constant_pool_index = e->constant_pool_index();
+    ConstantValue* cv = _constants.at(constant_pool_index);
+    if (!cv->has_linkage())  continue;
+    methodHandle m = cv->linkage();
+    int index;
+    switch (cv->tag()) {
+    case JVM_CONSTANT_Methodref:
+      index = m->vtable_index();
+      if (m->is_static()) {
+        e->set_method(Bytecodes::_invokestatic, m, index);
+      } else {
+        e->set_method(Bytecodes::_invokespecial, m, index);
+        e->set_method(Bytecodes::_invokevirtual, m, index);
+      }
+      break;
+    case JVM_CONSTANT_InterfaceMethodref:
+      index = klassItable::compute_itable_index(m());
+      e->set_interface_call(m, index);
+      break;
+    }
+  }
+
   // Set the invocation counter's count to the invoke count of the
   // original call site.
   InvocationCounter* ic = m->invocation_counter();
@@ -1696,6 +1844,9 @@
       _param_state(0),
       _temp_num(0)
   {
+    out->print("MethodHandle:");
+    java_lang_invoke_MethodType::print_signature(java_lang_invoke_MethodHandle::type(root()), out);
+    out->print(" : #");
     start_params();
   }
   virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) {
@@ -1759,12 +1910,12 @@
     _strbuf.print(")");
     return maybe_make_temp("fetch", type, "x");
   }
-  virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid,
+  virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid,
                                Bytecodes::Code op, bool tailcall,
                                int argc, ArgToken* argv, TRAPS) {
     Symbol* name;
     Symbol* sig;
-    if (m != NULL) {
+    if (m.not_null()) {
       name = m->name();
       sig  = m->signature();
     } else {
--- a/hotspot/src/share/vm/prims/methodHandleWalk.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandleWalk.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -98,6 +98,7 @@
   int       bound_arg_slot()    { assert(is_bound(), ""); return _arg_slot; }
   oop       bound_arg_oop()     { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); }
 
+  methodHandle last_method()    { assert(is_last(), ""); return _last_method; }
   methodOop last_method_oop()   { assert(is_last(), ""); return _last_method(); }
   Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; }
 
@@ -181,6 +182,8 @@
   GrowableArray<ArgToken>  _outgoing;       // current outgoing parameter slots
   int                      _outgoing_argc;  // # non-empty outgoing slots
 
+  vmIntrinsics::ID _return_conv;            // Return conversion required by raw retypes.
+
   // Replace a value of type old_type at slot (and maybe slot+1) with the new value.
   // If old_type != T_VOID, remove the old argument at that point.
   // If new_type != T_VOID, insert the new argument at that point.
@@ -219,7 +222,8 @@
     : _chain(root, THREAD),
       _for_invokedynamic(for_invokedynamic),
       _outgoing(THREAD, 10),
-      _outgoing_argc(0)
+      _outgoing_argc(0),
+      _return_conv(vmIntrinsics::_none)
   {
     _local_index = for_invokedynamic ? 0 : 1;
   }
@@ -228,6 +232,10 @@
 
   bool for_invokedynamic() const { return _for_invokedynamic; }
 
+  vmIntrinsics::ID return_conv() const { return _return_conv; }
+  void set_return_conv(vmIntrinsics::ID c) { _return_conv = c; }
+  static vmIntrinsics::ID zero_return_conv() { return vmIntrinsics::_min; }
+
   int new_local_index(BasicType bt) {
     //int index = _for_invokedynamic ? _local_index : _local_index - 1;
     int index = _local_index;
@@ -243,9 +251,9 @@
   virtual ArgToken make_oop_constant(oop con, TRAPS) = 0;
   virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0;
   virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0;
-  virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
+  virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
 
-  // For make_invoke, the methodOop can be NULL if the intrinsic ID
+  // For make_invoke, the methodHandle can be NULL if the intrinsic ID
   // is something other than vmIntrinsics::_none.
 
   // and in case anyone cares to related the previous actions to the chain:
@@ -280,6 +288,7 @@
     JavaValue _value;
     Handle    _handle;
     Symbol*   _sym;
+    methodHandle _method;  // pre-linkage
 
   public:
     // Constructor for oop types.
@@ -328,11 +337,21 @@
     jlong     get_jlong()    const { return _value.get_jlong();   }
     jfloat    get_jfloat()   const { return _value.get_jfloat();  }
     jdouble   get_jdouble()  const { return _value.get_jdouble(); }
+
+    void set_linkage(methodHandle method) {
+      assert(_method.is_null(), "");
+      _method = method;
+    }
+    bool     has_linkage()   const { return _method.not_null(); }
+    methodHandle linkage()   const { return _method; }
   };
 
   // Fake constant pool.
   GrowableArray<ConstantValue*> _constants;
 
+  // Non-BCP classes that appear in associated MethodTypes (require special handling).
+  GrowableArray<KlassHandle> _non_bcp_klasses;
+
   // Accumulated compiler state:
   GrowableArray<unsigned char> _bytecode;
 
@@ -368,15 +387,20 @@
     return _constants.append(cv);
   }
 
-  int cpool_oop_reference_put(int tag, int first_index, int second_index) {
+  int cpool_oop_reference_put(int tag, int first_index, int second_index, methodHandle method) {
     if (first_index == 0 && second_index == 0)  return 0;
     assert(first_index != 0 && second_index != 0, "no zero indexes");
     ConstantValue* cv = new ConstantValue(tag, first_index, second_index);
+    if (method.not_null())  cv->set_linkage(method);
     return _constants.append(cv);
   }
 
   int cpool_primitive_put(BasicType type, jvalue* con);
 
+  bool check_non_bcp_klasses(Handle method_type, TRAPS);
+  bool check_non_bcp_klass(klassOop klass, TRAPS);
+  void record_non_bcp_klasses();
+
   int cpool_int_put(jint value) {
     jvalue con; con.i = value;
     return cpool_primitive_put(T_INT, &con);
@@ -403,11 +427,12 @@
   int cpool_klass_put(klassOop klass) {
     return cpool_oop_put(JVM_CONSTANT_Class, klass);
   }
-  int cpool_methodref_put(int class_index, int name_and_type_index) {
-    return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index);
+  int cpool_methodref_put(Bytecodes::Code op, int class_index, int name_and_type_index, methodHandle method) {
+    int tag = (op == Bytecodes::_invokeinterface ? JVM_CONSTANT_InterfaceMethodref : JVM_CONSTANT_Methodref);
+    return cpool_oop_reference_put(tag, class_index, name_and_type_index, method);
   }
   int cpool_name_and_type_put(int name_index, int signature_index) {
-    return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
+    return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index, methodHandle());
   }
 
   void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1);
@@ -428,7 +453,7 @@
 
   virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
   virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS);
-  virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);
+  virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);
 
   // Get a real constant pool.
   constantPoolHandle get_constant_pool(TRAPS) const;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp	Thu Jun 23 17:14:06 2011 -0700
@@ -24,12 +24,14 @@
 
 #include "precompiled.hpp"
 #include "classfile/symbolTable.hpp"
+#include "compiler/compileBroker.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/oopMapCache.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/oopFactory.hpp"
 #include "prims/methodHandles.hpp"
 #include "prims/methodHandleWalk.hpp"
+#include "runtime/compilationPolicy.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/reflection.hpp"
 #include "runtime/signature.hpp"
@@ -767,7 +769,9 @@
         m = NULL;
         // try again with a different class loader...
       }
-      if (m != NULL) {
+      if (m != NULL &&
+          m->is_method_handle_invoke() &&
+          java_lang_invoke_MethodType::equals(polymorphic_method_type(), m->method_handle_type())) {
         int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
         java_lang_invoke_MemberName::set_vmtarget(mname(),  m);
         java_lang_invoke_MemberName::set_vmindex(mname(),   m->vtable_index());
@@ -986,6 +990,48 @@
 // This is for debugging and reflection.
 oop MethodHandles::encode_target(Handle mh, int format, TRAPS) {
   assert(java_lang_invoke_MethodHandle::is_instance(mh()), "must be a MH");
+  if (format == ETF_FORCE_DIRECT_HANDLE ||
+      format == ETF_COMPILE_DIRECT_HANDLE) {
+    // Internal function for stress testing.
+    Handle mt = java_lang_invoke_MethodHandle::type(mh());
+    int invocation_count = 10000;
+    TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK_NULL);
+    bool omit_receiver_argument = true;
+    MethodHandleCompiler mhc(mh, vmSymbols::invoke_name(), signature, invocation_count, omit_receiver_argument, CHECK_NULL);
+    methodHandle m = mhc.compile(CHECK_NULL);
+    if (StressMethodHandleWalk && Verbose || PrintMiscellaneous) {
+      tty->print_cr("MethodHandleNatives.getTarget(%s)",
+                    format == ETF_FORCE_DIRECT_HANDLE ? "FORCE_DIRECT" : "COMPILE_DIRECT");
+      if (Verbose) {
+        m->print_codes();
+      }
+    }
+    if (StressMethodHandleWalk) {
+      InterpreterOopMap mask;
+      OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
+    }
+    if ((format == ETF_COMPILE_DIRECT_HANDLE ||
+         CompilationPolicy::must_be_compiled(m))
+        && !instanceKlass::cast(m->method_holder())->is_not_initialized()
+        && CompilationPolicy::can_be_compiled(m)) {
+      // Force compilation
+      CompileBroker::compile_method(m, InvocationEntryBci,
+                                    CompLevel_initial_compile,
+                                    methodHandle(), 0, "MethodHandleNatives.getTarget",
+                                    CHECK_NULL);
+    }
+    // Now wrap m in a DirectMethodHandle.
+    instanceKlassHandle dmh_klass(THREAD, SystemDictionary::DirectMethodHandle_klass());
+    Handle dmh = dmh_klass->allocate_instance_handle(CHECK_NULL);
+    JavaValue ignore_result(T_VOID);
+    Symbol* init_name = vmSymbols::object_initializer_name();
+    Symbol* init_sig  = vmSymbols::notifyGenericMethodType_signature();
+    JavaCalls::call_special(&ignore_result, dmh,
+                            SystemDictionaryHandles::MethodHandle_klass(), init_name, init_sig,
+                            java_lang_invoke_MethodHandle::type(mh()), CHECK_NULL);
+    MethodHandles::init_DirectMethodHandle(dmh, m, false, CHECK_NULL);
+    return dmh();
+  }
   if (format == ETF_HANDLE_OR_METHOD_NAME) {
     oop target = java_lang_invoke_MethodHandle::vmtarget(mh());
     if (target == NULL) {
@@ -1221,6 +1267,12 @@
           klassOop aklass_oop = SystemDictionary::resolve_or_null(name, loader, domain, CHECK);
           if (aklass_oop != NULL)
             aklass = KlassHandle(THREAD, aklass_oop);
+          if (aklass.is_null() &&
+              pklass.not_null() &&
+              loader.is_null() &&
+              pklass->name() == name)
+            // accept name equivalence here, since that's the best we can do
+            aklass = pklass;
         }
       } else {
         // for method handle invokers we don't look at the name in the signature
@@ -2654,6 +2706,17 @@
     }
     InterpreterOopMap mask;
     OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
+    // compile to object code if -Xcomp or WizardMode
+    if ((WizardMode ||
+         CompilationPolicy::must_be_compiled(m))
+        && !instanceKlass::cast(m->method_holder())->is_not_initialized()
+        && CompilationPolicy::can_be_compiled(m)) {
+      // Force compilation
+      CompileBroker::compile_method(m, InvocationEntryBci,
+                                    CompLevel_initial_compile,
+                                    methodHandle(), 0, "StressMethodHandleWalk",
+                                    CHECK);
+    }
   }
 }
 
@@ -2773,7 +2836,12 @@
     // Build a BMH on top of a DMH or another BMH:
     MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
   }
-  stress_method_handle_walk(mh, CHECK);
+
+  if (StressMethodHandleWalk) {
+    if (mh->klass() == SystemDictionary::BoundMethodHandle_klass())
+      stress_method_handle_walk(mh, CHECK);
+    // else don't, since the subclass has not yet initialized its own fields
+  }
 }
 JVM_END
 
--- a/hotspot/src/share/vm/prims/methodHandles.hpp	Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp	Thu Jun 23 17:14:06 2011 -0700
@@ -588,6 +588,8 @@
     ETF_DIRECT_HANDLE         = 1, // ultimate method handle (will be a DMH, may be self)
     ETF_METHOD_NAME           = 2, // ultimate method as MemberName
     ETF_REFLECT_METHOD        = 3, // ultimate method as java.lang.reflect object (sans refClass)
+    ETF_FORCE_DIRECT_HANDLE   = 64,
+    ETF_COMPILE_DIRECT_HANDLE = 65,
 
     // ad hoc constants
     OP_ROT_ARGS_DOWN_LIMIT_BIAS = -1