提交 f2a7a11c 编写于 作者: A acorn

8011311: Private interface methods. Default conflicts:ICCE. no erased_super_default.

Reviewed-by: coleenp, bharadwaj, minqi
上级 b65ffa09
......@@ -2545,7 +2545,9 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
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;
}
......
......@@ -325,6 +325,7 @@ class MethodFamily : public ResourceObj {
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 @@ class MethodFamily : public ResourceObj {
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 @@ class MethodFamily : public ResourceObj {
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 @@ class MethodFamily : public ResourceObj {
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 @@ class MethodFamily : public ResourceObj {
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 @@ class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
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 @@ void DefaultMethods::generate_default_methods(
#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 @@ static int assemble_redirect(
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 @@ static void create_overpasses(
&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(
......
/*
* 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 @@ class DefaultMethods : AllStatic {
// 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
/*
* 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 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
}
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 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
}
}
}
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 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
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 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
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 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
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 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
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 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
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 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
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 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
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 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
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 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
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()));
}
}
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()));
}
// 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 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
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);
}
......
......@@ -1419,6 +1419,8 @@ Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) c
}
// 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 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name,
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;
}
}
......
......@@ -292,9 +292,10 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
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 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
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 @@ bool klassVtable::is_miranda_entry_at(int i) {
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 @@ bool klassVtable::is_miranda_entry_at(int i) {
// "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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册