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()
{