8011311: Private interface methods. Default conflicts:ICCE. no erased_super_default.
Reviewed-by: coleenp, bharadwaj, minqi
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Oct 01 08:10:42 2013 -0400
@@ -2545,7 +2545,9 @@
if (method->is_final()) {
*has_final_method = true;
}
- if (is_interface && !method->is_abstract() && !method->is_static()) {
+ if (is_interface && !(*has_default_methods)
+ && !method->is_abstract() && !method->is_static()
+ && !method->is_private()) {
// default method
*has_default_methods = true;
}
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Tue Oct 01 08:10:42 2013 -0400
@@ -325,6 +325,7 @@
Method* _selected_target; // Filled in later, if a unique target exists
Symbol* _exception_message; // If no unique target is found
+ Symbol* _exception_name; // If no unique target is found
bool contains_method(Method* method) {
int* lookup = _member_index.get(method);
@@ -350,7 +351,7 @@
public:
MethodFamily()
- : _selected_target(NULL), _exception_message(NULL) {}
+ : _selected_target(NULL), _exception_message(NULL), _exception_name(NULL) {}
void set_target_if_empty(Method* m) {
if (_selected_target == NULL && !m->is_overpass()) {
@@ -383,6 +384,7 @@
Method* get_selected_target() { return _selected_target; }
Symbol* get_exception_message() { return _exception_message; }
+ Symbol* get_exception_name() { return _exception_name; }
// Either sets the target or the exception error message
void determine_target(InstanceKlass* root, TRAPS) {
@@ -400,15 +402,18 @@
if (qualified_methods.length() == 0) {
_exception_message = generate_no_defaults_message(CHECK);
+ _exception_name = vmSymbols::java_lang_AbstractMethodError();
} else if (qualified_methods.length() == 1) {
Method* method = qualified_methods.at(0);
if (method->is_abstract()) {
_exception_message = generate_abstract_method_message(method, CHECK);
+ _exception_name = vmSymbols::java_lang_AbstractMethodError();
} else {
_selected_target = qualified_methods.at(0);
}
} else {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK);
+ _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
}
assert((has_target() ^ throws_exception()) == 1,
@@ -459,8 +464,9 @@
void print_exception(outputStream* str, int indent) {
assert(throws_exception(), "Should be called otherwise");
+ assert(_exception_name != NULL, "exception_name should be set");
streamIndentor si(str, indent * 2);
- str->indent().print_cr("%s", _exception_message->as_C_string());
+ str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string());
}
#endif // ndef PRODUCT
};
@@ -670,7 +676,10 @@
InstanceKlass* iklass = current_class();
Method* m = iklass->find_method(_method_name, _method_signature);
- if (m != NULL) {
+ // private interface methods are not candidates for default methods
+ // invokespecial to private interface methods doesn't use default method logic
+ // future: take access controls into account for superclass methods
+ if (m != NULL && (!iklass->is_interface() || m->is_public())) {
if (_family == NULL) {
_family = new StatefulMethodFamily();
}
@@ -782,200 +791,7 @@
#endif // ndef PRODUCT
}
-/**
- * Interface inheritance rules were used to find a unique default method
- * candidate for the resolved class. This
- * method is only viable if it would also be in the set of default method
- * candidates if we ran a full analysis on the current class.
- *
- * The only reason that the method would not be in the set of candidates for
- * the current class is if that there's another matching method
- * which is "more specific" than the found method -- i.e., one could find a
- * path in the interface hierarchy in which the matching method appears
- * before we get to '_target'.
- *
- * In order to determine this, we examine all of the implemented
- * interfaces. If we find path that leads to the '_target' interface, then
- * we examine that path to see if there are any methods that would shadow
- * the selected method along that path.
- */
-class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
- protected:
- Thread* THREAD;
- InstanceKlass* _target;
-
- Symbol* _method_name;
- InstanceKlass* _method_holder;
- 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) {}
-};
-
-// 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) {
-
- FindMethodsByErasedSig visitor(method_name, sig);
- visitor.run(super_class); // find candidates from resolved_klass
-
- MethodFamily* family;
- visitor.get_discovered_family(&family);
-
- if (family != NULL) {
- family->determine_target(current_class, CHECK_NULL); // get target from current_class
-
- if (family->has_target()) {
- Method* target = family->get_selected_target();
- InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
-
- // 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(" Only candidate found was shadowed.");
- }
-#endif // ndef PRODUCT
- 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);
- }
- } else {
- // no method found
- ResourceMark rm(THREAD);
- THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(),
- Method::name_and_sig_as_C_string(current_class,
- method_name, sig), 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;
- 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
@@ -1035,10 +851,9 @@
return parameter_count;
}
-static int assemble_abstract_method_error(
- BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* message, TRAPS) {
+static int assemble_method_error(
+ BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) {
- Symbol* errorName = vmSymbols::java_lang_AbstractMethodError();
Symbol* init = vmSymbols::object_initializer_name();
Symbol* sig = vmSymbols::string_void_signature();
@@ -1150,8 +965,7 @@
&bpool, &buffer, slot->signature(), selected, CHECK);
}
} else if (method->throws_exception()) {
- max_stack = assemble_abstract_method_error(
- &bpool, &buffer, method->get_exception_message(), CHECK);
+ max_stack = assemble_method_error(&bpool, &buffer, method->get_exception_name(), method->get_exception_message(), CHECK);
}
if (max_stack != 0) {
AccessFlags flags = accessFlags_from(
--- a/hotspot/src/share/vm/classfile/defaultMethods.hpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/classfile/defaultMethods.hpp Tue Oct 01 08:10:42 2013 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,15 +44,5 @@
// the class.
static void generate_default_methods(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS);
-
-
- // Called during linking when an invokespecial to an direct interface
- // method is found. Selects and returns a method if there is a unique
- // default method in the 'super_iface' part of the hierarchy which is
- // also a candidate default for 'this_klass'. Otherwise throws an AME.
- static Method* find_super_default(
- Klass* this_klass, Klass* super_iface,
- Symbol* method_name, Symbol* method_sig, TRAPS);
};
-
#endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Tue Oct 01 08:10:42 2013 -0400
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -573,6 +572,16 @@
}
if (check_access) {
+ // JDK8 adds non-public interface methods, and accessability check requirement
+ assert(current_klass.not_null() , "current_klass should not be null");
+
+ // check if method can be accessed by the referring class
+ check_method_accessability(current_klass,
+ resolved_klass,
+ KlassHandle(THREAD, resolved_method->method_holder()),
+ resolved_method,
+ CHECK);
+
HandleMark hm(THREAD);
Handle loader (THREAD, InstanceKlass::cast(current_klass())->class_loader());
Handle class_loader (THREAD, resolved_method->method_holder()->class_loader());
@@ -604,6 +613,20 @@
}
}
}
+
+ if (TraceItables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokeinterface resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
+ (current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ resolved_method->method_holder()->internal_name()
+ );
+ resolved_method->access_flags().print_on(tty);
+ tty->cr();
+ }
}
//------------------------------------------------------------------------------------------------------------------------
@@ -795,26 +818,12 @@
Symbol* method_name, Symbol* method_signature,
KlassHandle current_klass, bool check_access, TRAPS) {
- if (resolved_klass->is_interface() && current_klass() != NULL) {
- // If the target class is a direct interface, treat this as a "super"
- // default call.
- //
- // If the current method is an overpass that happens to call a direct
- // super-interface's method, then we'll end up rerunning the default method
- // analysis even though we don't need to, but that's ok since it will end
- // up with the same answer.
- InstanceKlass* ik = InstanceKlass::cast(current_klass());
- Array<Klass*>* interfaces = ik->local_interfaces();
- int num_interfaces = interfaces->length();
- for (int index = 0; index < num_interfaces; index++) {
- if (interfaces->at(index) == resolved_klass()) {
- Method* method = DefaultMethods::find_super_default(current_klass(),
- resolved_klass(), method_name, method_signature, CHECK);
- resolved_method = methodHandle(THREAD, method);
- return;
- }
- }
- }
+ // Invokespecial is called for multiple special reasons:
+ // <init>
+ // local private method invocation, for classes and interfaces
+ // superclass.method, which can also resolve to a default method
+ // and the selected method is recalculated relative to the direct superclass
+ // superinterface.method, which explicitly does not check shadowing
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
@@ -844,6 +853,26 @@
resolved_method->signature()));
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
+ if (TraceItables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
+ (current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ resolved_method->method_holder()->internal_name()
+ );
+ resolved_method->access_flags().print_on(tty);
+ if (resolved_method->method_holder()->is_interface() &&
+ !resolved_method->is_abstract()) {
+ tty->print("default");
+ }
+ if (resolved_method->is_overpass()) {
+ tty->print("overpass");
+ }
+ tty->cr();
+ }
}
// throws runtime exceptions
@@ -851,23 +880,24 @@
KlassHandle current_klass, bool check_access, TRAPS) {
// resolved method is selected method unless we have an old-style lookup
+ // for a superclass method
+ // Invokespecial for a superinterface, resolved method is selected method,
+ // no checks for shadowing
methodHandle sel_method(THREAD, resolved_method());
// check if this is an old-style super call and do a new lookup if so
{ KlassHandle method_klass = KlassHandle(THREAD,
resolved_method->method_holder());
- const bool direct_calling_default_method =
- resolved_klass() != NULL && resolved_method() != NULL &&
- resolved_klass->is_interface() && !resolved_method->is_abstract();
-
- if (!direct_calling_default_method &&
- check_access &&
+ if (check_access &&
// a) check if ACC_SUPER flag is set for the current class
(current_klass->is_super() || !AllowNonVirtualCalls) &&
- // b) check if the method class is a superclass of the current class (superclass relation is not reflexive!)
- current_klass->is_subtype_of(method_klass()) &&
- current_klass() != method_klass() &&
+ // b) check if the class of the resolved_klass is a superclass
+ // (not supertype in order to exclude interface classes) of the current class.
+ // This check is not performed for super.invoke for interface methods
+ // in super interfaces.
+ current_klass->is_subclass_of(resolved_klass()) &&
+ current_klass() != resolved_klass() &&
// c) check if the method is not <init>
resolved_method->name() != vmSymbols::object_initializer_name()) {
// Lookup super method
@@ -905,6 +935,23 @@
sel_method->signature()));
}
+ if (TraceItables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokespecial selected method: resolved-class:%s, method:%s, method_holder:%s, access_flags: ",
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ sel_method->name(),
+ sel_method->signature()),
+ sel_method->method_holder()->internal_name()
+ );
+ sel_method->access_flags().print_on(tty);
+ if (sel_method->method_holder()->is_interface() &&
+ !sel_method->is_abstract()) {
+ tty->print("default");
+ }
+ tty->cr();
+ }
+
// setup result
result.set_static(resolved_klass, sel_method, CHECK);
}
@@ -927,6 +974,18 @@
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
+ // check if private interface method
+ if (resolved_klass->is_interface() && resolved_method->is_private()) {
+ ResourceMark rm(THREAD);
+ char buf[200];
+ jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s",
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ (current_klass.is_null() ? "<NULL>" : current_klass->internal_name()));
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+ }
+
// check if not static
if (resolved_method->is_static()) {
ResourceMark rm(THREAD);
@@ -936,6 +995,27 @@
resolved_method->signature()));
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
+
+ if (PrintVtables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
+ (current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ resolved_method->method_holder()->internal_name()
+ );
+ resolved_method->access_flags().print_on(tty);
+ if (resolved_method->method_holder()->is_interface() &&
+ !resolved_method->is_abstract()) {
+ tty->print("default");
+ }
+ if (resolved_method->is_overpass()) {
+ tty->print("overpass");
+ }
+ tty->cr();
+ }
}
// throws runtime exceptions
@@ -1012,6 +1092,27 @@
selected_method->signature()));
}
+ if (PrintVtables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokevirtual selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, vtable_index:%d, access_flags: ",
+ (recv_klass.is_null() ? "<NULL>" : recv_klass->internal_name()),
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ selected_method->method_holder()->internal_name(),
+ vtable_index
+ );
+ selected_method->access_flags().print_on(tty);
+ if (selected_method->method_holder()->is_interface() &&
+ !selected_method->is_abstract()) {
+ tty->print("default");
+ }
+ if (resolved_method->is_overpass()) {
+ tty->print("overpass");
+ }
+ tty->cr();
+ }
// setup result
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
}
@@ -1042,6 +1143,17 @@
THROW(vmSymbols::java_lang_NullPointerException());
}
+ // check if private interface method
+ if (resolved_klass->is_interface() && resolved_method->is_private()) {
+ ResourceMark rm(THREAD);
+ char buf[200];
+ jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokeinterface: method %s",
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()));
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+ }
+
// check if receiver klass implements the resolved interface
if (!recv_klass->is_subtype_of(resolved_klass())) {
ResourceMark rm(THREAD);
@@ -1071,28 +1183,15 @@
resolved_method->signature()));
}
// check access
- if (sel_method->method_holder()->is_interface()) {
- // Method holder is an interface. Throw Illegal Access Error if sel_method
- // is neither public nor private.
- if (!(sel_method->is_public() || sel_method->is_private())) {
- ResourceMark rm(THREAD);
- THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
- Method::name_and_sig_as_C_string(recv_klass(),
- sel_method->name(),
- sel_method->signature()));
- }
+ // Throw Illegal Access Error if sel_method is not public.
+ if (!sel_method->is_public()) {
+ ResourceMark rm(THREAD);
+ THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
+ Method::name_and_sig_as_C_string(recv_klass(),
+ sel_method->name(),
+ sel_method->signature()));
}
- else {
- // Method holder is a class. Throw Illegal Access Error if sel_method
- // is not public.
- if (!sel_method->is_public()) {
- ResourceMark rm(THREAD);
- THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
- Method::name_and_sig_as_C_string(recv_klass(),
- sel_method->name(),
- sel_method->signature()));
- }
- }
+
// check if abstract
if (check_null_and_abstract && sel_method->is_abstract()) {
ResourceMark rm(THREAD);
@@ -1109,6 +1208,27 @@
return;
}
int itable_index = resolved_method()->itable_index();
+
+ if (TraceItables && Verbose) {
+ ResourceMark rm(THREAD);
+ tty->print("invokeinterface selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, access_flags: ",
+ (recv_klass.is_null() ? "<NULL>" : recv_klass->internal_name()),
+ (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()),
+ sel_method->method_holder()->internal_name()
+ );
+ sel_method->access_flags().print_on(tty);
+ if (sel_method->method_holder()->is_interface() &&
+ !sel_method->is_abstract()) {
+ tty->print("default");
+ }
+ if (resolved_method->is_overpass()) {
+ tty->print("overpass");
+ }
+ tty->cr();
+ }
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
}
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Oct 01 08:10:42 2013 -0400
@@ -1419,6 +1419,8 @@
}
// lookup a method in all the interfaces that this class implements
+// Do NOT return private or static methods, new in JDK8 which are not externally visible
+// They should only be found in the initial InterfaceMethodRef
Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name,
Symbol* signature) const {
Array<Klass*>* all_ifs = transitive_interfaces();
@@ -1427,7 +1429,7 @@
for (int i = 0; i < num_ifs; i++) {
ik = InstanceKlass::cast(all_ifs->at(i));
Method* m = ik->lookup_method(name, signature);
- if (m != NULL) {
+ if (m != NULL && m->is_public() && !m->is_static()) {
return m;
}
}
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Fri Sep 27 10:08:56 2013 -0400
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Tue Oct 01 08:10:42 2013 -0400
@@ -292,9 +292,10 @@
return allocate_new;
}
- // private methods always have a new entry in the vtable
+ // private methods in classes always have a new entry in the vtable
// specification interpretation since classic has
// private methods not overriding
+ // JDK8 adds private methods in interfaces which require invokespecial
if (target_method()->is_private()) {
return allocate_new;
}
@@ -442,9 +443,10 @@
return true;
}
- // private methods always have a new entry in the vtable
+ // private methods in classes always have a new entry in the vtable
// specification interpretation since classic has
// private methods not overriding
+ // JDK8 adds private methods in interfaces which require invokespecial
if (target_method()->is_private()) {
return true;
}
@@ -520,7 +522,7 @@
Klass* method_holder = m->method_holder();
InstanceKlass *mhk = InstanceKlass::cast(method_holder);
- // miranda methods are interface methods in a class's vtable
+ // miranda methods are public abstract instance interface methods in a class's vtable
if (mhk->is_interface()) {
assert(m->is_public(), "should be public");
assert(ik()->implements_interface(method_holder) , "this class should implement the interface");
@@ -534,6 +536,8 @@
// "miranda" means not static, not defined by this class, and not defined
// in super unless it is private and therefore inaccessible to this class.
// the caller must make sure that the method belongs to an interface implemented by the class
+// Miranda methods only include public interface instance methods
+// Not private methods, not static methods, not default = concrete abstract
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
if (m->is_static()) {
return false;