8022887: Assertion hit while using class and redefining it with RedefineClasses simultaneously
Summary: Need to refetch each method from InstanceKlass after all safepoints. Removed leaky PreviousVersionInfo code.
Reviewed-by: dcubed, sspitsyn
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Fri Sep 20 09:30:02 2013 -0400
@@ -103,9 +103,10 @@
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k);
for (int i = 0; i < ik->methods()->length(); i++) {
- ResourceMark rm;
Method* m = ik->methods()->at(i);
- (new Fingerprinter(m))->fingerprint();
+ Fingerprinter fp(m);
+ // The side effect of this call sets method's fingerprint field.
+ fp.fingerprint();
}
}
}
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Sep 20 09:30:02 2013 -0400
@@ -2847,24 +2847,17 @@
st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr();
st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr();
{
- ResourceMark rm;
- // PreviousVersionInfo objects returned via PreviousVersionWalker
- // contain a GrowableArray of handles. We have to clean up the
- // GrowableArray _after_ the PreviousVersionWalker destructor
- // has destroyed the handles.
- {
- bool have_pv = false;
- PreviousVersionWalker pvw((InstanceKlass*)this);
- for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
- pv_info != NULL; pv_info = pvw.next_previous_version()) {
- if (!have_pv)
- st->print(BULLET"previous version: ");
- have_pv = true;
- pv_info->prev_constant_pool_handle()()->print_value_on(st);
- }
- if (have_pv) st->cr();
- } // pvw is cleaned up
- } // rm is cleaned up
+ bool have_pv = false;
+ PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
+ for (PreviousVersionNode * pv_node = pvw.next_previous_version();
+ pv_node != NULL; pv_node = pvw.next_previous_version()) {
+ if (!have_pv)
+ st->print(BULLET"previous version: ");
+ have_pv = true;
+ pv_node->prev_constant_pool()->print_value_on(st);
+ }
+ if (have_pv) st->cr();
+ } // pvw is cleaned up
if (generic_signature() != NULL) {
st->print(BULLET"generic signature: ");
@@ -3392,34 +3385,34 @@
Array<Method*>* old_methods = ikh->methods();
if (cp_ref->on_stack()) {
- PreviousVersionNode * pv_node = NULL;
- if (emcp_method_count == 0) {
+ PreviousVersionNode * pv_node = NULL;
+ if (emcp_method_count == 0) {
// non-shared ConstantPool gets a reference
- pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), NULL);
- RC_TRACE(0x00000400,
- ("add: all methods are obsolete; flushing any EMCP refs"));
- } else {
- int local_count = 0;
+ pv_node = new PreviousVersionNode(cp_ref, NULL);
+ RC_TRACE(0x00000400,
+ ("add: all methods are obsolete; flushing any EMCP refs"));
+ } else {
+ int local_count = 0;
GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
- GrowableArray<Method*>(emcp_method_count, true);
- for (int i = 0; i < old_methods->length(); i++) {
- if (emcp_methods->at(i)) {
- // this old method is EMCP. Save it only if it's on the stack
- Method* old_method = old_methods->at(i);
- if (old_method->on_stack()) {
- method_refs->append(old_method);
+ GrowableArray<Method*>(emcp_method_count, true);
+ for (int i = 0; i < old_methods->length(); i++) {
+ if (emcp_methods->at(i)) {
+ // this old method is EMCP. Save it only if it's on the stack
+ Method* old_method = old_methods->at(i);
+ if (old_method->on_stack()) {
+ method_refs->append(old_method);
+ }
+ if (++local_count >= emcp_method_count) {
+ // no more EMCP methods so bail out now
+ break;
}
- if (++local_count >= emcp_method_count) {
- // no more EMCP methods so bail out now
- break;
}
}
- }
// non-shared ConstantPool gets a reference
- pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), method_refs);
+ pv_node = new PreviousVersionNode(cp_ref, method_refs);
}
// append new previous version.
- _previous_versions->append(pv_node);
+ _previous_versions->append(pv_node);
}
// Since the caller is the VMThread and we are at a safepoint, this
@@ -3520,6 +3513,8 @@
return m;
}
}
+ // None found, return null for the caller to handle.
+ return NULL;
}
return m;
}
@@ -3536,10 +3531,9 @@
// Construct a PreviousVersionNode entry for the array hung off
// the InstanceKlass.
PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
- bool prev_cp_is_weak, GrowableArray<Method*>* prev_EMCP_methods) {
+ GrowableArray<Method*>* prev_EMCP_methods) {
_prev_constant_pool = prev_constant_pool;
- _prev_cp_is_weak = prev_cp_is_weak;
_prev_EMCP_methods = prev_EMCP_methods;
}
@@ -3555,99 +3549,38 @@
}
}
-
-// Construct a PreviousVersionInfo entry
-PreviousVersionInfo::PreviousVersionInfo(PreviousVersionNode *pv_node) {
- _prev_constant_pool_handle = constantPoolHandle(); // NULL handle
- _prev_EMCP_method_handles = NULL;
-
- ConstantPool* cp = pv_node->prev_constant_pool();
- assert(cp != NULL, "constant pool ref was unexpectedly cleared");
- if (cp == NULL) {
- return; // robustness
- }
-
- // make the ConstantPool* safe to return
- _prev_constant_pool_handle = constantPoolHandle(cp);
-
- GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
- if (method_refs == NULL) {
- // the InstanceKlass did not have any EMCP methods
- return;
- }
-
- _prev_EMCP_method_handles = new GrowableArray<methodHandle>(10);
-
- int n_methods = method_refs->length();
- for (int i = 0; i < n_methods; i++) {
- Method* method = method_refs->at(i);
- assert (method != NULL, "method has been cleared");
- if (method == NULL) {
- continue; // robustness
- }
- // make the Method* safe to return
- _prev_EMCP_method_handles->append(methodHandle(method));
- }
-}
-
-
-// Destroy a PreviousVersionInfo
-PreviousVersionInfo::~PreviousVersionInfo() {
- // Since _prev_EMCP_method_handles is not C-heap allocated, we
- // don't have to delete it.
-}
-
-
// Construct a helper for walking the previous versions array
-PreviousVersionWalker::PreviousVersionWalker(InstanceKlass *ik) {
+PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) {
+ _thread = thread;
_previous_versions = ik->previous_versions();
_current_index = 0;
- // _hm needs no initialization
_current_p = NULL;
-}
-
-
-// Destroy a PreviousVersionWalker
-PreviousVersionWalker::~PreviousVersionWalker() {
- // Delete the current info just in case the caller didn't walk to
- // the end of the previous versions list. No harm if _current_p is
- // already NULL.
- delete _current_p;
-
- // When _hm is destroyed, all the Handles returned in
- // PreviousVersionInfo objects will be destroyed.
- // Also, after this destructor is finished it will be
- // safe to delete the GrowableArray allocated in the
- // PreviousVersionInfo objects.
+ _current_constant_pool_handle = constantPoolHandle(thread, ik->constants());
}
// Return the interesting information for the next previous version
// of the klass. Returns NULL if there are no more previous versions.
-PreviousVersionInfo* PreviousVersionWalker::next_previous_version() {
+PreviousVersionNode* PreviousVersionWalker::next_previous_version() {
if (_previous_versions == NULL) {
// no previous versions so nothing to return
return NULL;
}
- delete _current_p; // cleanup the previous info for the caller
- _current_p = NULL; // reset to NULL so we don't delete same object twice
+ _current_p = NULL; // reset to NULL
+ _current_constant_pool_handle = NULL;
int length = _previous_versions->length();
while (_current_index < length) {
PreviousVersionNode * pv_node = _previous_versions->at(_current_index++);
- PreviousVersionInfo * pv_info = new (ResourceObj::C_HEAP, mtClass)
- PreviousVersionInfo(pv_node);
-
- constantPoolHandle cp_h = pv_info->prev_constant_pool_handle();
- assert (!cp_h.is_null(), "null cp found in previous version");
-
- // The caller will need to delete pv_info when they are done with it.
- _current_p = pv_info;
- return pv_info;
+
+ // Save a handle to the constant pool for this previous version,
+ // which keeps all the methods from being deallocated.
+ _current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool());
+ _current_p = pv_node;
+ return pv_node;
}
- // all of the underlying nodes' info has been deleted
return NULL;
} // end next_previous_version()
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Sep 20 09:30:02 2013 -0400
@@ -1136,21 +1136,11 @@
// A collection point for interesting information about the previous
-// version(s) of an InstanceKlass. This class uses weak references to
-// the information so that the information may be collected as needed
-// by the system. If the information is shared, then a regular
-// reference must be used because a weak reference would be seen as
-// collectible. A GrowableArray of PreviousVersionNodes is attached
-// to the InstanceKlass as needed. See PreviousVersionWalker below.
+// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes
+// is attached to the InstanceKlass as needed. See PreviousVersionWalker below.
class PreviousVersionNode : public CHeapObj<mtClass> {
private:
- // A shared ConstantPool is never collected so we'll always have
- // a reference to it so we can update items in the cache. We'll
- // have a weak reference to a non-shared ConstantPool until all
- // of the methods (EMCP or obsolete) have been collected; the
- // non-shared ConstantPool becomes collectible at that point.
- ConstantPool* _prev_constant_pool; // regular or weak reference
- bool _prev_cp_is_weak; // true if not a shared ConstantPool
+ ConstantPool* _prev_constant_pool;
// If the previous version of the InstanceKlass doesn't have any
// EMCP methods, then _prev_EMCP_methods will be NULL. If all the
@@ -1159,8 +1149,8 @@
GrowableArray<Method*>* _prev_EMCP_methods;
public:
- PreviousVersionNode(ConstantPool* prev_constant_pool, bool prev_cp_is_weak,
- GrowableArray<Method*>* prev_EMCP_methods);
+ PreviousVersionNode(ConstantPool* prev_constant_pool,
+ GrowableArray<Method*>* prev_EMCP_methods);
~PreviousVersionNode();
ConstantPool* prev_constant_pool() const {
return _prev_constant_pool;
@@ -1171,59 +1161,26 @@
};
-// A Handle-ized version of PreviousVersionNode.
-class PreviousVersionInfo : public ResourceObj {
- private:
- constantPoolHandle _prev_constant_pool_handle;
- // If the previous version of the InstanceKlass doesn't have any
- // EMCP methods, then _prev_EMCP_methods will be NULL. Since the
- // methods cannot be collected while we hold a handle,
- // _prev_EMCP_methods should never have a length of zero.
- GrowableArray<methodHandle>* _prev_EMCP_method_handles;
-
-public:
- PreviousVersionInfo(PreviousVersionNode *pv_node);
- ~PreviousVersionInfo();
- constantPoolHandle prev_constant_pool_handle() const {
- return _prev_constant_pool_handle;
- }
- GrowableArray<methodHandle>* prev_EMCP_method_handles() const {
- return _prev_EMCP_method_handles;
- }
-};
-
-
-// Helper object for walking previous versions. This helper cleans up
-// the Handles that it allocates when the helper object is destroyed.
-// The PreviousVersionInfo object returned by next_previous_version()
-// is only valid until a subsequent call to next_previous_version() or
-// the helper object is destroyed.
+// Helper object for walking previous versions.
class PreviousVersionWalker : public StackObj {
private:
+ Thread* _thread;
GrowableArray<PreviousVersionNode *>* _previous_versions;
int _current_index;
- // Fields for cleaning up when we are done walking the previous versions:
- // A HandleMark for the PreviousVersionInfo handles:
- HandleMark _hm;
+
+ // A pointer to the current node object so we can handle the deletes.
+ PreviousVersionNode* _current_p;
- // It would be nice to have a ResourceMark field in this helper also,
- // but the ResourceMark code says to be careful to delete handles held
- // in GrowableArrays _before_ deleting the GrowableArray. Since we
- // can't guarantee the order in which the fields are destroyed, we
- // have to let the creator of the PreviousVersionWalker object do
- // the right thing. Also, adding a ResourceMark here causes an
- // include loop.
-
- // A pointer to the current info object so we can handle the deletes.
- PreviousVersionInfo * _current_p;
+ // The constant pool handle keeps all the methods in this class from being
+ // deallocated from the metaspace during class unloading.
+ constantPoolHandle _current_constant_pool_handle;
public:
- PreviousVersionWalker(InstanceKlass *ik);
- ~PreviousVersionWalker();
+ PreviousVersionWalker(Thread* thread, InstanceKlass *ik);
// Return the interesting information for the next previous version
// of the klass. Returns NULL if there are no more previous versions.
- PreviousVersionInfo* next_previous_version();
+ PreviousVersionNode* next_previous_version();
};
--- a/hotspot/src/share/vm/prims/jvm.cpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvm.cpp Fri Sep 20 09:30:02 2013 -0400
@@ -1835,16 +1835,27 @@
}
JVM_END
-JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly))
-{
- JVMWrapper("JVM_GetClassDeclaredMethods");
+static bool select_method(methodHandle method, bool want_constructor) {
+ if (want_constructor) {
+ return (method->is_initializer() && !method->is_static());
+ } else {
+ return (!method->is_initializer() && !method->is_overpass());
+ }
+}
+
+static jobjectArray get_class_declared_methods_helper(
+ JNIEnv *env,
+ jclass ofClass, jboolean publicOnly,
+ bool want_constructor,
+ Klass* klass, TRAPS) {
+
JvmtiVMObjectAllocEventCollector oam;
// Exclude primitive types and array types
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
// Return empty array
- oop res = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), 0, CHECK_NULL);
+ oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
return (jobjectArray) JNIHandles::make_local(env, res);
}
@@ -1855,87 +1866,67 @@
Array<Method*>* methods = k->methods();
int methods_length = methods->length();
+
+ // Save original method_idnum in case of redefinition, which can change
+ // the idnum of obsolete methods. The new method will have the same idnum
+ // but if we refresh the methods array, the counts will be wrong.
+ ResourceMark rm(THREAD);
+ GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
int num_methods = 0;
- int i;
- for (i = 0; i < methods_length; i++) {
+ for (int i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(i));
- if (!method->is_initializer() && !method->is_overpass()) {
+ if (select_method(method, want_constructor)) {
if (!publicOnly || method->is_public()) {
+ idnums->push(method->method_idnum());
++num_methods;
}
}
}
// Allocate result
- objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), num_methods, CHECK_NULL);
+ objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
objArrayHandle result (THREAD, r);
- int out_idx = 0;
- for (i = 0; i < methods_length; i++) {
- methodHandle method(THREAD, methods->at(i));
- if (!method->is_initializer() && !method->is_overpass()) {
- if (!publicOnly || method->is_public()) {
- oop m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL);
- result->obj_at_put(out_idx, m);
- ++out_idx;
+ // Now just put the methods that we selected above, but go by their idnum
+ // in case of redefinition. The methods can be redefined at any safepoint,
+ // so above when allocating the oop array and below when creating reflect
+ // objects.
+ for (int i = 0; i < num_methods; i++) {
+ methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
+ if (method.is_null()) {
+ // Method may have been deleted and seems this API can handle null
+ // Otherwise should probably put a method that throws NSME
+ result->obj_at_put(i, NULL);
+ } else {
+ oop m;
+ if (want_constructor) {
+ m = Reflection::new_constructor(method, CHECK_NULL);
+ } else {
+ m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL);
}
+ result->obj_at_put(i, m);
}
}
- assert(out_idx == num_methods, "just checking");
+
return (jobjectArray) JNIHandles::make_local(env, result());
}
+
+JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly))
+{
+ JVMWrapper("JVM_GetClassDeclaredMethods");
+ return get_class_declared_methods_helper(env, ofClass, publicOnly,
+ /*want_constructor*/ false,
+ SystemDictionary::reflect_Method_klass(), THREAD);
+}
JVM_END
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
JVMWrapper("JVM_GetClassDeclaredConstructors");
- JvmtiVMObjectAllocEventCollector oam;
-
- // Exclude primitive types and array types
- if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
- || java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
- // Return empty array
- oop res = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0 , CHECK_NULL);
- return (jobjectArray) JNIHandles::make_local(env, res);
- }
-
- instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass)));
-
- // Ensure class is linked
- k->link_class(CHECK_NULL);
-
- Array<Method*>* methods = k->methods();
- int methods_length = methods->length();
- int num_constructors = 0;
-
- int i;
- for (i = 0; i < methods_length; i++) {
- methodHandle method(THREAD, methods->at(i));
- if (method->is_initializer() && !method->is_static()) {
- if (!publicOnly || method->is_public()) {
- ++num_constructors;
- }
- }
- }
-
- // Allocate result
- objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), num_constructors, CHECK_NULL);
- objArrayHandle result(THREAD, r);
-
- int out_idx = 0;
- for (i = 0; i < methods_length; i++) {
- methodHandle method(THREAD, methods->at(i));
- if (method->is_initializer() && !method->is_static()) {
- if (!publicOnly || method->is_public()) {
- oop m = Reflection::new_constructor(method, CHECK_NULL);
- result->obj_at_put(out_idx, m);
- ++out_idx;
- }
- }
- }
- assert(out_idx == num_constructors, "just checking");
- return (jobjectArray) JNIHandles::make_local(env, result());
+ return get_class_declared_methods_helper(env, ofClass, publicOnly,
+ /*want_constructor*/ true,
+ SystemDictionary::reflect_Constructor_klass(), THREAD);
}
JVM_END
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Fri Sep 20 09:30:02 2013 -0400
@@ -273,59 +273,49 @@
// add/remove breakpoint to/from versions of the method that
// are EMCP. Directly or transitively obsolete methods are
- // not saved in the PreviousVersionInfo.
+ // not saved in the PreviousVersionNodes.
Thread *thread = Thread::current();
instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder());
Symbol* m_name = _method->name();
Symbol* m_signature = _method->signature();
- {
- ResourceMark rm(thread);
- // PreviousVersionInfo objects returned via PreviousVersionWalker
- // contain a GrowableArray of handles. We have to clean up the
- // GrowableArray _after_ the PreviousVersionWalker destructor
- // has destroyed the handles.
- {
- // search previous versions if they exist
- PreviousVersionWalker pvw((InstanceKlass *)ikh());
- for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
- pv_info != NULL; pv_info = pvw.next_previous_version()) {
- GrowableArray<methodHandle>* methods =
- pv_info->prev_EMCP_method_handles();
+ // search previous versions if they exist
+ PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh());
+ for (PreviousVersionNode * pv_node = pvw.next_previous_version();
+ pv_node != NULL; pv_node = pvw.next_previous_version()) {
+ GrowableArray<Method*>* methods = pv_node->prev_EMCP_methods();
- if (methods == NULL) {
- // We have run into a PreviousVersion generation where
- // all methods were made obsolete during that generation's
- // RedefineClasses() operation. At the time of that
- // operation, all EMCP methods were flushed so we don't
- // have to go back any further.
- //
- // A NULL methods array is different than an empty methods
- // array. We cannot infer any optimizations about older
- // generations from an empty methods array for the current
- // generation.
- break;
- }
+ if (methods == NULL) {
+ // We have run into a PreviousVersion generation where
+ // all methods were made obsolete during that generation's
+ // RedefineClasses() operation. At the time of that
+ // operation, all EMCP methods were flushed so we don't
+ // have to go back any further.
+ //
+ // A NULL methods array is different than an empty methods
+ // array. We cannot infer any optimizations about older
+ // generations from an empty methods array for the current
+ // generation.
+ break;
+ }
- for (int i = methods->length() - 1; i >= 0; i--) {
- methodHandle method = methods->at(i);
- // obsolete methods that are running are not deleted from
- // previous version array, but they are skipped here.
- if (!method->is_obsolete() &&
- method->name() == m_name &&
- method->signature() == m_signature) {
- RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
- meth_act == &Method::set_breakpoint ? "sett" : "clear",
- method->name()->as_C_string(),
- method->signature()->as_C_string()));
+ for (int i = methods->length() - 1; i >= 0; i--) {
+ Method* method = methods->at(i);
+ // obsolete methods that are running are not deleted from
+ // previous version array, but they are skipped here.
+ if (!method->is_obsolete() &&
+ method->name() == m_name &&
+ method->signature() == m_signature) {
+ RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
+ meth_act == &Method::set_breakpoint ? "sett" : "clear",
+ method->name()->as_C_string(),
+ method->signature()->as_C_string()));
- ((Method*)method()->*meth_act)(_bci);
- break;
- }
- }
+ (method->*meth_act)(_bci);
+ break;
}
- } // pvw is cleaned up
- } // rm is cleaned up
+ }
+ }
}
void JvmtiBreakpoint::set() {
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Sep 20 09:30:02 2013 -0400
@@ -2807,28 +2807,20 @@
&trace_name_printed);
}
}
- {
- ResourceMark rm(_thread);
- // PreviousVersionInfo objects returned via PreviousVersionWalker
- // contain a GrowableArray of handles. We have to clean up the
- // GrowableArray _after_ the PreviousVersionWalker destructor
- // has destroyed the handles.
- {
- // the previous versions' constant pool caches may need adjustment
- PreviousVersionWalker pvw(ik);
- for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
- pv_info != NULL; pv_info = pvw.next_previous_version()) {
- other_cp = pv_info->prev_constant_pool_handle();
- cp_cache = other_cp->cache();
- if (cp_cache != NULL) {
- cp_cache->adjust_method_entries(_matching_old_methods,
- _matching_new_methods,
- _matching_methods_length,
- &trace_name_printed);
- }
- }
- } // pvw is cleaned up
- } // rm is cleaned up
+
+ // the previous versions' constant pool caches may need adjustment
+ PreviousVersionWalker pvw(_thread, ik);
+ for (PreviousVersionNode * pv_node = pvw.next_previous_version();
+ pv_node != NULL; pv_node = pvw.next_previous_version()) {
+ other_cp = pv_node->prev_constant_pool();
+ cp_cache = other_cp->cache();
+ if (cp_cache != NULL) {
+ cp_cache->adjust_method_entries(_matching_old_methods,
+ _matching_new_methods,
+ _matching_methods_length,
+ &trace_name_printed);
+ }
+ }
}
}
@@ -2942,10 +2934,9 @@
// obsolete methods need a unique idnum
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
if (num != ConstMethod::UNSET_IDNUM) {
-// u2 old_num = old_method->method_idnum();
old_method->set_method_idnum(num);
-// TO DO: attach obsolete annotations to obsolete method's new idnum
}
+
// With tracing we try not to "yack" too much. The position of
// this trace assumes there are fewer obsolete methods than
// EMCP methods.
--- a/hotspot/src/share/vm/runtime/handles.hpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/runtime/handles.hpp Fri Sep 20 09:30:02 2013 -0400
@@ -136,7 +136,7 @@
// Specific Handles for different oop types
#define DEF_METADATA_HANDLE(name, type) \
class name##Handle; \
- class name##Handle { \
+ class name##Handle : public StackObj { \
type* _value; \
Thread* _thread; \
protected: \
@@ -175,7 +175,7 @@
// Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't
// provide the necessary Klass* <-> Klass* conversions. This Klass
// could be removed when we don't have the Klass* typedef anymore.
-class KlassHandle {
+class KlassHandle : public StackObj {
Klass* _value;
protected:
Klass* obj() const { return _value; }
--- a/hotspot/src/share/vm/runtime/handles.inline.hpp Thu Sep 19 08:47:46 2013 +0200
+++ b/hotspot/src/share/vm/runtime/handles.inline.hpp Fri Sep 20 09:30:02 2013 -0400
@@ -79,6 +79,7 @@
} else { \
_thread = Thread::current(); \
} \
+ assert (_thread->is_in_stack((address)this), "not on stack?"); \
_thread->metadata_handles()->push((Metadata*)_value); \
} else { \
_thread = NULL; \
@@ -95,6 +96,7 @@
} else { \
_thread = Thread::current(); \
} \
+ assert (_thread->is_in_stack((address)this), "not on stack?"); \
_thread->metadata_handles()->push((Metadata*)_value); \
} else { \
_thread = NULL; \