changeset 4943:23c2ba8dc6b6

8008511: JSR 292: MemberName vmtarget refs to methods must be updated at class redefinition Summary: Lazily create and maintain the MemberNameTable to be able to update MemberName's Reviewed-by: coleenp, jrose, dholmes, twisti Contributed-by: serguei.spitsyn@oracle.com
author sspitsyn
date Fri, 07 Feb 2014 16:06:44 -0800
parents 1448ebfef4f1
children 9423ca47562b
files src/share/vm/classfile/javaClasses.cpp src/share/vm/classfile/javaClasses.hpp src/share/vm/oops/instanceKlass.cpp src/share/vm/oops/instanceKlass.hpp src/share/vm/prims/jvmtiRedefineClasses.cpp src/share/vm/prims/methodHandles.cpp src/share/vm/prims/methodHandles.hpp src/share/vm/runtime/mutexLocker.cpp src/share/vm/runtime/mutexLocker.hpp
diffstat 9 files changed, 233 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/javaClasses.cpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/classfile/javaClasses.cpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -2497,6 +2497,13 @@
   return mname->obj_field(_vmtarget_offset);
 }
 
+// Can be executed on VM thread only
+void java_lang_invoke_MemberName::adjust_vmtarget(oop mname, oop ref) {
+  assert((is_instance(mname) && (flags(mname) & (MN_IS_METHOD | MN_IS_CONSTRUCTOR)) > 0), "wrong type");
+  assert(Thread::current()->is_VM_thread(), "not VM thread");
+  mname->address_field_put(_vmtarget_offset, (address)ref);
+}
+
 void java_lang_invoke_MemberName::set_vmtarget(oop mname, oop ref) {
   assert(is_instance(mname), "wrong type");
 #ifdef ASSERT
--- a/src/share/vm/classfile/javaClasses.hpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/classfile/javaClasses.hpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -988,6 +988,7 @@
 
   static oop            vmtarget(oop mname);
   static void       set_vmtarget(oop mname, oop target);
+  static void       adjust_vmtarget(oop mname, oop target);
 
   static intptr_t       vmindex(oop mname);
   static void       set_vmindex(oop mname, intptr_t index);
--- a/src/share/vm/oops/instanceKlass.cpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/oops/instanceKlass.cpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1901,6 +1901,12 @@
     FreeHeap(jmeths);
   }
 
+  MemberNameTable* mnt = member_names();
+  if (mnt != NULL) {
+    delete mnt;
+    set_member_names(NULL);
+  }
+
   int* indices = methods_cached_itable_indices_acquire();
   if (indices != (int*)NULL) {
     release_set_methods_cached_itable_indices(NULL);
@@ -2333,6 +2339,17 @@
   return NULL;
 }
 
+void instanceKlass::add_member_name(Handle mem_name) {
+  jweak mem_name_wref = JNIHandles::make_weak_global(mem_name);
+  MutexLocker ml(MemberNameTable_lock);
+  DEBUG_ONLY(No_Safepoint_Verifier nsv);
+
+  if (_member_names == NULL) {
+    _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable();
+  }
+  _member_names->add_member_name(mem_name_wref);
+}
+
 // -----------------------------------------------------------------------------------------------------
 #ifndef PRODUCT
 
--- a/src/share/vm/oops/instanceKlass.hpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/oops/instanceKlass.hpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -94,6 +94,7 @@
 class nmethodBucket;
 class PreviousVersionNode;
 class JvmtiCachedClassFieldMap;
