Index: vm/jitrino/src/vm/VMInterface.cpp =================================================================== --- vm/jitrino/src/vm/VMInterface.cpp (revision 660100) +++ 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/include/open/vm_ee.h =================================================================== --- vm/include/open/vm_ee.h (revision 660100) +++ 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/include/open/vm_class_support.h =================================================================== --- vm/include/open/vm_class_support.h (revision 660100) +++ vm/include/open/vm_class_support.h (working copy) @@ -50,28 +50,6 @@ void vm_patch_code_block(U_8* code_block, U_8* 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/vmcore/include/class_member.h =================================================================== --- vm/vmcore/include/class_member.h (revision 660100) +++ 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; } @@ -606,6 +600,7 @@ // destructor should be instead of this function, but it's not allowed to use it because copy for Method class is // done with memcpy, and old value is destroyed with delete operator. void MethodClearInternals(); + void NotifyUnloading(); // // access modifiers @@ -717,6 +712,9 @@ /** Information about methods inlined to this. */ InlineInfo* _inline_info; + + + MethodSet* _recompilation_callbacks; public: /** Index: vm/vmcore/include/classloader.h =================================================================== --- vm/vmcore/include/classloader.h (revision 660100) +++ vm/vmcore/include/classloader.h (working copy) @@ -240,6 +240,9 @@ STD_FREE(m_table); m_table = NULL; } + + void NotifyUnloading(); + inline void* Alloc(size_t size) { assert(pool); Lock(); Index: vm/vmcore/include/Class.h =================================================================== --- vm/vmcore/include/Class.h (revision 660100) +++ vm/vmcore/include/Class.h (working copy) @@ -1059,6 +1059,8 @@ /** Clears member variables within a class.*/ void clear_internals(); + void notify_unloading(); + /** Determines whether the given class has a super class. * @return true if the current class has a super class; * otherwise false.*/ Index: vm/vmcore/src/class_support/C_Interface.cpp =================================================================== --- vm/vmcore/src/class_support/C_Interface.cpp (revision 660100) +++ vm/vmcore/src/class_support/C_Interface.cpp (working copy) @@ -1729,12 +1729,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 660100) +++ vm/vmcore/src/class_support/Class.cpp (working copy) @@ -144,6 +144,13 @@ m_verify_data = 0; } +void Class::notify_unloading() { + if(m_methods != NULL) { + for (int i = 0; i < m_num_methods; i++){ + m_methods[i].NotifyUnloading(); + } + } +} void Class::clear_internals() { if(m_fields != NULL) @@ -615,6 +622,7 @@ _method_sig = 0; _notify_recompiled_records = NULL; + _recompilation_callbacks = NULL; _index = 0; _max_stack=_max_locals=_n_exceptions=_n_handlers=0; _exceptions = NULL; @@ -639,6 +647,18 @@ _inline_info = NULL; } //Method::Method + +void Method::NotifyUnloading() +{ + 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); + } + } +} + void Method::MethodClearInternals() { CodeChunkInfo *jit_info; @@ -656,6 +676,10 @@ } jit_info->_target_exception_handlers = NULL; } + + if (_recompilation_callbacks != NULL) { + delete _recompilation_callbacks; + } if (_notify_recompiled_records != NULL) { Index: vm/vmcore/src/class_support/method.cpp =================================================================== --- vm/vmcore/src/class_support/method.cpp (revision 660100) +++ 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,43 @@ // 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. + ClassLoader* this_loader = get_class()->get_class_loader(); + ClassLoader* caller_loader = caller->get_class()->get_class_loader(); + if (this_loader == caller_loader || caller_loader->IsBootstrap()) return; + + MethodSet *vec = caller->_recompilation_callbacks; + if (vec == NULL) { + 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) { + TRACE2("cu.debug", "unregister jit callback, 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; + STD_FREE(nr); + nr = next; + } else { + prev = nr; + nr = nr->next; + } + } +} void Method::do_jit_recompiled_method_callbacks() { Index: vm/vmcore/src/class_support/classloader.cpp =================================================================== --- vm/vmcore/src/class_support/classloader.cpp (revision 660100) +++ vm/vmcore/src/class_support/classloader.cpp (working copy) @@ -106,6 +106,22 @@ return true; } +void ClassLoader::NotifyUnloading() +{ + Global_Env *env = VM_Global_State::loader_env; + env->em_interface->ClassloaderUnloadingCallback((Class_Loader_Handle)this); + + ClassTable::iterator it; + ClassTable* LoadedClasses = GetLoadedClasses(); + for (it = LoadedClasses->begin(); it != LoadedClasses->end(); it++) + { + Class* c; + c = it->second; + assert(c); + c->notify_unloading(); + } +} + ClassLoader::~ClassLoader() { Global_Env *env = VM_Global_State::loader_env; @@ -147,7 +163,6 @@ natives_unload_library(info->handle); } - env->em_interface->ClassloaderUnloadingCallback((Class_Loader_Handle)this); delete CodeMemoryManager; CodeMemoryManager = NULL; @@ -582,9 +597,15 @@ unloadinglist.push_back(m_table[i]); } + vector::reverse_iterator it; + for (it = unloadinglist.rbegin(); it != unloadinglist.rend(); it++) + { + (*it)->NotifyUnloading(); + } + // 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 + for (it = unloadinglist.rbegin(); it != unloadinglist.rend(); it++) { UnloadClassLoader(*it); }