< prev index next >
src/hotspot/share/classfile/defaultMethods.cpp
Print this page
rev 53972 : 8219713: Reduce work in DefaultMethods::generate_default_methods
Reviewed-by: hseigel, dholmes, lfoltan, kkinnear
*** 151,184 ****
InstanceKlass* next_interface() {
return interface_at(interface_index());
}
};
! bool _cancelled;
GrowableArray<Node*> _path;
Node* current_top() const { return _path.top(); }
bool has_more_nodes() const { return !_path.is_empty(); }
void push(InstanceKlass* cls, void* data) {
assert(cls != NULL, "Requires a valid instance class");
Node* node = new Node(cls, data, has_super(cls));
_path.push(node);
}
void pop() { _path.pop(); }
! void reset_iteration() {
! _cancelled = false;
! _path.clear();
! }
! bool is_cancelled() const { return _cancelled; }
!
! // This code used to skip interface classes because their only
! // superclass was j.l.Object which would be also covered by class
! // superclass hierarchy walks. Now that the starting point can be
! // an interface, we must ensure we catch j.l.Object as the super.
! static bool has_super(InstanceKlass* cls) {
! return cls->super() != NULL;
}
Node* node_at_depth(int i) const {
return (i >= _path.length()) ? NULL : _path.at(_path.length() - i - 1);
}
--- 151,181 ----
InstanceKlass* next_interface() {
return interface_at(interface_index());
}
};
! bool _visited_Object;
GrowableArray<Node*> _path;
Node* current_top() const { return _path.top(); }
bool has_more_nodes() const { return !_path.is_empty(); }
void push(InstanceKlass* cls, void* data) {
assert(cls != NULL, "Requires a valid instance class");
Node* node = new Node(cls, data, has_super(cls));
+ if (cls == SystemDictionary::Object_klass()) {
+ _visited_Object = true;
+ }
_path.push(node);
}
void pop() { _path.pop(); }
! // Since the starting point can be an interface, we must ensure we catch
! // j.l.Object as the super once in those cases. The _visited_Object flag
! // only ensures we don't then repeatedly enqueue Object for each interface
! // in the class hierarchy.
! bool has_super(InstanceKlass* cls) {
! return cls->super() != NULL && (!_visited_Object || !cls->is_interface());
}
Node* node_at_depth(int i) const {
return (i >= _path.length()) ? NULL : _path.at(_path.length() - i - 1);
}
*** 198,216 ****
Node* n = node_at_depth(i);
return n == NULL ? NULL : n->_algorithm_data;
}
void* current_data() { return data_at_depth(0); }
- void cancel_iteration() { _cancelled = true; }
-
public:
void run(InstanceKlass* root) {
ALGO* algo = static_cast<ALGO*>(this);
- reset_iteration();
-
void* algo_data = algo->new_node_data(root);
push(root, algo_data);
bool top_needs_visit = true;
do {
--- 195,209 ----
*** 240,250 ****
assert(next != NULL, "Otherwise we shouldn't be here");
algo_data = algo->new_node_data(next);
push(next, algo_data);
top_needs_visit = true;
}
! } while (!is_cancelled() && has_more_nodes());
}
};
class PrintHierarchy : public HierarchyVisitor<PrintHierarchy> {
private:
--- 233,243 ----
assert(next != NULL, "Otherwise we shouldn't be here");
algo_data = algo->new_node_data(next);
push(next, algo_data);
top_needs_visit = true;
}
! } while (has_more_nodes());
}
};
class PrintHierarchy : public HierarchyVisitor<PrintHierarchy> {
private:
*** 442,460 ****
ls.cr();
}
}
}
- bool contains_signature(Symbol* query) {
- for (int i = 0; i < _members.length(); ++i) {
- if (query == _members.at(i).first->signature()) {
- return true;
- }
- }
- return false;
- }
-
void print_selected(outputStream* str, int indent) const {
assert(has_target(), "Should be called otherwise");
streamIndentor si(str, indent * 2);
str->indent().print("Selected method: ");
print_method(str, _selected_target);
--- 435,444 ----
*** 519,544 ****
void set_qualification_state(QualifiedState state) {
_qualification_state = state;
}
protected:
! MethodFamily* _method_family;
public:
StatefulMethodFamily() {
- _method_family = new MethodFamily();
- _qualification_state = QUALIFIED;
- }
-
- StatefulMethodFamily(MethodFamily* mf) {
- _method_family = mf;
_qualification_state = QUALIFIED;
}
! void set_target_if_empty(Method* m) { _method_family->set_target_if_empty(m); }
! MethodFamily* get_method_family() { return _method_family; }
StateRestorer* record_method_and_dq_further(Method* mo);
};
class StateRestorer : public PseudoScopeMark {
--- 503,522 ----
void set_qualification_state(QualifiedState state) {
_qualification_state = state;
}
protected:
! MethodFamily _method_family;
public:
StatefulMethodFamily() {
_qualification_state = QUALIFIED;
}
! void set_target_if_empty(Method* m) { _method_family.set_target_if_empty(m); }
! MethodFamily* get_method_family() { return &_method_family; }
StateRestorer* record_method_and_dq_further(Method* mo);
};
class StateRestorer : public PseudoScopeMark {
*** 554,566 ****
};
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
StateRestorer* mark = new StateRestorer(this, _qualification_state);
if (_qualification_state == QUALIFIED) {
! _method_family->record_qualified_method(mo);
} else {
! _method_family->record_disqualified_method(mo);
}
// Everything found "above"??? this method in the hierarchy walk is set to
// disqualified
set_qualification_state(DISQUALIFIED);
return mark;
--- 532,544 ----
};
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
StateRestorer* mark = new StateRestorer(this, _qualification_state);
if (_qualification_state == QUALIFIED) {
! _method_family.record_qualified_method(mo);
} else {
! _method_family.record_disqualified_method(mo);
}
// Everything found "above"??? this method in the hierarchy walk is set to
// disqualified
set_qualification_state(DISQUALIFIED);
return mark;
*** 604,620 ****
}
}
return found;
}
! static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
- GrowableArray<EmptyVtableSlot*>* slots = new GrowableArray<EmptyVtableSlot*>();
-
// All miranda methods are obvious candidates
for (int i = 0; i < mirandas->length(); ++i) {
Method* m = mirandas->at(i);
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
--- 582,596 ----
}
}
return found;
}
! static void find_empty_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
// All miranda methods are obvious candidates
for (int i = 0; i < mirandas->length(); ++i) {
Method* m = mirandas->at(i);
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
*** 625,642 ****
// (can't use the vtable because it is not guaranteed to be initialized yet)
InstanceKlass* super = klass->java_super();
while (super != NULL) {
for (int i = 0; i < super->methods()->length(); ++i) {
Method* m = super->methods()->at(i);
! if (m->is_overpass() || m->is_static()) {
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
- Method* impl = klass->lookup_method(m->name(), m->signature());
- if (impl == NULL || impl->is_overpass() || impl->is_static()) {
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
--- 601,618 ----
// (can't use the vtable because it is not guaranteed to be initialized yet)
InstanceKlass* super = klass->java_super();
while (super != NULL) {
for (int i = 0; i < super->methods()->length(); ++i) {
Method* m = super->methods()->at(i);
! if (m->is_overpass() || (m->is_static() && !SystemDictionary::is_nonpublic_Object_method(m))) {
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
if (!already_in_vtable_slots(slots, m)) {
+ Method *impl = klass->lookup_method(m->name(), m->signature());
+ if (impl == NULL || impl->is_overpass() || impl->is_static()) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
*** 647,659 ****
Method* m = super->default_methods()->at(i);
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass() || impl->is_static()) {
- if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
--- 623,635 ----
Method* m = super->default_methods()->at(i);
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
+ if (!already_in_vtable_slots(slots, m)) {
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass() || impl->is_static()) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
*** 670,681 ****
ls.indent();
slots->at(i)->print_on(&ls);
ls.cr();
}
}
-
- return slots;
}
// Iterates over the superinterface type hierarchy looking for all methods
// with a specific erased signature.
class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
--- 646,655 ----
*** 747,758 ****
static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
static void generate_erased_defaults(
! InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
! EmptyVtableSlot* slot, bool is_intf, TRAPS) {
// sets up a set of methods with the same exact erased signature
FindMethodsByErasedSig visitor(slot->name(), slot->signature(), is_intf);
visitor.run(klass);
--- 721,731 ----
static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
static void generate_erased_defaults(
! InstanceKlass* klass, EmptyVtableSlot* slot, bool is_intf, TRAPS) {
// sets up a set of methods with the same exact erased signature
FindMethodsByErasedSig visitor(slot->name(), slot->signature(), is_intf);
visitor.run(klass);
*** 782,791 ****
--- 755,765 ----
// overpass method that throws an exception and add it to the klass methods list.
// The JVM does not create bridges nor handle generic signatures here.
void DefaultMethods::generate_default_methods(
InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "invariant");
+ assert(klass != SystemDictionary::Object_klass(), "Shouldn't be called for Object");
// This resource mark is the bound for all memory allocation that takes
// place during default method processing. After this goes out of scope,
// all (Resource) objects' memory will be reclaimed. Be careful if adding an
// embedded resource mark under here as that memory can't be used outside
*** 807,833 ****
LogStream ls(lt);
PrintHierarchy printer(&ls);
printer.run(klass);
}
! GrowableArray<EmptyVtableSlot*>* empty_slots =
! find_empty_vtable_slots(klass, mirandas, CHECK);
! for (int i = 0; i < empty_slots->length(); ++i) {
! EmptyVtableSlot* slot = empty_slots->at(i);
LogTarget(Debug, defaultmethods) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
streamIndentor si(&ls, 2);
ls.indent().print("Looking for default methods for slot ");
slot->print_on(&ls);
ls.cr();
}
! generate_erased_defaults(klass, empty_slots, slot, klass->is_interface(), CHECK);
}
log_debug(defaultmethods)("Creating defaults and overpasses...");
! create_defaults_and_exceptions(empty_slots, klass, CHECK);
log_debug(defaultmethods)("Default method processing complete");
}
static int assemble_method_error(
BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) {
--- 781,809 ----
LogStream ls(lt);
PrintHierarchy printer(&ls);
printer.run(klass);
}
! GrowableArray<EmptyVtableSlot*> empty_slots;
! find_empty_vtable_slots(&empty_slots, klass, mirandas, CHECK);
! if (empty_slots.length() > 0) {
! for (int i = 0; i < empty_slots.length(); ++i) {
! EmptyVtableSlot* slot = empty_slots.at(i);
LogTarget(Debug, defaultmethods) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
streamIndentor si(&ls, 2);
ls.indent().print("Looking for default methods for slot ");
slot->print_on(&ls);
ls.cr();
}
! generate_erased_defaults(klass, slot, klass->is_interface(), CHECK);
}
log_debug(defaultmethods)("Creating defaults and overpasses...");
! create_defaults_and_exceptions(&empty_slots, klass, CHECK);
! }
log_debug(defaultmethods)("Default method processing complete");
}
static int assemble_method_error(
BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) {
*** 912,923 ****
//
// Note that if overpass method are ever created that are not exception
// throwing methods then the loader constraint checking logic for vtable and
// itable creation needs to be changed to check loader constraints for the
// overpass methods that do not throw exceptions.
! static void create_defaults_and_exceptions(
! GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, TRAPS) {
GrowableArray<Method*> overpasses;
GrowableArray<Method*> defaults;
BytecodeConstantPool bpool(klass->constants());
--- 888,898 ----
//
// Note that if overpass method are ever created that are not exception
// throwing methods then the loader constraint checking logic for vtable and
// itable creation needs to be changed to check loader constraints for the
// overpass methods that do not throw exceptions.
! static void create_defaults_and_exceptions(GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, TRAPS) {
GrowableArray<Method*> overpasses;
GrowableArray<Method*> defaults;
BytecodeConstantPool bpool(klass->constants());
*** 977,987 ****
if (defaults.length() > 0) {
create_default_methods(klass, &defaults, CHECK);
}
}
! static void create_default_methods( InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS) {
int new_size = new_methods->length();
Array<Method*>* total_default_methods = MetadataFactory::new_array<Method*>(
klass->class_loader_data(), new_size, NULL, CHECK);
--- 952,962 ----
if (defaults.length() > 0) {
create_default_methods(klass, &defaults, CHECK);
}
}
! static void create_default_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS) {
int new_size = new_methods->length();
Array<Method*>* total_default_methods = MetadataFactory::new_array<Method*>(
klass->class_loader_data(), new_size, NULL, CHECK);
< prev index next >