mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
7182152: Instrumentation hot swap test incorrect monitor count
Add/refine new tracing support using -XX:TraceRedefineClasses=16384. Reviewed-by: coleenp, acorn, sspitsyn
This commit is contained in:
parent
de47c5722f
commit
8ef946f380
11 changed files with 253 additions and 152 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -401,8 +401,9 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(constantPoolHandle cpool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// If this constantPoolCacheEntry refers to old_method then update it
|
// If this ConstantPoolCacheEntry refers to old_method then update it
|
||||||
// to refer to new_method.
|
// to refer to new_method.
|
||||||
bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||||
Method* new_method, bool * trace_name_printed) {
|
Method* new_method, bool * trace_name_printed) {
|
||||||
|
@ -460,16 +461,24 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
// a constant pool cache entry should never contain old or obsolete methods
|
||||||
bool ConstantPoolCacheEntry::check_no_old_entries() {
|
bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
|
||||||
if (is_vfinal()) {
|
if (is_vfinal()) {
|
||||||
|
// virtual and final so _f2 contains method ptr instead of vtable index
|
||||||
Metadata* f2 = (Metadata*)_f2;
|
Metadata* f2 = (Metadata*)_f2;
|
||||||
return (f2->is_valid() && f2->is_method() && !((Method*)f2)->is_old());
|
// Return false if _f2 refers to an old or an obsolete method.
|
||||||
} else {
|
// _f2 == NULL || !_f2->is_method() are just as unexpected here.
|
||||||
return (_f1 == NULL || (_f1->is_valid() && _f1->is_method() && !((Method*)_f1)->is_old()));
|
return (f2 != NULL NOT_PRODUCT(&& f2->is_valid()) && f2->is_method() &&
|
||||||
|
!((Method*)f2)->is_old() && !((Method*)f2)->is_obsolete());
|
||||||
|
} else if (_f1 == NULL ||
|
||||||
|
(NOT_PRODUCT(_f1->is_valid() &&) !_f1->is_method())) {
|
||||||
|
// _f1 == NULL || !_f1->is_method() are OK here
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
// return false if _f1 refers to an old or an obsolete method
|
||||||
|
return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() &&
|
||||||
|
!((Method*)_f1)->is_old() && !((Method*)_f1)->is_obsolete());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) {
|
bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) {
|
||||||
if (!is_method_entry()) {
|
if (!is_method_entry()) {
|
||||||
|
@ -502,13 +511,15 @@ bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) {
|
||||||
// the method is in the interesting class so the entry is interesting
|
// the method is in the interesting class so the entry is interesting
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::print(outputStream* st, int index) const {
|
void ConstantPoolCacheEntry::print(outputStream* st, int index) const {
|
||||||
// print separator
|
// print separator
|
||||||
if (index == 0) st->print_cr(" -------------");
|
if (index == 0) st->print_cr(" -------------");
|
||||||
// print entry
|
// print entry
|
||||||
st->print("%3d ("PTR_FORMAT") ", index, (intptr_t)this);
|
st->print("%3d ("PTR_FORMAT") ", index, (intptr_t)this);
|
||||||
st->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), constant_pool_index());
|
st->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(),
|
||||||
|
constant_pool_index());
|
||||||
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f1);
|
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f1);
|
||||||
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f2);
|
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f2);
|
||||||
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_flags);
|
st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_flags);
|
||||||
|
@ -552,8 +563,9 @@ void ConstantPoolCache::initialize(intArray& inverse_index_map, intArray& invoke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// If any entry of this constantPoolCache points to any of
|
// If any entry of this ConstantPoolCache points to any of
|
||||||
// old_methods, replace it with the corresponding new_method.
|
// old_methods, replace it with the corresponding new_method.
|
||||||
void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new_methods,
|
void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed) {
|
int methods_length, bool * trace_name_printed) {
|
||||||
|
@ -572,7 +584,7 @@ void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The constantPoolCache contains entries for several different
|
// The ConstantPoolCache contains entries for several different
|
||||||
// things, but we only care about methods. In fact, we only care
|
// things, but we only care about methods. In fact, we only care
|
||||||
// about methods in the same class as the one that contains the
|
// about methods in the same class as the one that contains the
|
||||||
// old_methods. At this point, we have an interesting entry.
|
// old_methods. At this point, we have an interesting entry.
|
||||||
|
@ -591,17 +603,25 @@ void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
// the constant pool cache should never contain old or obsolete methods
|
||||||
bool ConstantPoolCache::check_no_old_entries() {
|
bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
|
||||||
for (int i = 1; i < length(); i++) {
|
for (int i = 1; i < length(); i++) {
|
||||||
if (entry_at(i)->is_interesting_method_entry(NULL) &&
|
if (entry_at(i)->is_interesting_method_entry(NULL) &&
|
||||||
!entry_at(i)->check_no_old_entries()) {
|
!entry_at(i)->check_no_old_or_obsolete_entries()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
|
||||||
|
void ConstantPoolCache::dump_cache() {
|
||||||
|
for (int i = 1; i < length(); i++) {
|
||||||
|
if (entry_at(i)->is_interesting_method_entry(NULL)) {
|
||||||
|
entry_at(i)->print(tty, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -337,16 +337,18 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); }
|
static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); }
|
||||||
static ByteSize flags_offset() { return byte_offset_of(ConstantPoolCacheEntry, _flags); }
|
static ByteSize flags_offset() { return byte_offset_of(ConstantPoolCacheEntry, _flags); }
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// If this constantPoolCacheEntry refers to old_method then update it
|
// If this ConstantPoolCacheEntry refers to old_method then update it
|
||||||
// to refer to new_method.
|
// to refer to new_method.
|
||||||
// trace_name_printed is set to true if the current call has
|
// trace_name_printed is set to true if the current call has
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
bool adjust_method_entry(Method* old_method, Method* new_method,
|
bool adjust_method_entry(Method* old_method, Method* new_method,
|
||||||
bool * trace_name_printed);
|
bool * trace_name_printed);
|
||||||
NOT_PRODUCT(bool check_no_old_entries();)
|
bool check_no_old_or_obsolete_entries();
|
||||||
bool is_interesting_method_entry(Klass* k);
|
bool is_interesting_method_entry(Klass* k);
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Debugging & Printing
|
// Debugging & Printing
|
||||||
void print (outputStream* st, int index) const;
|
void print (outputStream* st, int index) const;
|
||||||
|
@ -423,15 +425,18 @@ class ConstantPoolCache: public MetaspaceObj {
|
||||||
return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index);
|
return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// If any entry of this constantPoolCache points to any of
|
// If any entry of this ConstantPoolCache points to any of
|
||||||
// old_methods, replace it with the corresponding new_method.
|
// old_methods, replace it with the corresponding new_method.
|
||||||
// trace_name_printed is set to true if the current call has
|
// trace_name_printed is set to true if the current call has
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed);
|
int methods_length, bool * trace_name_printed);
|
||||||
NOT_PRODUCT(bool check_no_old_entries();)
|
bool check_no_old_or_obsolete_entries();
|
||||||
|
void dump_cache();
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Deallocate - no fields to deallocate
|
// Deallocate - no fields to deallocate
|
||||||
DEBUG_ONLY(bool on_stack() { return false; })
|
DEBUG_ONLY(bool on_stack() { return false; })
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -610,6 +610,7 @@ void klassVtable::copy_vtable_to(vtableEntry* start) {
|
||||||
Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size());
|
Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed) {
|
int methods_length, bool * trace_name_printed) {
|
||||||
// search the vtable for uses of either obsolete or EMCP methods
|
// search the vtable for uses of either obsolete or EMCP methods
|
||||||
|
@ -638,11 +639,39 @@ void klassVtable::adjust_method_entries(Method** old_methods, Method** new_metho
|
||||||
new_method->name()->as_C_string(),
|
new_method->name()->as_C_string(),
|
||||||
new_method->signature()->as_C_string()));
|
new_method->signature()->as_C_string()));
|
||||||
}
|
}
|
||||||
|
// cannot 'break' here; see for-loop comment above.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a vtable should never contain old or obsolete methods
|
||||||
|
bool klassVtable::check_no_old_or_obsolete_entries() {
|
||||||
|
for (int i = 0; i < length(); i++) {
|
||||||
|
Method* m = unchecked_method_at(i);
|
||||||
|
if (m != NULL &&
|
||||||
|
(NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void klassVtable::dump_vtable() {
|
||||||
|
tty->print_cr("vtable dump --");
|
||||||
|
for (int i = 0; i < length(); i++) {
|
||||||
|
Method* m = unchecked_method_at(i);
|
||||||
|
if (m != NULL) {
|
||||||
|
tty->print(" (%5d) ", i);
|
||||||
|
m->access_flags().print_on(tty);
|
||||||
|
tty->print(" -- ");
|
||||||
|
m->print_name(tty);
|
||||||
|
tty->cr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// CDS/RedefineClasses support - clear vtables so they can be reinitialized
|
// CDS/RedefineClasses support - clear vtables so they can be reinitialized
|
||||||
void klassVtable::clear_vtable() {
|
void klassVtable::clear_vtable() {
|
||||||
for (int i = 0; i < _length; i++) table()[i].clear();
|
for (int i = 0; i < _length; i++) table()[i].clear();
|
||||||
|
@ -805,6 +834,7 @@ void klassItable::initialize_with_method(Method* m) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
void klassItable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
void klassItable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed) {
|
int methods_length, bool * trace_name_printed) {
|
||||||
// search the itable for uses of either obsolete or EMCP methods
|
// search the itable for uses of either obsolete or EMCP methods
|
||||||
|
@ -833,13 +863,44 @@ void klassItable::adjust_method_entries(Method** old_methods, Method** new_metho
|
||||||
new_method->name()->as_C_string(),
|
new_method->name()->as_C_string(),
|
||||||
new_method->signature()->as_C_string()));
|
new_method->signature()->as_C_string()));
|
||||||
}
|
}
|
||||||
// Cannot break because there might be another entry for this method
|
// cannot 'break' here; see for-loop comment above.
|
||||||
}
|
}
|
||||||
ime++;
|
ime++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an itable should never contain old or obsolete methods
|
||||||
|
bool klassItable::check_no_old_or_obsolete_entries() {
|
||||||
|
itableMethodEntry* ime = method_entry(0);
|
||||||
|
for (int i = 0; i < _size_method_table; i++) {
|
||||||
|
Method* m = ime->method();
|
||||||
|
if (m != NULL &&
|
||||||
|
(NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ime++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void klassItable::dump_itable() {
|
||||||
|
itableMethodEntry* ime = method_entry(0);
|
||||||
|
tty->print_cr("itable dump --");
|
||||||
|
for (int i = 0; i < _size_method_table; i++) {
|
||||||
|
Method* m = ime->method();
|
||||||
|
if (m != NULL) {
|
||||||
|
tty->print(" (%5d) ", i);
|
||||||
|
m->access_flags().print_on(tty);
|
||||||
|
tty->print(" -- ");
|
||||||
|
m->print_name(tty);
|
||||||
|
tty->cr();
|
||||||
|
}
|
||||||
|
ime++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
class InterfaceVisiterClosure : public StackObj {
|
class InterfaceVisiterClosure : public StackObj {
|
||||||
|
@ -1126,43 +1187,6 @@ void klassVtable::print_statistics() {
|
||||||
tty->print_cr("%6d bytes total", total);
|
tty->print_cr("%6d bytes total", total);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool klassVtable::check_no_old_entries() {
|
|
||||||
// Check that there really is no entry
|
|
||||||
for (int i = 0; i < length(); i++) {
|
|
||||||
Method* m = unchecked_method_at(i);
|
|
||||||
if (m != NULL) {
|
|
||||||
if (!m->is_valid() || m->is_old()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void klassVtable::dump_vtable() {
|
|
||||||
tty->print_cr("vtable dump --");
|
|
||||||
for (int i = 0; i < length(); i++) {
|
|
||||||
Method* m = unchecked_method_at(i);
|
|
||||||
if (m != NULL) {
|
|
||||||
tty->print(" (%5d) ", i);
|
|
||||||
m->access_flags().print_on(tty);
|
|
||||||
tty->print(" -- ");
|
|
||||||
m->print_name(tty);
|
|
||||||
tty->cr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool klassItable::check_no_old_entries() {
|
|
||||||
itableMethodEntry* ime = method_entry(0);
|
|
||||||
for(int i = 0; i < _size_method_table; i++) {
|
|
||||||
Method* m = ime->method();
|
|
||||||
if (m != NULL && (!m->is_valid() || m->is_old())) return false;
|
|
||||||
ime++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int klassItable::_total_classes; // Total no. of classes with itables
|
int klassItable::_total_classes; // Total no. of classes with itables
|
||||||
long klassItable::_total_size; // Total no. of bytes used for itables
|
long klassItable::_total_size; // Total no. of bytes used for itables
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -90,6 +90,7 @@ class klassVtable : public ResourceObj {
|
||||||
Array<Method*>* methods, AccessFlags class_flags, Handle classloader,
|
Array<Method*>* methods, AccessFlags class_flags, Handle classloader,
|
||||||
Symbol* classname, Array<Klass*>* local_interfaces, TRAPS);
|
Symbol* classname, Array<Klass*>* local_interfaces, TRAPS);
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// If any entry of this vtable points to any of old_methods,
|
// If any entry of this vtable points to any of old_methods,
|
||||||
// replace it with the corresponding new_method.
|
// replace it with the corresponding new_method.
|
||||||
|
@ -98,17 +99,15 @@ class klassVtable : public ResourceObj {
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed);
|
int methods_length, bool * trace_name_printed);
|
||||||
|
bool check_no_old_or_obsolete_entries();
|
||||||
|
void dump_vtable();
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Debugging code
|
// Debugging code
|
||||||
void print() PRODUCT_RETURN;
|
void print() PRODUCT_RETURN;
|
||||||
void verify(outputStream* st, bool force = false);
|
void verify(outputStream* st, bool force = false);
|
||||||
static void print_statistics() PRODUCT_RETURN;
|
static void print_statistics() PRODUCT_RETURN;
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
bool check_no_old_entries();
|
|
||||||
void dump_vtable();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class vtableEntry;
|
friend class vtableEntry;
|
||||||
private:
|
private:
|
||||||
|
@ -275,6 +274,7 @@ class klassItable : public ResourceObj {
|
||||||
// Updates
|
// Updates
|
||||||
void initialize_with_method(Method* m);
|
void initialize_with_method(Method* m);
|
||||||
|
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
// RedefineClasses() API support:
|
// RedefineClasses() API support:
|
||||||
// if any entry of this itable points to any of old_methods,
|
// if any entry of this itable points to any of old_methods,
|
||||||
// replace it with the corresponding new_method.
|
// replace it with the corresponding new_method.
|
||||||
|
@ -283,6 +283,9 @@ class klassItable : public ResourceObj {
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed);
|
int methods_length, bool * trace_name_printed);
|
||||||
|
bool check_no_old_or_obsolete_entries();
|
||||||
|
void dump_itable();
|
||||||
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Setup of itable
|
// Setup of itable
|
||||||
static int compute_itable_size(Array<Klass*>* transitive_interfaces);
|
static int compute_itable_size(Array<Klass*>* transitive_interfaces);
|
||||||
|
@ -307,11 +310,6 @@ class klassItable : public ResourceObj {
|
||||||
NOT_PRODUCT(static long _total_size;) // Total no. of bytes used for itables
|
NOT_PRODUCT(static long _total_size;) // Total no. of bytes used for itables
|
||||||
|
|
||||||
static void update_stats(int size) PRODUCT_RETURN NOT_PRODUCT({ _total_classes++; _total_size += size; })
|
static void update_stats(int size) PRODUCT_RETURN NOT_PRODUCT({ _total_classes++; _total_size += size; })
|
||||||
|
|
||||||
public:
|
|
||||||
#ifndef PRODUCT
|
|
||||||
bool check_no_old_entries();
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_OOPS_KLASSVTABLE_HPP
|
#endif // SHARE_VM_OOPS_KLASSVTABLE_HPP
|
||||||
|
|
|
@ -1386,9 +1386,9 @@ void Method::sort_methods(Array<Method*>* methods,
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
// Non-product code
|
// Non-product code unless JVM/TI needs it
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#if !defined(PRODUCT) || INCLUDE_JVMTI
|
||||||
class SignatureTypePrinter : public SignatureTypeNames {
|
class SignatureTypePrinter : public SignatureTypeNames {
|
||||||
private:
|
private:
|
||||||
outputStream* _st;
|
outputStream* _st;
|
||||||
|
@ -1423,8 +1423,13 @@ void Method::print_name(outputStream* st) {
|
||||||
sig.print_parameters();
|
sig.print_parameters();
|
||||||
st->print(")");
|
st->print(")");
|
||||||
}
|
}
|
||||||
|
#endif // !PRODUCT || INCLUDE_JVMTI
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
// Non-product code
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
void Method::print_codes_on(outputStream* st) const {
|
void Method::print_codes_on(outputStream* st) const {
|
||||||
print_codes_on(0, code_size(), st);
|
print_codes_on(0, code_size(), st);
|
||||||
}
|
}
|
||||||
|
|
|
@ -800,8 +800,12 @@ class Method : public Metadata {
|
||||||
static bool has_unloaded_classes_in_signature(methodHandle m, TRAPS);
|
static bool has_unloaded_classes_in_signature(methodHandle m, TRAPS);
|
||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
void print_short_name(outputStream* st = tty) /*PRODUCT_RETURN*/; // prints as klassname::methodname; Exposed so field engineers can debug VM
|
void print_short_name(outputStream* st = tty); // prints as klassname::methodname; Exposed so field engineers can debug VM
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
void print_name(outputStream* st = tty); // prints as "virtual void foo(int)"; exposed for TraceRedefineClasses
|
||||||
|
#else
|
||||||
void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)"
|
void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Helper routine used for method sorting
|
// Helper routine used for method sorting
|
||||||
static void sort_methods(Array<Method*>* methods,
|
static void sort_methods(Array<Method*>* methods,
|
||||||
|
|
|
@ -154,8 +154,15 @@ void VM_RedefineClasses::doit() {
|
||||||
// See jvmtiExport.hpp for detailed explanation.
|
// See jvmtiExport.hpp for detailed explanation.
|
||||||
JvmtiExport::set_has_redefined_a_class();
|
JvmtiExport::set_has_redefined_a_class();
|
||||||
|
|
||||||
#ifdef ASSERT
|
// check_class() is optionally called for product bits, but is
|
||||||
|
// always called for non-product bits.
|
||||||
|
#ifdef PRODUCT
|
||||||
|
if (RC_TRACE_ENABLED(0x00004000)) {
|
||||||
|
#endif
|
||||||
|
RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class"));
|
||||||
SystemDictionary::classes_do(check_class, thread);
|
SystemDictionary::classes_do(check_class, thread);
|
||||||
|
#ifdef PRODUCT
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1564,9 +1571,9 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method,
|
||||||
bcp, cp_index, new_index));
|
bcp, cp_index, new_index));
|
||||||
// Rewriter::rewrite_method() uses put_native_u2() in this
|
// Rewriter::rewrite_method() uses put_native_u2() in this
|
||||||
// situation because it is reusing the constant pool index
|
// situation because it is reusing the constant pool index
|
||||||
// location for a native index into the constantPoolCache.
|
// location for a native index into the ConstantPoolCache.
|
||||||
// Since we are updating the constant pool index prior to
|
// Since we are updating the constant pool index prior to
|
||||||
// verification and constantPoolCache initialization, we
|
// verification and ConstantPoolCache initialization, we
|
||||||
// need to keep the new index in Java byte order.
|
// need to keep the new index in Java byte order.
|
||||||
Bytes::put_Java_u2(p, new_index);
|
Bytes::put_Java_u2(p, new_index);
|
||||||
}
|
}
|
||||||
|
@ -3371,7 +3378,6 @@ void VM_RedefineClasses::increment_class_counter(InstanceKlass *ik, TRAPS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void VM_RedefineClasses::check_class(Klass* k_oop,
|
void VM_RedefineClasses::check_class(Klass* k_oop,
|
||||||
ClassLoaderData* initiating_loader,
|
ClassLoaderData* initiating_loader,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
@ -3379,82 +3385,110 @@ void VM_RedefineClasses::check_class(Klass* k_oop,
|
||||||
if (k->oop_is_instance()) {
|
if (k->oop_is_instance()) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
InstanceKlass *ik = (InstanceKlass *) k;
|
InstanceKlass *ik = (InstanceKlass *) k;
|
||||||
|
bool no_old_methods = true; // be optimistic
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
|
||||||
if (ik->vtable_length() > 0) {
|
// a vtable should never contain old or obsolete methods
|
||||||
ResourceMark rm(THREAD);
|
if (ik->vtable_length() > 0 &&
|
||||||
if (!ik->vtable()->check_no_old_entries()) {
|
!ik->vtable()->check_no_old_or_obsolete_entries()) {
|
||||||
tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name());
|
if (RC_TRACE_ENABLED(0x00004000)) {
|
||||||
|
RC_TRACE_WITH_THREAD(0x00004000, THREAD,
|
||||||
|
("klassVtable::check_no_old_or_obsolete_entries failure"
|
||||||
|
" -- OLD or OBSOLETE method found -- class: %s",
|
||||||
|
ik->signature_name()));
|
||||||
ik->vtable()->dump_vtable();
|
ik->vtable()->dump_vtable();
|
||||||
assert(false, "OLD method found");
|
|
||||||
}
|
}
|
||||||
|
no_old_methods = false;
|
||||||
}
|
}
|
||||||
if (ik->itable_length() > 0) {
|
|
||||||
ResourceMark rm(THREAD);
|
// an itable should never contain old or obsolete methods
|
||||||
if (!ik->itable()->check_no_old_entries()) {
|
if (ik->itable_length() > 0 &&
|
||||||
tty->print_cr("klassItable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name());
|
!ik->itable()->check_no_old_or_obsolete_entries()) {
|
||||||
assert(false, "OLD method found");
|
if (RC_TRACE_ENABLED(0x00004000)) {
|
||||||
|
RC_TRACE_WITH_THREAD(0x00004000, THREAD,
|
||||||
|
("klassItable::check_no_old_or_obsolete_entries failure"
|
||||||
|
" -- OLD or OBSOLETE method found -- class: %s",
|
||||||
|
ik->signature_name()));
|
||||||
|
ik->itable()->dump_itable();
|
||||||
}
|
}
|
||||||
|
no_old_methods = false;
|
||||||
}
|
}
|
||||||
// Check that the constant pool cache has no deleted entries.
|
|
||||||
|
// the constant pool cache should never contain old or obsolete methods
|
||||||
if (ik->constants() != NULL &&
|
if (ik->constants() != NULL &&
|
||||||
ik->constants()->cache() != NULL &&
|
ik->constants()->cache() != NULL &&
|
||||||
!ik->constants()->cache()->check_no_old_entries()) {
|
!ik->constants()->cache()->check_no_old_or_obsolete_entries()) {
|
||||||
tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name());
|
if (RC_TRACE_ENABLED(0x00004000)) {
|
||||||
assert(false, "OLD method found");
|
RC_TRACE_WITH_THREAD(0x00004000, THREAD,
|
||||||
|
("cp-cache::check_no_old_or_obsolete_entries failure"
|
||||||
|
" -- OLD or OBSOLETE method found -- class: %s",
|
||||||
|
ik->signature_name()));
|
||||||
|
ik->constants()->cache()->dump_cache();
|
||||||
|
}
|
||||||
|
no_old_methods = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_old_methods) {
|
||||||
|
if (RC_TRACE_ENABLED(0x00004000)) {
|
||||||
|
dump_methods();
|
||||||
|
} else {
|
||||||
|
tty->print_cr("INFO: use the '-XX:TraceRedefineClasses=16384' option "
|
||||||
|
"to see more info about the following guarantee() failure.");
|
||||||
|
}
|
||||||
|
guarantee(false, "OLD and/or OBSOLETE method(s) found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM_RedefineClasses::dump_methods() {
|
void VM_RedefineClasses::dump_methods() {
|
||||||
int j;
|
int j;
|
||||||
tty->print_cr("_old_methods --");
|
RC_TRACE(0x00004000, ("_old_methods --"));
|
||||||
for (j = 0; j < _old_methods->length(); ++j) {
|
for (j = 0; j < _old_methods->length(); ++j) {
|
||||||
Method* m = _old_methods->at(j);
|
Method* m = _old_methods->at(j);
|
||||||
tty->print("%4d (%5d) ", j, m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->print(" -- ");
|
tty->print(" -- ");
|
||||||
m->print_name(tty);
|
m->print_name(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
tty->print_cr("_new_methods --");
|
RC_TRACE(0x00004000, ("_new_methods --"));
|
||||||
for (j = 0; j < _new_methods->length(); ++j) {
|
for (j = 0; j < _new_methods->length(); ++j) {
|
||||||
Method* m = _new_methods->at(j);
|
Method* m = _new_methods->at(j);
|
||||||
tty->print("%4d (%5d) ", j, m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->print(" -- ");
|
tty->print(" -- ");
|
||||||
m->print_name(tty);
|
m->print_name(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
tty->print_cr("_matching_(old/new)_methods --");
|
RC_TRACE(0x00004000, ("_matching_(old/new)_methods --"));
|
||||||
for (j = 0; j < _matching_methods_length; ++j) {
|
for (j = 0; j < _matching_methods_length; ++j) {
|
||||||
Method* m = _matching_old_methods[j];
|
Method* m = _matching_old_methods[j];
|
||||||
tty->print("%4d (%5d) ", j, m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->print(" -- ");
|
tty->print(" -- ");
|
||||||
m->print_name(tty);
|
m->print_name(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
m = _matching_new_methods[j];
|
m = _matching_new_methods[j];
|
||||||
tty->print(" (%5d) ", m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, (" (%5d) ", m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
tty->print_cr("_deleted_methods --");
|
RC_TRACE(0x00004000, ("_deleted_methods --"));
|
||||||
for (j = 0; j < _deleted_methods_length; ++j) {
|
for (j = 0; j < _deleted_methods_length; ++j) {
|
||||||
Method* m = _deleted_methods[j];
|
Method* m = _deleted_methods[j];
|
||||||
tty->print("%4d (%5d) ", j, m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->print(" -- ");
|
tty->print(" -- ");
|
||||||
m->print_name(tty);
|
m->print_name(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
tty->print_cr("_added_methods --");
|
RC_TRACE(0x00004000, ("_added_methods --"));
|
||||||
for (j = 0; j < _added_methods_length; ++j) {
|
for (j = 0; j < _added_methods_length; ++j) {
|
||||||
Method* m = _added_methods[j];
|
Method* m = _added_methods[j];
|
||||||
tty->print("%4d (%5d) ", j, m->vtable_index());
|
RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index()));
|
||||||
m->access_flags().print_on(tty);
|
m->access_flags().print_on(tty);
|
||||||
tty->print(" -- ");
|
tty->print(" -- ");
|
||||||
m->print_name(tty);
|
m->print_name(tty);
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -468,9 +468,9 @@ class VM_RedefineClasses: public VM_Operation {
|
||||||
|
|
||||||
void flush_dependent_code(instanceKlassHandle k_h, TRAPS);
|
void flush_dependent_code(instanceKlassHandle k_h, TRAPS);
|
||||||
|
|
||||||
static void check_class(Klass* k_oop, ClassLoaderData* initiating_loader, TRAPS) PRODUCT_RETURN;
|
static void check_class(Klass* k_oop, ClassLoaderData* initiating_loader,
|
||||||
|
TRAPS);
|
||||||
static void dump_methods() PRODUCT_RETURN;
|
static void dump_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VM_RedefineClasses(jint class_count,
|
VM_RedefineClasses(jint class_count,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
// 0x00000800 | 2048 - previous class breakpoint mgmt
|
// 0x00000800 | 2048 - previous class breakpoint mgmt
|
||||||
// 0x00001000 | 4096 - detect calls to obsolete methods
|
// 0x00001000 | 4096 - detect calls to obsolete methods
|
||||||
// 0x00002000 | 8192 - fail a guarantee() in addition to detection
|
// 0x00002000 | 8192 - fail a guarantee() in addition to detection
|
||||||
// 0x00004000 | 16384 - unused
|
// 0x00004000 | 16384 - detect old/obsolete methods in metadata
|
||||||
// 0x00008000 | 32768 - old/new method matching/add/delete
|
// 0x00008000 | 32768 - old/new method matching/add/delete
|
||||||
// 0x00010000 | 65536 - impl details: CP size info
|
// 0x00010000 | 65536 - impl details: CP size info
|
||||||
// 0x00020000 | 131072 - impl details: CP merge pass info
|
// 0x00020000 | 131072 - impl details: CP merge pass info
|
||||||
|
@ -82,6 +82,13 @@
|
||||||
tty->print_cr args; \
|
tty->print_cr args; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define RC_TRACE_NO_CR(level, args) \
|
||||||
|
if ((TraceRedefineClasses & level) != 0) { \
|
||||||
|
ResourceMark rm; \
|
||||||
|
tty->print("RedefineClasses-0x%x: ", level); \
|
||||||
|
tty->print args; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define RC_TRACE_WITH_THREAD(level, thread, args) \
|
#define RC_TRACE_WITH_THREAD(level, thread, args) \
|
||||||
if ((TraceRedefineClasses & level) != 0) { \
|
if ((TraceRedefineClasses & level) != 0) { \
|
||||||
ResourceMark rm(thread); \
|
ResourceMark rm(thread); \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -59,7 +59,7 @@ void AccessFlags::atomic_clear_bits(jint bits) {
|
||||||
} while(f != old_flags);
|
} while(f != old_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#if !defined(PRODUCT) || INCLUDE_JVMTI
|
||||||
|
|
||||||
void AccessFlags::print_on(outputStream* st) const {
|
void AccessFlags::print_on(outputStream* st) const {
|
||||||
if (is_public ()) st->print("public " );
|
if (is_public ()) st->print("public " );
|
||||||
|
@ -80,7 +80,7 @@ void AccessFlags::print_on(outputStream* st) const {
|
||||||
if (on_stack ()) st->print("{on_stack} " );
|
if (on_stack ()) st->print("{on_stack} " );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // !PRODUCT || INCLUDE_JVMTI
|
||||||
|
|
||||||
void accessFlags_init() {
|
void accessFlags_init() {
|
||||||
assert(sizeof(AccessFlags) == sizeof(jint), "just checking size of flags");
|
assert(sizeof(AccessFlags) == sizeof(jint), "just checking size of flags");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -239,7 +239,11 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
|
||||||
inline friend AccessFlags accessFlags_from(jint flags);
|
inline friend AccessFlags accessFlags_from(jint flags);
|
||||||
|
|
||||||
// Printing/debugging
|
// Printing/debugging
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
void print_on(outputStream* st) const;
|
||||||
|
#else
|
||||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline AccessFlags accessFlags_from(jint flags) {
|
inline AccessFlags accessFlags_from(jint flags) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue