Index: vm/include/open/vm_class_support.h =================================================================== --- vm/include/open/vm_class_support.h (revision 654467) +++ vm/include/open/vm_class_support.h (working copy) @@ -51,28 +51,6 @@ void vm_patch_code_block(Byte* code_block, Byte* new_code, size_t size); /** - * Called by a EE in order to be notified whenever the vtable entries for the given method - * are changed. This could happen, e.g., when a method is first compiled, or when it is - * recompiled. The callback_data pointer will be passed back to the JIT during the callback. - * The callback method is JIT_recompiled_method_callback. - */ -void vm_register_jit_recompiled_method_callback(JIT_Handle jit, Method_Handle method, void* callback_data); - -/** - * Called by a JIT in order to be notified whenever the given method is overridden by a newly - * loaded class. The callback_data pointer will be passed back to the JIT during the callback. - * The callback function is JIT_overridden_method_callback. - */ -void vm_register_jit_overridden_method_callback(JIT_Handle jit, Method_Handle method, void* callback_data); - -/** - * Called by a JIT in order to be notified whenever the given class is extended. - * The callback_data pointer will be passed back to the JIT during the callback. - * The callback function is JIT_extended_class_callback. - */ -void vm_register_jit_extended_class_callback(JIT_Handle jit, Class_Handle clss, void* callback_data); - -/** * Called by a JIT to have the VM recompile a method using the specified JIT. After * recompilation, the corresponding vtable entries will be updated, and the necessary * callbacks to JIT_recompiled_method_callback will be made. It is a requirement that Index: vm/include/open/vm_ee.h =================================================================== --- vm/include/open/vm_ee.h (revision 654467) +++ vm/include/open/vm_ee.h (working copy) @@ -198,8 +198,10 @@ * will be passed back to the JIT during the callback. The callback method is * JIT_recompiled_method_callback. */ -DECLARE_OPEN(void, vm_register_jit_recompiled_method_callback, (JIT_Handle jit, Method_Handle method, - void *callback_data)); +DECLARE_OPEN(void, vm_register_jit_recompiled_method_callback, (JIT_Handle jit, + Method_Handle method, + Method_Handle caller, + void *callback_data)); /** * Called by a JIT to have the VM replace a section of executable code in a Index: vm/jitrino/src/vm/VMInterface.cpp =================================================================== --- vm/jitrino/src/vm/VMInterface.cpp (revision 654467) +++ vm/jitrino/src/vm/VMInterface.cpp (working copy) @@ -1036,7 +1036,8 @@ void CompilationInterface::setNotifyWhenMethodIsRecompiled(MethodDesc * methodDesc, void * callbackData) { Method_Handle drlMethod = methodDesc->getMethodHandle(); - vm_register_jit_recompiled_method_callback(getJitHandle(),drlMethod,callbackData); + vm_register_jit_recompiled_method_callback(getJitHandle(),drlMethod, + getMethodToCompile()->getMethodHandle(), callbackData); } void CompilationInterface::sendCompiledMethodLoadEvent(MethodDesc* methodDesc, MethodDesc* outerDesc, Index: vm/vmcore/include/class_member.h =================================================================== --- vm/vmcore/include/class_member.h (revision 654467) +++ vm/vmcore/include/class_member.h (working copy) @@ -22,6 +22,8 @@ #include "Class.h" #include "vm_java_support.h" +typedef std::vector MethodSet; + struct String; class ByteReader; class JIT; @@ -347,20 +349,11 @@ // Used to notify interested JITs whenever a method is changed: overwritten, recompiled, // or initially compiled. struct Method_Change_Notification_Record { - Method *method_of_interest; + Method *caller; JIT *jit; void *callback_data; Method_Change_Notification_Record *next; - bool equals(Method *method_of_interest_, JIT *jit_, void *callback_data_) { - if ((method_of_interest == method_of_interest_) && - (jit == jit_) && - (callback_data == callback_data_)) { - return true; - } - return false; - } - // Optimized equals method. Most callbacks know method of interest, so we could skip one check. inline bool equals(JIT *jit_, void *callback_data_) { if ((callback_data == callback_data_) && (jit == jit_)) { @@ -569,8 +562,9 @@ CodeChunkInfo *create_code_chunk_info_mt(); // Notify JITs whenever this method is recompiled or initially compiled. - void register_jit_recompiled_method_callback(JIT *jit_to_be_notified, void *callback_data); + void register_jit_recompiled_method_callback(JIT *jit_to_be_notified, Method* caller, void *callback_data); void do_jit_recompiled_method_callbacks(); + void unregister_jit_recompiled_method_callbacks(const Method* caller); Method_Side_Effects get_side_effects() { return _side_effects; } void set_side_effects(Method_Side_Effects mse) { _side_effects = mse; } @@ -717,6 +711,9 @@ /** Information about methods inlined to this. */ InlineInfo* _inline_info; + + + MethodSet* _recompilation_callbacks; public: /** Index: vm/vmcore/src/class_support/C_Interface.cpp =================================================================== --- vm/vmcore/src/class_support/C_Interface.cpp (revision 654467) +++ vm/vmcore/src/class_support/C_Interface.cpp (working copy) @@ -1731,12 +1731,14 @@ // initially compiled. The callback_data pointer will be passed back to the JIT during the callback. // The callback method is JIT_recompiled_method_callback. void vm_register_jit_recompiled_method_callback(JIT_Handle jit, Method_Handle method, + Method_Handle caller, void *callback_data) { assert(method); + assert(caller); JIT *jit_to_be_notified = (JIT *)jit; Method *m = (Method *)method; - m->register_jit_recompiled_method_callback(jit_to_be_notified, callback_data); + m->register_jit_recompiled_method_callback(jit_to_be_notified, caller, callback_data); } //vm_register_jit_recompiled_method_callback Index: vm/vmcore/src/class_support/Class.cpp =================================================================== --- vm/vmcore/src/class_support/Class.cpp (revision 654467) +++ vm/vmcore/src/class_support/Class.cpp (working copy) @@ -615,6 +615,7 @@ _method_sig = 0; _notify_recompiled_records = NULL; + _recompilation_callbacks = NULL; _index = 0; _max_stack=_max_locals=_n_exceptions=_n_handlers=0; _exceptions = NULL; @@ -656,6 +657,15 @@ } jit_info->_target_exception_handlers = NULL; } + + if (_recompilation_callbacks != NULL) { + MethodSet::const_iterator it; + for (it = _recompilation_callbacks->begin(); it != _recompilation_callbacks->end(); it++) + { + (*it)->unregister_jit_recompiled_method_callbacks(this); + } + delete _recompilation_callbacks; + } if (_notify_recompiled_records != NULL) { Index: vm/vmcore/src/class_support/classloader.cpp =================================================================== --- vm/vmcore/src/class_support/classloader.cpp (revision 654467) +++ vm/vmcore/src/class_support/classloader.cpp (working copy) @@ -583,8 +583,9 @@ } // safely remove classloaders from m_table - vector::iterator it; - for (it = unloadinglist.begin(); it != unloadinglist.end(); it++) + // iterate in reverse order to unload child loaders first + vector::reverse_iterator it; + for (it = unloadinglist.rbegin(); it != unloadinglist.rend(); it++) { UnloadClassLoader(*it); } Index: vm/vmcore/src/class_support/method.cpp =================================================================== --- vm/vmcore/src/class_support/method.cpp (revision 654467) +++ vm/vmcore/src/class_support/method.cpp (working copy) @@ -553,7 +553,9 @@ // Notify the given JIT whenever this method is recompiled or initially compiled. // The callback_data pointer will be passed back to the JIT during the callback. // The JIT's callback function is JIT_recompiled_method_callback. -void Method::register_jit_recompiled_method_callback(JIT *jit_to_be_notified, void *callback_data) +void Method::register_jit_recompiled_method_callback(JIT *jit_to_be_notified, + Method* caller, + void *callback_data) { // Don't insert the same entry repeatedly on the _notify_recompiled_records list. Method_Change_Notification_Record *nr = _notify_recompiled_records; @@ -567,13 +569,70 @@ // Insert a new notification record. Method_Change_Notification_Record *new_nr = (Method_Change_Notification_Record *)STD_MALLOC(sizeof(Method_Change_Notification_Record)); - new_nr->method_of_interest = this; + new_nr->caller = caller; new_nr->jit = jit_to_be_notified; new_nr->callback_data = callback_data; new_nr->next = _notify_recompiled_records; _notify_recompiled_records = new_nr; + + // Record a callback in the caller method to let it unregister itself if unloaded. + // Actual only when caller is in parent loader so callback can outlive the caller (well, devirtualization may invalidate this assumption) + ClassLoader* this_loader = get_class()->get_class_loader(); + ClassLoader* caller_loader = caller->get_class()->get_class_loader(); + if (this_loader == caller_loader) return; + if ( !this_loader->IsBootstrap()) { + // FIXME estimate loaders superiority, not truly correct but helps to break circularity + unsigned num = ClassLoader::GetClassLoaderNumber(); + ClassLoader** table = ClassLoader::GetClassLoaderTable(); + unsigned this_loader_idx = num; + for(unsigned i = 0; i < num; ++i) { + if (table[i] == caller_loader) { + if (i > this_loader_idx) { + break; + } else { + return; + } + } + if (table[i] == this_loader) { + this_loader_idx = i; + } + } + } + //while (caller_loader != NULL && this_loader != caller_loader->GetParent()) { + // caller_loader = caller_loader->GetParent(); + //} + //if (caller_loader == NULL) return; + + MethodSet *vec = caller->_recompilation_callbacks; + if (vec == NULL) { + TRACE2("cu.debug", "add caller=" << caller << " callee=" << this << " data=" << callback_data); + vec = caller->_recompilation_callbacks = new MethodSet(); + } + vec->push_back(this); } //Method::register_jit_recompiled_method_callback +void Method::unregister_jit_recompiled_method_callbacks(const Method* caller) { + //caller->lock(); + TRACE2("cu.debug", "unregister caller=" << caller << " callee=" << this); + Method_Change_Notification_Record *nr,*prev = NULL; + for (nr = _notify_recompiled_records; nr != NULL; ) { + if (nr->caller == caller) { + if (prev) { + prev->next = nr->next; + } else { + _notify_recompiled_records = nr->next; + } + Method_Change_Notification_Record *next = nr->next; + TRACE2("cu.debug", "caller=" << caller << " callee=" << this << " data=" <callback_data); + STD_FREE(nr); + nr = next; + } else { + prev = nr; + nr = nr->next; + } + } + //caller->unlock(); +} void Method::do_jit_recompiled_method_callbacks() {