# HG changeset patch # User coleenp # Date 1480620091 18000 # Node ID 11431bbc954957b8ae7abd3303a9d5b066486e85 # Parent d090627aedb82163c62d270989313f3a889b2177 8168699: Validate special case invocations Reviewed-by: acorn, kvn, lfoltan, ctornqvi, ahgross, vlivanov diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1221,12 +1221,19 @@ obj.load_item(); // info for exceptions - CodeEmitInfo* info_for_exception = state_for(x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); CodeStub* stub; if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp --- a/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1453,10 +1453,11 @@ ciKlass* k = op->klass(); assert_different_registers(res, k_RInfo, klass_RInfo, Rtemp); + if (stub->is_simple_exception_stub()) { // TODO: ARM - Late binding is used to prevent confusion of register allocator assert(stub->is_exception_throw_stub(), "must be"); ((SimpleExceptionStub*)stub)->set_obj(op->result_opr()); - + } ciMethodData* md; ciProfileData* data; int mdo_offset_bias = 0; diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp --- a/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -1412,12 +1412,20 @@ obj.load_item(); - CodeEmitInfo* info_for_exception = state_for(x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); + CodeStub* stub; if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, LIR_OprFact::illegalOpr, info_for_exception); diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1131,12 +1131,19 @@ obj.load_item(); LIR_Opr out_reg = rlock_result(x); CodeStub* stub; - CodeEmitInfo* info_for_exception = state_for(x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/s390/vm/c1_LIRGenerator_s390.cpp --- a/hotspot/src/cpu/s390/vm/c1_LIRGenerator_s390.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/s390/vm/c1_LIRGenerator_s390.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -993,12 +993,19 @@ obj.load_item(); // info for exceptions - CodeEmitInfo* info_for_exception = state_for (x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); CodeStub* stub; if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1196,11 +1196,18 @@ obj.load_item(); LIR_Opr out_reg = rlock_result(x); CodeStub* stub; - CodeEmitInfo* info_for_exception = state_for(x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1429,12 +1429,17 @@ obj.load_item(); // info for exceptions - CodeEmitInfo* info_for_exception = state_for(x); + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/)); CodeStub* stub; if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, Deoptimization::Reason_class_check, Deoptimization::Action_none); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/c1/c1_CodeStubs.hpp --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -58,6 +58,7 @@ virtual bool is_exception_throw_stub() const { return false; } virtual bool is_range_check_stub() const { return false; } virtual bool is_divbyzero_stub() const { return false; } + virtual bool is_simple_exception_stub() const { return false; } #ifndef PRODUCT virtual void print_name(outputStream* out) const = 0; #endif @@ -483,6 +484,7 @@ virtual void emit_code(LIR_Assembler* e); virtual CodeEmitInfo* info() const { return _info; } virtual bool is_exception_throw_stub() const { return true; } + virtual bool is_simple_exception_stub() const { return true; } virtual void visit(LIR_OpVisitState* visitor) { if (_obj->is_valid()) visitor->do_input(_obj); visitor->do_slow_case(_info); diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1829,6 +1829,20 @@ log->identify(target), Bytecodes::name(code)); + // invoke-special-super + if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) { + ciInstanceKlass* sender_klass = + calling_klass->is_anonymous() ? calling_klass->host_klass() : + calling_klass; + if (sender_klass->is_interface()) { + int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); + Value receiver = state()->stack_at(index); + CheckCast* c = new CheckCast(sender_klass, receiver, copy_state_before()); + c->set_invokespecial_receiver_check(); + state()->stack_at_put(index, append_split(c)); + } + } + // Some methods are obviously bindable without any type checks so // convert them directly to an invokespecial or invokestatic. if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) { diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/c1/c1_Instruction.hpp --- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -372,6 +372,7 @@ UnorderedIsTrueFlag, NeedsPatchingFlag, ThrowIncompatibleClassChangeErrorFlag, + InvokeSpecialReceiverCheckFlag, ProfileMDOFlag, IsLinkedInBlockFlag, NeedsRangeCheckFlag, @@ -1454,6 +1455,16 @@ bool is_incompatible_class_change_check() const { return check_flag(ThrowIncompatibleClassChangeErrorFlag); } + void set_invokespecial_receiver_check() { + set_flag(InvokeSpecialReceiverCheckFlag, true); + } + bool is_invokespecial_receiver_check() const { + return check_flag(InvokeSpecialReceiverCheckFlag); + } + + virtual bool needs_exception_state() const { + return !is_invokespecial_receiver_check(); + } ciType* declared_type() const; }; diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -595,6 +595,16 @@ return impl; } +ciInstanceKlass* ciInstanceKlass::host_klass() { + assert(is_loaded(), "must be loaded"); + if (is_anonymous()) { + VM_ENTRY_MARK + Klass* host_klass = get_instanceKlass()->host_klass(); + return CURRENT_ENV->get_instance_klass(host_klass); + } + return NULL; +} + // Utility class for printing of the contents of the static fields for // use by compilation replay. It only prints out the information that // could be consumed by the compiler, so for primitive types it prints diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/ci/ciInstanceKlass.hpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -260,6 +260,8 @@ return NULL; } + ciInstanceKlass* host_klass(); + bool can_be_instantiated() { assert(is_loaded(), "must be loaded"); return !is_interface() && !is_abstract(); diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -952,6 +952,13 @@ } // ------------------------------------------------------------------ +// ciMethod::is_object_initializer +// +bool ciMethod::is_object_initializer() const { + return name() == ciSymbol::object_initializer_name(); +} + +// ------------------------------------------------------------------ // ciMethod::has_member_arg // // Return true if the method is a linker intrinsic like _linkToVirtual. diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -337,6 +337,7 @@ bool has_reserved_stack_access() const { return _has_reserved_stack_access; } bool is_boxing_method() const; bool is_unboxing_method() const; + bool is_object_initializer() const; // Replay data methods void dump_name_as_ascii(outputStream* st); diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -720,7 +720,8 @@ Thread* THREAD = thread; // extract receiver from the outgoing argument list if necessary Handle receiver(thread, NULL); - if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) { + if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface || + bytecode == Bytecodes::_invokespecial) { ResourceMark rm(thread); methodHandle m (thread, method(thread)); Bytecode_invoke call(m, bci(thread)); @@ -783,16 +784,25 @@ int index = info.resolved_method()->itable_index(); assert(info.itable_index() == index, ""); } + } else if (bytecode == Bytecodes::_invokespecial) { + assert(info.call_kind() == CallInfo::direct_call, "must be direct call"); } else { assert(info.call_kind() == CallInfo::direct_call || info.call_kind() == CallInfo::vtable_call, ""); } #endif + // Get sender or sender's host_klass, and only set cpCache entry to resolved if + // it is not an interface. The receiver for invokespecial calls within interface + // methods must be checked for every call. + InstanceKlass* sender = pool->pool_holder(); + sender = sender->is_anonymous() ? sender->host_klass() : sender; + switch (info.call_kind()) { case CallInfo::direct_call: cp_cache_entry->set_direct_call( bytecode, - info.resolved_method()); + info.resolved_method(), + sender->is_interface()); break; case CallInfo::vtable_call: cp_cache_entry->set_vtable_call( diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1057,12 +1057,14 @@ void LinkResolver::resolve_special_call(CallInfo& result, + Handle recv, const LinkInfo& link_info, TRAPS) { methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK); runtime_resolve_special_method(result, resolved_method, link_info.resolved_klass(), link_info.current_klass(), + recv, link_info.check_access(), CHECK); } @@ -1149,6 +1151,7 @@ const methodHandle& resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, + Handle recv, bool check_access, TRAPS) { // resolved method is selected method unless we have an old-style lookup @@ -1157,21 +1160,19 @@ // 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()); + if (check_access && + // check if the method is not + resolved_method->name() != vmSymbols::object_initializer_name()) { - if (check_access && + // check if this is an old-style super call and do a new lookup if so // a) check if ACC_SUPER flag is set for the current class - (current_klass->is_super() || !AllowNonVirtualCalls) && + if ((current_klass->is_super() || !AllowNonVirtualCalls) && // 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()) { + current_klass() != resolved_klass()) { // Lookup super method KlassHandle super_klass(THREAD, current_klass->super()); sel_method = lookup_instance_method_in_klasses(super_klass, @@ -1186,6 +1187,27 @@ resolved_method->signature())); } } + + // Check that the class of objectref (the receiver) is the current class or interface, + // or a subtype of the current class or interface (the sender), otherwise invokespecial + // throws IllegalAccessError. + // The verifier checks that the sender is a subtype of the class in the I/MR operand. + // The verifier also checks that the receiver is a subtype of the sender, if the sender is + // a class. If the sender is an interface, the check has to be performed at runtime. + InstanceKlass* sender = InstanceKlass::cast(current_klass()); + sender = sender->is_anonymous() ? sender->host_klass() : sender; + if (sender->is_interface() && recv.not_null()) { + Klass* receiver_klass = recv->klass(); + if (!receiver_klass->is_subtype_of(sender)) { + ResourceMark rm(THREAD); + char buf[500]; + jio_snprintf(buf, sizeof(buf), + "Receiver class %s must be the current class or a subtype of interface %s", + receiver_klass->name()->as_C_string(), + sender->name()->as_C_string()); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf); + } + } } // check if not static @@ -1518,7 +1540,7 @@ methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, link_info, THREAD); + resolve_special_call(info, Handle(), link_info, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1534,7 +1556,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) { switch (byte) { case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break; - case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break; + case Bytecodes::_invokespecial : resolve_invokespecial (result, recv, pool, index, CHECK); break; case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break; case Bytecodes::_invokehandle : resolve_invokehandle (result, pool, index, CHECK); break; case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break; @@ -1563,7 +1585,7 @@ resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK); break; case Bytecodes::_invokespecial: - resolve_special_call(result, link_info, CHECK); + resolve_special_call(result, recv, link_info, CHECK); break; default: fatal("bad call: %s", Bytecodes::name(byte)); @@ -1576,9 +1598,10 @@ } -void LinkResolver::resolve_invokespecial(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { +void LinkResolver::resolve_invokespecial(CallInfo& result, Handle recv, + const constantPoolHandle& pool, int index, TRAPS) { LinkInfo link_info(pool, index, CHECK); - resolve_special_call(result, link_info, CHECK); + resolve_special_call(result, recv, link_info, CHECK); } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -230,6 +230,7 @@ const methodHandle& resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, + Handle recv, bool check_access, TRAPS); static void runtime_resolve_virtual_method (CallInfo& result, const methodHandle& resolved_method, @@ -256,7 +257,7 @@ // runtime resolving from constant pool static void resolve_invokestatic (CallInfo& result, const constantPoolHandle& pool, int index, TRAPS); - static void resolve_invokespecial (CallInfo& result, + static void resolve_invokespecial (CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, TRAPS); static void resolve_invokevirtual (CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, TRAPS); @@ -289,6 +290,7 @@ const LinkInfo& link_info, bool initialize_klass, TRAPS); static void resolve_special_call (CallInfo& result, + Handle recv, const LinkInfo& link_info, TRAPS); static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/oops/cpCache.cpp --- a/hotspot/src/share/vm/oops/cpCache.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/oops/cpCache.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -140,7 +140,8 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code, methodHandle method, - int vtable_index) { + int vtable_index, + bool sender_is_interface) { bool is_vtable_call = (vtable_index >= 0); // FIXME: split this method on this boolean assert(method->interpreter_entry() != NULL, "should have been set at this point"); assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache"); @@ -204,7 +205,13 @@ if (byte_no == 1) { assert(invoke_code != Bytecodes::_invokevirtual && invoke_code != Bytecodes::_invokeinterface, ""); + // Don't mark invokespecial to method as resolved if sender is an interface. The receiver + // has to be checked that it is a subclass of the current class every time this bytecode + // is executed. + if (invoke_code != Bytecodes::_invokespecial || !sender_is_interface || + method->name() == vmSymbols::object_initializer_name()) { set_bytecode_1(invoke_code); + } } else if (byte_no == 2) { if (change_to_virtual) { assert(invoke_code == Bytecodes::_invokeinterface, ""); @@ -234,17 +241,18 @@ NOT_PRODUCT(verify(tty)); } -void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method) { +void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method, + bool sender_is_interface) { int index = Method::nonvirtual_vtable_index; // index < 0; FIXME: inline and customize set_direct_or_vtable_call - set_direct_or_vtable_call(invoke_code, method, index); + set_direct_or_vtable_call(invoke_code, method, index, sender_is_interface); } void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, methodHandle method, int index) { // either the method is a miranda or its holder should accept the given index assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), ""); // index >= 0; FIXME: inline and customize set_direct_or_vtable_call - set_direct_or_vtable_call(invoke_code, method, index); + set_direct_or_vtable_call(invoke_code, method, index, false); } void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, const methodHandle& method, int index) { diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/oops/cpCache.hpp --- a/hotspot/src/share/vm/oops/cpCache.hpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/oops/cpCache.hpp Thu Dec 01 14:21:31 2016 -0500 @@ -230,13 +230,15 @@ void set_direct_or_vtable_call( Bytecodes::Code invoke_code, // the bytecode used for invoking the method methodHandle method, // the method/prototype if any (NULL, otherwise) - int vtable_index // the vtable index if any, else negative + int vtable_index, // the vtable index if any, else negative + bool sender_is_interface ); public: void set_direct_call( // sets entry to exact concrete method entry Bytecodes::Code invoke_code, // the bytecode used for invoking the method - methodHandle method // the method to call + methodHandle method, // the method to call + bool sender_is_interface ); void set_vtable_call( // sets entry to vtable index diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/opto/doCall.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -505,6 +505,30 @@ speculative_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL; } + // invoke-super-special + if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_initializer()) { + ciInstanceKlass* calling_klass = method()->holder(); + ciInstanceKlass* sender_klass = + calling_klass->is_anonymous() ? calling_klass->host_klass() : + calling_klass; + if (sender_klass->is_interface()) { + Node* receiver_node = stack(sp() - nargs); + Node* cls_node = makecon(TypeKlassPtr::make(sender_klass)); + Node* bad_type_ctrl = NULL; + Node* casted_receiver = gen_checkcast(receiver_node, cls_node, &bad_type_ctrl); + if (bad_type_ctrl != NULL) { + PreserveJVMState pjvms(this); + set_control(bad_type_ctrl); + uncommon_trap(Deoptimization::Reason_class_check, + Deoptimization::Action_none); + } + if (stopped()) { + return; // MUST uncommon-trap? + } + set_stack(sp() - nargs, casted_receiver); + } + } + // Note: It's OK to try to inline a virtual call. // The call generator will not attempt to inline a polymorphic call // unless it knows how to optimize the receiver dispatch. diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -727,7 +727,7 @@ assert(!is_signature_polymorphic_static(mh_invoke_id), ""); LinkResolver::resolve_handle_call(result, link_info, THREAD); } else if (ref_kind == JVM_REF_invokeSpecial) { - LinkResolver::resolve_special_call(result, + LinkResolver::resolve_special_call(result, Handle(), link_info, THREAD); } else if (ref_kind == JVM_REF_invokeVirtual) { LinkResolver::resolve_virtual_call(result, Handle(), defc, @@ -755,7 +755,7 @@ { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { - LinkResolver::resolve_special_call(result, link_info, THREAD); + LinkResolver::resolve_special_call(result, Handle(), link_info, THREAD); } else { break; // will throw after end of switch } diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/runtime/javaCalls.cpp --- a/hotspot/src/share/vm/runtime/javaCalls.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -221,7 +221,7 @@ void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; LinkInfo link_info(klass, name, signature); - LinkResolver::resolve_special_call(callinfo, link_info, CHECK); + LinkResolver::resolve_special_call(callinfo, args->receiver(), link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception");