From f2a7a11c049c1a1b3167c4e0f2bc541cdf4d2789 Mon Sep 17 00:00:00 2001 From: acorn Date: Tue, 1 Oct 2013 08:10:42 -0400 Subject: [PATCH] 8011311: Private interface methods. Default conflicts:ICCE. no erased_super_default. Reviewed-by: coleenp, bharadwaj, minqi --- src/share/vm/classfile/classFileParser.cpp | 4 +- src/share/vm/classfile/defaultMethods.cpp | 216 ++------------------ src/share/vm/classfile/defaultMethods.hpp | 12 +- src/share/vm/interpreter/linkResolver.cpp | 222 ++++++++++++++++----- src/share/vm/oops/instanceKlass.cpp | 4 +- src/share/vm/oops/klassVtable.cpp | 10 +- 6 files changed, 200 insertions(+), 268 deletions(-) diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp index 70662d3e8..68a3eb4bd 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp @@ -2545,7 +2545,9 @@ Array* 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; } diff --git a/src/share/vm/classfile/defaultMethods.cpp b/src/share/vm/classfile/defaultMethods.cpp index 99a45b55b..df3878a1e 100644 --- a/src/share/vm/classfile/defaultMethods.cpp +++ b/src/share/vm/classfile/defaultMethods.cpp @@ -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 { 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 { - 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( diff --git a/src/share/vm/classfile/defaultMethods.hpp b/src/share/vm/classfile/defaultMethods.hpp index 8a31eee6b..9c7470aa9 100644 --- a/src/share/vm/classfile/defaultMethods.hpp +++ b/src/share/vm/classfile/defaultMethods.hpp @@ -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 @@ class DefaultMethods : AllStatic { // the class. static void generate_default_methods( InstanceKlass* klass, GrowableArray* 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 diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp index 3f9d0d193..a12b68b2f 100644 --- a/src/share/vm/interpreter/linkResolver.cpp +++ b/src/share/vm/interpreter/linkResolver.cpp @@ -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 @@ 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() ? "" : current_klass->internal_name()), + (resolved_klass.is_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* 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: + // + // 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() ? "" : current_klass->internal_name()), + (resolved_klass.is_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 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() ? "" : 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() ? "" : 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() ? "" : current_klass->internal_name()), + (resolved_klass.is_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() ? "" : recv_klass->internal_name()), + (resolved_klass.is_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() ? "" : recv_klass->internal_name()), + (resolved_klass.is_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); } diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp index 859c6aa3e..82997ed6d 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp @@ -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* 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; } } diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp index 710536884..6788c619c 100644 --- a/src/share/vm/oops/klassVtable.cpp +++ b/src/share/vm/oops/klassVtable.cpp @@ -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* class_methods, Klass* super) { if (m->is_static()) { return false; -- GitLab