# HG changeset patch # User coleenp # Date 1481657824 18000 # Node ID 0b85ccd6240991e1a501602ff5addec6b88ae0af # Parent 5ee58c7d3938e7118a926410de9fa006077d9032 8168699: Validate special case invocations Reviewed-by: kevinw, vlivanov diff -r 5ee58c7d3938 -r 0b85ccd62409 src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1023,11 +1023,16 @@ 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); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r 5ee58c7d3938 -r 0b85ccd62409 src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1228,12 +1228,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); } else { stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); } diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -57,6 +57,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 @@ -484,6 +485,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1823,6 +1823,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/c1/c1_Instruction.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -381,6 +381,7 @@ UnorderedIsTrueFlag, NeedsPatchingFlag, ThrowIncompatibleClassChangeErrorFlag, + InvokeSpecialReceiverCheckFlag, ProfileMDOFlag, IsLinkedInBlockFlag, NeedsRangeCheckFlag, @@ -1456,6 +1457,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, 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 @@ -58,6 +58,7 @@ _nonstatic_field_size = ik->nonstatic_field_size(); _has_nonstatic_fields = ik->has_nonstatic_fields(); _has_default_methods = ik->has_default_methods(); + _is_anonymous = ik->is_anonymous(); _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: _implementor = NULL; // we will fill these lazily @@ -100,6 +101,7 @@ _nonstatic_field_size = -1; _has_nonstatic_fields = false; _nonstatic_fields = NULL; + _is_anonymous = false; _loader = loader; _protection_domain = protection_domain; _is_shared = false; @@ -591,6 +593,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/ci/ciInstanceKlass.hpp --- a/src/share/vm/ci/ciInstanceKlass.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/ci/ciInstanceKlass.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -53,6 +53,7 @@ bool _has_subklass; bool _has_nonstatic_fields; bool _has_default_methods; + bool _is_anonymous; ciFlags _flags; jint _nonstatic_field_size; @@ -177,6 +178,10 @@ return _has_default_methods; } + bool is_anonymous() { + return _is_anonymous; + } + ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); @@ -248,6 +253,8 @@ return NULL; } + ciInstanceKlass* host_klass(); + // Dump the current state of this klass for compilation replay. virtual void dump_replay_data(outputStream* out); }; diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/ci/ciMethod.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -948,6 +948,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/ci/ciMethod.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -316,6 +316,7 @@ bool can_be_statically_bound() const { return _can_be_statically_bound; } 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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -690,7 +690,8 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode)) { // 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)); @@ -756,16 +757,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() ? InstanceKlass::cast(sender->host_klass()) : sender; + switch (info.call_kind()) { case CallInfo::direct_call: cache_entry(thread)->set_direct_call( bytecode, - info.resolved_method()); + info.resolved_method(), + sender->is_interface()); break; case CallInfo::vtable_call: cache_entry(thread)->set_vtable_call( diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -913,11 +913,11 @@ } -void LinkResolver::resolve_special_call(CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, +void LinkResolver::resolve_special_call(CallInfo& result, Handle recv, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { methodHandle resolved_method; linktime_resolve_special_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); - runtime_resolve_special_method(result, resolved_method, resolved_klass, current_klass, check_access, CHECK); + runtime_resolve_special_method(result, resolved_method, resolved_klass, current_klass, recv, check_access, CHECK); } // throws linktime exceptions @@ -1016,7 +1016,7 @@ // throws runtime exceptions void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, - KlassHandle current_klass, bool check_access, TRAPS) { + KlassHandle current_klass, Handle recv, bool check_access, TRAPS) { // resolved method is selected method unless we have an old-style lookup // for a superclass method @@ -1024,21 +1024,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()); lookup_instance_method_in_klasses(sel_method, super_klass, @@ -1053,6 +1051,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() ? InstanceKlass::cast(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 @@ -1479,7 +1498,7 @@ bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD); + resolve_special_call(info, Handle(), resolved_klass, name, signature, current_klass, check_access, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1495,7 +1514,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, 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; @@ -1526,13 +1545,13 @@ } -void LinkResolver::resolve_invokespecial(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { +void LinkResolver::resolve_invokespecial(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS) { KlassHandle resolved_klass; Symbol* method_name = NULL; Symbol* method_signature = NULL; KlassHandle current_klass; resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); - resolve_special_call(result, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + resolve_special_call(result, recv, resolved_klass, method_name, method_signature, current_klass, true, CHECK); } diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/interpreter/linkResolver.hpp --- a/src/share/vm/interpreter/linkResolver.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/interpreter/linkResolver.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -142,7 +142,7 @@ static void linktime_resolve_virtual_method (methodHandle &resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature,KlassHandle current_klass, bool check_access, TRAPS); static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); - static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS); + static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, Handle recv, bool check_access, TRAPS); static void runtime_resolve_virtual_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS); static void runtime_resolve_interface_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS); @@ -173,7 +173,7 @@ // resolved_klass = specified class (i.e., static receiver class) // current_klass = sending method holder (i.e., class containing the method containing the call being resolved) static void resolve_static_call (CallInfo& result, KlassHandle& resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool initialize_klass, TRAPS); - static void resolve_special_call (CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); + static void resolve_special_call (CallInfo& result, Handle recv, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS); static void resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS); static void resolve_handle_call (CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, TRAPS); @@ -196,7 +196,7 @@ // runtime resolving from constant pool static void resolve_invokestatic (CallInfo& result, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokespecial (CallInfo& result, constantPoolHandle pool, int index, TRAPS); + static void resolve_invokespecial (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS); static void resolve_invokevirtual (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS); static void resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS); static void resolve_invokedynamic (CallInfo& result, constantPoolHandle pool, int index, TRAPS); diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/oops/cpCache.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, 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 @@ -144,7 +144,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"); @@ -208,7 +209,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, ""); @@ -238,17 +245,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, methodHandle method, int index) { diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/oops/cpCache.hpp --- a/src/share/vm/oops/cpCache.hpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/oops/cpCache.hpp Tue Dec 13 14:37:04 2016 -0500 @@ -229,13 +229,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/opto/doCall.cpp Tue Dec 13 14:37:04 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 @@ -477,6 +477,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 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/prims/methodHandles.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, 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 @@ -679,7 +679,7 @@ defc, name, type, caller, THREAD); } else if (ref_kind == JVM_REF_invokeSpecial) { LinkResolver::resolve_special_call(result, - defc, name, type, caller, caller.not_null(), THREAD); + Handle(), defc, name, type, caller, caller.not_null(), THREAD); } else if (ref_kind == JVM_REF_invokeVirtual) { LinkResolver::resolve_virtual_call(result, Handle(), defc, defc, name, type, caller, caller.not_null(), false, THREAD); @@ -706,7 +706,7 @@ assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { LinkResolver::resolve_special_call(result, - defc, name, type, caller, caller.not_null(), THREAD); + Handle(), defc, name, type, caller, caller.not_null(), THREAD); } else { break; // will throw after end of switch } diff -r 5ee58c7d3938 -r 0b85ccd62409 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Tue Dec 13 10:07:12 2016 -0800 +++ b/src/share/vm/runtime/javaCalls.cpp Tue Dec 13 14:37:04 2016 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -231,7 +231,7 @@ void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkResolver::resolve_special_call(callinfo, klass, name, signature, KlassHandle(), false, CHECK); + LinkResolver::resolve_special_call(callinfo, args->receiver(), klass, name, signature, KlassHandle(), false, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception");