8168699: Validate special case invocations
Reviewed-by: acorn, kvn, lfoltan, ctornqvi, ahgross, vlivanov
--- 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);
}
--- 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;
--- 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);
--- 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);
}
--- 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);
}
--- 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);
}
--- 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);
}
--- 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);
--- 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()) {
--- 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;
};
--- 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
--- 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();
--- 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.
--- 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);
--- 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(
--- 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 <init>
+ 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 <init>
- 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);
}
--- 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,
--- 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) {
--- 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
--- 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.
--- 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
}
--- 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");