提交 567a6555 编写于 作者: A acorn

Merge

...@@ -318,17 +318,17 @@ class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> { ...@@ -318,17 +318,17 @@ class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> {
} }
}; };
// A method family contains a set of all methods that implement a single // A method family contains a set of all methods that implement a single
// language-level method. Because of erasure, these methods may have different // erased method. As members of the set are collected while walking over the
// signatures. As members of the set are collected while walking over the
// hierarchy, they are tagged with a qualification state. The qualification // hierarchy, they are tagged with a qualification state. The qualification
// state for an erased method is set to disqualified if there exists a path // state for an erased method is set to disqualified if there exists a path
// from the root of hierarchy to the method that contains an interleaving // from the root of hierarchy to the method that contains an interleaving
// language-equivalent method defined in an interface. // erased method defined in an interface.
class MethodFamily : public ResourceObj { class MethodFamily : public ResourceObj {
private: private:
generic::MethodDescriptor* _descriptor; // language-level description
GrowableArray<Pair<Method*,QualifiedState> > _members; GrowableArray<Pair<Method*,QualifiedState> > _members;
ResourceHashtable<Method*, int> _member_index; ResourceHashtable<Method*, int> _member_index;
...@@ -358,15 +358,8 @@ class MethodFamily : public ResourceObj { ...@@ -358,15 +358,8 @@ class MethodFamily : public ResourceObj {
public: public:
MethodFamily(generic::MethodDescriptor* canonical_desc) MethodFamily()
: _descriptor(canonical_desc), _selected_target(NULL), : _selected_target(NULL), _exception_message(NULL) {}
_exception_message(NULL) {}
generic::MethodDescriptor* descriptor() const { return _descriptor; }
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
return descriptor()->covariant_match(md, ctx);
}
void set_target_if_empty(Method* m) { void set_target_if_empty(Method* m) {
if (_selected_target == NULL && !m->is_overpass()) { if (_selected_target == NULL && !m->is_overpass()) {
...@@ -441,16 +434,10 @@ class MethodFamily : public ResourceObj { ...@@ -441,16 +434,10 @@ class MethodFamily : public ResourceObj {
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_on(outputStream* str) const { void print_sig_on(outputStream* str, Symbol* signature, int indent) const {
print_on(str, 0);
}
void print_on(outputStream* str, int indent) const {
streamIndentor si(str, indent * 2); streamIndentor si(str, indent * 2);
generic::Context ctx(NULL); // empty, as _descriptor already canonicalized str->indent().print_cr("Logical Method %s:", signature->as_C_string());
TempNewSymbol family = descriptor()->reify_signature(&ctx, Thread::current());
str->indent().print_cr("Logical Method %s:", family->as_C_string());
streamIndentor si2(str); streamIndentor si2(str);
for (int i = 0; i < _members.length(); ++i) { for (int i = 0; i < _members.length(); ++i) {
...@@ -516,38 +503,94 @@ Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods ...@@ -516,38 +503,94 @@ Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods
return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL); return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL);
} }
// A generic method family contains a set of all methods that implement a single
// language-level method. Because of erasure, these methods may have different
// signatures. As members of the set are collected while walking over the
// hierarchy, they are tagged with a qualification state. The qualification
// state for an erased method is set to disqualified if there exists a path
// from the root of hierarchy to the method that contains an interleaving
// language-equivalent method defined in an interface.
class GenericMethodFamily : public MethodFamily {
private:
generic::MethodDescriptor* _descriptor; // language-level description
public:
GenericMethodFamily(generic::MethodDescriptor* canonical_desc)
: _descriptor(canonical_desc) {}
generic::MethodDescriptor* descriptor() const { return _descriptor; }
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
return descriptor()->covariant_match(md, ctx);
}
#ifndef PRODUCT
Symbol* get_generic_sig() const {
generic::Context ctx(NULL); // empty, as _descriptor already canonicalized
TempNewSymbol sig = descriptor()->reify_signature(&ctx, Thread::current());
return sig;
}
#endif // ndef PRODUCT
};
class StateRestorer; class StateRestorer;
// StatefulMethodFamily is a wrapper around MethodFamily that maintains the // StatefulMethodFamily is a wrapper around a MethodFamily that maintains the
// qualification state during hierarchy visitation, and applies that state // qualification state during hierarchy visitation, and applies that state
// when adding members to the MethodFamily. // when adding members to the MethodFamily
class StatefulMethodFamily : public ResourceObj { class StatefulMethodFamily : public ResourceObj {
friend class StateRestorer; friend class StateRestorer;
private: private:
MethodFamily* _method;
QualifiedState _qualification_state; QualifiedState _qualification_state;
void set_qualification_state(QualifiedState state) { void set_qualification_state(QualifiedState state) {
_qualification_state = state; _qualification_state = state;
} }
protected:
MethodFamily* _method_family;
public: public:
StatefulMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx) { StatefulMethodFamily() {
_method = new MethodFamily(md->canonicalize(ctx)); _method_family = new MethodFamily();
_qualification_state = QUALIFIED; _qualification_state = QUALIFIED;
} }
void set_target_if_empty(Method* m) { _method->set_target_if_empty(m); } StatefulMethodFamily(MethodFamily* mf) {
_method_family = mf;
_qualification_state = QUALIFIED;
}
MethodFamily* get_method_family() { return _method; } void set_target_if_empty(Method* m) { _method_family->set_target_if_empty(m); }
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) { MethodFamily* get_method_family() { return _method_family; }
return _method->descriptor_matches(md, ctx);
}
StateRestorer* record_method_and_dq_further(Method* mo); StateRestorer* record_method_and_dq_further(Method* mo);
}; };
// StatefulGenericMethodFamily is a wrapper around GenericMethodFamily that maintains the
// qualification state during hierarchy visitation, and applies that state
// when adding members to the GenericMethodFamily.
class StatefulGenericMethodFamily : public StatefulMethodFamily {
public:
StatefulGenericMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx)
: StatefulMethodFamily(new GenericMethodFamily(md->canonicalize(ctx))) {
}
GenericMethodFamily* get_method_family() {
return (GenericMethodFamily*)_method_family;
}
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
return get_method_family()->descriptor_matches(md, ctx);
}
};
class StateRestorer : public PseudoScopeMark { class StateRestorer : public PseudoScopeMark {
private: private:
StatefulMethodFamily* _method; StatefulMethodFamily* _method;
...@@ -563,9 +606,9 @@ class StateRestorer : public PseudoScopeMark { ...@@ -563,9 +606,9 @@ class StateRestorer : public PseudoScopeMark {
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) { StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
StateRestorer* mark = new StateRestorer(this, _qualification_state); StateRestorer* mark = new StateRestorer(this, _qualification_state);
if (_qualification_state == QUALIFIED) { if (_qualification_state == QUALIFIED) {
_method->record_qualified_method(mo); _method_family->record_qualified_method(mo);
} else { } else {
_method->record_disqualified_method(mo); _method_family->record_disqualified_method(mo);
} }
// Everything found "above"??? this method in the hierarchy walk is set to // Everything found "above"??? this method in the hierarchy walk is set to
// disqualified // disqualified
...@@ -573,15 +616,15 @@ StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) { ...@@ -573,15 +616,15 @@ StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
return mark; return mark;
} }
class StatefulMethodFamilies : public ResourceObj { class StatefulGenericMethodFamilies : public ResourceObj {
private: private:
GrowableArray<StatefulMethodFamily*> _methods; GrowableArray<StatefulGenericMethodFamily*> _methods;
public: public:
StatefulMethodFamily* find_matching( StatefulGenericMethodFamily* find_matching(
generic::MethodDescriptor* md, generic::Context* ctx) { generic::MethodDescriptor* md, generic::Context* ctx) {
for (int i = 0; i < _methods.length(); ++i) { for (int i = 0; i < _methods.length(); ++i) {
StatefulMethodFamily* existing = _methods.at(i); StatefulGenericMethodFamily* existing = _methods.at(i);
if (existing->descriptor_matches(md, ctx)) { if (existing->descriptor_matches(md, ctx)) {
return existing; return existing;
} }
...@@ -589,17 +632,17 @@ class StatefulMethodFamilies : public ResourceObj { ...@@ -589,17 +632,17 @@ class StatefulMethodFamilies : public ResourceObj {
return NULL; return NULL;
} }
StatefulMethodFamily* find_matching_or_create( StatefulGenericMethodFamily* find_matching_or_create(
generic::MethodDescriptor* md, generic::Context* ctx) { generic::MethodDescriptor* md, generic::Context* ctx) {
StatefulMethodFamily* method = find_matching(md, ctx); StatefulGenericMethodFamily* method = find_matching(md, ctx);
if (method == NULL) { if (method == NULL) {
method = new StatefulMethodFamily(md, ctx); method = new StatefulGenericMethodFamily(md, ctx);
_methods.append(method); _methods.append(method);
} }
return method; return method;
} }
void extract_families_into(GrowableArray<MethodFamily*>* array) { void extract_families_into(GrowableArray<GenericMethodFamily*>* array) {
for (int i = 0; i < _methods.length(); ++i) { for (int i = 0; i < _methods.length(); ++i) {
array->append(_methods.at(i)->get_method_family()); array->append(_methods.at(i)->get_method_family());
} }
...@@ -683,26 +726,79 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots( ...@@ -683,26 +726,79 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
return slots; return slots;
} }
// Iterates over the superinterface type hierarchy looking for all methods
// with a specific erased signature.
class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
private:
// Context data
Symbol* _method_name;
Symbol* _method_signature;
StatefulMethodFamily* _family;
public:
FindMethodsByErasedSig(Symbol* name, Symbol* signature) :
_method_name(name), _method_signature(signature),
_family(NULL) {}
void get_discovered_family(MethodFamily** family) {
if (_family != NULL) {
*family = _family->get_method_family();
} else {
*family = NULL;
}
}
void* new_node_data(InstanceKlass* cls) { return new PseudoScope(); }
void free_node_data(void* node_data) {
PseudoScope::cast(node_data)->destroy();
}
// Find all methods on this hierarchy that match this
// method's erased (name, signature)
bool visit() {
PseudoScope* scope = PseudoScope::cast(current_data());
InstanceKlass* iklass = current_class();
Method* m = iklass->find_method(_method_name, _method_signature);
if (m != NULL) {
if (_family == NULL) {
_family = new StatefulMethodFamily();
}
if (iklass->is_interface()) {
StateRestorer* restorer = _family->record_method_and_dq_further(m);
scope->add_mark(restorer);
} else {
// This is the rule that methods in classes "win" (bad word) over
// methods in interfaces. This works because of single inheritance
_family->set_target_if_empty(m);
}
}
return true;
}
};
// Iterates over the type hierarchy looking for all methods with a specific // Iterates over the type hierarchy looking for all methods with a specific
// method name. The result of this is a set of method families each of // method name. The result of this is a set of method families each of
// which is populated with a set of methods that implement the same // which is populated with a set of methods that implement the same
// language-level signature. // language-level signature.
class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> { class FindMethodsByGenericSig : public HierarchyVisitor<FindMethodsByGenericSig> {
private: private:
// Context data // Context data
Thread* THREAD; Thread* THREAD;
generic::DescriptorCache* _cache; generic::DescriptorCache* _cache;
Symbol* _method_name; Symbol* _method_name;
generic::Context* _ctx; generic::Context* _ctx;
StatefulMethodFamilies _families; StatefulGenericMethodFamilies _families;
public: public:
FindMethodsByName(generic::DescriptorCache* cache, Symbol* name, FindMethodsByGenericSig(generic::DescriptorCache* cache, Symbol* name,
generic::Context* ctx, Thread* thread) : generic::Context* ctx, Thread* thread) :
_cache(cache), _method_name(name), _ctx(ctx), THREAD(thread) {} _cache(cache), _method_name(name), _ctx(ctx), THREAD(thread) {}
void get_discovered_families(GrowableArray<MethodFamily*>* methods) { void get_discovered_families(GrowableArray<GenericMethodFamily*>* methods) {
_families.extract_families_into(methods); _families.extract_families_into(methods);
} }
...@@ -733,7 +829,7 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> { ...@@ -733,7 +829,7 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
// Find all methods on this hierarchy that match this method // Find all methods on this hierarchy that match this method
// (name, signature). This class collects other families of this // (name, signature). This class collects other families of this
// method name. // method name.
StatefulMethodFamily* family = StatefulGenericMethodFamily* family =
_families.find_matching_or_create(md, _ctx); _families.find_matching_or_create(md, _ctx);
if (klass->is_interface()) { if (klass->is_interface()) {
...@@ -752,8 +848,8 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> { ...@@ -752,8 +848,8 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
}; };
#ifndef PRODUCT #ifndef PRODUCT
static void print_families( static void print_generic_families(
GrowableArray<MethodFamily*>* methods, Symbol* match) { GrowableArray<GenericMethodFamily*>* methods, Symbol* match) {
streamIndentor si(tty, 4); streamIndentor si(tty, 4);
if (methods->length() == 0) { if (methods->length() == 0) {
tty->indent(); tty->indent();
...@@ -761,22 +857,87 @@ static void print_families( ...@@ -761,22 +857,87 @@ static void print_families(
} }
for (int i = 0; i < methods->length(); ++i) { for (int i = 0; i < methods->length(); ++i) {
tty->indent(); tty->indent();
MethodFamily* lm = methods->at(i); GenericMethodFamily* lm = methods->at(i);
if (lm->contains_signature(match)) { if (lm->contains_signature(match)) {
tty->print_cr("<Matching>"); tty->print_cr("<Matching>");
} else { } else {
tty->print_cr("<Non-Matching>"); tty->print_cr("<Non-Matching>");
} }
lm->print_on(tty, 1); lm->print_sig_on(tty, lm->get_generic_sig(), 1);
} }
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
static void merge_in_new_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS);
static void create_overpasses( static void create_overpasses(
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS); GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
static void generate_generic_defaults(
InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
EmptyVtableSlot* slot, int current_slot_index, TRAPS) {
if (slot->is_bound()) {
#ifndef PRODUCT
if (TraceDefaultMethods) {
streamIndentor si(tty, 4);
tty->indent().print_cr("Already bound to logical method:");
GenericMethodFamily* lm = (GenericMethodFamily*)(slot->get_binding());
lm->print_sig_on(tty, lm->get_generic_sig(), 1);
}
#endif // ndef PRODUCT
return; // covered by previous processing
}
generic::DescriptorCache cache;
generic::Context ctx(&cache);
FindMethodsByGenericSig visitor(&cache, slot->name(), &ctx, CHECK);
visitor.run(klass);
GrowableArray<GenericMethodFamily*> discovered_families;
visitor.get_discovered_families(&discovered_families);
#ifndef PRODUCT
if (TraceDefaultMethods) {
print_generic_families(&discovered_families, slot->signature());
}
#endif // ndef PRODUCT
// Find and populate any other slots that match the discovered families
for (int j = current_slot_index; j < empty_slots->length(); ++j) {
EmptyVtableSlot* open_slot = empty_slots->at(j);
if (slot->name() == open_slot->name()) {
for (int k = 0; k < discovered_families.length(); ++k) {
GenericMethodFamily* lm = discovered_families.at(k);
if (lm->contains_signature(open_slot->signature())) {
lm->determine_target(klass, CHECK);
open_slot->bind_family(lm);
}
}
}
}
}
static void generate_erased_defaults(
InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
EmptyVtableSlot* slot, TRAPS) {
// sets up a set of methods with the same exact erased signature
FindMethodsByErasedSig visitor(slot->name(), slot->signature());
visitor.run(klass);
MethodFamily* family;
visitor.get_discovered_family(&family);
if (family != NULL) {
family->determine_target(klass, CHECK);
slot->bind_family(family);
}
}
static void merge_in_new_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS);
// This is the guts of the default methods implementation. This is called just // This is the guts of the default methods implementation. This is called just
// after the classfile has been parsed if some ancestor has default methods. // after the classfile has been parsed if some ancestor has default methods.
// //
...@@ -807,8 +968,6 @@ void DefaultMethods::generate_default_methods( ...@@ -807,8 +968,6 @@ void DefaultMethods::generate_default_methods(
// whatever scope it's in. // whatever scope it's in.
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
generic::DescriptorCache cache;
// Keep entire hierarchy alive for the duration of the computation // Keep entire hierarchy alive for the duration of the computation
KeepAliveRegistrar keepAlive(THREAD); KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive); KeepAliveVisitor loadKeepAlive(&keepAlive);
...@@ -837,47 +996,13 @@ void DefaultMethods::generate_default_methods( ...@@ -837,47 +996,13 @@ void DefaultMethods::generate_default_methods(
tty->print_cr(""); tty->print_cr("");
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
if (slot->is_bound()) {
#ifndef PRODUCT
if (TraceDefaultMethods) {
streamIndentor si(tty, 4);
tty->indent().print_cr("Already bound to logical method:");
slot->get_binding()->print_on(tty, 1);
}
#endif // ndef PRODUCT
continue; // covered by previous processing
}
generic::Context ctx(&cache);
FindMethodsByName visitor(&cache, slot->name(), &ctx, CHECK);
visitor.run(klass);
GrowableArray<MethodFamily*> discovered_families;
visitor.get_discovered_families(&discovered_families);
#ifndef PRODUCT
if (TraceDefaultMethods) {
print_families(&discovered_families, slot->signature());
}
#endif // ndef PRODUCT
// Find and populate any other slots that match the discovered families if (ParseGenericDefaults) {
for (int j = i; j < empty_slots->length(); ++j) { generate_generic_defaults(klass, empty_slots, slot, i, CHECK);
EmptyVtableSlot* open_slot = empty_slots->at(j); } else {
generate_erased_defaults(klass, empty_slots, slot, CHECK);
if (slot->name() == open_slot->name()) {
for (int k = 0; k < discovered_families.length(); ++k) {
MethodFamily* lm = discovered_families.at(k);
if (lm->contains_signature(open_slot->signature())) {
lm->determine_target(klass, CHECK);
open_slot->bind_family(lm);
}
}
}
} }
} }
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
tty->print_cr("Creating overpasses..."); tty->print_cr("Creating overpasses...");
...@@ -893,7 +1018,6 @@ void DefaultMethods::generate_default_methods( ...@@ -893,7 +1018,6 @@ void DefaultMethods::generate_default_methods(
#endif // ndef PRODUCT #endif // ndef PRODUCT
} }
/** /**
* Generic analysis was used upon interface '_target' and found a unique * Generic analysis was used upon interface '_target' and found a unique
* default method candidate with generic signature '_method_desc'. This * default method candidate with generic signature '_method_desc'. This
...@@ -912,17 +1036,85 @@ void DefaultMethods::generate_default_methods( ...@@ -912,17 +1036,85 @@ void DefaultMethods::generate_default_methods(
* the selected method along that path. * the selected method along that path.
*/ */
class ShadowChecker : public HierarchyVisitor<ShadowChecker> { class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
private: protected:
generic::DescriptorCache* _cache;
Thread* THREAD; Thread* THREAD;
InstanceKlass* _target; InstanceKlass* _target;
Symbol* _method_name; Symbol* _method_name;
InstanceKlass* _method_holder; InstanceKlass* _method_holder;
generic::MethodDescriptor* _method_desc;
bool _found_shadow; bool _found_shadow;
public:
ShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder,
InstanceKlass* target)
: THREAD(thread), _method_name(name), _method_holder(holder),
_target(target), _found_shadow(false) {}
void* new_node_data(InstanceKlass* cls) { return NULL; }
void free_node_data(void* data) { return; }
bool visit() {
InstanceKlass* ik = current_class();
if (ik == _target && current_depth() == 1) {
return false; // This was the specified super -- no need to search it
}
if (ik == _method_holder || ik == _target) {
// We found a path that should be examined to see if it shadows _method
if (path_has_shadow()) {
_found_shadow = true;
cancel_iteration();
}
return false; // no need to continue up hierarchy
}
return true;
}
virtual bool path_has_shadow() = 0;
bool found_shadow() { return _found_shadow; }
};
// Used for Invokespecial.
// Invokespecial is allowed to invoke a concrete interface method
// and can be used to disambuiguate among qualified candidates,
// which are methods in immediate superinterfaces,
// but may not be used to invoke a candidate that would be shadowed
// from the perspective of the caller.
// Invokespecial is also used in the overpass generation today
// We re-run the shadowchecker because we can't distinguish this case,
// but it should return the same answer, since the overpass target
// is now the invokespecial caller.
class ErasedShadowChecker : public ShadowChecker {
private:
bool path_has_shadow() {
for (int i = current_depth() - 1; i > 0; --i) {
InstanceKlass* ik = class_at_depth(i);
if (ik->is_interface()) {
int end;
int start = ik->find_method_by_name(_method_name, &end);
if (start != -1) {
return true;
}
}
}
return false;
}
public:
ErasedShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder,
InstanceKlass* target)
: ShadowChecker(thread, name, holder, target) {}
};
class GenericShadowChecker : public ShadowChecker {
private:
generic::DescriptorCache* _cache;
generic::MethodDescriptor* _method_desc;
bool path_has_shadow() { bool path_has_shadow() {
generic::Context ctx(_cache); generic::Context ctx(_cache);
...@@ -950,90 +1142,93 @@ class ShadowChecker : public HierarchyVisitor<ShadowChecker> { ...@@ -950,90 +1142,93 @@ class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
public: public:
ShadowChecker(generic::DescriptorCache* cache, Thread* thread, GenericShadowChecker(generic::DescriptorCache* cache, Thread* thread,
Symbol* name, InstanceKlass* holder, generic::MethodDescriptor* desc, Symbol* name, InstanceKlass* holder, generic::MethodDescriptor* desc,
InstanceKlass* target) InstanceKlass* target)
: _cache(cache), THREAD(thread), _method_name(name), _method_holder(holder), : ShadowChecker(thread, name, holder, target) {
_method_desc(desc), _target(target), _found_shadow(false) {} _cache = cache;
_method_desc = desc;
}
};
void* new_node_data(InstanceKlass* cls) { return NULL; }
void free_node_data(void* data) { return; }
bool visit() {
InstanceKlass* ik = current_class();
if (ik == _target && current_depth() == 1) {
return false; // This was the specified super -- no need to search it
}
if (ik == _method_holder || ik == _target) {
// We found a path that should be examined to see if it shadows _method
if (path_has_shadow()) {
_found_shadow = true;
cancel_iteration();
}
return false; // no need to continue up hierarchy
}
return true;
}
bool found_shadow() { return _found_shadow; } // Find the unique qualified candidate from the perspective of the super_class
}; // which is the resolved_klass, which must be an immediate superinterface
// of klass
Method* find_erased_super_default(InstanceKlass* current_class, InstanceKlass* super_class, Symbol* method_name, Symbol* sig, TRAPS) {
// This is called during linktime when we find an invokespecial call that FindMethodsByErasedSig visitor(method_name, sig);
// refers to a direct superinterface. It indicates that we should find the visitor.run(super_class); // find candidates from resolved_klass
// default method in the hierarchy of that superinterface, and if that method
// would have been a candidate from the point of view of 'this' class, then we
// return that method.
Method* DefaultMethods::find_super_default(
Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
ResourceMark rm(THREAD); MethodFamily* family;
visitor.get_discovered_family(&family);
assert(cls != NULL && super != NULL, "Need real classes"); if (family != NULL) {
family->determine_target(current_class, CHECK_NULL); // get target from current_class
}
InstanceKlass* current_class = InstanceKlass::cast(cls); if (family->has_target()) {
InstanceKlass* direction = InstanceKlass::cast(super); Method* target = family->get_selected_target();
InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
// Keep entire hierarchy alive for the duration of the computation // Verify that the identified method is valid from the context of
KeepAliveRegistrar keepAlive(THREAD); // the current class, which is the caller class for invokespecial
KeepAliveVisitor loadKeepAlive(&keepAlive); // link resolution, i.e. ensure there it is not shadowed.
loadKeepAlive.run(current_class); // You can use invokespecial to disambiguate interface methods, but
// you can not use it to skip over an interface method that would shadow it.
ErasedShadowChecker checker(THREAD, target->name(), holder, super_class);
checker.run(current_class);
if (checker.found_shadow()) {
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
tty->print_cr("Finding super default method %s.%s%s from %s", tty->print_cr(" Only candidate found was shadowed.");
direction->name()->as_C_string(),
method_name->as_C_string(), sig->as_C_string(),
current_class->name()->as_C_string());
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
if (!direction->is_interface()) { "Accessible default method not found", NULL);
// We should not be here } else {
return NULL; #ifndef PRODUCT
if (TraceDefaultMethods) {
family->print_sig_on(tty, target->signature(), 1);
}
#endif // ndef PRODUCT
return target;
} }
} else {
assert(family->throws_exception(), "must have target or throw");
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
family->get_exception_message()->as_C_string(), NULL);
}
}
// super_class is assumed to be the direct super of current_class
Method* find_generic_super_default( InstanceKlass* current_class,
InstanceKlass* super_class,
Symbol* method_name, Symbol* sig, TRAPS) {
generic::DescriptorCache cache; generic::DescriptorCache cache;
generic::Context ctx(&cache); generic::Context ctx(&cache);
// Prime the initial generic context for current -> direction // Prime the initial generic context for current -> super_class
ctx.apply_type_arguments(current_class, direction, CHECK_NULL); ctx.apply_type_arguments(current_class, super_class, CHECK_NULL);
FindMethodsByName visitor(&cache, method_name, &ctx, CHECK_NULL); FindMethodsByGenericSig visitor(&cache, method_name, &ctx, CHECK_NULL);
visitor.run(direction); visitor.run(super_class);
GrowableArray<MethodFamily*> families; GrowableArray<GenericMethodFamily*> families;
visitor.get_discovered_families(&families); visitor.get_discovered_families(&families);
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
print_families(&families, sig); print_generic_families(&families, sig);
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
MethodFamily* selected_family = NULL; GenericMethodFamily* selected_family = NULL;
for (int i = 0; i < families.length(); ++i) { for (int i = 0; i < families.length(); ++i) {
MethodFamily* lm = families.at(i); GenericMethodFamily* lm = families.at(i);
if (lm->contains_signature(sig)) { if (lm->contains_signature(sig)) {
lm->determine_target(current_class, CHECK_NULL); lm->determine_target(current_class, CHECK_NULL);
selected_family = lm; selected_family = lm;
...@@ -1046,8 +1241,8 @@ Method* DefaultMethods::find_super_default( ...@@ -1046,8 +1241,8 @@ Method* DefaultMethods::find_super_default(
// Verify that the identified method is valid from the context of // Verify that the identified method is valid from the context of
// the current class // the current class
ShadowChecker checker(&cache, THREAD, target->name(), GenericShadowChecker checker(&cache, THREAD, target->name(),
holder, selected_family->descriptor(), direction); holder, selected_family->descriptor(), super_class);
checker.run(current_class); checker.run(current_class);
if (checker.found_shadow()) { if (checker.found_shadow()) {
...@@ -1059,22 +1254,80 @@ Method* DefaultMethods::find_super_default( ...@@ -1059,22 +1254,80 @@ Method* DefaultMethods::find_super_default(
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(), THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
"Accessible default method not found", NULL); "Accessible default method not found", NULL);
} else { } else {
return target;
}
} else {
assert(selected_family->throws_exception(), "must have target or throw");
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
selected_family->get_exception_message()->as_C_string(), NULL);
}
}
// This is called during linktime when we find an invokespecial call that
// refers to a direct superinterface. It indicates that we should find the
// default method in the hierarchy of that superinterface, and if that method
// would have been a candidate from the point of view of 'this' class, then we
// return that method.
// This logic assumes that the super is a direct superclass of the caller
Method* DefaultMethods::find_super_default(
Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
ResourceMark rm(THREAD);
assert(cls != NULL && super != NULL, "Need real classes");
InstanceKlass* current_class = InstanceKlass::cast(cls);
InstanceKlass* super_class = InstanceKlass::cast(super);
// Keep entire hierarchy alive for the duration of the computation
KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive);
loadKeepAlive.run(current_class); // get hierarchy from current class
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Finding super default method %s.%s%s from %s",
super_class->name()->as_C_string(),
method_name->as_C_string(), sig->as_C_string(),
current_class->name()->as_C_string());
}
#endif // ndef PRODUCT
assert(super_class->is_interface(), "only call for default methods");
Method* target = NULL;
if (ParseGenericDefaults) {
target = find_generic_super_default(current_class, super_class,
method_name, sig, CHECK_NULL);
} else {
target = find_erased_super_default(current_class, super_class,
method_name, sig, CHECK_NULL);
}
#ifndef PRODUCT #ifndef PRODUCT
if (target != NULL) {
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
tty->print(" Returning "); tty->print(" Returning ");
print_method(tty, target, true); print_method(tty, target, true);
tty->print_cr(""); tty->print_cr("");
} }
}
#endif // ndef PRODUCT #endif // ndef PRODUCT
return target; return target;
}
#ifndef PRODUCT
// Return true is broad type is a covariant return of narrow type
static bool covariant_return_type(BasicType narrow, BasicType broad) {
if (narrow == broad) {
return true;
} }
} else { if (broad == T_OBJECT) {
assert(selected_family->throws_exception(), "must have target or throw"); return true;
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
selected_family->get_exception_message()->as_C_string(), NULL);
} }
return false;
} }
#endif // ndef PRODUCT
static int assemble_redirect( static int assemble_redirect(
BytecodeConstantPool* cp, BytecodeBuffer* buffer, BytecodeConstantPool* cp, BytecodeBuffer* buffer,
...@@ -1103,7 +1356,7 @@ static int assemble_redirect( ...@@ -1103,7 +1356,7 @@ static int assemble_redirect(
out.next(); out.next();
} }
assert(out.at_return_type(), "Parameter counts do not match"); assert(out.at_return_type(), "Parameter counts do not match");
assert(in.type() == out.type(), "Return types are not compatible"); assert(covariant_return_type(out.type(), in.type()), "Return types are not compatible");
if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) { if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) {
++parameter_count; // need room for return value ++parameter_count; // need room for return value
...@@ -1144,10 +1397,15 @@ static Method* new_method( ...@@ -1144,10 +1397,15 @@ static Method* new_method(
Symbol* sig, AccessFlags flags, int max_stack, int params, Symbol* sig, AccessFlags flags, int max_stack, int params,
ConstMethod::MethodType mt, TRAPS) { ConstMethod::MethodType mt, TRAPS) {
address code_start = static_cast<address>(bytecodes->adr_at(0)); address code_start = 0;
int code_length = bytecodes->length(); int code_length = 0;
InlineTableSizes sizes; InlineTableSizes sizes;
if (bytecodes != NULL && bytecodes->length() > 0) {
code_start = static_cast<address>(bytecodes->adr_at(0));
code_length = bytecodes->length();
}
Method* m = Method::allocate(cp->pool_holder()->class_loader_data(), Method* m = Method::allocate(cp->pool_holder()->class_loader_data(),
code_length, flags, &sizes, code_length, flags, &sizes,
mt, CHECK_NULL); mt, CHECK_NULL);
......
...@@ -3679,6 +3679,9 @@ class CommandLineFlags { ...@@ -3679,6 +3679,9 @@ class CommandLineFlags {
develop(bool, VerifyGenericSignatures, false, \ develop(bool, VerifyGenericSignatures, false, \
"Abort VM on erroneous or inconsistent generic signatures") \ "Abort VM on erroneous or inconsistent generic signatures") \
\ \
product(bool, ParseGenericDefaults, false, \
"Parse generic signatures for default method handling") \
\
product(bool, UseVMInterruptibleIO, false, \ product(bool, UseVMInterruptibleIO, false, \
"(Unstable, Solaris-specific) Thread interrupt before or with " \ "(Unstable, Solaris-specific) Thread interrupt before or with " \
"EINTR for I/O operations results in OS_INTRPT. The default value"\ "EINTR for I/O operations results in OS_INTRPT. The default value"\
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册