+class MemberNameTable;
 
 // This is used in iterators below.
 class FieldClosure: public StackObj {
@@ -265,6 +266,7 @@
   int             _vtable_len;           // length of Java vtable (in words)
   int             _itable_len;           // length of Java itable (in words)
   OopMapCache*    volatile _oop_map_cache;   // OopMapCache for all methods in the klass (allocated lazily)
+  MemberNameTable* _member_names;        // Member names
   JNIid*          _jni_ids;              // First JNI identifier for static fields in this class
   jmethodID*      _methods_jmethod_ids;  // jmethodIDs corresponding to method_idnum, or NULL if none
   int*            _methods_cached_itable_indices;  // itable_index cache for JNI invoke corresponding to methods idnum, or NULL
@@ -972,6 +974,11 @@
   // jvm support
   jint compute_modifier_flags(TRAPS) const;
 
+  // JSR-292 support
+  MemberNameTable* member_names() { return _member_names; }
+  void set_member_names(MemberNameTable* member_names) { _member_names = member_names; }
+  void add_member_name(Handle member_name);
+
 public:
   // JVMTI support
   jint jvmti_class_status() const;
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
 #include "prims/jvmtiImpl.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "prims/methodComparator.hpp"
+#include "prims/methodHandles.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/relocator.hpp"
 #include "utilities/bitMap.inline.hpp"
@@ -3294,6 +3295,16 @@
   // that reference methods of the evolved class.
   SystemDictionary::classes_do(adjust_cpool_cache_and_vtable, THREAD);
 
+  // JSR-292 support
+  MemberNameTable* mnt = the_class->member_names();
+  if (mnt != NULL) {
+    bool trace_name_printed = false;
+    mnt->adjust_method_entries(_matching_old_methods,
+                               _matching_new_methods,
+                               _matching_methods_length,
+                               &trace_name_printed);
+  }
+
   if (the_class->oop_map_cache() != NULL) {
     // Flush references to any obsolete methods from the oop map cache
     // so that obsolete methods are not pinned.
--- a/src/share/vm/prims/methodHandles.cpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/prims/methodHandles.cpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 #include "interpreter/oopMapCache.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/oopFactory.hpp"
+#include "prims/jvmtiRedefineClassesTrace.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/compilationPolicy.hpp"
 #include "runtime/javaCalls.hpp"
@@ -123,7 +124,9 @@
   return Handle(THREAD, k->allocate_instance(THREAD));
 }
 
-oop MethodHandles::init_MemberName(oop mname_oop, oop target_oop) {
+oop MethodHandles::init_MemberName(Handle mname, Handle target) {
+  Thread* thread = Thread::current();
+  oop target_oop = target();
   klassOop target_klass = target_oop->klass();
   if (target_klass == SystemDictionary::reflect_Field_klass()) {
     oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
@@ -131,24 +134,24 @@
     int mods  = java_lang_reflect_Field::modifiers(target_oop);
     oop type  = java_lang_reflect_Field::type(target_oop);
     oop name  = java_lang_reflect_Field::name(target_oop);
-    klassOop k = java_lang_Class::as_klassOop(clazz);
-    intptr_t offset = instanceKlass::cast(k)->field_offset(slot);
-    return init_field_MemberName(mname_oop, k, accessFlags_from(mods), type, name, offset);
+    KlassHandle k(thread, java_lang_Class::as_klassOop(clazz));
+    intptr_t offset = instanceKlass::cast(k())->field_offset(slot);
+    return init_field_MemberName(mname, k, accessFlags_from(mods), type, name, offset);
   } else if (target_klass == SystemDictionary::reflect_Method_klass()) {
     oop clazz  = java_lang_reflect_Method::clazz(target_oop);
     int slot   = java_lang_reflect_Method::slot(target_oop);
-    klassOop k = java_lang_Class::as_klassOop(clazz);
-    if (k != NULL && Klass::cast(k)->oop_is_instance()) {
-      methodOop m = instanceKlass::cast(k)->method_with_idnum(slot);
-      return init_method_MemberName(mname_oop, m, true, k);
+    KlassHandle k(thread, java_lang_Class::as_klassOop(clazz));
+    if (!k.is_null() && k->oop_is_instance()) {
+      methodOop m = instanceKlass::cast(k())->method_with_idnum(slot);
+      return init_method_MemberName(mname, m, true, k);
     }
   } else if (target_klass == SystemDictionary::reflect_Constructor_klass()) {
     oop clazz  = java_lang_reflect_Constructor::clazz(target_oop);
     int slot   = java_lang_reflect_Constructor::slot(target_oop);
-    klassOop k = java_lang_Class::as_klassOop(clazz);
-    if (k != NULL && Klass::cast(k)->oop_is_instance()) {
-      methodOop m = instanceKlass::cast(k)->method_with_idnum(slot);
-      return init_method_MemberName(mname_oop, m, false, k);
+    KlassHandle k(thread, java_lang_Class::as_klassOop(clazz));
+    if (!k.is_null() && k->oop_is_instance()) {
+      methodOop m = instanceKlass::cast(k())->method_with_idnum(slot);
+      return init_method_MemberName(mname, m, false, k);
     }
   } else if (target_klass == SystemDictionary::MemberName_klass()) {
     // Note: This only works if the MemberName has already been resolved.
@@ -156,17 +159,18 @@
     int flags        = java_lang_invoke_MemberName::flags(target_oop);
     oop vmtarget     = java_lang_invoke_MemberName::vmtarget(target_oop);
     intptr_t vmindex = java_lang_invoke_MemberName::vmindex(target_oop);
-    klassOop k       = java_lang_Class::as_klassOop(clazz);
+    KlassHandle k(thread, java_lang_Class::as_klassOop(clazz));
     int ref_kind     = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
     if (vmtarget == NULL)  return NULL;  // not resolved
     if ((flags & IS_FIELD) != 0) {
       assert(vmtarget->is_klass(), "field vmtarget is klassOop");
       int basic_mods = (ref_kind_is_static(ref_kind) ? JVM_ACC_STATIC : 0);
       // FIXME:  how does k (receiver_limit) contribute?
-      return init_field_MemberName(mname_oop, klassOop(vmtarget), accessFlags_from(basic_mods), NULL, NULL, vmindex);
+      KlassHandle k_vmtarget(thread, klassOop(vmtarget));
+      return init_field_MemberName(mname, k_vmtarget, accessFlags_from(basic_mods), NULL, NULL, vmindex);
     } else if ((flags & (IS_METHOD | IS_CONSTRUCTOR)) != 0) {
       assert(vmtarget->is_method(), "method or constructor vmtarget is methodOop");
-      return init_method_MemberName(mname_oop, methodOop(vmtarget), ref_kind_does_dispatch(ref_kind), k);
+      return init_method_MemberName(mname, methodOop(vmtarget), ref_kind_does_dispatch(ref_kind), k);
     } else {
       return NULL;
     }
@@ -174,8 +178,9 @@
   return NULL;
 }
 
-oop MethodHandles::init_method_MemberName(oop mname_oop, methodOop m, bool do_dispatch,
-                                          klassOop resolved_klass) {
+oop MethodHandles::init_method_MemberName(Handle mname, methodOop m, bool do_dispatch,
+                                          KlassHandle resolved_klass_h) {
+  klassOop resolved_klass = resolved_klass_h();
   AccessFlags mods = m->access_flags();
   int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
   int vmindex = methodOopDesc::nonvirtual_vtable_index; // implies never any dispatch
@@ -235,6 +240,7 @@
     }
   }
 
+  oop mname_oop = mname();
   java_lang_invoke_MemberName::set_flags(mname_oop,    flags);
   java_lang_invoke_MemberName::set_vmtarget(mname_oop, m);
   java_lang_invoke_MemberName::set_vmindex(mname_oop,  vmindex);   // vtable/itable index
@@ -246,11 +252,11 @@
   // If relevant, the vtable or itable value is stored as vmindex.
   // This is done eagerly, since it is readily available without
   // constructing any new objects.
-  // TO DO: maybe intern mname_oop
-  return mname_oop;
+  instanceKlass::cast(m->method_holder())->add_member_name(mname);
+  return mname();
 }
 
-Handle MethodHandles::init_method_MemberName(oop mname_oop, CallInfo& info, TRAPS) {
+Handle MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, TRAPS) {
   Handle empty;
   if (info.resolved_appendix().not_null()) {
     // The resolved MemberName must not be accompanied by an appendix argument,
@@ -270,23 +276,24 @@
   } else {
     vmindex = info.vtable_index();
   }
-  oop res = init_method_MemberName(mname_oop, m(), (vmindex >= 0), defc());
+  oop res = init_method_MemberName(mname, m(), (vmindex >= 0), defc());
   assert(res == NULL || (java_lang_invoke_MemberName::vmindex(res) == vmindex), "");
   return Handle(THREAD, res);
 }
 
-oop MethodHandles::init_field_MemberName(oop mname_oop, klassOop field_holder,
+oop MethodHandles::init_field_MemberName(Handle mname, KlassHandle field_holder,
                                          AccessFlags mods, oop type, oop name,
                                          intptr_t offset, bool is_setter) {
   int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS );
   flags |= IS_FIELD | ((mods.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT);
   if (is_setter)  flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT);
-  oop vmtarget = field_holder;
+  oop vmtarget = field_holder();
   int vmindex  = offset;  // determines the field uniquely when combined with static bit
+  oop mname_oop = mname();
   java_lang_invoke_MemberName::set_flags(mname_oop,    flags);
   java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget);
   java_lang_invoke_MemberName::set_vmindex(mname_oop,  vmindex);
-  java_lang_invoke_MemberName::set_clazz(mname_oop,    Klass::cast(field_holder)->java_mirror());
+  java_lang_invoke_MemberName::set_clazz(mname_oop,    field_holder()->java_mirror());
   if (name != NULL)
     java_lang_invoke_MemberName::set_name(mname_oop,   name);
   if (type != NULL)
@@ -298,11 +305,11 @@
   // because they unambiguously identify the field.
   // Although the fieldDescriptor::_index would also identify the field,
   // we do not use it, because it is harder to decode.
-  // TO DO: maybe intern mname_oop
-  return mname_oop;
+  instanceKlass::cast(field_holder())->add_member_name(mname);
+  return mname();
 }
 
-Handle MethodHandles::init_field_MemberName(oop mname_oop, FieldAccessInfo& info, TRAPS) {
+Handle MethodHandles::init_field_MemberName(Handle mname, FieldAccessInfo& info, TRAPS) {
   return Handle();
 #if 0
   KlassHandle field_holder = info.klass();
@@ -728,7 +735,7 @@
           return empty;
         }
       }
-      return init_method_MemberName(mname(), result, THREAD);
+      return init_method_MemberName(mname, result, THREAD);
     }
   case IS_CONSTRUCTOR:
     {
@@ -746,7 +753,7 @@
         }
       }
       assert(result.is_statically_bound(), "");
-      return init_method_MemberName(mname(), result, THREAD);
+      return init_method_MemberName(mname, result, THREAD);
     }
   case IS_FIELD:
     {
@@ -759,7 +766,7 @@
       oop name = field_name_or_null(fd.name());
       bool is_setter = (ref_kind_is_valid(ref_kind) && ref_kind_is_setter(ref_kind));
       mname = Handle(THREAD,
-                     init_field_MemberName(mname(), sel_klass->as_klassOop(),
+                     init_field_MemberName(mname, sel_klass,
                                            fd.access_flags(), type, name, fd.offset(), is_setter));
       return mname;
     }
@@ -851,16 +858,16 @@
   THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format");
 }
 
-int MethodHandles::find_MemberNames(klassOop k,
+int MethodHandles::find_MemberNames(KlassHandle k,
                                     Symbol* name, Symbol* sig,
-                                    int mflags, klassOop caller,
-                                    int skip, objArrayOop results) {
-  DEBUG_ONLY(No_Safepoint_Verifier nsv);
-  // this code contains no safepoints!
+                                    int mflags, KlassHandle caller,
+                                    int skip, objArrayHandle results) {
 
   // %%% take caller into account!
 
-  if (k == NULL || !Klass::cast(k)->oop_is_instance())  return -1;
+  Thread* thread = Thread::current();
+
+  if (k.is_null() || !k->oop_is_instance())  return -1;
 
   int rfill = 0, rlimit = results->length(), rskip = skip;
   // overflow measurement:
@@ -888,7 +895,7 @@
   }
 
   if ((match_flags & IS_FIELD) != 0) {
-    for (FieldStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
+    for (FieldStream st(k(), local_only, !search_intfc); !st.eos(); st.next()) {
       if (name != NULL && st.name() != name)
           continue;
       if (sig != NULL && st.signature() != sig)
@@ -897,15 +904,15 @@
       if (rskip > 0) {
         --rskip;
       } else if (rfill < rlimit) {
-        oop result = results->obj_at(rfill++);
-        if (!java_lang_invoke_MemberName::is_instance(result))
+        Handle result(thread, results->obj_at(rfill++));
+        if (!java_lang_invoke_MemberName::is_instance(result()))
           return -99;  // caller bug!
         oop type = field_signature_type_or_null(st.signature());
         oop name = field_name_or_null(st.name());
-        oop saved = MethodHandles::init_field_MemberName(result, st.klass()->as_klassOop(),
+        oop saved = MethodHandles::init_field_MemberName(result, st.klass(),
                                                          st.access_flags(), type, name,
                                                          st.offset());
-        if (saved != result)
+        if (saved != result())
           results->obj_at_put(rfill-1, saved);  // show saved instance to user
       } else if (++overflow >= overflow_limit) {
         match_flags = 0; break; // got tired of looking at overflow
@@ -938,7 +945,7 @@
     } else {
       // caller will accept either sort; no need to adjust name
     }
-    for (MethodStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
+    for (MethodStream st(k(), local_only, !search_intfc); !st.eos(); st.next()) {
       methodOop m = st.method();
       Symbol* m_name = m->name();
       if (m_name == clinit_name)
@@ -951,11 +958,11 @@
       if (rskip > 0) {
         --rskip;
       } else if (rfill < rlimit) {
-        oop result = results->obj_at(rfill++);
-        if (!java_lang_invoke_MemberName::is_instance(result))
+        Handle result(thread, results->obj_at(rfill++));
+        if (!java_lang_invoke_MemberName::is_instance(result()))
           return -99;  // caller bug!
-        oop saved = MethodHandles::init_method_MemberName(result, m, true, NULL);
-        if (saved != result)
+        oop saved = MethodHandles::init_method_MemberName(result, m, true, KlassHandle());
+        if (saved != result())
           results->obj_at_put(rfill-1, saved);  // show saved instance to user
       } else if (++overflow >= overflow_limit) {
         match_flags = 0; break; // got tired of looking at overflow
@@ -967,6 +974,96 @@
   return rfill + overflow;
 }
 
+//------------------------------------------------------------------------------
+// MemberNameTable
+//
+
+MemberNameTable::MemberNameTable() : GrowableArray<jweak>(10, true) {
+  assert_locked_or_safepoint(MemberNameTable_lock);
+}
+
+MemberNameTable::~MemberNameTable() {
+  assert_locked_or_safepoint(MemberNameTable_lock);
+  int len = this->length();
+
+  for (int idx = 0; idx < len; idx++) {
+    jweak ref = this->at(idx);
+    JNIHandles::destroy_weak_global(ref);
+  }
+}
+
+// Return entry index if found, return -1 otherwise.
+int MemberNameTable::find_member_name(oop mem_name) {
+  assert_locked_or_safepoint(MemberNameTable_lock);
+  int len = this->length();
+
+  for (int idx = 0; idx < len; idx++) {
+    jweak ref = this->at(idx);
+    oop entry = JNIHandles::resolve(ref);
+    if (entry == mem_name) {
+      return idx;
+    }
+  }
+  return -1;
+}
+
+void MemberNameTable::add_member_name(jweak mem_name_wref) {
+  assert_locked_or_safepoint(MemberNameTable_lock);
+  oop mem_name = JNIHandles::resolve(mem_name_wref);
+
+  // Each member name may appear just once: add only if not found
+  if (find_member_name(mem_name) == -1) {
+    this->append(mem_name_wref);
+  }
+}
+
+oop MemberNameTable::find_member_name_by_method(methodOop old_method) {
+  assert_locked_or_safepoint(MemberNameTable_lock);
+  oop found = NULL;
+  int len = this->length();
+
+  for (int idx = 0; idx < len; idx++) {
+    oop mem_name = JNIHandles::resolve(this->at(idx));
+    if (mem_name == NULL) {
+      continue;
+    }
+    methodOop method = (methodOop)java_lang_invoke_MemberName::vmtarget(mem_name);
+    if (method == old_method) {
+      found = mem_name;
+      break;
+    }
+  }
+  return found;
+}
+
+// It is called at safepoint only
+void MemberNameTable::adjust_method_entries(methodOop* old_methods, methodOop* new_methods,
+                                            int methods_length, bool *trace_name_printed) {
+  assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
+  // search the MemberNameTable for uses of either obsolete or EMCP methods
+  for (int j = 0; j < methods_length; j++) {
+    methodOop old_method = old_methods[j];
+    methodOop new_method = new_methods[j];
+    oop mem_name = find_member_name_by_method(old_method);
+    if (mem_name != NULL) {
+      java_lang_invoke_MemberName::adjust_vmtarget(mem_name, new_method);
+
+      if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
+        if (!(*trace_name_printed)) {
+          // RC_TRACE_MESG macro has an embedded ResourceMark
+          RC_TRACE_MESG(("adjust: name=%s",
+                         Klass::cast(old_method->method_holder())->external_name()));
+          *trace_name_printed = true;
+        }
+        // RC_TRACE macro has an embedded ResourceMark
+        RC_TRACE(0x00400000, ("MemberName method update: %s(%s)",
+                              new_method->name()->as_C_string(),
+                              new_method->signature()->as_C_string()));
+      }
+    }
+  }
+}
+
 //
 // Here are the native methods in java.lang.invoke.MethodHandleNatives
 // They are the private interface between this JVM and the HotSpot-specific
@@ -1058,8 +1155,8 @@
   if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); }
   if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); }
   Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
-  oop target_oop = JNIHandles::resolve_non_null(target_jh);
-  MethodHandles::init_MemberName(mname(), target_oop);
+  Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
+  MethodHandles::init_MemberName(mname, target);
 }
 JVM_END
 
@@ -1176,7 +1273,7 @@
   } else {
     Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL);
     if (vmtarget->is_method())
