aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/x86
diff options
context:
space:
mode:
authortwisti <none@none>2010-02-01 19:29:46 +0100
committertwisti <none@none>2010-02-01 19:29:46 +0100
commit04d9efc8775f2c4366f545514e027bc15b2ccb33 (patch)
treecc3134a757094eefa013ebd187d94eef5ad94dd3 /src/cpu/x86
parent5e4a23adb86f0e79b012e68ad92f6ee13db0678e (diff)
6921352: JSR 292 needs its own deopt handler
Summary: We need to introduce a new MH deopt handler so we can easily determine if the deopt happened at a MH call site or not. Reviewed-by: never, jrose
Diffstat (limited to 'src/cpu/x86')
-rw-r--r--src/cpu/x86/vm/c1_LIRAssembler_x86.cpp32
-rw-r--r--src/cpu/x86/vm/frame_x86.cpp110
-rw-r--r--src/cpu/x86/vm/frame_x86.hpp8
-rw-r--r--src/cpu/x86/vm/frame_x86.inline.hpp27
4 files changed, 117 insertions, 60 deletions
diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
index 2fae54068..d481137da 100644
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2000-2010 Sun Microsystems, Inc. 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
@@ -418,13 +418,12 @@ int LIR_Assembler::initial_frame_size_in_bytes() {
}
-void LIR_Assembler::emit_exception_handler() {
+int LIR_Assembler::emit_exception_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
// failures when searching for the corresponding bci => add a nop
// (was bug 5/14/1999 - gri)
-
__ nop();
// generate code for exception handler
@@ -432,13 +431,10 @@ void LIR_Assembler::emit_exception_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("exception handler overflow");
- return;
+ return -1;
}
-#ifdef ASSERT
- int offset = code_offset();
-#endif // ASSERT
- compilation()->offsets()->set_value(CodeOffsets::Exceptions, code_offset());
+ int offset = code_offset();
// if the method does not have an exception handler, then there is
// no reason to search for one
@@ -474,19 +470,19 @@ void LIR_Assembler::emit_exception_handler() {
// unwind activation and forward exception to caller
// rax,: exception
__ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
-
assert(code_offset() - offset <= exception_handler_size, "overflow");
-
__ end_a_stub();
+
+ return offset;
}
-void LIR_Assembler::emit_deopt_handler() {
+
+int LIR_Assembler::emit_deopt_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
// failures when searching for the corresponding bci => add a nop
// (was bug 5/14/1999 - gri)
-
__ nop();
// generate code for exception handler
@@ -494,23 +490,17 @@ void LIR_Assembler::emit_deopt_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("deopt handler overflow");
- return;
+ return -1;
}
-#ifdef ASSERT
- int offset = code_offset();
-#endif // ASSERT
-
- compilation()->offsets()->set_value(CodeOffsets::Deopt, code_offset());
+ int offset = code_offset();
InternalAddress here(__ pc());
__ pushptr(here.addr());
-
__ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
-
assert(code_offset() - offset <= deopt_handler_size, "overflow");
-
__ end_a_stub();
+ return offset;
}
diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
index 7bbd7311d..01f49e3db 100644
--- a/src/cpu/x86/vm/frame_x86.cpp
+++ b/src/cpu/x86/vm/frame_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -222,9 +222,9 @@ void frame::patch_pc(Thread* thread, address pc) {
}
((address *)sp())[-1] = pc;
_cb = CodeCache::find_blob(pc);
- if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
- address orig = (((nmethod*)_cb)->get_original_pc(this));
- assert(orig == _pc, "expected original to be stored before patching");
+ address original_pc = nmethod::get_deopt_original_pc(this);
+ if (original_pc != NULL) {
+ assert(original_pc == _pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// leave _pc as is
} else {
@@ -323,19 +323,61 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
return fr;
}
+
+//------------------------------------------------------------------------------
+// frame::verify_deopt_original_pc
+//
+// Verifies the calculated original PC of a deoptimization PC for the
+// given unextended SP. The unextended SP might also be the saved SP
+// for MethodHandle call sites.
+#if ASSERT
+void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
+ frame fr;
+
+ // This is ugly but it's better than to change {get,set}_original_pc
+ // to take an SP value as argument. And it's only a debugging
+ // method anyway.
+ fr._unextended_sp = unextended_sp;
+
+ address original_pc = nm->get_original_pc(&fr);
+ assert(nm->code_contains(original_pc), "original PC must be in nmethod");
+ assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
- // sp is the raw sp from the sender after adapter or interpreter extension
- intptr_t* sp = (intptr_t*) addr_at(sender_sp_offset);
+ // SP is the raw SP from the sender after adapter or interpreter
+ // extension.
+ intptr_t* sender_sp = this->sender_sp();
// This is the sp before any possible extension (adapter/locals).
intptr_t* unextended_sp = interpreter_frame_sender_sp();
+ // Stored FP.
+ intptr_t* saved_fp = link();
+
address sender_pc = this->sender_pc();
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
- if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
- unextended_sp = (intptr_t*) at(link_offset);
+
+ if (sender_nm != NULL) {
+ // If the sender PC is a deoptimization point, get the original
+ // PC. For MethodHandle call site the unextended_sp is stored in
+ // saved_fp.
+ if (sender_nm->is_deopt_mh_entry(sender_pc)) {
+ DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
+ unextended_sp = saved_fp;
+ }
+ else if (sender_nm->is_deopt_entry(sender_pc)) {
+ DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
+ }
+ else if (sender_nm->is_method_handle_return(sender_pc)) {
+ unextended_sp = saved_fp;
+ }
}
// The interpreter and compiler(s) always save EBP/RBP in a known
@@ -359,40 +401,51 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
}
#endif // AMD64
}
-#endif /* COMPILER2 */
- return frame(sp, unextended_sp, link(), sender_pc);
+#endif // COMPILER2
+
+ return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
}
-//------------------------------sender_for_compiled_frame-----------------------
+//------------------------------------------------------------------------------
+// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
- const bool c1_compiled = _cb->is_compiled_by_c1();
// frame owned by optimizing compiler
- intptr_t* sender_sp = NULL;
-
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
- sender_sp = unextended_sp() + _cb->frame_size();
+ intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
+ intptr_t* unextended_sp = sender_sp;
// On Intel the return_address is always the word on the stack
address sender_pc = (address) *(sender_sp-1);
- // This is the saved value of ebp which may or may not really be an fp.
- // it is only an fp if the sender is an interpreter frame (or c1?)
+ // This is the saved value of EBP which may or may not really be an FP.
+ // It is only an FP if the sender is an interpreter frame (or C1?).
+ intptr_t* saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
- intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
-
- intptr_t* unextended_sp = sender_sp;
- // If we are returning to a compiled method handle call site,
- // the saved_fp will in fact be a saved value of the unextended SP.
- // The simplest way to tell whether we are returning to such a call
- // site is as follows:
+ // If we are returning to a compiled MethodHandle call site, the
+ // saved_fp will in fact be a saved value of the unextended SP. The
+ // simplest way to tell whether we are returning to such a call site
+ // is as follows:
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
- if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
- unextended_sp = saved_fp;
+
+ if (sender_nm != NULL) {
+ // If the sender PC is a deoptimization point, get the original
+ // PC. For MethodHandle call site the unextended_sp is stored in
+ // saved_fp.
+ if (sender_nm->is_deopt_mh_entry(sender_pc)) {
+ DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
+ unextended_sp = saved_fp;
+ }
+ else if (sender_nm->is_deopt_entry(sender_pc)) {
+ DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
+ }
+ else if (sender_nm->is_method_handle_return(sender_pc)) {
+ unextended_sp = saved_fp;
+ }
}
if (map->update_map()) {
@@ -403,7 +456,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
- // Since the prolog does the save and restore of epb there is no oopmap
+ // Since the prolog does the save and restore of EBP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
map->set_location(rbp->as_VMReg(), (address) (sender_sp - frame::sender_sp_offset));
@@ -422,6 +475,9 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
}
+
+//------------------------------------------------------------------------------
+// frame::sender
frame frame::sender(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
diff --git a/src/cpu/x86/vm/frame_x86.hpp b/src/cpu/x86/vm/frame_x86.hpp
index 3668f2da2..b21449f84 100644
--- a/src/cpu/x86/vm/frame_x86.hpp
+++ b/src/cpu/x86/vm/frame_x86.hpp
@@ -163,6 +163,14 @@
return (intptr_t*) addr_at(offset);
}
+#if ASSERT
+ // Used in frame::sender_for_{interpreter,compiled}_frame
+ static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
+ static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
+ verify_deopt_original_pc(nm, unextended_sp, true);
+ }
+#endif
+
public:
// Constructors
diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
index 1f2065ba4..809e26cfa 100644
--- a/src/cpu/x86/vm/frame_x86.inline.hpp
+++ b/src/cpu/x86/vm/frame_x86.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -35,32 +35,35 @@ inline frame::frame() {
_deopt_state = unknown;
}
-inline frame:: frame(intptr_t* sp, intptr_t* fp, address pc) {
+inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
_sp = sp;
_unextended_sp = sp;
_fp = fp;
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
- _deopt_state = not_deoptimized;
- if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
- _pc = (((nmethod*)_cb)->get_original_pc(this));
+
+ address original_pc = nmethod::get_deopt_original_pc(this);
+ if (original_pc != NULL) {
+ _pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
}
}
-inline frame:: frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
_sp = sp;
_unextended_sp = unextended_sp;
_fp = fp;
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
- _deopt_state = not_deoptimized;
- if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
- _pc = (((nmethod*)_cb)->get_original_pc(this));
+
+ address original_pc = nmethod::get_deopt_original_pc(this);
+ if (original_pc != NULL) {
+ _pc = original_pc;
+ assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
@@ -86,9 +89,9 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_cb = CodeCache::find_blob(_pc);
- _deopt_state = not_deoptimized;
- if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
- _pc = (((nmethod*)_cb)->get_original_pc(this));
+ address original_pc = nmethod::get_deopt_original_pc(this);
+ if (original_pc != NULL) {
+ _pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;