提交 8f6f72b9 编写于 作者: T twisti

7007377: JSR 292 MethodHandlesTest.testCastFailure fails on SPARC with -Xcomp +DeoptimizeALot

Reviewed-by: kvn, jrose
上级 c006d3f4
...@@ -395,18 +395,23 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { ...@@ -395,18 +395,23 @@ int MethodHandles::adapter_conversion_ops_supported_mask() {
// //
// Generate an "entry" field for a method handle. // Generate an "entry" field for a method handle.
// This determines how the method handle will respond to calls. // This determines how the method handle will respond to calls.
void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) {
// Here is the register state during an interpreted call, // Here is the register state during an interpreted call,
// as set up by generate_method_handle_interpreter_entry(): // as set up by generate_method_handle_interpreter_entry():
// - G5: garbage temp (was MethodHandle.invoke methodOop, unused) // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
// - G3: receiver method handle // - G3: receiver method handle
// - O5_savedSP: sender SP (must preserve) // - O5_savedSP: sender SP (must preserve)
Register O0_argslot = O0; const Register O0_argslot = O0;
Register O1_scratch = O1; const Register O1_scratch = O1;
Register O2_scratch = O2; const Register O2_scratch = O2;
Register O3_scratch = O3; const Register O3_scratch = O3;
Register G5_index = G5; const Register G5_index = G5;
// Argument registers for _raise_exception.
const Register O0_code = O0;
const Register O1_actual = O1;
const Register O2_required = O2;
guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
...@@ -439,48 +444,36 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -439,48 +444,36 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
case _raise_exception: case _raise_exception:
{ {
// Not a real MH entry, but rather shared code for raising an // Not a real MH entry, but rather shared code for raising an
// exception. Extra local arguments are passed in scratch // exception. Since we use a C2I adapter to set up the
// registers, as required type in O3, failing object (or NULL) // interpreter state, arguments are expected in compiler
// in O2, failing bytecode type in O1. // argument registers.
methodHandle mh(raise_exception_method());
address c2i_entry = methodOopDesc::make_adapters(mh, CATCH);
__ mov(O5_savedSP, SP); // Cut the stack back to where the caller started. __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started.
// Push arguments as if coming from the interpreter. Label L_no_method;
Register O0_scratch = O0_argslot;
int stackElementSize = Interpreter::stackElementSize;
// Make space on the stack for the arguments and set Gargs
// correctly.
__ sub(SP, 4*stackElementSize, SP); // Keep stack aligned.
__ add(SP, (frame::varargs_offset)*wordSize - 1*Interpreter::stackElementSize + STACK_BIAS + BytesPerWord, Gargs);
// void raiseException(int code, Object actual, Object required)
__ st( O1_scratch, Address(Gargs, 2*stackElementSize)); // code
__ st_ptr(O2_scratch, Address(Gargs, 1*stackElementSize)); // actual
__ st_ptr(O3_scratch, Address(Gargs, 0*stackElementSize)); // required
Label no_method;
// FIXME: fill in _raise_exception_method with a suitable sun.dyn method // FIXME: fill in _raise_exception_method with a suitable sun.dyn method
__ set(AddressLiteral((address) &_raise_exception_method), G5_method); __ set(AddressLiteral((address) &_raise_exception_method), G5_method);
__ ld_ptr(Address(G5_method, 0), G5_method); __ ld_ptr(Address(G5_method, 0), G5_method);
__ tst(G5_method); __ tst(G5_method);
__ brx(Assembler::zero, false, Assembler::pn, no_method); __ brx(Assembler::zero, false, Assembler::pn, L_no_method);
__ delayed()->nop(); __ delayed()->nop();
int jobject_oop_offset = 0; const int jobject_oop_offset = 0;
__ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method);
__ tst(G5_method); __ tst(G5_method);
__ brx(Assembler::zero, false, Assembler::pn, no_method); __ brx(Assembler::zero, false, Assembler::pn, L_no_method);
__ delayed()->nop(); __ delayed()->nop();
__ verify_oop(G5_method); __ verify_oop(G5_method);
__ jump_indirect_to(G5_method_fie, O1_scratch); __ jump_to(AddressLiteral(c2i_entry), O3_scratch);
__ delayed()->nop(); __ delayed()->nop();
// If we get here, the Java runtime did not do its job of creating the exception. // If we get here, the Java runtime did not do its job of creating the exception.
// Do something that is at least causes a valid throw from the interpreter. // Do something that is at least causes a valid throw from the interpreter.
__ bind(no_method); __ bind(L_no_method);
__ unimplemented("_raise_exception no method"); __ unimplemented("call throw_WrongMethodType_entry");
} }
break; break;
...@@ -570,10 +563,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -570,10 +563,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// Throw an exception. // Throw an exception.
// For historical reasons, it will be IncompatibleClassChangeError. // For historical reasons, it will be IncompatibleClassChangeError.
__ unimplemented("not tested yet"); __ unimplemented("not tested yet");
__ ld_ptr(Address(O1_intf, java_mirror_offset), O3_scratch); // required interface __ ld_ptr(Address(O1_intf, java_mirror_offset), O2_required); // required interface
__ mov(O0_klass, O2_scratch); // bad receiver __ mov( O0_klass, O1_actual); // bad receiver
__ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch);
__ delayed()->mov(Bytecodes::_invokeinterface, O1_scratch); // who is complaining? __ delayed()->mov(Bytecodes::_invokeinterface, O0_code); // who is complaining?
} }
break; break;
...@@ -663,11 +656,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -663,11 +656,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, O2_scratch, done); __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, O2_scratch, done);
// If we get here, the type check failed! // If we get here, the type check failed!
__ ldsw(G3_amh_vmargslot, O0_argslot); // reload argslot field __ load_heap_oop(G3_amh_argument, O2_required); // required class
__ load_heap_oop(G3_amh_argument, O3_scratch); // required class __ ld_ptr( vmarg, O1_actual); // bad object
__ ld_ptr(vmarg, O2_scratch); // bad object __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch);
__ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); __ delayed()->mov(Bytecodes::_checkcast, O0_code); // who is complaining?
__ delayed()->mov(Bytecodes::_checkcast, O1_scratch); // who is complaining?
__ bind(done); __ bind(done);
// Get the new MH: // Get the new MH:
......
...@@ -385,9 +385,12 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { ...@@ -385,9 +385,12 @@ int MethodHandles::adapter_conversion_ops_supported_mask() {
// FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS. // FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS.
} }
//------------------------------------------------------------------------------
// MethodHandles::generate_method_handle_stub
//
// Generate an "entry" field for a method handle. // Generate an "entry" field for a method handle.
// This determines how the method handle will respond to calls. // This determines how the method handle will respond to calls.
void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) {
// Here is the register state during an interpreted call, // Here is the register state during an interpreted call,
// as set up by generate_method_handle_interpreter_entry(): // as set up by generate_method_handle_interpreter_entry():
// - rbx: garbage temp (was MethodHandle.invoke methodOop, unused) // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
...@@ -396,14 +399,21 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -396,14 +399,21 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
// - rdx: garbage temp, can blow away // - rdx: garbage temp, can blow away
Register rcx_recv = rcx; const Register rcx_recv = rcx;
Register rax_argslot = rax; const Register rax_argslot = rax;
Register rbx_temp = rbx; const Register rbx_temp = rbx;
Register rdx_temp = rdx; const Register rdx_temp = rdx;
// This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls) // This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls)
// and gen_c2i_adapter (from compiled calls): // and gen_c2i_adapter (from compiled calls):
Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi); const Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi);
// Argument registers for _raise_exception.
// 32-bit: Pass first two oop/int args in registers ECX and EDX.
const Register rarg0_code = LP64_ONLY(j_rarg0) NOT_LP64(rcx);
const Register rarg1_actual = LP64_ONLY(j_rarg1) NOT_LP64(rdx);
const Register rarg2_required = LP64_ONLY(j_rarg2) NOT_LP64(rdi);
assert_different_registers(rarg0_code, rarg1_actual, rarg2_required, saved_last_sp);
guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
...@@ -437,47 +447,41 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -437,47 +447,41 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
switch ((int) ek) { switch ((int) ek) {
case _raise_exception: case _raise_exception:
{ {
// Not a real MH entry, but rather shared code for raising an exception. // Not a real MH entry, but rather shared code for raising an
// Extra local arguments are pushed on stack, as required type at TOS+8, // exception. Since we use a C2I adapter to set up the
// failing object (or NULL) at TOS+4, failing bytecode type at TOS. // interpreter state, arguments are expected in compiler
// Beyond those local arguments are the PC, of course. // argument registers.
Register rdx_code = rdx_temp; methodHandle mh(raise_exception_method());
Register rcx_fail = rcx_recv; address c2i_entry = methodOopDesc::make_adapters(mh, CHECK);
Register rax_want = rax_argslot;
Register rdi_pc = rdi; const Register rdi_pc = rax;
__ pop(rdx_code); // TOS+0
__ pop(rcx_fail); // TOS+4
__ pop(rax_want); // TOS+8
__ pop(rdi_pc); // caller PC __ pop(rdi_pc); // caller PC
__ mov(rsp, saved_last_sp); // cut the stack back to where the caller started
__ mov(rsp, rsi); // cut the stack back to where the caller started
// Repush the arguments as if coming from the interpreter.
__ push(rdx_code);
__ push(rcx_fail);
__ push(rax_want);
Register rbx_method = rbx_temp; Register rbx_method = rbx_temp;
Label no_method; Label L_no_method;
// FIXME: fill in _raise_exception_method with a suitable sun.dyn method // FIXME: fill in _raise_exception_method with a suitable sun.dyn method
__ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
__ testptr(rbx_method, rbx_method); __ testptr(rbx_method, rbx_method);
__ jccb(Assembler::zero, no_method); __ jccb(Assembler::zero, L_no_method);
int jobject_oop_offset = 0;
const int jobject_oop_offset = 0;
__ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject
__ testptr(rbx_method, rbx_method); __ testptr(rbx_method, rbx_method);
__ jccb(Assembler::zero, no_method); __ jccb(Assembler::zero, L_no_method);
__ verify_oop(rbx_method); __ verify_oop(rbx_method);
__ push(rdi_pc); // and restore caller PC
__ jmp(rbx_method_fie); // 32-bit: push remaining arguments as if coming from the compiler.
NOT_LP64(__ push(rarg2_required));
__ push(rdi_pc); // restore caller PC
__ jump(ExternalAddress(c2i_entry)); // do C2I transition
// If we get here, the Java runtime did not do its job of creating the exception. // If we get here, the Java runtime did not do its job of creating the exception.
// Do something that is at least causes a valid throw from the interpreter. // Do something that is at least causes a valid throw from the interpreter.
__ bind(no_method); __ bind(L_no_method);
__ pop(rax_want); __ push(rarg2_required);
__ pop(rcx_fail); __ push(rarg1_actual);
__ push(rax_want);
__ push(rcx_fail);
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
} }
break; break;
...@@ -572,9 +576,11 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -572,9 +576,11 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ bind(no_such_interface); __ bind(no_such_interface);
// Throw an exception. // Throw an exception.
// For historical reasons, it will be IncompatibleClassChangeError. // For historical reasons, it will be IncompatibleClassChangeError.
__ pushptr(Address(rdx_intf, java_mirror_offset)); // required interface __ mov(rbx_temp, rcx_recv); // rarg2_required might be RCX
__ push(rcx_recv); // bad receiver assert_different_registers(rarg2_required, rbx_temp);
__ push((int)Bytecodes::_invokeinterface); // who is complaining? __ movptr(rarg2_required, Address(rdx_intf, java_mirror_offset)); // required interface
__ mov( rarg1_actual, rbx_temp); // bad receiver
__ movl( rarg0_code, (int) Bytecodes::_invokeinterface); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
} }
break; break;
...@@ -669,10 +675,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -669,10 +675,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field
__ movptr(rdx_temp, vmarg); __ movptr(rdx_temp, vmarg);
__ load_heap_oop(rbx_klass, rcx_amh_argument); // required class assert_different_registers(rarg2_required, rdx_temp);
__ push(rbx_klass); __ load_heap_oop(rarg2_required, rcx_amh_argument); // required class
__ push(rdx_temp); // bad object __ mov( rarg1_actual, rdx_temp); // bad object
__ push((int)Bytecodes::_checkcast); // who is complaining? __ movl( rarg0_code, (int) Bytecodes::_checkcast); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
__ bind(done); __ bind(done);
...@@ -1189,16 +1195,18 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan ...@@ -1189,16 +1195,18 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ bind(bad_array_klass); __ bind(bad_array_klass);
UNPUSH_RSI_RDI; UNPUSH_RSI_RDI;
__ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type assert(!vmarg.uses(rarg2_required), "must be different registers");
__ pushptr(vmarg); // bad array __ movptr(rarg2_required, Address(rdx_array_klass, java_mirror_offset)); // required type
__ push((int)Bytecodes::_aaload); // who is complaining? __ movptr(rarg1_actual, vmarg); // bad array
__ movl( rarg0_code, (int) Bytecodes::_aaload); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
__ bind(bad_array_length); __ bind(bad_array_length);
UNPUSH_RSI_RDI; UNPUSH_RSI_RDI;
__ push(rcx_recv); // AMH requiring a certain length assert(!vmarg.uses(rarg2_required), "must be different registers");
__ pushptr(vmarg); // bad array __ mov (rarg2_required, rcx_recv); // AMH requiring a certain length
__ push((int)Bytecodes::_arraylength); // who is complaining? __ movptr(rarg1_actual, vmarg); // bad array
__ movl( rarg0_code, (int) Bytecodes::_arraylength); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
#undef UNPUSH_RSI_RDI #undef UNPUSH_RSI_RDI
......
...@@ -111,7 +111,7 @@ bool MethodHandles::spot_check_entry_names() { ...@@ -111,7 +111,7 @@ bool MethodHandles::spot_check_entry_names() {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// MethodHandles::generate_adapters // MethodHandles::generate_adapters
// //
void MethodHandles::generate_adapters() { void MethodHandles::generate_adapters(TRAPS) {
if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return;
assert(_adapter_code == NULL, "generate only once"); assert(_adapter_code == NULL, "generate only once");
...@@ -123,20 +123,20 @@ void MethodHandles::generate_adapters() { ...@@ -123,20 +123,20 @@ void MethodHandles::generate_adapters() {
vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters");
CodeBuffer code(_adapter_code); CodeBuffer code(_adapter_code);
MethodHandlesAdapterGenerator g(&code); MethodHandlesAdapterGenerator g(&code);
g.generate(); g.generate(CHECK);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// MethodHandlesAdapterGenerator::generate // MethodHandlesAdapterGenerator::generate
// //
void MethodHandlesAdapterGenerator::generate() { void MethodHandlesAdapterGenerator::generate(TRAPS) {
// Generate generic method handle adapters. // Generate generic method handle adapters.
for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
ek < MethodHandles::_EK_LIMIT; ek < MethodHandles::_EK_LIMIT;
ek = MethodHandles::EntryKind(1 + (int)ek)) { ek = MethodHandles::EntryKind(1 + (int)ek)) {
StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
MethodHandles::generate_method_handle_stub(_masm, ek); MethodHandles::generate_method_handle_stub(_masm, ek, CHECK);
} }
} }
...@@ -2645,5 +2645,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) ...@@ -2645,5 +2645,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
MethodHandles::set_enabled(true); MethodHandles::set_enabled(true);
} }
} }
// Generate method handles adapters if enabled.
if (MethodHandles::enabled()) {
MethodHandles::generate_adapters(CHECK);
}
} }
JVM_END JVM_END
...@@ -294,11 +294,11 @@ class MethodHandles: AllStatic { ...@@ -294,11 +294,11 @@ class MethodHandles: AllStatic {
enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
// Generate MethodHandles adapters. // Generate MethodHandles adapters.
static void generate_adapters(); static void generate_adapters(TRAPS);
// Called from InterpreterGenerator and MethodHandlesAdapterGenerator. // Called from InterpreterGenerator and MethodHandlesAdapterGenerator.
static address generate_method_handle_interpreter_entry(MacroAssembler* _masm); static address generate_method_handle_interpreter_entry(MacroAssembler* _masm);
static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek); static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek, TRAPS);
// argument list parsing // argument list parsing
static int argument_slot(oop method_type, int arg); static int argument_slot(oop method_type, int arg);
...@@ -530,7 +530,7 @@ class MethodHandlesAdapterGenerator : public StubCodeGenerator { ...@@ -530,7 +530,7 @@ class MethodHandlesAdapterGenerator : public StubCodeGenerator {
public: public:
MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {} MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {}
void generate(); void generate(TRAPS);
}; };
#endif // SHARE_VM_PRIMS_METHODHANDLES_HPP #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP
...@@ -125,9 +125,6 @@ jint init_globals() { ...@@ -125,9 +125,6 @@ jint init_globals() {
javaClasses_init(); // must happen after vtable initialization javaClasses_init(); // must happen after vtable initialization
stubRoutines_init2(); // note: StubRoutines need 2-phase init stubRoutines_init2(); // note: StubRoutines need 2-phase init
// Generate MethodHandles adapters.
MethodHandles::generate_adapters();
// Although we'd like to, we can't easily do a heap verify // Although we'd like to, we can't easily do a heap verify
// here because the main thread isn't yet a JavaThread, so // here because the main thread isn't yet a JavaThread, so
// its TLAB may not be made parseable from the usual interfaces. // its TLAB may not be made parseable from the usual interfaces.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册