-      x = MethodHandles::init_method_MemberName(mname2(), methodOop(vmtarget()), false, NULL);
+      x = MethodHandles::init_method_MemberName(mname2, methodOop(vmtarget()), false, KlassHandle());
     else
       x = MethodHandles::init_MemberName(mname2(), vmtarget());
   }
@@ -1221,8 +1318,8 @@
     // %%% TO DO
   }
 
-  int res = MethodHandles::find_MemberNames(k(), name, sig, mflags,
-                                            caller(), skip, results());
+  int res = MethodHandles::find_MemberNames(k, name, sig, mflags,
+                                            caller, skip, results);
   // TO DO: expand at least some of the MemberNames, to avoid massive callbacks
   return res;
 }
--- a/src/share/vm/prims/methodHandles.hpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/prims/methodHandles.hpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@
   // in java.lang.invoke and sun.invoke.
   // See also  javaClasses for layouts java_lang_invoke_Method{Handle,Type,Type::Form}.
  public:
- public:
   static bool enabled()                         { return _enabled; }
   static void set_enabled(bool z);
 
@@ -54,18 +53,18 @@
   static Handle resolve_MemberName(Handle mname, KlassHandle caller, TRAPS); // compute vmtarget/vmindex from name/type
   static void expand_MemberName(Handle mname, int suppress, TRAPS);  // expand defc/name/type if missing
   static Handle new_MemberName(TRAPS);  // must be followed by init_MemberName
-  static oop init_MemberName(oop mname_oop, oop target_oop); // compute vmtarget/vmindex from target
-  static oop init_method_MemberName(oop mname_oop, methodOop m, bool do_dispatch,
-                                    klassOop resolved_klass);
-  static oop init_field_MemberName(oop mname_oop, klassOop field_holder,
+  static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target
+  static oop init_method_MemberName(Handle mname_h, methodOop m, bool do_dispatch,
+                                    KlassHandle resolved_klass_h);
+  static oop init_field_MemberName(Handle mname_h, KlassHandle field_holder_h,
                                    AccessFlags mods, oop type, oop name,
                                    intptr_t offset, bool is_setter = false);
-  static Handle init_method_MemberName(oop mname_oop, CallInfo& info, TRAPS);
-  static Handle init_field_MemberName(oop mname_oop, FieldAccessInfo& info, TRAPS);
+  static Handle init_method_MemberName(Handle mname_h, CallInfo& info, TRAPS);
+  static Handle init_field_MemberName(Handle mname_h, FieldAccessInfo& info, TRAPS);
   static int method_ref_kind(methodOop m, bool do_dispatch_if_possible = true);
-  static int find_MemberNames(klassOop k, Symbol* name, Symbol* sig,
-                              int mflags, klassOop caller,
-                              int skip, objArrayOop results);
+  static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig,
+                              int mflags, KlassHandle caller,
+                              int skip, objArrayHandle results);
   // bit values for suppress argument to expand_MemberName:
   enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
 
@@ -230,4 +229,25 @@
   void generate();
 };
 
+//------------------------------------------------------------------------------
+// MemberNameTable
+//
+class MemberNameTable : public GrowableArray<jweak> {
+ public:
+  MemberNameTable();
+  ~MemberNameTable();
+  void add_member_name(jweak mem_name_wref);
+ private:
+  int find_member_name(oop mem_name);
+
+ public:
+  // RedefineClasses() API support:
+  // If a MemberName refers to old_method then update it
+  // to refer to new_method.
+  void adjust_method_entries(methodOop* old_methods, methodOop* new_methods,
+                             int methods_length, bool *trace_name_printed);
+ private:
+  oop find_member_name_by_method(methodOop old_method);
+};
+
 #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP
--- a/src/share/vm/runtime/mutexLocker.cpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/runtime/mutexLocker.cpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,7 @@
 Mutex*   JNIGlobalHandle_lock         = NULL;
 Mutex*   JNIHandleBlockFreeList_lock  = NULL;
 Mutex*   JNICachedItableIndex_lock    = NULL;
+Mutex*   MemberNameTable_lock         = NULL;
 Mutex*   JmethodIdCreation_lock       = NULL;
 Mutex*   JfieldIdCreation_lock        = NULL;
 Monitor* JNICritical_lock             = NULL;
