--- old/src/share/vm/classfile/javaClasses.cpp Mon Mar 25 19:59:54 2013 +++ new/src/share/vm/classfile/javaClasses.cpp Mon Mar 25 19:59:51 2013 @@ -2625,8 +2625,18 @@ return (Metadata*)mname->address_field(_vmtarget_offset); } +#if INCLUDE_JVMTI +// Can be executed on VM thread only +void java_lang_invoke_MemberName::adjust_vmtarget(oop mname, Metadata* 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); +} +#endif // INCLUDE_JVMTI + void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) { assert(is_instance(mname), "wrong type"); + // check the type of the vmtarget oop dependency = NULL; if (ref != NULL) { @@ -2637,6 +2647,7 @@ case MN_IS_CONSTRUCTOR: assert(ref->is_method(), "should be a method"); dependency = ((Method*)ref)->method_holder()->java_mirror(); + ((Method*)ref)->method_holder()->add_member_name(mname); break; case MN_IS_FIELD: assert(ref->is_klass(), "should be a class"); --- old/src/share/vm/classfile/javaClasses.hpp Mon Mar 25 20:00:15 2013 +++ new/src/share/vm/classfile/javaClasses.hpp Mon Mar 25 20:00:12 2013 @@ -1036,6 +1036,9 @@ static Metadata* vmtarget(oop mname); static void set_vmtarget(oop mname, Metadata* target); +#if INCLUDE_JVMTI + static void adjust_vmtarget(oop mname, Metadata* target); +#endif // INCLUDE_JVMTI static intptr_t vmindex(oop mname); static void set_vmindex(oop mname, intptr_t index); --- old/src/share/vm/oops/instanceKlass.cpp Mon Mar 25 20:00:35 2013 +++ new/src/share/vm/oops/instanceKlass.cpp Mon Mar 25 20:00:32 2013 @@ -2290,6 +2290,11 @@ FreeHeap(jmeths); } + MemberNameTable* mnt = member_names(); + if (mnt != NULL) { + delete mnt; + } + int* indices = methods_cached_itable_indices_acquire(); if (indices != (int*)NULL) { release_set_methods_cached_itable_indices(NULL); @@ -2718,6 +2723,15 @@ return NULL; } +void InstanceKlass::add_member_name(oop mem_name) { + MutexLocker ml(MemberNameTable_lock); + + if (_member_names == NULL) { + _member_names = new (ResourceObj::C_HEAP, mtInternal) MemberNameTable(); + } + _member_names->add_member_name(mem_name); +} + // ----------------------------------------------------------------------------------------------------- // Printing --- old/src/share/vm/oops/instanceKlass.hpp Mon Mar 25 20:00:53 2013 +++ new/src/share/vm/oops/instanceKlass.hpp Mon Mar 25 20:00:50 2013 @@ -90,6 +90,7 @@ class nmethodBucket; class PreviousVersionNode; class JvmtiCachedClassFieldMap; +class MemberNameTable; // This is used in iterators below. class FieldClosure: public StackObj { @@ -245,6 +246,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 @@ -1012,6 +1014,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(oop mem_name); + public: // JVMTI support jint jvmti_class_status() const; --- old/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Mar 25 20:01:12 2013 +++ new/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Mar 25 20:01:10 2013 @@ -3284,6 +3284,17 @@ // 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(); + scratch_class->set_member_names(mnt); + if (mnt != NULL) { + bool trace_name_printed = false; + mnt->adjust_method_entries(_matching_old_methods, + _matching_new_methods, + _matching_methods_length, + &trace_name_printed); + } + // Fix Resolution Error table also to remove old constant pools SystemDictionary::delete_resolution_error(old_constants); --- old/src/share/vm/prims/methodHandles.cpp Mon Mar 25 20:01:34 2013 +++ new/src/share/vm/prims/methodHandles.cpp Mon Mar 25 20:01:31 2013 @@ -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" @@ -800,9 +801,6 @@ Symbol* name, Symbol* sig, int mflags, Klass* caller, int skip, objArrayOop results) { - DEBUG_ONLY(No_Safepoint_Verifier nsv); - // this code contains no safepoints! - // %%% take caller into account! if (k == NULL || !k->oop_is_instance()) return -1; @@ -911,7 +909,94 @@ // return number of elements we at leasted wanted to initialize return rfill + overflow; } + +//------------------------------------------------------------------------------ +// MemberNameTable // + +MemberNameTable::MemberNameTable() : GrowableArray(10, true) { +} + +MemberNameTable::~MemberNameTable() { + 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) { + 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(oop mem_name) { + // Each member name may appear just once: add only if not found + if (find_member_name(mem_name) == -1) { + this->append(JNIHandles::make_weak_global(mem_name)); + } +} + +#if INCLUDE_JVMTI +// It is called at safepoint only from the MemberNameTable::adjust_method_entries(). +// No synchronization is needed. +oop MemberNameTable::find_member_name_by_method(Method* old_method) { + 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; + } + Method* method = (Method*)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(Method** old_methods, Method** new_methods, + int methods_length, bool *trace_name_printed) { + // search the MemberNameTable for uses of either obsolete or EMCP methods + for (int j = 0; j < methods_length; j++) { + Method* old_method = old_methods[j]; + Method* 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", + 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())); + } + } + } +} +#endif // INCLUDE_JVMTI + +// // Here are the native methods in java.lang.invoke.MethodHandleNatives // They are the private interface between this JVM and the HotSpot-specific // Java code that implements JSR 292 method handles. --- old/src/share/vm/prims/methodHandles.hpp Mon Mar 25 20:01:53 2013 +++ new/src/share/vm/prims/methodHandles.hpp Mon Mar 25 20:01:51 2013 @@ -230,4 +230,27 @@ void generate(); }; +//------------------------------------------------------------------------------ +// MemberNameTable +// +class MemberNameTable : public GrowableArray { + public: + MemberNameTable(); + ~MemberNameTable(); + void add_member_name(oop mem_name); + private: + int find_member_name(oop mem_name); + +#if INCLUDE_JVMTI + public: + // RedefineClasses() API support: + // If a MemberName refers to old_method then update it + // to refer to new_method. + void adjust_method_entries(Method** old_methods, Method** new_methods, + int methods_length, bool *trace_name_printed); + private: + oop find_member_name_by_method(Method* old_method); +#endif // INCLUDE_JVMTI +}; + #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP --- old/src/share/vm/runtime/mutexLocker.cpp Mon Mar 25 20:02:11 2013 +++ new/src/share/vm/runtime/mutexLocker.cpp Mon Mar 25 20:02:09 2013 @@ -46,6 +46,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; @@ -252,6 +253,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 ); --- old/src/share/vm/runtime/mutexLocker.hpp Mon Mar 25 20:02:31 2013 +++ new/src/share/vm/runtime/mutexLocker.hpp Mon Mar 25 20:02:28 2013 @@ -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