aboutsummaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorbdelsart <none@none>2012-01-26 16:49:22 +0100
committerbdelsart <none@none>2012-01-26 16:49:22 +0100
commitcfaa898ffb85b1aab07a72ca1309036a101c3e04 (patch)
tree0514d5172860b653eb3a1300fb227340d7937af4 /src/cpu
parent8a412a19ba89c6a659976b4ccd2416e4f78b5d70 (diff)
7120468: SPARC/x86: use frame::describe to enhance trace_method_handle
Summary: improvements of TraceMethodHandles for JSR292 Reviewed-by: never, twisti
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/sparc/vm/frame_sparc.cpp2
-rw-r--r--src/cpu/sparc/vm/methodHandles_sparc.cpp113
-rw-r--r--src/cpu/sparc/vm/methodHandles_sparc.hpp2
-rw-r--r--src/cpu/x86/vm/frame_x86.cpp2
-rw-r--r--src/cpu/x86/vm/methodHandles_x86.cpp113
-rw-r--r--src/cpu/x86/vm/methodHandles_x86.hpp2
-rw-r--r--src/cpu/zero/vm/frame_zero.cpp2
7 files changed, 204 insertions, 32 deletions
diff --git a/src/cpu/sparc/vm/frame_sparc.cpp b/src/cpu/sparc/vm/frame_sparc.cpp
index fdcfffef8..f7bccc84a 100644
--- a/src/cpu/sparc/vm/frame_sparc.cpp
+++ b/src/cpu/sparc/vm/frame_sparc.cpp
@@ -810,7 +810,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
}
-#ifdef ASSERT
+#ifndef PRODUCT
#define DESCRIBE_FP_OFFSET(name) \
values.describe(frame_no, fp() + frame::name##_offset, #name)
diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp
index 96b8ff859..9adb9d93b 100644
--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
@@ -177,7 +177,7 @@ void MethodHandles::RicochetFrame::generate_ricochet_blob(MacroAssembler* _masm,
BLOCK_COMMENT("ricochet_blob.bounce");
if (VerifyMethodHandles) RicochetFrame::verify_clean(_masm);
- trace_method_handle(_masm, "ricochet_blob.bounce");
+ trace_method_handle(_masm, "return/ricochet_blob.bounce");
__ JMP(L1_continuation, 0);
__ delayed()->nop();
@@ -268,14 +268,16 @@ void MethodHandles::RicochetFrame::leave_ricochet_frame(MacroAssembler* _masm,
}
// Emit code to verify that FP is pointing at a valid ricochet frame.
-#ifdef ASSERT
+#ifndef PRODUCT
enum {
ARG_LIMIT = 255, SLOP = 45,
// use this parameter for checking for garbage stack movements:
UNREASONABLE_STACK_MOVE = (ARG_LIMIT + SLOP)
// the slop defends against false alarms due to fencepost errors
};
+#endif
+#ifdef ASSERT
void MethodHandles::RicochetFrame::verify_clean(MacroAssembler* _masm) {
// The stack should look like this:
// ... keep1 | dest=42 | keep2 | magic | handler | magic | recursive args | [RF]
@@ -1000,7 +1002,7 @@ void MethodHandles::move_return_value(MacroAssembler* _masm, BasicType type,
BLOCK_COMMENT("} move_return_value");
}
-#ifdef ASSERT
+#ifndef PRODUCT
void MethodHandles::RicochetFrame::describe(const frame* fr, FrameValues& values, int frame_no) {
RicochetFrame* rf = new RicochetFrame(*fr);
@@ -1022,28 +1024,121 @@ void MethodHandles::RicochetFrame::describe(const frame* fr, FrameValues& values
extern "C" void print_method_handle(oop mh);
void trace_method_handle_stub(const char* adaptername,
oopDesc* mh,
- intptr_t* saved_sp) {
+ intptr_t* saved_sp,
+ intptr_t* args,
+ intptr_t* tracing_fp) {
bool has_mh = (strstr(adaptername, "return/") == NULL); // return adapters don't have mh
- tty->print_cr("MH %s mh="INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT, adaptername, (intptr_t) mh, saved_sp);
- if (has_mh)
+
+ tty->print_cr("MH %s mh="INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT " args=" INTPTR_FORMAT, adaptername, (intptr_t) mh, saved_sp, args);
+
+ if (Verbose) {
+ // dumping last frame with frame::describe
+
+ JavaThread* p = JavaThread::active();
+
+ ResourceMark rm;
+ PRESERVE_EXCEPTION_MARK; // may not be needed by safer and unexpensive here
+ FrameValues values;
+
+ // Note: We want to allow trace_method_handle from any call site.
+ // While trace_method_handle creates a frame, it may be entered
+ // without a valid return PC in O7 (e.g. not just after a call).
+ // Walking that frame could lead to failures due to that invalid PC.
+ // => carefully detect that frame when doing the stack walking
+
+ // walk up to the right frame using the "tracing_fp" argument
+ intptr_t* cur_sp = StubRoutines::Sparc::flush_callers_register_windows_func()();
+ frame cur_frame(cur_sp, frame::unpatchable, NULL);
+
+ while (cur_frame.fp() != (intptr_t *)(STACK_BIAS+(uintptr_t)tracing_fp)) {
+ cur_frame = os::get_sender_for_C_frame(&cur_frame);
+ }
+
+ // safely create a frame and call frame::describe
+ intptr_t *dump_sp = cur_frame.sender_sp();
+ intptr_t *dump_fp = cur_frame.link();
+
+ bool walkable = has_mh; // whether the traced frame shoud be walkable
+
+ // the sender for cur_frame is the caller of trace_method_handle
+ if (walkable) {
+ // The previous definition of walkable may have to be refined
+ // if new call sites cause the next frame constructor to start
+ // failing. Alternatively, frame constructors could be
+ // modified to support the current or future non walkable
+ // frames (but this is more intrusive and is not considered as
+ // part of this RFE, which will instead use a simpler output).
+ frame dump_frame = frame(dump_sp,
+ cur_frame.sp(), // younger_sp
+ false); // no adaptation
+ dump_frame.describe(values, 1);
+ } else {
+ // Robust dump for frames which cannot be constructed from sp/younger_sp
+ // Add descriptions without building a Java frame to avoid issues
+ values.describe(-1, dump_fp, "fp for #1 <not parsed, cannot trust pc>");
+ values.describe(-1, dump_sp, "sp");
+ }
+
+ bool has_args = has_mh; // whether Gargs is meaningful
+
+ // mark args, if seems valid (may not be valid for some adapters)
+ if (has_args) {
+ if ((args >= dump_sp) && (args < dump_fp)) {
+ values.describe(-1, args, "*G4_args");
+ }
+ }
+
+ // mark saved_sp, if seems valid (may not be valid for some adapters)
+ intptr_t *unbiased_sp = (intptr_t *)(STACK_BIAS+(uintptr_t)saved_sp);
+ if ((unbiased_sp >= dump_sp - UNREASONABLE_STACK_MOVE) && (unbiased_sp < dump_fp)) {
+ values.describe(-1, unbiased_sp, "*saved_sp+STACK_BIAS");
+ }
+
+ // Note: the unextended_sp may not be correct
+ tty->print_cr(" stack layout:");
+ values.print(p);
+ }
+
+ if (has_mh) {
print_method_handle(mh);
+ }
}
+
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
BLOCK_COMMENT("trace_method_handle {");
// save: Gargs, O5_savedSP
- __ save_frame(16);
+ __ save_frame(16); // need space for saving required FPU state
+
__ set((intptr_t) adaptername, O0);
__ mov(G3_method_handle, O1);
__ mov(I5_savedSP, O2);
+ __ mov(Gargs, O3);
+ __ mov(I6, O4); // frame identifier for safe stack walking
+
+ // Save scratched registers that might be needed. Robustness is more
+ // important than optimizing the saves for this debug only code.
+
+ // save FP result, valid at some call sites (adapter_opt_return_float, ...)
+ Address d_save(FP, -sizeof(jdouble) + STACK_BIAS);
+ __ stf(FloatRegisterImpl::D, Ftos_d, d_save);
+ // Safely save all globals but G2 (handled by call_VM_leaf) and G7
+ // (OS reserved).
__ mov(G3_method_handle, L3);
__ mov(Gargs, L4);
__ mov(G5_method_type, L5);
- __ call_VM_leaf(L7, CAST_FROM_FN_PTR(address, trace_method_handle_stub));
+ __ mov(G6, L6);
+ __ mov(G1, L1);
+
+ __ call_VM_leaf(L2 /* for G2 */, CAST_FROM_FN_PTR(address, trace_method_handle_stub));
__ mov(L3, G3_method_handle);
__ mov(L4, Gargs);
__ mov(L5, G5_method_type);
+ __ mov(L6, G6);
+ __ mov(L1, G1);
+ __ ldf(FloatRegisterImpl::D, d_save, Ftos_d);
+
__ restore();
BLOCK_COMMENT("} trace_method_handle");
}
@@ -1268,7 +1363,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
move_typed_arg(_masm, arg_type, false,
prim_value_addr,
Address(O0_argslot, 0),
- O2_scratch); // must be an even register for !_LP64 long moves (uses O2/O3)
+ O2_scratch); // must be an even register for !_LP64 long moves (uses O2/O3)
}
if (direct_to_method) {
diff --git a/src/cpu/sparc/vm/methodHandles_sparc.hpp b/src/cpu/sparc/vm/methodHandles_sparc.hpp
index 2c3d810b8..7382b9c4e 100644
--- a/src/cpu/sparc/vm/methodHandles_sparc.hpp
+++ b/src/cpu/sparc/vm/methodHandles_sparc.hpp
@@ -146,7 +146,7 @@ class RicochetFrame : public ResourceObj {
static void verify_clean(MacroAssembler* _masm) NOT_DEBUG_RETURN;
- static void describe(const frame* fr, FrameValues& values, int frame_no) NOT_DEBUG_RETURN;
+ static void describe(const frame* fr, FrameValues& values, int frame_no) PRODUCT_RETURN;
};
// Additional helper methods for MethodHandles code generation:
diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
index 4051cdf59..4255be664 100644
--- a/src/cpu/x86/vm/frame_x86.cpp
+++ b/src/cpu/x86/vm/frame_x86.cpp
@@ -651,7 +651,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
return &interpreter_frame_tos_address()[index];
}
-#ifdef ASSERT
+#ifndef PRODUCT
#define DESCRIBE_FP_OFFSET(name) \
values.describe(frame_no, fp() + frame::name##_offset, #name)
diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
index 38694718b..a6ccfb830 100644
--- a/src/cpu/x86/vm/methodHandles_x86.cpp
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp
@@ -279,14 +279,16 @@ void MethodHandles::RicochetFrame::leave_ricochet_frame(MacroAssembler* _masm,
}
// Emit code to verify that RBP is pointing at a valid ricochet frame.
-#ifdef ASSERT
+#ifndef PRODUCT
enum {
ARG_LIMIT = 255, SLOP = 4,
// use this parameter for checking for garbage stack movements:
UNREASONABLE_STACK_MOVE = (ARG_LIMIT + SLOP)
// the slop defends against false alarms due to fencepost errors
};
+#endif
+#ifdef ASSERT
void MethodHandles::RicochetFrame::verify_clean(MacroAssembler* _masm) {
// The stack should look like this:
// ... keep1 | dest=42 | keep2 | RF | magic | handler | magic | recursive args |
@@ -990,7 +992,7 @@ void MethodHandles::move_return_value(MacroAssembler* _masm, BasicType type,
BLOCK_COMMENT("} move_return_value");
}
-#ifdef ASSERT
+#ifndef PRODUCT
#define DESCRIBE_RICOCHET_OFFSET(rf, name) \
values.describe(frame_no, (intptr_t *) (((uintptr_t)rf) + MethodHandles::RicochetFrame::name##_offset_in_bytes()), #name)
@@ -1021,6 +1023,7 @@ void trace_method_handle_stub(const char* adaptername,
intptr_t* saved_bp) {
// called as a leaf from native code: do not block the JVM!
bool has_mh = (strstr(adaptername, "return/") == NULL); // return adapters don't have rcx_mh
+
intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset];
intptr_t* base_sp = last_sp;
typedef MethodHandles::RicochetFrame RicochetFrame;
@@ -1050,13 +1053,64 @@ void trace_method_handle_stub(const char* adaptername,
tty->cr();
if (last_sp != saved_sp && last_sp != NULL)
tty->print_cr("*** last_sp="PTR_FORMAT, (intptr_t)last_sp);
- int stack_dump_count = 16;
- if (stack_dump_count < (int)(saved_bp + 2 - saved_sp))
- stack_dump_count = (int)(saved_bp + 2 - saved_sp);
- if (stack_dump_count > 64) stack_dump_count = 48;
- for (i = 0; i < stack_dump_count; i += 4) {
- tty->print_cr(" dump at SP[%d] "PTR_FORMAT": "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT,
- i, (intptr_t) &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]);
+
+ {
+ // dumping last frame with frame::describe
+
+ JavaThread* p = JavaThread::active();
+
+ ResourceMark rm;
+ PRESERVE_EXCEPTION_MARK; // may not be needed by safer and unexpensive here
+ FrameValues values;
+
+ // Note: We want to allow trace_method_handle from any call site.
+ // While trace_method_handle creates a frame, it may be entered
+ // without a PC on the stack top (e.g. not just after a call).
+ // Walking that frame could lead to failures due to that invalid PC.
+ // => carefully detect that frame when doing the stack walking
+
+ // Current C frame
+ frame cur_frame = os::current_frame();
+
+ // Robust search of trace_calling_frame (independant of inlining).
+ // Assumes saved_regs comes from a pusha in the trace_calling_frame.
+ assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?");
+ frame trace_calling_frame = os::get_sender_for_C_frame(&cur_frame);
+ while (trace_calling_frame.fp() < saved_regs) {
+ trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame);
+ }
+
+ // safely create a frame and call frame::describe
+ intptr_t *dump_sp = trace_calling_frame.sender_sp();
+ intptr_t *dump_fp = trace_calling_frame.link();
+
+ bool walkable = has_mh; // whether the traced frame shoud be walkable
+
+ if (walkable) {
+ // The previous definition of walkable may have to be refined
+ // if new call sites cause the next frame constructor to start
+ // failing. Alternatively, frame constructors could be
+ // modified to support the current or future non walkable
+ // frames (but this is more intrusive and is not considered as
+ // part of this RFE, which will instead use a simpler output).
+ frame dump_frame = frame(dump_sp, dump_fp);
+ dump_frame.describe(values, 1);
+ } else {
+ // Stack may not be walkable (invalid PC above FP):
+ // Add descriptions without building a Java frame to avoid issues
+ values.describe(-1, dump_fp, "fp for #1 <not parsed, cannot trust pc>");
+ values.describe(-1, dump_sp, "sp for #1");
+ }
+
+ // mark saved_sp if seems valid
+ if (has_mh) {
+ if ((saved_sp >= dump_sp - UNREASONABLE_STACK_MOVE) && (saved_sp < dump_fp)) {
+ values.describe(-1, saved_sp, "*saved_sp");
+ }
+ }
+
+ tty->print_cr(" stack layout:");
+ values.print(p);
}
if (has_mh)
print_method_handle(mh);
@@ -1086,26 +1140,49 @@ void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) {
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
BLOCK_COMMENT("trace_method_handle {");
- __ push(rax);
- __ lea(rax, Address(rsp, wordSize * NOT_LP64(6) LP64_ONLY(14))); // entry_sp __ pusha();
- __ pusha();
- __ mov(rbx, rsp);
__ enter();
+ __ andptr(rsp, -16); // align stack if needed for FPU state
+ __ pusha();
+ __ mov(rbx, rsp); // for retreiving saved_regs
+ // Note: saved_regs must be in the entered frame for the
+ // robust stack walking implemented in trace_method_handle_stub.
+
+ // save FP result, valid at some call sites (adapter_opt_return_float, ...)
+ __ increment(rsp, -2 * wordSize);
+ if (UseSSE >= 2) {
+ __ movdbl(Address(rsp, 0), xmm0);
+ } else if (UseSSE == 1) {
+ __ movflt(Address(rsp, 0), xmm0);
+ } else {
+ __ fst_d(Address(rsp, 0));
+ }
+
// incoming state:
// rcx: method handle
// r13 or rsi: saved sp
// To avoid calling convention issues, build a record on the stack and pass the pointer to that instead.
+ // Note: fix the increment below if pushing more arguments
__ push(rbp); // saved_bp
- __ push(rsi); // saved_sp
- __ push(rax); // entry_sp
+ __ push(saved_last_sp_register()); // saved_sp
+ __ push(rbp); // entry_sp (with extra align space)
__ push(rbx); // pusha saved_regs
__ push(rcx); // mh
- __ push(rcx); // adaptername
+ __ push(rcx); // slot for adaptername
__ movptr(Address(rsp, 0), (intptr_t) adaptername);
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub_wrapper), rsp);
- __ leave();
+ __ increment(rsp, 6 * wordSize); // MethodHandleStubArguments
+
+ if (UseSSE >= 2) {
+ __ movdbl(xmm0, Address(rsp, 0));
+ } else if (UseSSE == 1) {
+ __ movflt(xmm0, Address(rsp, 0));
+ } else {
+ __ fld_d(Address(rsp, 0));
+ }
+ __ increment(rsp, 2 * wordSize);
+
__ popa();
- __ pop(rax);
+ __ leave();
BLOCK_COMMENT("} trace_method_handle");
}
#endif //PRODUCT
diff --git a/src/cpu/x86/vm/methodHandles_x86.hpp b/src/cpu/x86/vm/methodHandles_x86.hpp
index 9f8e1a560..755738380 100644
--- a/src/cpu/x86/vm/methodHandles_x86.hpp
+++ b/src/cpu/x86/vm/methodHandles_x86.hpp
@@ -225,7 +225,7 @@ class RicochetFrame {
static void verify_clean(MacroAssembler* _masm) NOT_DEBUG_RETURN;
- static void describe(const frame* fr, FrameValues& values, int frame_no) NOT_DEBUG_RETURN;
+ static void describe(const frame* fr, FrameValues& values, int frame_no) PRODUCT_RETURN;
};
// Additional helper methods for MethodHandles code generation:
diff --git a/src/cpu/zero/vm/frame_zero.cpp b/src/cpu/zero/vm/frame_zero.cpp
index 35b6e52e4..85f023049 100644
--- a/src/cpu/zero/vm/frame_zero.cpp
+++ b/src/cpu/zero/vm/frame_zero.cpp
@@ -418,7 +418,7 @@ void ZeroFrame::identify_vp_word(int frame_index,
}
}
-#ifdef ASSERT
+#ifndef PRODUCT
void frame::describe_pd(FrameValues& values, int frame_no) {