@@ -263,6 +264,7 @@
   def(Heap_lock                    , Monitor, nonleaf+1,   false);
   def(JfieldIdCreation_lock        , Mutex  , nonleaf+1,   true ); // jfieldID, Used in VM_Operation
   def(JNICachedItableIndex_lock    , Mutex  , nonleaf+1,   false); // Used to cache an itable index during JNI invoke
+  def(MemberNameTable_lock         , Mutex  , nonleaf+1,   false); // Used to protect MemberNameTable
 
   def(CompiledIC_lock              , Mutex  , nonleaf+2,   false); // locks VtableStubs_lock, InlineCacheBuffer_lock
   def(CompileTaskAlloc_lock        , Mutex  , nonleaf+2,   true );
--- a/src/share/vm/runtime/mutexLocker.hpp	Fri Feb 07 12:44:16 2014 +0100
+++ b/src/share/vm/runtime/mutexLocker.hpp	Fri Feb 07 16:06:44 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,7 @@
 extern Mutex*   JNIGlobalHandle_lock;            // a lock on creating JNI global handles
 extern Mutex*   JNIHandleBlockFreeList_lock;     // a lock on the JNI handle block free list
 extern Mutex*   JNICachedItableIndex_lock;       // a lock on caching an itable index during JNI invoke
+extern Mutex*   MemberNameTable_lock;            // a lock on the MemberNameTable updates
 extern Mutex*   JmethodIdCreation_lock;          // a lock on creating JNI method identifiers
 extern Mutex*   JfieldIdCreation_lock;           // a lock on creating JNI static field identifiers
 extern Monitor* JNICritical_lock;                // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in