aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/classfile/defaultMethods.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/vm/classfile/defaultMethods.cpp')
-rw-r--r--src/share/vm/classfile/defaultMethods.cpp588
1 files changed, 423 insertions, 165 deletions
diff --git a/src/share/vm/classfile/defaultMethods.cpp b/src/share/vm/classfile/defaultMethods.cpp
index d6529ca44..3ff2996b3 100644
--- a/src/share/vm/classfile/defaultMethods.cpp
+++ b/src/share/vm/classfile/defaultMethods.cpp
@@ -318,17 +318,17 @@ class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> {
}
};
+
// A 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
+// erased method. 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.
+// erased method defined in an interface.
+
class MethodFamily : public ResourceObj {
private:
- generic::MethodDescriptor* _descriptor; // language-level description
GrowableArray<Pair<Method*,QualifiedState> > _members;
ResourceHashtable<Method*, int> _member_index;
@@ -358,15 +358,8 @@ class MethodFamily : public ResourceObj {
public:
- MethodFamily(generic::MethodDescriptor* canonical_desc)
- : _descriptor(canonical_desc), _selected_target(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);
- }
+ MethodFamily()
+ : _selected_target(NULL), _exception_message(NULL) {}
void set_target_if_empty(Method* m) {
if (_selected_target == NULL && !m->is_overpass()) {
@@ -441,16 +434,10 @@ class MethodFamily : public ResourceObj {
}
#ifndef PRODUCT
- void print_on(outputStream* str) const {
- print_on(str, 0);
- }
-
- void print_on(outputStream* str, int indent) const {
+ void print_sig_on(outputStream* str, Symbol* signature, int indent) const {
streamIndentor si(str, indent * 2);
- generic::Context ctx(NULL); // empty, as _descriptor already canonicalized
- TempNewSymbol family = descriptor()->reify_signature(&ctx, Thread::current());
- str->indent().print_cr("Logical Method %s:", family->as_C_string());
+ str->indent().print_cr("Logical Method %s:", signature->as_C_string());
streamIndentor si2(str);
for (int i = 0; i < _members.length(); ++i) {
@@ -516,38 +503,94 @@ Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods
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;
-// 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
-// when adding members to the MethodFamily.
+// when adding members to the MethodFamily
class StatefulMethodFamily : public ResourceObj {
friend class StateRestorer;
private:
- MethodFamily* _method;
QualifiedState _qualification_state;
void set_qualification_state(QualifiedState state) {
_qualification_state = state;
}
+ protected:
+ MethodFamily* _method_family;
+
public:
- StatefulMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx) {
- _method = new MethodFamily(md->canonicalize(ctx));
- _qualification_state = QUALIFIED;
+ StatefulMethodFamily() {
+ _method_family = new MethodFamily();
+ _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) {
- return _method->descriptor_matches(md, ctx);
- }
+ MethodFamily* get_method_family() { return _method_family; }
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 {
private:
StatefulMethodFamily* _method;
@@ -563,9 +606,9 @@ class StateRestorer : public PseudoScopeMark {
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
StateRestorer* mark = new StateRestorer(this, _qualification_state);
if (_qualification_state == QUALIFIED) {
- _method->record_qualified_method(mo);
+ _method_family->record_qualified_method(mo);
} else {
- _method->record_disqualified_method(mo);
+ _method_family->record_disqualified_method(mo);
}
// Everything found "above"??? this method in the hierarchy walk is set to
// disqualified
@@ -573,15 +616,15 @@ StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
return mark;
}
-class StatefulMethodFamilies : public ResourceObj {
+class StatefulGenericMethodFamilies : public ResourceObj {
private:
- GrowableArray<StatefulMethodFamily*> _methods;
+ GrowableArray<StatefulGenericMethodFamily*> _methods;
public:
- StatefulMethodFamily* find_matching(
+ StatefulGenericMethodFamily* find_matching(
generic::MethodDescriptor* md, generic::Context* ctx) {
for (int i = 0; i < _methods.length(); ++i) {
- StatefulMethodFamily* existing = _methods.at(i);
+ StatefulGenericMethodFamily* existing = _methods.at(i);
if (existing->descriptor_matches(md, ctx)) {
return existing;
}
@@ -589,17 +632,17 @@ class StatefulMethodFamilies : public ResourceObj {
return NULL;
}
- StatefulMethodFamily* find_matching_or_create(
+ StatefulGenericMethodFamily* find_matching_or_create(
generic::MethodDescriptor* md, generic::Context* ctx) {
- StatefulMethodFamily* method = find_matching(md, ctx);
+ StatefulGenericMethodFamily* method = find_matching(md, ctx);
if (method == NULL) {
- method = new StatefulMethodFamily(md, ctx);
+ method = new StatefulGenericMethodFamily(md, ctx);
_methods.append(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) {
array->append(_methods.at(i)->get_method_family());
}
@@ -683,26 +726,79 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_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
// 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
// language-level signature.
-class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
+class FindMethodsByGenericSig : public HierarchyVisitor<FindMethodsByGenericSig> {
private:
// Context data
Thread* THREAD;
generic::DescriptorCache* _cache;
Symbol* _method_name;
generic::Context* _ctx;
- StatefulMethodFamilies _families;
+ StatefulGenericMethodFamilies _families;
public:
- FindMethodsByName(generic::DescriptorCache* cache, Symbol* name,
+ FindMethodsByGenericSig(generic::DescriptorCache* cache, Symbol* name,
generic::Context* 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);
}
@@ -733,7 +829,7 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
// Find all methods on this hierarchy that match this method
// (name, signature). This class collects other families of this
// method name.
- StatefulMethodFamily* family =
+ StatefulGenericMethodFamily* family =
_families.find_matching_or_create(md, _ctx);
if (klass->is_interface()) {
@@ -752,8 +848,8 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
};
#ifndef PRODUCT
-static void print_families(
- GrowableArray<MethodFamily*>* methods, Symbol* match) {
+static void print_generic_families(
+ GrowableArray<GenericMethodFamily*>* methods, Symbol* match) {
streamIndentor si(tty, 4);
if (methods->length() == 0) {
tty->indent();
@@ -761,22 +857,87 @@ static void print_families(
}
for (int i = 0; i < methods->length(); ++i) {
tty->indent();
- MethodFamily* lm = methods->at(i);
+ GenericMethodFamily* lm = methods->at(i);
if (lm->contains_signature(match)) {
tty->print_cr("<Matching>");
} else {
tty->print_cr("<Non-Matching>");
}
- lm->print_on(tty, 1);
+ lm->print_sig_on(tty, lm->get_generic_sig(), 1);
}
}
#endif // ndef PRODUCT
-static void merge_in_new_methods(InstanceKlass* klass,
- GrowableArray<Method*>* new_methods, TRAPS);
static void create_overpasses(
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
// after the classfile has been parsed if some ancestor has default methods.
//
@@ -807,8 +968,6 @@ void DefaultMethods::generate_default_methods(
// whatever scope it's in.
ResourceMark rm(THREAD);
- generic::DescriptorCache cache;
-
// Keep entire hierarchy alive for the duration of the computation
KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive);
@@ -837,47 +996,13 @@ void DefaultMethods::generate_default_methods(
tty->print_cr("");
}
#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
- for (int j = i; 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) {
- MethodFamily* lm = discovered_families.at(k);
-
- if (lm->contains_signature(open_slot->signature())) {
- lm->determine_target(klass, CHECK);
- open_slot->bind_family(lm);
- }
- }
- }
+ if (ParseGenericDefaults) {
+ generate_generic_defaults(klass, empty_slots, slot, i, CHECK);
+ } else {
+ generate_erased_defaults(klass, empty_slots, slot, CHECK);
}
- }
-
+ }
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Creating overpasses...");
@@ -893,7 +1018,6 @@ void DefaultMethods::generate_default_methods(
#endif // ndef PRODUCT
}
-
/**
* Generic analysis was used upon interface '_target' and found a unique
* default method candidate with generic signature '_method_desc'. This
@@ -912,17 +1036,85 @@ void DefaultMethods::generate_default_methods(
* the selected method along that path.
*/
class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
- private:
- generic::DescriptorCache* _cache;
+ protected:
Thread* THREAD;
InstanceKlass* _target;
Symbol* _method_name;
InstanceKlass* _method_holder;
- generic::MethodDescriptor* _method_desc;
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() {
generic::Context ctx(_cache);
@@ -950,90 +1142,93 @@ class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
public:
- ShadowChecker(generic::DescriptorCache* cache, Thread* thread,
+ GenericShadowChecker(generic::DescriptorCache* cache, Thread* thread,
Symbol* name, InstanceKlass* holder, generic::MethodDescriptor* desc,
InstanceKlass* target)
- : _cache(cache), THREAD(thread), _method_name(name), _method_holder(holder),
- _method_desc(desc), _target(target), _found_shadow(false) {}
+ : ShadowChecker(thread, name, holder, target) {
+ _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
-// 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.
-Method* DefaultMethods::find_super_default(
- Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
+ FindMethodsByErasedSig visitor(method_name, sig);
+ visitor.run(super_class); // find candidates from resolved_klass
- 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);
- InstanceKlass* direction = InstanceKlass::cast(super);
+ if (family->has_target()) {
+ Method* target = family->get_selected_target();
+ InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
- // Keep entire hierarchy alive for the duration of the computation
- KeepAliveRegistrar keepAlive(THREAD);
- KeepAliveVisitor loadKeepAlive(&keepAlive);
- loadKeepAlive.run(current_class);
+ // Verify that the identified method is valid from the context of
+ // the current class, which is the caller class for invokespecial
+ // link resolution, i.e. ensure there it is not shadowed.
+ // 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
- if (TraceDefaultMethods) {
- tty->print_cr("Finding super default method %s.%s%s from %s",
- direction->name()->as_C_string(),
- method_name->as_C_string(), sig->as_C_string(),
- current_class->name()->as_C_string());
- }
+ if (TraceDefaultMethods) {
+ tty->print_cr(" Only candidate found was shadowed.");
+ }
#endif // ndef PRODUCT
-
- if (!direction->is_interface()) {
- // We should not be here
- return NULL;
+ THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
+ "Accessible default method not found", NULL);
+ } else {
+#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::Context ctx(&cache);
- // Prime the initial generic context for current -> direction
- ctx.apply_type_arguments(current_class, direction, CHECK_NULL);
+ // Prime the initial generic context for current -> super_class
+ ctx.apply_type_arguments(current_class, super_class, CHECK_NULL);
- FindMethodsByName visitor(&cache, method_name, &ctx, CHECK_NULL);
- visitor.run(direction);
+ FindMethodsByGenericSig visitor(&cache, method_name, &ctx, CHECK_NULL);
+ visitor.run(super_class);
- GrowableArray<MethodFamily*> families;
+ GrowableArray<GenericMethodFamily*> families;
visitor.get_discovered_families(&families);
#ifndef PRODUCT
if (TraceDefaultMethods) {
- print_families(&families, sig);
+ print_generic_families(&families, sig);
}
#endif // ndef PRODUCT
- MethodFamily* selected_family = NULL;
+ GenericMethodFamily* selected_family = NULL;
for (int i = 0; i < families.length(); ++i) {
- MethodFamily* lm = families.at(i);
+ GenericMethodFamily* lm = families.at(i);
if (lm->contains_signature(sig)) {
lm->determine_target(current_class, CHECK_NULL);
selected_family = lm;
@@ -1046,8 +1241,8 @@ Method* DefaultMethods::find_super_default(
// Verify that the identified method is valid from the context of
// the current class
- ShadowChecker checker(&cache, THREAD, target->name(),
- holder, selected_family->descriptor(), direction);
+ GenericShadowChecker checker(&cache, THREAD, target->name(),
+ holder, selected_family->descriptor(), super_class);
checker.run(current_class);
if (checker.found_shadow()) {
@@ -1059,13 +1254,6 @@ Method* DefaultMethods::find_super_default(
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
"Accessible default method not found", NULL);
} else {
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print(" Returning ");
- print_method(tty, target, true);
- tty->print_cr("");
- }
-#endif // ndef PRODUCT
return target;
}
} else {
@@ -1075,6 +1263,71 @@ Method* DefaultMethods::find_super_default(
}
}
+// 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
+ if (target != NULL) {
+ if (TraceDefaultMethods) {
+ tty->print(" Returning ");
+ print_method(tty, target, true);
+ tty->print_cr("");
+ }
+ }
+#endif // ndef PRODUCT
+ 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;
+ }
+ if (broad == T_OBJECT) {
+ return true;
+ }
+ return false;
+}
+#endif // ndef PRODUCT
static int assemble_redirect(
BytecodeConstantPool* cp, BytecodeBuffer* buffer,
@@ -1103,7 +1356,7 @@ static int assemble_redirect(
out.next();
}
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)) {
++parameter_count; // need room for return value
@@ -1144,10 +1397,15 @@ static Method* new_method(
Symbol* sig, AccessFlags flags, int max_stack, int params,
ConstMethod::MethodType mt, TRAPS) {
- address code_start = static_cast<address>(bytecodes->adr_at(0));
- int code_length = bytecodes->length();
+ address code_start = 0;
+ int code_length = 0;
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(),
code_length, flags, &sizes,
mt, CHECK_NULL);