mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8022887: Assertion hit while using class and redefining it with RedefineClasses simultaneously
Need to refetch each method from InstanceKlass after all safepoints. Removed leaky PreviousVersionInfo code. Reviewed-by: dcubed, sspitsyn
This commit is contained in:
parent
d2b68f0d0f
commit
ec5e07f810
8 changed files with 169 additions and 304 deletions
|
@ -103,9 +103,10 @@ static void calculate_fingerprints() {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2846,25 +2846,18 @@ void InstanceKlass::print_on(outputStream* st) const {
|
|||
st->print(BULLET"class type annotations: "); class_type_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();
|
||||
{
|
||||
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()) {
|
||||
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_info->prev_constant_pool_handle()()->print_value_on(st);
|
||||
pv_node->prev_constant_pool()->print_value_on(st);
|
||||
}
|
||||
if (have_pv) st->cr();
|
||||
} // pvw is cleaned up
|
||||
} // rm is cleaned up
|
||||
|
||||
if (generic_signature() != NULL) {
|
||||
st->print(BULLET"generic signature: ");
|
||||
|
@ -3395,7 +3388,7 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
|||
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);
|
||||
pv_node = new PreviousVersionNode(cp_ref, NULL);
|
||||
RC_TRACE(0x00000400,
|
||||
("add: all methods are obsolete; flushing any EMCP refs"));
|
||||
} else {
|
||||
|
@ -3416,7 +3409,7 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
|||
}
|
||||
}
|
||||
// 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);
|
||||
|
@ -3520,6 +3513,8 @@ Method* InstanceKlass::method_with_idnum(int idnum) {
|
|||
return m;
|
||||
}
|
||||
}
|
||||
// None found, return null for the caller to handle.
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
@ -3536,10 +3531,9 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() {
|
|||
// 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 @@ 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
|
||||
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()
|
||||
|
|
|
@ -1136,21 +1136,11 @@ class BreakpointInfo;
|
|||
|
||||
|
||||
// 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,7 +1149,7 @@ class PreviousVersionNode : public CHeapObj<mtClass> {
|
|||
GrowableArray<Method*>* _prev_EMCP_methods;
|
||||
|
||||
public:
|
||||
PreviousVersionNode(ConstantPool* prev_constant_pool, bool prev_cp_is_weak,
|
||||
PreviousVersionNode(ConstantPool* prev_constant_pool,
|
||||
GrowableArray<Method*>* prev_EMCP_methods);
|
||||
~PreviousVersionNode();
|
||||
ConstantPool* prev_constant_pool() const {
|
||||
|
@ -1171,59 +1161,26 @@ public:
|
|||
};
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// 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 node object so we can handle the deletes.
|
||||
PreviousVersionNode* _current_p;
|
||||
|
||||
// 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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1835,16 +1835,27 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
|
|||
}
|
||||
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 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass,
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -273,25 +273,17 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
|
|||
|
||||
// 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();
|
||||
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
|
||||
|
@ -308,7 +300,7 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
|
|||
}
|
||||
|
||||
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
|
||||
// previous version array, but they are skipped here.
|
||||
if (!method->is_obsolete() &&
|
||||
|
@ -319,13 +311,11 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
|
|||
method->name()->as_C_string(),
|
||||
method->signature()->as_C_string()));
|
||||
|
||||
((Method*)method()->*meth_act)(_bci);
|
||||
(method->*meth_act)(_bci);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // pvw is cleaned up
|
||||
} // rm is cleaned up
|
||||
}
|
||||
|
||||
void JvmtiBreakpoint::set() {
|
||||
|
|
|
@ -2807,18 +2807,12 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
|||
&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();
|
||||
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,
|
||||
|
@ -2827,8 +2821,6 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
|||
&trace_name_printed);
|
||||
}
|
||||
}
|
||||
} // pvw is cleaned up
|
||||
} // rm is cleaned up
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2942,10 +2934,9 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
|||
// 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.
|
||||
|
|
|
@ -136,7 +136,7 @@ DEF_HANDLE(typeArray , is_typeArray )
|
|||
// 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 @@ DEF_METADATA_HANDLE(constantPool, ConstantPool)
|
|||
// 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; }
|
||||
|
|
|
@ -79,6 +79,7 @@ inline name##Handle::name##Handle(const name##Handle &h) { \
|
|||
} 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 @@ inline name##Handle& name##Handle::operator=(const name##Handle &s) { \
|
|||
} else { \
|
||||
_thread = Thread::current(); \
|
||||
} \
|
||||
assert (_thread->is_in_stack((address)this), "not on stack?"); \
|
||||
_thread->metadata_handles()->push((Metadata*)_value); \
|
||||
} else { \
|
||||
_thread = NULL; \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue