src/share/vm/oops/instanceKlass.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
8055008_3 Cdiff src/share/vm/oops/instanceKlass.cpp
src/share/vm/oops/instanceKlass.cpp
Print this page
*** 2435,2454 ****
if (breakpoints() != 0x0) {
methods_do(clear_all_breakpoints);
assert(breakpoints() == 0x0, "should have cleared breakpoints");
}
- // deallocate information about previous versions
- if (_previous_versions != NULL) {
- for (int i = _previous_versions->length() - 1; i >= 0; i--) {
- PreviousVersionNode * pv_node = _previous_versions->at(i);
- delete pv_node;
- }
- delete _previous_versions;
- _previous_versions = NULL;
- }
-
// deallocate the cached class file
if (_cached_class_file != NULL) {
os::free(_cached_class_file, mtClass);
_cached_class_file = NULL;
}
--- 2435,2444 ----
*** 3018,3037 ****
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();
{
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: ");
generic_signature()->print_value_on(st);
st->cr();
--- 3008,3028 ----
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();
{
bool have_pv = false;
! // previous versions are linked together through the InstanceKlass
! for (InstanceKlass* pv_node = _previous_versions;
! pv_node != NULL;
! pv_node = pv_node->previous_versions()) {
if (!have_pv)
st->print(BULLET"previous version: ");
have_pv = true;
! pv_node->constants()->print_value_on(st);
}
if (have_pv) st->cr();
! }
if (generic_signature() != NULL) {
st->print(BULLET"generic signature: ");
generic_signature()->print_value_on(st);
st->cr();
*** 3441,3702 ****
// RedefineClasses() support for previous versions:
// Purge previous versions
! static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) {
if (ik->previous_versions() != NULL) {
// This klass has previous versions so see what we can cleanup
// while it is safe to do so.
int deleted_count = 0; // leave debugging breadcrumbs
int live_count = 0;
! ClassLoaderData* loader_data = ik->class_loader_data() == NULL ?
! ClassLoaderData::the_null_class_loader_data() :
! ik->class_loader_data();
// RC_TRACE macro has an embedded ResourceMark
! RC_TRACE(0x00000200, ("purge: %s: previous version length=%d",
! ik->external_name(), ik->previous_versions()->length()));
! for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) {
! // check the previous versions array
! PreviousVersionNode * pv_node = ik->previous_versions()->at(i);
! ConstantPool* cp_ref = pv_node->prev_constant_pool();
! assert(cp_ref != NULL, "cp ref was unexpectedly cleared");
- ConstantPool* pvcp = cp_ref;
if (!pvcp->on_stack()) {
// If the constant pool isn't on stack, none of the methods
! // are executing. Delete all the methods, the constant pool and
! // and this previous version node.
! GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
! if (method_refs != NULL) {
! for (int j = method_refs->length() - 1; j >= 0; j--) {
! Method* method = method_refs->at(j);
! assert(method != NULL, "method ref was unexpectedly cleared");
! method_refs->remove_at(j);
! // method will be freed with associated class.
! }
! }
! // Remove the constant pool
! delete pv_node;
! // Since we are traversing the array backwards, we don't have to
! // do anything special with the index.
! ik->previous_versions()->remove_at(i);
deleted_count++;
continue;
} else {
! RC_TRACE(0x00000200, ("purge: previous version @%d is alive", i));
assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
live_count++;
}
! // At least one method is live in this previous version, clean out
! // the others or mark them as obsolete.
! GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
if (method_refs != NULL) {
RC_TRACE(0x00000200, ("purge: previous methods length=%d",
method_refs->length()));
! for (int j = method_refs->length() - 1; j >= 0; j--) {
Method* method = method_refs->at(j);
- assert(method != NULL, "method ref was unexpectedly cleared");
- // Remove the emcp method if it's not executing
- // If it's been made obsolete by a redefinition of a non-emcp
- // method, mark it as obsolete but leave it to clean up later.
if (!method->on_stack()) {
! method_refs->remove_at(j);
! } else if (emcp_method_count == 0) {
! method->set_is_obsolete();
} else {
// RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00000200,
("purge: %s(%s): prev method @%d in version @%d is alive",
method->name()->as_C_string(),
! method->signature()->as_C_string(), j, i));
if (method->method_data() != NULL) {
! // Clean out any weak method links
method->method_data()->clean_weak_method_links();
}
}
}
}
}
- assert(ik->previous_versions()->length() == live_count, "sanity check");
RC_TRACE(0x00000200,
("purge: previous version stats: live=%d, deleted=%d", live_count,
deleted_count));
}
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index2 = 0; index2 < num_methods; ++index2) {
if (methods->at(index2)->method_data() != NULL) {
methods->at(index2)->method_data()->clean_weak_method_links();
}
}
}
! // External interface for use during class unloading.
! void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
! // Call with >0 emcp methods since they are not currently being redefined.
! purge_previous_versions_internal(ik, 1);
! }
!
!
! // Potentially add an information node that contains pointers to the
! // interesting parts of the previous version of the_class.
! // This is also where we clean out any unused references.
! // Note that while we delete nodes from the _previous_versions
! // array, we never delete the array itself until the klass is
! // unloaded. The has_been_redefined() query depends on that fact.
! //
! void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
! BitMap* emcp_methods, int emcp_method_count) {
! assert(Thread::current()->is_VM_thread(),
! "only VMThread can add previous versions");
!
! if (_previous_versions == NULL) {
! // This is the first previous version so make some space.
! // Start with 2 elements under the assumption that the class
! // won't be redefined much.
! _previous_versions = new (ResourceObj::C_HEAP, mtClass)
! GrowableArray<PreviousVersionNode *>(2, true);
! }
!
! ConstantPool* cp_ref = ikh->constants();
!
! // RC_TRACE macro has an embedded ResourceMark
! RC_TRACE(0x00000400, ("adding previous version ref for %s @%d, EMCP_cnt=%d "
! "on_stack=%d",
! ikh->external_name(), _previous_versions->length(), emcp_method_count,
! cp_ref->on_stack()));
!
! // If the constant pool for this previous version of the class
! // is not marked as being on the stack, then none of the methods
! // in this previous version of the class are on the stack so
! // we don't need to create a new PreviousVersionNode. However,
! // we still need to examine older previous versions below.
! Array<Method*>* old_methods = ikh->methods();
!
! if (cp_ref->on_stack()) {
! PreviousVersionNode * pv_node = NULL;
! if (emcp_method_count == 0) {
! // non-shared ConstantPool gets a reference
! 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);
! }
! 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, method_refs);
! }
! // append new previous version.
! _previous_versions->append(pv_node);
! }
!
! // Since the caller is the VMThread and we are at a safepoint, this
! // is a good time to clear out unused references.
!
! RC_TRACE(0x00000400, ("add: previous version length=%d",
! _previous_versions->length()));
!
! // Purge previous versions not executing on the stack
! purge_previous_versions_internal(this, emcp_method_count);
!
int obsolete_method_count = old_methods->length() - emcp_method_count;
if (emcp_method_count != 0 && obsolete_method_count != 0 &&
! _previous_versions->length() > 0) {
// We have a mix of obsolete and EMCP methods so we have to
// clear out any matching EMCP method entries the hard way.
int local_count = 0;
for (int i = 0; i < old_methods->length(); i++) {
- if (!emcp_methods->at(i)) {
- // only obsolete methods are interesting
Method* old_method = old_methods->at(i);
Symbol* m_name = old_method->name();
Symbol* m_signature = old_method->signature();
! // we might not have added the last entry
! for (int j = _previous_versions->length() - 1; j >= 0; j--) {
! // check the previous versions array for non executing obsolete methods
! PreviousVersionNode * pv_node = _previous_versions->at(j);
!
! GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
! if (method_refs == 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 method_refs is different than an empty method_refs.
! // We cannot infer any optimizations about older generations
! // from an empty method_refs for the current generation.
! break;
! }
! for (int k = method_refs->length() - 1; k >= 0; k--) {
Method* method = method_refs->at(k);
if (!method->is_obsolete() &&
method->name() == m_name &&
method->signature() == m_signature) {
// The current RedefineClasses() call has made all EMCP
// versions of this method obsolete so mark it as obsolete
- // and remove the reference.
RC_TRACE(0x00000400,
("add: %s(%s): flush obsolete method @%d in version @%d",
m_name->as_C_string(), m_signature->as_C_string(), k, j));
method->set_is_obsolete();
- // Leave obsolete methods on the previous version list to
- // clean up later.
break;
}
}
// The previous loop may not find a matching EMCP method, but
// that doesn't mean that we can optimize and not go any
// further back in the PreviousVersion generations. The EMCP
! // method for this generation could have already been deleted,
// but there still may be an older EMCP method that has not
! // been deleted.
}
if (++local_count >= obsolete_method_count) {
// no more obsolete methods so bail out now
break;
}
}
}
}
! } // end add_previous_version()
! // Determine if InstanceKlass has a previous version.
! bool InstanceKlass::has_previous_version() const {
! return (_previous_versions != NULL && _previous_versions->length() > 0);
! } // end has_previous_version()
Method* InstanceKlass::method_with_idnum(int idnum) {
Method* m = NULL;
if (idnum < methods()->length()) {
--- 3432,3641 ----
// RedefineClasses() support for previous versions:
// Purge previous versions
! void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
if (ik->previous_versions() != NULL) {
// This klass has previous versions so see what we can cleanup
// while it is safe to do so.
int deleted_count = 0; // leave debugging breadcrumbs
int live_count = 0;
! ClassLoaderData* loader_data = ik->class_loader_data();
! assert(loader_data != NULL, "should never be null");
// RC_TRACE macro has an embedded ResourceMark
! RC_TRACE(0x00000200, ("purge: %s: previous versions", ik->external_name()));
!
! // previous versions are linked together through the InstanceKlass
! InstanceKlass* pv_node = ik->previous_versions();
! InstanceKlass* last = ik;
! int version = 0;
!
! // check the previous versions list
! for (; pv_node != NULL; ) {
! ConstantPool* pvcp = pv_node->constants();
! assert(pvcp != NULL, "cp ref was unexpectedly cleared");
if (!pvcp->on_stack()) {
// If the constant pool isn't on stack, none of the methods
! // are executing. Unlink this previous_version.
! // The previous version InstanceKlass is on the ClassLoaderData deallocate list
! // so will be deallocated during the next phase of class unloading.
! pv_node = pv_node->previous_versions();
! last->link_previous_versions(pv_node);
deleted_count++;
+ version++;
continue;
} else {
! RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive",
! pv_node));
assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
live_count++;
}
! // At least one method is live in this previous version so clean its MethodData.
! // Reset dead EMCP methods not to get breakpoints.
! Array<Method*>* method_refs = pv_node->methods();
if (method_refs != NULL) {
RC_TRACE(0x00000200, ("purge: previous methods length=%d",
method_refs->length()));
! for (int j = 0; j < method_refs->length(); j++) {
Method* method = method_refs->at(j);
if (!method->on_stack()) {
! if (method->is_running_emcp()) {
! method->set_running_emcp(false); // no breakpoints for non-running methods
! }
} else {
+ assert (method->is_obsolete() || method->is_running_emcp(),
+ "emcp method cannot run after emcp bit is cleared");
// RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00000200,
("purge: %s(%s): prev method @%d in version @%d is alive",
method->name()->as_C_string(),
! method->signature()->as_C_string(), j, version));
if (method->method_data() != NULL) {
! // Clean out any weak method links for running methods
! // (also should include not EMCP methods)
method->method_data()->clean_weak_method_links();
}
}
}
}
+ // next previous version
+ last = pv_node;
+ pv_node = pv_node->previous_versions();
+ version++;
}
RC_TRACE(0x00000200,
("purge: previous version stats: live=%d, deleted=%d", live_count,
deleted_count));
}
+ // Clean MethodData of this class's methods so they don't refer to
+ // old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index2 = 0; index2 < num_methods; ++index2) {
if (methods->at(index2)->method_data() != NULL) {
methods->at(index2)->method_data()->clean_weak_method_links();
}
}
}
! void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
! int emcp_method_count) {
int obsolete_method_count = old_methods->length() - emcp_method_count;
if (emcp_method_count != 0 && obsolete_method_count != 0 &&
! _previous_versions != NULL) {
// We have a mix of obsolete and EMCP methods so we have to
// clear out any matching EMCP method entries the hard way.
int local_count = 0;
for (int i = 0; i < old_methods->length(); i++) {
Method* old_method = old_methods->at(i);
+ if (old_method->is_obsolete()) {
+ // only obsolete methods are interesting
Symbol* m_name = old_method->name();
Symbol* m_signature = old_method->signature();
! // previous versions are linked together through the InstanceKlass
! int j = 0;
! for (InstanceKlass* prev_version = _previous_versions;
! prev_version != NULL;
! prev_version = prev_version->previous_versions(), j++) {
! Array<Method*>* method_refs = prev_version->methods();
! for (int k = 0; k < method_refs->length(); k++) {
Method* method = method_refs->at(k);
if (!method->is_obsolete() &&
method->name() == m_name &&
method->signature() == m_signature) {
// The current RedefineClasses() call has made all EMCP
// versions of this method obsolete so mark it as obsolete
RC_TRACE(0x00000400,
("add: %s(%s): flush obsolete method @%d in version @%d",
m_name->as_C_string(), m_signature->as_C_string(), k, j));
method->set_is_obsolete();
break;
}
}
// The previous loop may not find a matching EMCP method, but
// that doesn't mean that we can optimize and not go any
// further back in the PreviousVersion generations. The EMCP
! // method for this generation could have already been made obsolete,
// but there still may be an older EMCP method that has not
! // been made obsolete.
}
if (++local_count >= obsolete_method_count) {
// no more obsolete methods so bail out now
break;
}
}
}
}
! }
!
! // Save the scratch_class as the previous version if any of the methods are running.
! // The previous_versions are used to set breakpoints in EMCP methods and they are
! // also used to clean MethodData links to redefined methods that are no longer running.
! void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
! int emcp_method_count) {
! assert(Thread::current()->is_VM_thread(),
! "only VMThread can add previous versions");
!
! // RC_TRACE macro has an embedded ResourceMark
! RC_TRACE(0x00000400, ("adding previous version ref for %s, EMCP_cnt=%d",
! scratch_class->external_name(), emcp_method_count));
+ // Clean out old previous versions
+ purge_previous_versions(this);
+
+ // Mark newly obsolete methods in remaining previous versions. An EMCP method from
+ // a previous redefinition may be made obsolete by this redefinition.
+ Array<Method*>* old_methods = scratch_class->methods();
+ mark_newly_obsolete_methods(old_methods, emcp_method_count);
+
+ // If the constant pool for this previous version of the class
+ // is not marked as being on the stack, then none of the methods
+ // in this previous version of the class are on the stack so
+ // we don't need to add this as a previous version.
+ ConstantPool* cp_ref = scratch_class->constants();
+ if (cp_ref->on_stack()) {
+ if (emcp_method_count == 0) {
+ RC_TRACE(0x00000400, ("add: all methods are obsolete; no added EMCP refs"));
+ } else {
+ // At least one method is still running, check for EMCP methods
+ for (int i = 0; i < old_methods->length(); i++) {
+ Method* old_method = old_methods->at(i);
+ if (!old_method->is_obsolete() && old_method->on_stack()) {
+ // if EMCP method (not obsolete) is on the stack, mark as EMCP so that
+ // we can add breakpoints for it.
+ old_method->set_running_emcp(true);
+ RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT, old_method->name_and_sig_as_C_string(), old_method));
+ } else if (!old_method->is_obsolete()) {
+ RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT, old_method->name_and_sig_as_C_string(), old_method));
+ }
+ }
+ }
! RC_TRACE(0x00000400, ("add: scratch class added; one of its methods is on_stack"));
! assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version");
! scratch_class->link_previous_versions(previous_versions());
! link_previous_versions(scratch_class());
! } else {
! RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running"));
! }
! } // end add_previous_version()
Method* InstanceKlass::method_with_idnum(int idnum) {
Method* m = NULL;
if (idnum < methods()->length()) {
*** 3720,3782 ****
}
unsigned char * InstanceKlass::get_cached_class_file_bytes() {
return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
}
-
-
- // Construct a PreviousVersionNode entry for the array hung off
- // the InstanceKlass.
- PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
- GrowableArray<Method*>* prev_EMCP_methods) {
-
- _prev_constant_pool = prev_constant_pool;
- _prev_EMCP_methods = prev_EMCP_methods;
- }
-
-
- // Destroy a PreviousVersionNode
- PreviousVersionNode::~PreviousVersionNode() {
- if (_prev_constant_pool != NULL) {
- _prev_constant_pool = NULL;
- }
-
- if (_prev_EMCP_methods != NULL) {
- delete _prev_EMCP_methods;
- }
- }
-
- // Construct a helper for walking the previous versions array
- PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) {
- _thread = thread;
- _previous_versions = ik->previous_versions();
- _current_index = 0;
- _current_p = NULL;
- _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.
- PreviousVersionNode* PreviousVersionWalker::next_previous_version() {
- if (_previous_versions == NULL) {
- // no previous versions so nothing to return
- return NULL;
- }
-
- _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++);
-
- // 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;
- }
-
- return NULL;
- } // end next_previous_version()
--- 3659,3663 ----
src/share/vm/oops/instanceKlass.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File