diff --git a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index f7ec771c1248ed2ced20ba238df15489084e6a68..d2c04c9aba2e8d65a4ab046a9c35f4a87fcb92e2 100644 --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -1023,11 +1023,16 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { 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 --git a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 70176a289ba3dec425c65721ff89be6c5f4e39a5..48cab82b0a4339d04af058fd35ba8a3d1455b6ef 100644 --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -1228,12 +1228,17 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { 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 --git a/src/share/vm/c1/c1_CodeStubs.hpp b/src/share/vm/c1/c1_CodeStubs.hpp index d3c5a0d8bbbc27b1a5dbebb10b6b536e0466b70b..9fef1d1547b45bf2f5ddbf6d0e000e5b5d2967bc 100644 --- a/src/share/vm/c1/c1_CodeStubs.hpp +++ b/src/share/vm/c1/c1_CodeStubs.hpp @@ -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 @@ class CodeStub: public CompilationResourceObj { 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 @@ class SimpleExceptionStub: public CodeStub { 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 --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp index 844bf7636f74027932876a3bfae6a56015f15e8b..bba1452da4833b6eeed7f4ef64ea7491a4e79e63 100644 --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1823,6 +1823,20 @@ void GraphBuilder::invoke(Bytecodes::Code code) { 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 --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp index 8f358c97ef25dd35678e0a3206ed70c04398911f..b4e77d672dbd3face08e48b7ece46198f450ed5a 100644 --- a/src/share/vm/c1/c1_Instruction.hpp +++ b/src/share/vm/c1/c1_Instruction.hpp @@ -381,6 +381,7 @@ class Instruction: public CompilationResourceObj { UnorderedIsTrueFlag, NeedsPatchingFlag, ThrowIncompatibleClassChangeErrorFlag, + InvokeSpecialReceiverCheckFlag, ProfileMDOFlag, IsLinkedInBlockFlag, NeedsRangeCheckFlag, @@ -1456,6 +1457,16 @@ LEAF(CheckCast, TypeCheck) 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 --git a/src/share/vm/ci/ciInstanceKlass.cpp b/src/share/vm/ci/ciInstanceKlass.cpp index f8b39ed79c98c42023331767a07bf466211ad189..8b17c9b2925d9127a61ecdf140c1ffb2095bca42 100644 --- a/src/share/vm/ci/ciInstanceKlass.cpp +++ b/src/share/vm/ci/ciInstanceKlass.cpp @@ -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 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : _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 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name, _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 @@ ciInstanceKlass* ciInstanceKlass::implementor() { 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 --git a/src/share/vm/ci/ciInstanceKlass.hpp b/src/share/vm/ci/ciInstanceKlass.hpp index 41c42935a6a4c7951c588eccb9881db0f79543bc..c1493dafefed42f43ac169b499ebcfd6f98afe32 100644 --- a/src/share/vm/ci/ciInstanceKlass.hpp +++ b/src/share/vm/ci/ciInstanceKlass.hpp @@ -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 @@ private: bool _has_subklass; bool _has_nonstatic_fields; bool _has_default_methods; + bool _is_anonymous; ciFlags _flags; jint _nonstatic_field_size; @@ -177,6 +178,10 @@ public: 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 @@ public: return NULL; } + ciInstanceKlass* host_klass(); + // Dump the current state of this klass for compilation replay. virtual void dump_replay_data(outputStream* out); }; diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp index 1f66105a9f08042591ff9cc086a71a4aa8523fa1..6646e143029752ed3fc05dddaeaa962fd32b53b9 100644 --- a/src/share/vm/ci/ciMethod.cpp +++ b/src/share/vm/ci/ciMethod.cpp @@ -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 @@ -947,6 +947,13 @@ bool ciMethod::is_compiled_lambda_form() const { return iid == vmIntrinsics::_compiledLambdaForm; } +// ------------------------------------------------------------------ +// ciMethod::is_object_initializer +// +bool ciMethod::is_object_initializer() const { + return name() == ciSymbol::object_initializer_name(); +} + // ------------------------------------------------------------------ // ciMethod::has_member_arg // diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp index af66c4f2dc35fb299a32ca3ba20c8d6644e52c71..68bc1eb2d949eca8a6712f5af4644457f7e2f252 100644 --- a/src/share/vm/ci/ciMethod.hpp +++ b/src/share/vm/ci/ciMethod.hpp @@ -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 @@ class ciMethod : public ciMetadata { 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 --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp index f2460da9cc61ce8bc71be5e0ff85580e9a56ac9f..25654646ce6e6ee95626155175218843df70f63f 100644 --- a/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/src/share/vm/interpreter/interpreterRuntime.cpp @@ -690,7 +690,8 @@ IRT_END 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 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes 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 --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp index 5a18a50c764982e2ae502d42c4b61799caa28846..ea505d2fe90b70920d2b0d3d63d319d5b29f69f9 100644 --- a/src/share/vm/interpreter/linkResolver.cpp +++ b/src/share/vm/interpreter/linkResolver.cpp @@ -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::linktime_resolve_static_method(methodHandle& resolved_method, } -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 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method // 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 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle // 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 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle 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 @@ methodHandle LinkResolver::resolve_special_call_or_null( 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 @@ methodHandle LinkResolver::resolve_special_call_or_null( 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_invokestatic(CallInfo& result, constantPoolHandle poo } -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 --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp index 5fa536491c926907d3c658e17ae8ace7c3505f93..0fc1712dc94f207d5efc8689131770e2a1298207 100644 --- a/src/share/vm/interpreter/linkResolver.hpp +++ b/src/share/vm/interpreter/linkResolver.hpp @@ -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 @@ class LinkResolver: AllStatic { 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 @@ class LinkResolver: AllStatic { // 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 @@ class LinkResolver: AllStatic { // 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 --git a/src/share/vm/oops/cpCache.cpp b/src/share/vm/oops/cpCache.cpp index d0c77501e9e2a4939eeabe24e484600c27aee159..3bbb40088269d72fac607d6fc0cbc8ea149d5215 100644 --- a/src/share/vm/oops/cpCache.cpp +++ b/src/share/vm/oops/cpCache.cpp @@ -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_parameter_size(int value) { 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 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co 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 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co 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 --git a/src/share/vm/oops/cpCache.hpp b/src/share/vm/oops/cpCache.hpp index d3bc3a2da76b60e0bea56401484c97ecb1b55265..17860b432778b476739115cd27aae42acb9ffc81 100644 --- a/src/share/vm/oops/cpCache.hpp +++ b/src/share/vm/oops/cpCache.hpp @@ -229,13 +229,15 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { 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 --git a/src/share/vm/opto/doCall.cpp b/src/share/vm/opto/doCall.cpp index f4ed1aed199b91d3d573cb9a21ce95fc3a01ca9e..5ec9aab78a48bb8c0d0022cce27e5304cc4c02f2 100644 --- a/src/share/vm/opto/doCall.cpp +++ b/src/share/vm/opto/doCall.cpp @@ -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 @@ void Parse::do_call() { 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 --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp index 62aece7324e27c5e2a12cb1214ceeaa2e2fc5caf..e477c70759f5f2a874a108064897d06dc6ab9ea4 100644 --- a/src/share/vm/prims/methodHandles.cpp +++ b/src/share/vm/prims/methodHandles.cpp @@ -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 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS 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 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS 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 --git a/src/share/vm/runtime/javaCalls.cpp b/src/share/vm/runtime/javaCalls.cpp index aefafadbe5efa21724999903706485b31f9a7354..52fe2fb2cf82dae463cd15942843515eea3ebf30 100644 --- a/src/share/vm/runtime/javaCalls.cpp +++ b/src/share/vm/runtime/javaCalls.cpp @@ -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_virtual(JavaValue* result, Handle receiver, KlassHandle spe 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");