mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-25 13:54:38 +02:00
7012914: JSR 292 MethodHandlesTest C1: frame::verify_return_pc(return_address) failed: must be a return pc
Reviewed-by: never, bdelsart
This commit is contained in:
parent
a74bc73598
commit
cd6c0b147e
13 changed files with 219 additions and 222 deletions
|
@ -395,9 +395,9 @@ int LIR_Assembler::emit_exception_handler() {
|
||||||
|
|
||||||
int offset = code_offset();
|
int offset = code_offset();
|
||||||
|
|
||||||
__ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type);
|
__ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
|
||||||
__ delayed()->nop();
|
__ delayed()->nop();
|
||||||
debug_only(__ stop("should have gone to the caller");)
|
__ should_not_reach_here();
|
||||||
assert(code_offset() - offset <= exception_handler_size, "overflow");
|
assert(code_offset() - offset <= exception_handler_size, "overflow");
|
||||||
__ end_a_stub();
|
__ end_a_stub();
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ static int frame_size_in_bytes = -1;
|
||||||
|
|
||||||
static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
|
static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
|
||||||
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
|
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
|
||||||
" mismatch in calculation");
|
"mismatch in calculation");
|
||||||
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
|
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
|
||||||
int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
|
int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
|
||||||
OopMap* oop_map = new OopMap(frame_size_in_slots, 0);
|
OopMap* oop_map = new OopMap(frame_size_in_slots, 0);
|
||||||
|
@ -176,9 +176,8 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
|
||||||
|
|
||||||
static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) {
|
static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) {
|
||||||
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
|
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
|
||||||
" mismatch in calculation");
|
"mismatch in calculation");
|
||||||
__ save_frame_c1(frame_size_in_bytes);
|
__ save_frame_c1(frame_size_in_bytes);
|
||||||
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
|
|
||||||
|
|
||||||
// Record volatile registers as callee-save values in an OopMap so their save locations will be
|
// Record volatile registers as callee-save values in an OopMap so their save locations will be
|
||||||
// propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for
|
// propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for
|
||||||
|
@ -367,23 +366,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case forward_exception_id:
|
case forward_exception_id:
|
||||||
{
|
{
|
||||||
// we're handling an exception in the context of a compiled
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
// frame. The registers have been saved in the standard
|
|
||||||
// places. Perform an exception lookup in the caller and
|
|
||||||
// dispatch to the handler if found. Otherwise unwind and
|
|
||||||
// dispatch to the callers exception handler.
|
|
||||||
|
|
||||||
oop_maps = new OopMapSet();
|
|
||||||
OopMap* oop_map = generate_oop_map(sasm, true);
|
|
||||||
|
|
||||||
// transfer the pending exception to the exception_oop
|
|
||||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception);
|
|
||||||
__ ld_ptr(Oexception, 0, G0);
|
|
||||||
__ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset()));
|
|
||||||
__ add(I7, frame::pc_return_offset, Oissuing_pc);
|
|
||||||
|
|
||||||
generate_handle_exception(sasm, oop_maps, oop_map);
|
|
||||||
__ should_not_reach_here();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -671,15 +654,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case handle_exception_id:
|
case handle_exception_id:
|
||||||
{
|
{ __ set_info("handle_exception", dont_gc_arguments);
|
||||||
__ set_info("handle_exception", dont_gc_arguments);
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
// make a frame and preserve the caller's caller-save registers
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
oop_maps = new OopMapSet();
|
case handle_exception_from_callee_id:
|
||||||
OopMap* oop_map = save_live_registers(sasm);
|
{ __ set_info("handle_exception_from_callee", dont_gc_arguments);
|
||||||
__ mov(Oexception->after_save(), Oexception);
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
__ mov(Oissuing_pc->after_save(), Oissuing_pc);
|
|
||||||
generate_handle_exception(sasm, oop_maps, oop_map);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -696,7 +678,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
G2_thread, Oissuing_pc->after_save());
|
G2_thread, Oissuing_pc->after_save());
|
||||||
__ verify_not_null_oop(Oexception->after_save());
|
__ verify_not_null_oop(Oexception->after_save());
|
||||||
|
|
||||||
// Restore SP from L7 if the exception PC is a MethodHandle call site.
|
// Restore SP from L7 if the exception PC is a method handle call site.
|
||||||
__ mov(O0, G5); // Save the target address.
|
__ mov(O0, G5); // Save the target address.
|
||||||
__ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0);
|
__ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0);
|
||||||
__ tst(L0); // Condition codes are preserved over the restore.
|
__ tst(L0); // Condition codes are preserved over the restore.
|
||||||
|
@ -1006,48 +988,89 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_maps, OopMap* oop_map, bool) {
|
OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
|
||||||
Label no_deopt;
|
__ block_comment("generate_handle_exception");
|
||||||
|
|
||||||
|
// Save registers, if required.
|
||||||
|
OopMapSet* oop_maps = new OopMapSet();
|
||||||
|
OopMap* oop_map = NULL;
|
||||||
|
switch (id) {
|
||||||
|
case forward_exception_id:
|
||||||
|
// We're handling an exception in the context of a compiled frame.
|
||||||
|
// The registers have been saved in the standard places. Perform
|
||||||
|
// an exception lookup in the caller and dispatch to the handler
|
||||||
|
// if found. Otherwise unwind and dispatch to the callers
|
||||||
|
// exception handler.
|
||||||
|
oop_map = generate_oop_map(sasm, true);
|
||||||
|
|
||||||
|
// transfer the pending exception to the exception_oop
|
||||||
|
__ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception);
|
||||||
|
__ ld_ptr(Oexception, 0, G0);
|
||||||
|
__ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset()));
|
||||||
|
__ add(I7, frame::pc_return_offset, Oissuing_pc);
|
||||||
|
break;
|
||||||
|
case handle_exception_id:
|
||||||
|
// At this point all registers MAY be live.
|
||||||
|
oop_map = save_live_registers(sasm);
|
||||||
|
__ mov(Oexception->after_save(), Oexception);
|
||||||
|
__ mov(Oissuing_pc->after_save(), Oissuing_pc);
|
||||||
|
break;
|
||||||
|
case handle_exception_from_callee_id:
|
||||||
|
// At this point all registers except exception oop (Oexception)
|
||||||
|
// and exception pc (Oissuing_pc) are dead.
|
||||||
|
oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
|
||||||
|
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
|
||||||
|
__ save_frame_c1(frame_size_in_bytes);
|
||||||
|
__ mov(Oexception->after_save(), Oexception);
|
||||||
|
__ mov(Oissuing_pc->after_save(), Oissuing_pc);
|
||||||
|
break;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
|
||||||
__ verify_not_null_oop(Oexception);
|
__ verify_not_null_oop(Oexception);
|
||||||
|
|
||||||
// save the exception and issuing pc in the thread
|
// save the exception and issuing pc in the thread
|
||||||
__ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
|
__ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
|
||||||
__ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset()));
|
__ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset()));
|
||||||
|
|
||||||
// save the real return address and use the throwing pc as the return address to lookup (has bci & oop map)
|
// use the throwing pc as the return address to lookup (has bci & oop map)
|
||||||
__ mov(I7, L0);
|
|
||||||
__ mov(Oissuing_pc, I7);
|
__ mov(Oissuing_pc, I7);
|
||||||
__ sub(I7, frame::pc_return_offset, I7);
|
__ sub(I7, frame::pc_return_offset, I7);
|
||||||
int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
|
int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
|
||||||
|
oop_maps->add_gc_map(call_offset, oop_map);
|
||||||
|
|
||||||
// Note: if nmethod has been deoptimized then regardless of
|
// Note: if nmethod has been deoptimized then regardless of
|
||||||
// whether it had a handler or not we will deoptimize
|
// whether it had a handler or not we will deoptimize
|
||||||
// by entering the deopt blob with a pending exception.
|
// by entering the deopt blob with a pending exception.
|
||||||
|
|
||||||
#ifdef ASSERT
|
// Restore the registers that were saved at the beginning, remove
|
||||||
Label done;
|
// the frame and jump to the exception handler.
|
||||||
__ tst(O0);
|
switch (id) {
|
||||||
__ br(Assembler::notZero, false, Assembler::pn, done);
|
case forward_exception_id:
|
||||||
__ delayed()->nop();
|
case handle_exception_id:
|
||||||
__ stop("should have found address");
|
restore_live_registers(sasm);
|
||||||
__ bind(done);
|
__ jmp(O0, 0);
|
||||||
#endif
|
__ delayed()->restore();
|
||||||
|
break;
|
||||||
|
case handle_exception_from_callee_id:
|
||||||
|
// Restore SP from L7 if the exception PC is a method handle call site.
|
||||||
|
__ mov(O0, G5); // Save the target address.
|
||||||
|
__ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0);
|
||||||
|
__ tst(L0); // Condition codes are preserved over the restore.
|
||||||
|
__ restore();
|
||||||
|
|
||||||
// restore the registers that were saved at the beginning and jump to the exception handler.
|
__ jmp(G5, 0); // jump to the exception handler
|
||||||
restore_live_registers(sasm);
|
__ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required.
|
||||||
|
break;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
|
||||||
__ jmp(O0, 0);
|
return oop_maps;
|
||||||
__ delayed()->restore();
|
|
||||||
|
|
||||||
oop_maps->add_gc_map(call_offset, oop_map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
#define __ masm->
|
|
||||||
|
|
||||||
const char *Runtime1::pd_name_for_address(address entry) {
|
const char *Runtime1::pd_name_for_address(address entry) {
|
||||||
return "<unknown function>";
|
return "<unknown function>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
|
|
||||||
// Some handy addresses:
|
// Some handy addresses:
|
||||||
Address G5_method_fie( G5_method, in_bytes(methodOopDesc::from_interpreted_offset()));
|
Address G5_method_fie( G5_method, in_bytes(methodOopDesc::from_interpreted_offset()));
|
||||||
|
Address G5_method_fce( G5_method, in_bytes(methodOopDesc::from_compiled_offset()));
|
||||||
|
|
||||||
Address G3_mh_vmtarget( G3_method_handle, java_dyn_MethodHandle::vmtarget_offset_in_bytes());
|
Address G3_mh_vmtarget( G3_method_handle, java_dyn_MethodHandle::vmtarget_offset_in_bytes());
|
||||||
|
|
||||||
|
@ -444,12 +445,10 @@ 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. Since we use a C2I adapter to set up the
|
// exception. Since we use the compiled entry, arguments are
|
||||||
// interpreter state, arguments are expected in compiler
|
// expected in compiler argument registers.
|
||||||
// argument registers.
|
|
||||||
assert(raise_exception_method(), "must be set");
|
assert(raise_exception_method(), "must be set");
|
||||||
address c2i_entry = raise_exception_method()->get_c2i_entry();
|
assert(raise_exception_method()->from_compiled_entry(), "method must be linked");
|
||||||
assert(c2i_entry, "method must be linked");
|
|
||||||
|
|
||||||
__ 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.
|
||||||
|
|
||||||
|
@ -468,10 +467,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
__ delayed()->nop();
|
__ delayed()->nop();
|
||||||
|
|
||||||
__ verify_oop(G5_method);
|
__ verify_oop(G5_method);
|
||||||
__ jump_to(AddressLiteral(c2i_entry), O3_scratch);
|
__ jump_indirect_to(G5_method_fce, O3_scratch); // jump to compiled entry
|
||||||
__ delayed()->nop();
|
__ delayed()->nop();
|
||||||
|
|
||||||
// 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(L_no_method);
|
__ bind(L_no_method);
|
||||||
__ unimplemented("call throw_WrongMethodType_entry");
|
__ unimplemented("call throw_WrongMethodType_entry");
|
||||||
|
|
|
@ -456,10 +456,8 @@ int LIR_Assembler::emit_exception_handler() {
|
||||||
__ verify_not_null_oop(rax);
|
__ verify_not_null_oop(rax);
|
||||||
|
|
||||||
// search an exception handler (rax: exception oop, rdx: throwing pc)
|
// search an exception handler (rax: exception oop, rdx: throwing pc)
|
||||||
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_nofpu_id)));
|
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
|
||||||
|
__ should_not_reach_here();
|
||||||
__ stop("should not reach here");
|
|
||||||
|
|
||||||
assert(code_offset() - offset <= exception_handler_size, "overflow");
|
assert(code_offset() - offset <= exception_handler_size, "overflow");
|
||||||
__ end_a_stub();
|
__ end_a_stub();
|
||||||
|
|
||||||
|
|
|
@ -248,11 +248,14 @@ enum reg_save_layout {
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
align_dummy_0, align_dummy_1,
|
align_dummy_0, align_dummy_1,
|
||||||
#endif // _LP64
|
#endif // _LP64
|
||||||
dummy1, SLOT2(dummy1H) // 0, 4
|
#ifdef _WIN64
|
||||||
dummy2, SLOT2(dummy2H) // 8, 12
|
// Windows always allocates space for it's argument registers (see
|
||||||
// Two temps to be used as needed by users of save/restore callee registers
|
// frame::arg_reg_save_area_bytes).
|
||||||
temp_2_off, SLOT2(temp_2H_off) // 16, 20
|
arg_reg_save_1, arg_reg_save_1H, // 0, 4
|
||||||
temp_1_off, SLOT2(temp_1H_off) // 24, 28
|
arg_reg_save_2, arg_reg_save_2H, // 8, 12
|
||||||
|
arg_reg_save_3, arg_reg_save_3H, // 16, 20
|
||||||
|
arg_reg_save_4, arg_reg_save_4H, // 24, 28
|
||||||
|
#endif // _WIN64
|
||||||
xmm_regs_as_doubles_off, // 32
|
xmm_regs_as_doubles_off, // 32
|
||||||
float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_slots, // 160
|
float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_slots, // 160
|
||||||
fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_slots, // 224
|
fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_slots, // 224
|
||||||
|
@ -282,24 +285,7 @@ enum reg_save_layout {
|
||||||
rax_off, SLOT2(raxH_off) // 480, 484
|
rax_off, SLOT2(raxH_off) // 480, 484
|
||||||
saved_rbp_off, SLOT2(saved_rbpH_off) // 488, 492
|
saved_rbp_off, SLOT2(saved_rbpH_off) // 488, 492
|
||||||
return_off, SLOT2(returnH_off) // 496, 500
|
return_off, SLOT2(returnH_off) // 496, 500
|
||||||
reg_save_frame_size, // As noted: neglects any parameters to runtime // 504
|
reg_save_frame_size // As noted: neglects any parameters to runtime // 504
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
c_rarg0_off = rcx_off,
|
|
||||||
#else
|
|
||||||
c_rarg0_off = rdi_off,
|
|
||||||
#endif // WIN64
|
|
||||||
|
|
||||||
// equates
|
|
||||||
|
|
||||||
// illegal instruction handler
|
|
||||||
continue_dest_off = temp_1_off,
|
|
||||||
|
|
||||||
// deoptimization equates
|
|
||||||
fp0_off = float_regs_as_doubles_off, // slot for java float/double return value
|
|
||||||
xmm0_off = xmm_regs_as_doubles_off, // slot for java float/double return value
|
|
||||||
deopt_type = temp_2_off, // slot for type of deopt in progress
|
|
||||||
ret_type = temp_1_off // slot for return type
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -405,11 +391,6 @@ static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args,
|
||||||
bool save_fpu_registers = true) {
|
bool save_fpu_registers = true) {
|
||||||
__ block_comment("save_live_registers");
|
__ block_comment("save_live_registers");
|
||||||
|
|
||||||
// 64bit passes the args in regs to the c++ runtime
|
|
||||||
int frame_size_in_slots = reg_save_frame_size NOT_LP64(+ num_rt_args); // args + thread
|
|
||||||
// frame_size = round_to(frame_size, 4);
|
|
||||||
sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word );
|
|
||||||
|
|
||||||
__ pusha(); // integer registers
|
__ pusha(); // integer registers
|
||||||
|
|
||||||
// assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset");
|
// assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset");
|
||||||
|
@ -642,19 +623,58 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_maps, OopMap* oop_map, bool save_fpu_registers) {
|
OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
|
||||||
|
__ block_comment("generate_handle_exception");
|
||||||
|
|
||||||
// incoming parameters
|
// incoming parameters
|
||||||
const Register exception_oop = rax;
|
const Register exception_oop = rax;
|
||||||
const Register exception_pc = rdx;
|
const Register exception_pc = rdx;
|
||||||
// other registers used in this stub
|
// other registers used in this stub
|
||||||
const Register real_return_addr = rbx;
|
|
||||||
const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
|
const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
|
||||||
|
|
||||||
__ block_comment("generate_handle_exception");
|
// Save registers, if required.
|
||||||
|
OopMapSet* oop_maps = new OopMapSet();
|
||||||
|
OopMap* oop_map = NULL;
|
||||||
|
switch (id) {
|
||||||
|
case forward_exception_id:
|
||||||
|
// We're handling an exception in the context of a compiled frame.
|
||||||
|
// The registers have been saved in the standard places. Perform
|
||||||
|
// an exception lookup in the caller and dispatch to the handler
|
||||||
|
// if found. Otherwise unwind and dispatch to the callers
|
||||||
|
// exception handler.
|
||||||
|
oop_map = generate_oop_map(sasm, 1 /*thread*/);
|
||||||
|
|
||||||
|
// load and clear pending exception oop into RAX
|
||||||
|
__ movptr(exception_oop, Address(thread, Thread::pending_exception_offset()));
|
||||||
|
__ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
|
||||||
|
|
||||||
|
// load issuing PC (the return address for this stub) into rdx
|
||||||
|
__ movptr(exception_pc, Address(rbp, 1*BytesPerWord));
|
||||||
|
|
||||||
|
// make sure that the vm_results are cleared (may be unnecessary)
|
||||||
|
__ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
|
||||||
|
__ movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
|
||||||
|
break;
|
||||||
|
case handle_exception_nofpu_id:
|
||||||
|
case handle_exception_id:
|
||||||
|
// At this point all registers MAY be live.
|
||||||
|
oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id);
|
||||||
|
break;
|
||||||
|
case handle_exception_from_callee_id: {
|
||||||
|
// At this point all registers except exception oop (RAX) and
|
||||||
|
// exception pc (RDX) are dead.
|
||||||
|
const int frame_size = 2 /*BP, return address*/ NOT_LP64(+ 1 /*thread*/) WIN64_ONLY(+ frame::arg_reg_save_area_bytes / BytesPerWord);
|
||||||
|
oop_map = new OopMap(frame_size * VMRegImpl::slots_per_word, 0);
|
||||||
|
sasm->set_frame_size(frame_size);
|
||||||
|
WIN64_ONLY(__ subq(rsp, frame::arg_reg_save_area_bytes));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TIERED
|
#ifdef TIERED
|
||||||
// C2 can leave the fpu stack dirty
|
// C2 can leave the fpu stack dirty
|
||||||
if (UseSSE < 2 ) {
|
if (UseSSE < 2) {
|
||||||
__ empty_FPU_stack();
|
__ empty_FPU_stack();
|
||||||
}
|
}
|
||||||
#endif // TIERED
|
#endif // TIERED
|
||||||
|
@ -686,11 +706,7 @@ void Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_map
|
||||||
// save exception oop and issuing pc into JavaThread
|
// save exception oop and issuing pc into JavaThread
|
||||||
// (exception handler will load it from here)
|
// (exception handler will load it from here)
|
||||||
__ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop);
|
__ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop);
|
||||||
__ movptr(Address(thread, JavaThread::exception_pc_offset()), exception_pc);
|
__ movptr(Address(thread, JavaThread::exception_pc_offset()), exception_pc);
|
||||||
|
|
||||||
// save real return address (pc that called this stub)
|
|
||||||
__ movptr(real_return_addr, Address(rbp, 1*BytesPerWord));
|
|
||||||
__ movptr(Address(rsp, temp_1_off * VMRegImpl::stack_slot_size), real_return_addr);
|
|
||||||
|
|
||||||
// patch throwing pc into return address (has bci & oop map)
|
// patch throwing pc into return address (has bci & oop map)
|
||||||
__ movptr(Address(rbp, 1*BytesPerWord), exception_pc);
|
__ movptr(Address(rbp, 1*BytesPerWord), exception_pc);
|
||||||
|
@ -700,33 +716,41 @@ void Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_map
|
||||||
int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
|
int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
|
||||||
oop_maps->add_gc_map(call_offset, oop_map);
|
oop_maps->add_gc_map(call_offset, oop_map);
|
||||||
|
|
||||||
// rax,: handler address
|
// rax: handler address
|
||||||
// will be the deopt blob if nmethod was deoptimized while we looked up
|
// will be the deopt blob if nmethod was deoptimized while we looked up
|
||||||
// handler regardless of whether handler existed in the nmethod.
|
// handler regardless of whether handler existed in the nmethod.
|
||||||
|
|
||||||
// only rax, is valid at this time, all other registers have been destroyed by the runtime call
|
// only rax, is valid at this time, all other registers have been destroyed by the runtime call
|
||||||
__ invalidate_registers(false, true, true, true, true, true);
|
__ invalidate_registers(false, true, true, true, true, true);
|
||||||
|
|
||||||
#ifdef ASSERT
|
// patch the return address, this stub will directly return to the exception handler
|
||||||
// Do we have an exception handler in the nmethod?
|
|
||||||
Label done;
|
|
||||||
__ testptr(rax, rax);
|
|
||||||
__ jcc(Assembler::notZero, done);
|
|
||||||
__ stop("no handler found");
|
|
||||||
__ bind(done);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// exception handler found
|
|
||||||
// patch the return address -> the stub will directly return to the exception handler
|
|
||||||
__ movptr(Address(rbp, 1*BytesPerWord), rax);
|
__ movptr(Address(rbp, 1*BytesPerWord), rax);
|
||||||
|
|
||||||
// restore registers
|
switch (id) {
|
||||||
restore_live_registers(sasm, save_fpu_registers);
|
case forward_exception_id:
|
||||||
|
case handle_exception_nofpu_id:
|
||||||
|
case handle_exception_id:
|
||||||
|
// Restore the registers that were saved at the beginning.
|
||||||
|
restore_live_registers(sasm, id == handle_exception_nofpu_id);
|
||||||
|
break;
|
||||||
|
case handle_exception_from_callee_id:
|
||||||
|
// WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP
|
||||||
|
// since we do a leave anyway.
|
||||||
|
|
||||||
// return to exception handler
|
// Pop the return address since we are possibly changing SP (restoring from BP).
|
||||||
__ leave();
|
__ leave();
|
||||||
__ ret(0);
|
__ pop(rcx);
|
||||||
|
|
||||||
|
// Restore SP from BP if the exception PC is a method handle call site.
|
||||||
|
NOT_LP64(__ get_thread(thread);)
|
||||||
|
__ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0);
|
||||||
|
__ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save);
|
||||||
|
__ jmp(rcx); // jump to exception handler
|
||||||
|
break;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
return oop_maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -791,7 +815,7 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
|
||||||
// the pop is also necessary to simulate the effect of a ret(0)
|
// the pop is also necessary to simulate the effect of a ret(0)
|
||||||
__ pop(exception_pc);
|
__ pop(exception_pc);
|
||||||
|
|
||||||
// Restore SP from BP if the exception PC is a MethodHandle call site.
|
// Restore SP from BP if the exception PC is a method handle call site.
|
||||||
NOT_LP64(__ get_thread(thread);)
|
NOT_LP64(__ get_thread(thread);)
|
||||||
__ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0);
|
__ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0);
|
||||||
__ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save);
|
__ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save);
|
||||||
|
@ -934,7 +958,6 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
return oop_maps;
|
return oop_maps;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -952,35 +975,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case forward_exception_id:
|
case forward_exception_id:
|
||||||
{
|
{
|
||||||
// we're handling an exception in the context of a compiled
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
// frame. The registers have been saved in the standard
|
__ leave();
|
||||||
// places. Perform an exception lookup in the caller and
|
__ ret(0);
|
||||||
// dispatch to the handler if found. Otherwise unwind and
|
|
||||||
// dispatch to the callers exception handler.
|
|
||||||
|
|
||||||
const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
|
|
||||||
const Register exception_oop = rax;
|
|
||||||
const Register exception_pc = rdx;
|
|
||||||
|
|
||||||
// load pending exception oop into rax,
|
|
||||||
__ movptr(exception_oop, Address(thread, Thread::pending_exception_offset()));
|
|
||||||
// clear pending exception
|
|
||||||
__ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
|
|
||||||
|
|
||||||
// load issuing PC (the return address for this stub) into rdx
|
|
||||||
__ movptr(exception_pc, Address(rbp, 1*BytesPerWord));
|
|
||||||
|
|
||||||
// make sure that the vm_results are cleared (may be unnecessary)
|
|
||||||
__ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
|
|
||||||
__ movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
|
|
||||||
|
|
||||||
// verify that that there is really a valid exception in rax,
|
|
||||||
__ verify_not_null_oop(exception_oop);
|
|
||||||
|
|
||||||
oop_maps = new OopMapSet();
|
|
||||||
OopMap* oop_map = generate_oop_map(sasm, 1);
|
|
||||||
generate_handle_exception(sasm, oop_maps, oop_map);
|
|
||||||
__ stop("should not reach here");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1315,13 +1312,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case handle_exception_nofpu_id:
|
case handle_exception_nofpu_id:
|
||||||
save_fpu_registers = false;
|
|
||||||
// fall through
|
|
||||||
case handle_exception_id:
|
case handle_exception_id:
|
||||||
{ StubFrame f(sasm, "handle_exception", dont_gc_arguments);
|
{ StubFrame f(sasm, "handle_exception", dont_gc_arguments);
|
||||||
oop_maps = new OopMapSet();
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
OopMap* oop_map = save_live_registers(sasm, 1, save_fpu_registers);
|
}
|
||||||
generate_handle_exception(sasm, oop_maps, oop_map, save_fpu_registers);
|
break;
|
||||||
|
|
||||||
|
case handle_exception_from_callee_id:
|
||||||
|
{ StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments);
|
||||||
|
oop_maps = generate_handle_exception(id, sasm);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
|
|
||||||
// some handy addresses
|
// some handy addresses
|
||||||
Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
|
Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
|
||||||
|
Address rbx_method_fce( rbx, methodOopDesc::from_compiled_offset() );
|
||||||
|
|
||||||
Address rcx_mh_vmtarget( rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() );
|
Address rcx_mh_vmtarget( rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() );
|
||||||
Address rcx_dmh_vmindex( rcx_recv, sun_dyn_DirectMethodHandle::vmindex_offset_in_bytes() );
|
Address rcx_dmh_vmindex( rcx_recv, sun_dyn_DirectMethodHandle::vmindex_offset_in_bytes() );
|
||||||
|
@ -448,12 +449,10 @@ 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. Since we use a C2I adapter to set up the
|
// exception. Since we use the compiled entry, arguments are
|
||||||
// interpreter state, arguments are expected in compiler
|
// expected in compiler argument registers.
|
||||||
// argument registers.
|
|
||||||
assert(raise_exception_method(), "must be set");
|
assert(raise_exception_method(), "must be set");
|
||||||
address c2i_entry = raise_exception_method()->get_c2i_entry();
|
assert(raise_exception_method()->from_compiled_entry(), "method must be linked");
|
||||||
assert(c2i_entry, "method must be linked");
|
|
||||||
|
|
||||||
const Register rdi_pc = rax;
|
const Register rdi_pc = rax;
|
||||||
__ pop(rdi_pc); // caller PC
|
__ pop(rdi_pc); // caller PC
|
||||||
|
@ -472,13 +471,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
__ jccb(Assembler::zero, L_no_method);
|
__ jccb(Assembler::zero, L_no_method);
|
||||||
__ verify_oop(rbx_method);
|
__ verify_oop(rbx_method);
|
||||||
|
|
||||||
// 32-bit: push remaining arguments as if coming from the compiler.
|
|
||||||
NOT_LP64(__ push(rarg2_required));
|
NOT_LP64(__ push(rarg2_required));
|
||||||
|
__ push(rdi_pc); // restore caller PC
|
||||||
|
__ jmp(rbx_method_fce); // jump to compiled entry
|
||||||
|
|
||||||
__ 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.
|
|
||||||
// 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(L_no_method);
|
__ bind(L_no_method);
|
||||||
__ push(rarg2_required);
|
__ push(rarg2_required);
|
||||||
|
|
|
@ -439,10 +439,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
// Verify that there is really a valid exception in RAX.
|
// Verify that there is really a valid exception in RAX.
|
||||||
__ verify_oop(exception_oop);
|
__ verify_oop(exception_oop);
|
||||||
|
|
||||||
// Restore SP from BP if the exception PC is a MethodHandle call site.
|
|
||||||
__ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0);
|
|
||||||
__ cmovptr(Assembler::notEqual, rsp, rbp);
|
|
||||||
|
|
||||||
// continue at exception handler (return address removed)
|
// continue at exception handler (return address removed)
|
||||||
// rax: exception
|
// rax: exception
|
||||||
// rbx: exception handler
|
// rbx: exception handler
|
||||||
|
|
|
@ -426,10 +426,9 @@ extern void vm_exit(int code);
|
||||||
// been deoptimized. If that is the case we return the deopt blob
|
// been deoptimized. If that is the case we return the deopt blob
|
||||||
// unpack_with_exception entry instead. This makes life for the exception blob easier
|
// unpack_with_exception entry instead. This makes life for the exception blob easier
|
||||||
// because making that same check and diverting is painful from assembly language.
|
// because making that same check and diverting is painful from assembly language.
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm))
|
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm))
|
||||||
|
// Reset method handle flag.
|
||||||
|
thread->set_is_method_handle_return(false);
|
||||||
|
|
||||||
Handle exception(thread, ex);
|
Handle exception(thread, ex);
|
||||||
nm = CodeCache::find_nmethod(pc);
|
nm = CodeCache::find_nmethod(pc);
|
||||||
|
@ -480,11 +479,12 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||||
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExceptionCache is used only for exceptions at call and not for implicit exceptions
|
// ExceptionCache is used only for exceptions at call sites and not for implicit exceptions
|
||||||
if (guard_pages_enabled) {
|
if (guard_pages_enabled) {
|
||||||
address fast_continuation = nm->handler_for_exception_and_pc(exception, pc);
|
address fast_continuation = nm->handler_for_exception_and_pc(exception, pc);
|
||||||
if (fast_continuation != NULL) {
|
if (fast_continuation != NULL) {
|
||||||
if (fast_continuation == ExceptionCache::unwind_handler()) fast_continuation = NULL;
|
// Set flag if return address is a method handle call site.
|
||||||
|
thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
|
||||||
return fast_continuation;
|
return fast_continuation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -522,14 +522,14 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||||
thread->set_exception_pc(pc);
|
thread->set_exception_pc(pc);
|
||||||
|
|
||||||
// the exception cache is used only by non-implicit exceptions
|
// the exception cache is used only by non-implicit exceptions
|
||||||
if (continuation == NULL) {
|
if (continuation != NULL) {
|
||||||
nm->add_handler_for_exception_and_pc(exception, pc, ExceptionCache::unwind_handler());
|
|
||||||
} else {
|
|
||||||
nm->add_handler_for_exception_and_pc(exception, pc, continuation);
|
nm->add_handler_for_exception_and_pc(exception, pc, continuation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->set_vm_result(exception());
|
thread->set_vm_result(exception());
|
||||||
|
// Set flag if return address is a method handle call site.
|
||||||
|
thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
|
||||||
|
|
||||||
if (TraceExceptions) {
|
if (TraceExceptions) {
|
||||||
ttyLocker ttyl;
|
ttyLocker ttyl;
|
||||||
|
@ -542,20 +542,19 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||||
JRT_END
|
JRT_END
|
||||||
|
|
||||||
// Enter this method from compiled code only if there is a Java exception handler
|
// Enter this method from compiled code only if there is a Java exception handler
|
||||||
// in the method handling the exception
|
// in the method handling the exception.
|
||||||
// We are entering here from exception stub. We don't do a normal VM transition here.
|
// We are entering here from exception stub. We don't do a normal VM transition here.
|
||||||
// We do it in a helper. This is so we can check to see if the nmethod we have just
|
// We do it in a helper. This is so we can check to see if the nmethod we have just
|
||||||
// searched for an exception handler has been deoptimized in the meantime.
|
// searched for an exception handler has been deoptimized in the meantime.
|
||||||
address Runtime1::exception_handler_for_pc(JavaThread* thread) {
|
address Runtime1::exception_handler_for_pc(JavaThread* thread) {
|
||||||
oop exception = thread->exception_oop();
|
oop exception = thread->exception_oop();
|
||||||
address pc = thread->exception_pc();
|
address pc = thread->exception_pc();
|
||||||
// Still in Java mode
|
// Still in Java mode
|
||||||
debug_only(ResetNoHandleMark rnhm);
|
DEBUG_ONLY(ResetNoHandleMark rnhm);
|
||||||
nmethod* nm = NULL;
|
nmethod* nm = NULL;
|
||||||
address continuation = NULL;
|
address continuation = NULL;
|
||||||
{
|
{
|
||||||
// Enter VM mode by calling the helper
|
// Enter VM mode by calling the helper
|
||||||
|
|
||||||
ResetNoHandleMark rnhm;
|
ResetNoHandleMark rnhm;
|
||||||
continuation = exception_handler_for_pc_helper(thread, exception, pc, nm);
|
continuation = exception_handler_for_pc_helper(thread, exception, pc, nm);
|
||||||
}
|
}
|
||||||
|
@ -563,11 +562,11 @@ address Runtime1::exception_handler_for_pc(JavaThread* thread) {
|
||||||
|
|
||||||
// Now check to see if the nmethod we were called from is now deoptimized.
|
// Now check to see if the nmethod we were called from is now deoptimized.
|
||||||
// If so we must return to the deopt blob and deoptimize the nmethod
|
// If so we must return to the deopt blob and deoptimize the nmethod
|
||||||
|
|
||||||
if (nm != NULL && caller_is_deopted()) {
|
if (nm != NULL && caller_is_deopted()) {
|
||||||
continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(continuation != NULL, "no handler found");
|
||||||
return continuation;
|
return continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ class StubAssembler;
|
||||||
stub(new_multi_array) \
|
stub(new_multi_array) \
|
||||||
stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
|
stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
|
||||||
stub(handle_exception) \
|
stub(handle_exception) \
|
||||||
|
stub(handle_exception_from_callee) \
|
||||||
stub(throw_array_store_exception) \
|
stub(throw_array_store_exception) \
|
||||||
stub(throw_class_cast_exception) \
|
stub(throw_class_cast_exception) \
|
||||||
stub(throw_incompatible_class_change_error) \
|
stub(throw_incompatible_class_change_error) \
|
||||||
|
@ -116,11 +117,11 @@ class Runtime1: public AllStatic {
|
||||||
static const char* _blob_names[];
|
static const char* _blob_names[];
|
||||||
|
|
||||||
// stub generation
|
// stub generation
|
||||||
static void generate_blob_for(BufferBlob* blob, StubID id);
|
static void generate_blob_for(BufferBlob* blob, StubID id);
|
||||||
static OopMapSet* generate_code_for(StubID id, StubAssembler* masm);
|
static OopMapSet* generate_code_for(StubID id, StubAssembler* sasm);
|
||||||
static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument);
|
static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument);
|
||||||
static void generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_maps, OopMap* oop_map, bool ignore_fpu_registers = false);
|
static OopMapSet* generate_handle_exception(StubID id, StubAssembler* sasm);
|
||||||
static void generate_unwind_exception(StubAssembler *sasm);
|
static void generate_unwind_exception(StubAssembler *sasm);
|
||||||
static OopMapSet* generate_patching(StubAssembler* sasm, address target);
|
static OopMapSet* generate_patching(StubAssembler* sasm, address target);
|
||||||
|
|
||||||
static OopMapSet* generate_stub_call(StubAssembler* sasm, Register result, address entry,
|
static OopMapSet* generate_stub_call(StubAssembler* sasm, Register result, address entry,
|
||||||
|
|
|
@ -190,15 +190,10 @@ struct nmethod_stats_struct {
|
||||||
} nmethod_stats;
|
} nmethod_stats;
|
||||||
#endif //PRODUCT
|
#endif //PRODUCT
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
// The _unwind_handler is a special marker address, which says that
|
|
||||||
// for given exception oop and address, the frame should be removed
|
|
||||||
// as the tuple cannot be caught in the nmethod
|
|
||||||
address ExceptionCache::_unwind_handler = (address) -1;
|
|
||||||
|
|
||||||
|
|
||||||
ExceptionCache::ExceptionCache(Handle exception, address pc, address handler) {
|
ExceptionCache::ExceptionCache(Handle exception, address pc, address handler) {
|
||||||
assert(pc != NULL, "Must be non null");
|
assert(pc != NULL, "Must be non null");
|
||||||
assert(exception.not_null(), "Must be non null");
|
assert(exception.not_null(), "Must be non null");
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
class ExceptionCache : public CHeapObj {
|
class ExceptionCache : public CHeapObj {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
private:
|
private:
|
||||||
static address _unwind_handler;
|
|
||||||
enum { cache_size = 16 };
|
enum { cache_size = 16 };
|
||||||
klassOop _exception_type;
|
klassOop _exception_type;
|
||||||
address _pc[cache_size];
|
address _pc[cache_size];
|
||||||
|
@ -62,8 +61,6 @@ class ExceptionCache : public CHeapObj {
|
||||||
bool match_exception_with_space(Handle exception) ;
|
bool match_exception_with_space(Handle exception) ;
|
||||||
address test_address(address addr);
|
address test_address(address addr);
|
||||||
bool add_address_and_handler(address addr, address handler) ;
|
bool add_address_and_handler(address addr, address handler) ;
|
||||||
|
|
||||||
static address unwind_handler() { return _unwind_handler; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -431,25 +431,24 @@ JRT_END
|
||||||
// previous frame depending on the return address.
|
// previous frame depending on the return address.
|
||||||
|
|
||||||
address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) {
|
address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) {
|
||||||
assert(frame::verify_return_pc(return_address), "must be a return pc");
|
assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address));
|
||||||
|
|
||||||
// Reset MethodHandle flag.
|
// Reset method handle flag.
|
||||||
thread->set_is_method_handle_return(false);
|
thread->set_is_method_handle_return(false);
|
||||||
|
|
||||||
// the fastest case first
|
// The fastest case first
|
||||||
CodeBlob* blob = CodeCache::find_blob(return_address);
|
CodeBlob* blob = CodeCache::find_blob(return_address);
|
||||||
if (blob != NULL && blob->is_nmethod()) {
|
nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL;
|
||||||
nmethod* code = (nmethod*)blob;
|
if (nm != NULL) {
|
||||||
assert(code != NULL, "nmethod must be present");
|
// Set flag if return address is a method handle call site.
|
||||||
// Check if the return address is a MethodHandle call site.
|
thread->set_is_method_handle_return(nm->is_method_handle_return(return_address));
|
||||||
thread->set_is_method_handle_return(code->is_method_handle_return(return_address));
|
|
||||||
// native nmethods don't have exception handlers
|
// native nmethods don't have exception handlers
|
||||||
assert(!code->is_native_method(), "no exception handler");
|
assert(!nm->is_native_method(), "no exception handler");
|
||||||
assert(code->header_begin() != code->exception_begin(), "no exception handler");
|
assert(nm->header_begin() != nm->exception_begin(), "no exception handler");
|
||||||
if (code->is_deopt_pc(return_address)) {
|
if (nm->is_deopt_pc(return_address)) {
|
||||||
return SharedRuntime::deopt_blob()->unpack_with_exception();
|
return SharedRuntime::deopt_blob()->unpack_with_exception();
|
||||||
} else {
|
} else {
|
||||||
return code->exception_begin();
|
return nm->exception_begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,22 +461,9 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre
|
||||||
return Interpreter::rethrow_exception_entry();
|
return Interpreter::rethrow_exception_entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiled code
|
guarantee(blob == NULL || !blob->is_runtime_stub(), "caller should have skipped stub");
|
||||||
if (CodeCache::contains(return_address)) {
|
|
||||||
CodeBlob* blob = CodeCache::find_blob(return_address);
|
|
||||||
if (blob->is_nmethod()) {
|
|
||||||
nmethod* code = (nmethod*)blob;
|
|
||||||
assert(code != NULL, "nmethod must be present");
|
|
||||||
// Check if the return address is a MethodHandle call site.
|
|
||||||
thread->set_is_method_handle_return(code->is_method_handle_return(return_address));
|
|
||||||
assert(code->header_begin() != code->exception_begin(), "no exception handler");
|
|
||||||
return code->exception_begin();
|
|
||||||
}
|
|
||||||
if (blob->is_runtime_stub()) {
|
|
||||||
ShouldNotReachHere(); // callers are responsible for skipping runtime stub frames
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guarantee(!VtableStubs::contains(return_address), "NULL exceptions in vtables should have been handled already!");
|
guarantee(!VtableStubs::contains(return_address), "NULL exceptions in vtables should have been handled already!");
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
{ ResourceMark rm;
|
{ ResourceMark rm;
|
||||||
tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", return_address);
|
tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", return_address);
|
||||||
|
@ -485,6 +471,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre
|
||||||
tty->print_cr("b) other problem");
|
tty->print_cr("b) other problem");
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -161,6 +161,14 @@
|
||||||
#define NOT_WINDOWS(code) code
|
#define NOT_WINDOWS(code) code
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define WIN64_ONLY(code) code
|
||||||
|
#define NOT_WIN64(code)
|
||||||
|
#else
|
||||||
|
#define WIN64_ONLY(code)
|
||||||
|
#define NOT_WIN64(code) code
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(IA32) || defined(AMD64)
|
#if defined(IA32) || defined(AMD64)
|
||||||
#define X86
|
#define X86
|
||||||
#define X86_ONLY(code) code
|
#define X86_ONLY(code) code
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue