提交 bcfd8622 编写于 作者: C coleenp

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
上级 7620084e
...@@ -103,9 +103,10 @@ static void calculate_fingerprints() { ...@@ -103,9 +103,10 @@ static void calculate_fingerprints() {
if (k->oop_is_instance()) { if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k); InstanceKlass* ik = InstanceKlass::cast(k);
for (int i = 0; i < ik->methods()->length(); i++) { for (int i = 0; i < ik->methods()->length(); i++) {
ResourceMark rm;
Method* m = ik->methods()->at(i); 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();
} }
} }
} }
......
...@@ -2847,24 +2847,17 @@ void InstanceKlass::print_on(outputStream* st) const { ...@@ -2847,24 +2847,17 @@ void InstanceKlass::print_on(outputStream* st) const {
st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); 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(); st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr();
{ {
ResourceMark rm; bool have_pv = false;
// PreviousVersionInfo objects returned via PreviousVersionWalker PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
// contain a GrowableArray of handles. We have to clean up the for (PreviousVersionNode * pv_node = pvw.next_previous_version();
// GrowableArray _after_ the PreviousVersionWalker destructor pv_node != NULL; pv_node = pvw.next_previous_version()) {
// has destroyed the handles. if (!have_pv)
{ st->print(BULLET"previous version: ");
bool have_pv = false; have_pv = true;
PreviousVersionWalker pvw((InstanceKlass*)this); pv_node->prev_constant_pool()->print_value_on(st);
for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); }
pv_info != NULL; pv_info = pvw.next_previous_version()) { if (have_pv) st->cr();
if (!have_pv) } // pvw is cleaned up
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
if (generic_signature() != NULL) { if (generic_signature() != NULL) {
st->print(BULLET"generic signature: "); st->print(BULLET"generic signature: ");
...@@ -3392,34 +3385,34 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh, ...@@ -3392,34 +3385,34 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
Array<Method*>* old_methods = ikh->methods(); Array<Method*>* old_methods = ikh->methods();
if (cp_ref->on_stack()) { if (cp_ref->on_stack()) {
PreviousVersionNode * pv_node = NULL; PreviousVersionNode * pv_node = NULL;
if (emcp_method_count == 0) { if (emcp_method_count == 0) {
// non-shared ConstantPool gets a reference // non-shared ConstantPool gets a reference
pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), NULL); pv_node = new PreviousVersionNode(cp_ref, NULL);
RC_TRACE(0x00000400, RC_TRACE(0x00000400,
("add: all methods are obsolete; flushing any EMCP refs")); ("add: all methods are obsolete; flushing any EMCP refs"));
} else { } else {
int local_count = 0; int local_count = 0;
GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
GrowableArray<Method*>(emcp_method_count, true); GrowableArray<Method*>(emcp_method_count, true);
for (int i = 0; i < old_methods->length(); i++) { for (int i = 0; i < old_methods->length(); i++) {
if (emcp_methods->at(i)) { if (emcp_methods->at(i)) {
// this old method is EMCP. Save it only if it's on the stack // this old method is EMCP. Save it only if it's on the stack
Method* old_method = old_methods->at(i); Method* old_method = old_methods->at(i);
if (old_method->on_stack()) { if (old_method->on_stack()) {
method_refs->append(old_method); 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 // 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. // 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 // Since the caller is the VMThread and we are at a safepoint, this
...@@ -3520,6 +3513,8 @@ Method* InstanceKlass::method_with_idnum(int idnum) { ...@@ -3520,6 +3513,8 @@ Method* InstanceKlass::method_with_idnum(int idnum) {
return m; return m;
} }
} }
// None found, return null for the caller to handle.
return NULL;
} }
return m; return m;
} }
...@@ -3536,10 +3531,9 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() { ...@@ -3536,10 +3531,9 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() {
// Construct a PreviousVersionNode entry for the array hung off // Construct a PreviousVersionNode entry for the array hung off
// the InstanceKlass. // the InstanceKlass.
PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool, 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_constant_pool = prev_constant_pool;
_prev_cp_is_weak = prev_cp_is_weak;
_prev_EMCP_methods = prev_EMCP_methods; _prev_EMCP_methods = prev_EMCP_methods;
} }
...@@ -3555,99 +3549,38 @@ PreviousVersionNode::~PreviousVersionNode() { ...@@ -3555,99 +3549,38 @@ PreviousVersionNode::~PreviousVersionNode() {
} }
} }
// 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 // 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(); _previous_versions = ik->previous_versions();
_current_index = 0; _current_index = 0;
// _hm needs no initialization
_current_p = NULL; _current_p = NULL;
} _current_constant_pool_handle = constantPoolHandle(thread, ik->constants());
// 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.
} }
// Return the interesting information for the next previous version // Return the interesting information for the next previous version
// of the klass. Returns NULL if there are no more previous versions. // 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) { if (_previous_versions == NULL) {
// no previous versions so nothing to return // no previous versions so nothing to return
return NULL; return NULL;
} }
delete _current_p; // cleanup the previous info for the caller _current_p = NULL; // reset to NULL
_current_p = NULL; // reset to NULL so we don't delete same object twice _current_constant_pool_handle = NULL;
int length = _previous_versions->length(); int length = _previous_versions->length();
while (_current_index < length) { while (_current_index < length) {
PreviousVersionNode * pv_node = _previous_versions->at(_current_index++); 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. // Save a handle to the constant pool for this previous version,
_current_p = pv_info; // which keeps all the methods from being deallocated.
return pv_info; _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; return NULL;
} // end next_previous_version() } // end next_previous_version()
...@@ -1136,21 +1136,11 @@ class BreakpointInfo; ...@@ -1136,21 +1136,11 @@ class BreakpointInfo;
// A collection point for interesting information about the previous // A collection point for interesting information about the previous
// version(s) of an InstanceKlass. This class uses weak references to // version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes
// the information so that the information may be collected as needed // is attached to the InstanceKlass as needed. See PreviousVersionWalker below.
// 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.
class PreviousVersionNode : public CHeapObj<mtClass> { class PreviousVersionNode : public CHeapObj<mtClass> {
private: private:
// A shared ConstantPool is never collected so we'll always have ConstantPool* _prev_constant_pool;
// 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
// If the previous version of the InstanceKlass doesn't have any // If the previous version of the InstanceKlass doesn't have any
// EMCP methods, then _prev_EMCP_methods will be NULL. If all the // EMCP methods, then _prev_EMCP_methods will be NULL. If all the
...@@ -1159,8 +1149,8 @@ class PreviousVersionNode : public CHeapObj<mtClass> { ...@@ -1159,8 +1149,8 @@ class PreviousVersionNode : public CHeapObj<mtClass> {
GrowableArray<Method*>* _prev_EMCP_methods; GrowableArray<Method*>* _prev_EMCP_methods;
public: public:
PreviousVersionNode(ConstantPool* prev_constant_pool, bool prev_cp_is_weak, PreviousVersionNode(ConstantPool* prev_constant_pool,
GrowableArray<Method*>* prev_EMCP_methods); GrowableArray<Method*>* prev_EMCP_methods);
~PreviousVersionNode(); ~PreviousVersionNode();
ConstantPool* prev_constant_pool() const { ConstantPool* prev_constant_pool() const {
return _prev_constant_pool; return _prev_constant_pool;
...@@ -1171,59 +1161,26 @@ public: ...@@ -1171,59 +1161,26 @@ public:
}; };
// A Handle-ized version of PreviousVersionNode. // Helper object for walking previous versions.
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.
class PreviousVersionWalker : public StackObj { class PreviousVersionWalker : public StackObj {
private: private:
Thread* _thread;
GrowableArray<PreviousVersionNode *>* _previous_versions; GrowableArray<PreviousVersionNode *>* _previous_versions;
int _current_index; int _current_index;
// Fields for cleaning up when we are done walking the previous versions:
// A HandleMark for the PreviousVersionInfo handles:
HandleMark _hm;
// It would be nice to have a ResourceMark field in this helper also, // A pointer to the current node object so we can handle the deletes.
// but the ResourceMark code says to be careful to delete handles held PreviousVersionNode* _current_p;
// 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. // The constant pool handle keeps all the methods in this class from being
PreviousVersionInfo * _current_p; // deallocated from the metaspace during class unloading.
constantPoolHandle _current_constant_pool_handle;
public: public:
PreviousVersionWalker(InstanceKlass *ik); PreviousVersionWalker(Thread* thread, InstanceKlass *ik);
~PreviousVersionWalker();
// Return the interesting information for the next previous version // Return the interesting information for the next previous version
// of the klass. Returns NULL if there are no more previous versions. // of the klass. Returns NULL if there are no more previous versions.
PreviousVersionInfo* next_previous_version(); PreviousVersionNode* next_previous_version();
}; };
......
...@@ -1835,16 +1835,27 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, ...@@ -1835,16 +1835,27 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
} }
JVM_END JVM_END
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly)) static bool select_method(methodHandle method, bool want_constructor) {
{ if (want_constructor) {
JVMWrapper("JVM_GetClassDeclaredMethods"); 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; JvmtiVMObjectAllocEventCollector oam;
// Exclude primitive types and array types // Exclude primitive types and array types
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) { || java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
// Return empty 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); return (jobjectArray) JNIHandles::make_local(env, res);
} }
...@@ -1855,87 +1866,67 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, ...@@ -1855,87 +1866,67 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass,
Array<Method*>* methods = k->methods(); Array<Method*>* methods = k->methods();
int methods_length = methods->length(); 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 num_methods = 0;
int i; for (int i = 0; i < methods_length; i++) {
for (i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(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()) { if (!publicOnly || method->is_public()) {
idnums->push(method->method_idnum());
++num_methods; ++num_methods;
} }
} }
} }
// Allocate result // 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); objArrayHandle result (THREAD, r);
int out_idx = 0; // Now just put the methods that we selected above, but go by their idnum
for (i = 0; i < methods_length; i++) { // in case of redefinition. The methods can be redefined at any safepoint,
methodHandle method(THREAD, methods->at(i)); // so above when allocating the oop array and below when creating reflect
if (!method->is_initializer() && !method->is_overpass()) { // objects.
if (!publicOnly || method->is_public()) { for (int i = 0; i < num_methods; i++) {
oop m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL); methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
result->obj_at_put(out_idx, m); if (method.is_null()) {
++out_idx; // 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()); 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_END
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly)) JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{ {
JVMWrapper("JVM_GetClassDeclaredConstructors"); JVMWrapper("JVM_GetClassDeclaredConstructors");
JvmtiVMObjectAllocEventCollector oam; return get_class_declared_methods_helper(env, ofClass, publicOnly,
/*want_constructor*/ true,
// Exclude primitive types and array types SystemDictionary::reflect_Constructor_klass(), THREAD);
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());
} }
JVM_END JVM_END
......
...@@ -273,59 +273,49 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { ...@@ -273,59 +273,49 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
// add/remove breakpoint to/from versions of the method that // add/remove breakpoint to/from versions of the method that
// are EMCP. Directly or transitively obsolete methods are // are EMCP. Directly or transitively obsolete methods are
// not saved in the PreviousVersionInfo. // not saved in the PreviousVersionNodes.
Thread *thread = Thread::current(); Thread *thread = Thread::current();
instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder()); instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder());
Symbol* m_name = _method->name(); Symbol* m_name = _method->name();
Symbol* m_signature = _method->signature(); Symbol* m_signature = _method->signature();
{ // search previous versions if they exist
ResourceMark rm(thread); PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh());
// PreviousVersionInfo objects returned via PreviousVersionWalker for (PreviousVersionNode * pv_node = pvw.next_previous_version();
// contain a GrowableArray of handles. We have to clean up the pv_node != NULL; pv_node = pvw.next_previous_version()) {
// GrowableArray _after_ the PreviousVersionWalker destructor GrowableArray<Method*>* methods = pv_node->prev_EMCP_methods();
// has destroyed the handles.
{ if (methods == NULL) {
// search previous versions if they exist // We have run into a PreviousVersion generation where
PreviousVersionWalker pvw((InstanceKlass *)ikh()); // all methods were made obsolete during that generation's
for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); // RedefineClasses() operation. At the time of that
pv_info != NULL; pv_info = pvw.next_previous_version()) { // operation, all EMCP methods were flushed so we don't
GrowableArray<methodHandle>* methods = // have to go back any further.
pv_info->prev_EMCP_method_handles(); //
// A NULL methods array is different than an empty methods
if (methods == NULL) { // array. We cannot infer any optimizations about older
// We have run into a PreviousVersion generation where // generations from an empty methods array for the current
// all methods were made obsolete during that generation's // generation.
// RedefineClasses() operation. At the time of that break;
// 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--) { for (int i = methods->length() - 1; i >= 0; i--) {
methodHandle method = methods->at(i); Method* method = methods->at(i);
// obsolete methods that are running are not deleted from // obsolete methods that are running are not deleted from
// previous version array, but they are skipped here. // previous version array, but they are skipped here.
if (!method->is_obsolete() && if (!method->is_obsolete() &&
method->name() == m_name && method->name() == m_name &&
method->signature() == m_signature) { method->signature() == m_signature) {
RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)", RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
meth_act == &Method::set_breakpoint ? "sett" : "clear", meth_act == &Method::set_breakpoint ? "sett" : "clear",
method->name()->as_C_string(), method->name()->as_C_string(),
method->signature()->as_C_string())); method->signature()->as_C_string()));
((Method*)method()->*meth_act)(_bci); (method->*meth_act)(_bci);
break; break;
}
}
} }
} // pvw is cleaned up }
} // rm is cleaned up }
} }
void JvmtiBreakpoint::set() { void JvmtiBreakpoint::set() {
......
...@@ -2807,28 +2807,20 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) { ...@@ -2807,28 +2807,20 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
&trace_name_printed); &trace_name_printed);
} }
} }
{
ResourceMark rm(_thread); // the previous versions' constant pool caches may need adjustment
// PreviousVersionInfo objects returned via PreviousVersionWalker PreviousVersionWalker pvw(_thread, ik);
// contain a GrowableArray of handles. We have to clean up the for (PreviousVersionNode * pv_node = pvw.next_previous_version();
// GrowableArray _after_ the PreviousVersionWalker destructor pv_node != NULL; pv_node = pvw.next_previous_version()) {
// has destroyed the handles. other_cp = pv_node->prev_constant_pool();
{ cp_cache = other_cp->cache();
// the previous versions' constant pool caches may need adjustment if (cp_cache != NULL) {
PreviousVersionWalker pvw(ik); cp_cache->adjust_method_entries(_matching_old_methods,
for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); _matching_new_methods,
pv_info != NULL; pv_info = pvw.next_previous_version()) { _matching_methods_length,
other_cp = pv_info->prev_constant_pool_handle(); &trace_name_printed);
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
} }
} }
...@@ -2942,10 +2934,9 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete( ...@@ -2942,10 +2934,9 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
// obsolete methods need a unique idnum // obsolete methods need a unique idnum
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum(); u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
if (num != ConstMethod::UNSET_IDNUM) { if (num != ConstMethod::UNSET_IDNUM) {
// u2 old_num = old_method->method_idnum();
old_method->set_method_idnum(num); 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 // With tracing we try not to "yack" too much. The position of
// this trace assumes there are fewer obsolete methods than // this trace assumes there are fewer obsolete methods than
// EMCP methods. // EMCP methods.
......
...@@ -136,7 +136,7 @@ DEF_HANDLE(typeArray , is_typeArray ) ...@@ -136,7 +136,7 @@ DEF_HANDLE(typeArray , is_typeArray )
// Specific Handles for different oop types // Specific Handles for different oop types
#define DEF_METADATA_HANDLE(name, type) \ #define DEF_METADATA_HANDLE(name, type) \
class name##Handle; \ class name##Handle; \
class name##Handle { \ class name##Handle : public StackObj { \
type* _value; \ type* _value; \
Thread* _thread; \ Thread* _thread; \
protected: \ protected: \
...@@ -175,7 +175,7 @@ DEF_METADATA_HANDLE(constantPool, ConstantPool) ...@@ -175,7 +175,7 @@ DEF_METADATA_HANDLE(constantPool, ConstantPool)
// Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't // Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't
// provide the necessary Klass* <-> Klass* conversions. This Klass // provide the necessary Klass* <-> Klass* conversions. This Klass
// could be removed when we don't have the Klass* typedef anymore. // could be removed when we don't have the Klass* typedef anymore.
class KlassHandle { class KlassHandle : public StackObj {
Klass* _value; Klass* _value;
protected: protected:
Klass* obj() const { return _value; } Klass* obj() const { return _value; }
......
...@@ -79,6 +79,7 @@ inline name##Handle::name##Handle(const name##Handle &h) { \ ...@@ -79,6 +79,7 @@ inline name##Handle::name##Handle(const name##Handle &h) { \
} else { \ } else { \
_thread = Thread::current(); \ _thread = Thread::current(); \
} \ } \
assert (_thread->is_in_stack((address)this), "not on stack?"); \
_thread->metadata_handles()->push((Metadata*)_value); \ _thread->metadata_handles()->push((Metadata*)_value); \
} else { \ } else { \
_thread = NULL; \ _thread = NULL; \
...@@ -95,6 +96,7 @@ inline name##Handle& name##Handle::operator=(const name##Handle &s) { \ ...@@ -95,6 +96,7 @@ inline name##Handle& name##Handle::operator=(const name##Handle &s) { \
} else { \ } else { \
_thread = Thread::current(); \ _thread = Thread::current(); \
} \ } \
assert (_thread->is_in_stack((address)this), "not on stack?"); \
_thread->metadata_handles()->push((Metadata*)_value); \ _thread->metadata_handles()->push((Metadata*)_value); \
} else { \ } else { \
_thread = NULL; \ _thread = NULL; \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册