Commit 9b4369c7 authored by peter.rybin@gmail.com's avatar peter.rybin@gmail.com

LiveEdit: Support debug break slots in frame dropping implementation

Review URL: http://codereview.chromium.org/2844030

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4995 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 97ecc503
...@@ -854,7 +854,7 @@ Object* Debug::Break(Arguments args) { ...@@ -854,7 +854,7 @@ Object* Debug::Break(Arguments args) {
HandleScope scope; HandleScope scope;
ASSERT(args.length() == 0); ASSERT(args.length() == 0);
thread_local_.frames_are_dropped_ = false; thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
// Get the top-most JavaScript frame. // Get the top-most JavaScript frame.
JavaScriptFrameIterator it; JavaScriptFrameIterator it;
...@@ -932,12 +932,22 @@ Object* Debug::Break(Arguments args) { ...@@ -932,12 +932,22 @@ Object* Debug::Break(Arguments args) {
PrepareStep(step_action, step_count); PrepareStep(step_action, step_count);
} }
if (thread_local_.frames_are_dropped_) { if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
// We must have been calling IC stub. Do not return there anymore. SetAfterBreakTarget(frame);
} else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_IC_CALL) {
// We must have been calling IC stub. Do not go there anymore.
Code* plain_return = Builtins::builtin(Builtins::PlainReturn_LiveEdit); Code* plain_return = Builtins::builtin(Builtins::PlainReturn_LiveEdit);
thread_local_.after_break_target_ = plain_return->entry(); thread_local_.after_break_target_ = plain_return->entry();
} else if (thread_local_.frame_drop_mode_ ==
FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
// Debug break slot stub does not return normally, instead it manually
// cleans the stack and jumps. We should patch the jump address.
Code* plain_return = Builtins::builtin(Builtins::FrameDropper_LiveEdit);
thread_local_.after_break_target_ = plain_return->entry();
} else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_DIRECT_CALL) {
// Nothing to do, after_break_target is not used here.
} else { } else {
SetAfterBreakTarget(frame); UNREACHABLE();
} }
return Heap::undefined_value(); return Heap::undefined_value();
...@@ -1749,8 +1759,9 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { ...@@ -1749,8 +1759,9 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
} }
void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id) { void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
thread_local_.frames_are_dropped_ = true; FrameDropMode mode) {
thread_local_.frame_drop_mode_ = mode;
thread_local_.break_frame_id_ = new_break_frame_id; thread_local_.break_frame_id_ = new_break_frame_id;
} }
......
...@@ -400,7 +400,22 @@ class Debug { ...@@ -400,7 +400,22 @@ class Debug {
// Called from stub-cache.cc. // Called from stub-cache.cc.
static void GenerateCallICDebugBreak(MacroAssembler* masm); static void GenerateCallICDebugBreak(MacroAssembler* masm);
static void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id); // Describes how exactly a frame has been dropped from stack.
enum FrameDropMode {
// No frame has been dropped.
FRAMES_UNTOUCHED,
// The top JS frame had been calling IC stub. IC stub mustn't be called now.
FRAME_DROPPED_IN_IC_CALL,
// The top JS frame had been calling debug break slot stub. Patch the
// address this stub jumps to in the end.
FRAME_DROPPED_IN_DEBUG_SLOT_CALL,
// The top JS frame had been calling some C++ function. The return address
// gets patched automatically.
FRAME_DROPPED_IN_DIRECT_CALL
};
static void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
FrameDropMode mode);
static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame, static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
Handle<Code> code); Handle<Code> code);
...@@ -471,8 +486,9 @@ class Debug { ...@@ -471,8 +486,9 @@ class Debug {
// Storage location for jump when exiting debug break calls. // Storage location for jump when exiting debug break calls.
Address after_break_target_; Address after_break_target_;
// Indicates that LiveEdit has patched the stack. // Stores the way how LiveEdit has patched the stack. It is used when
bool frames_are_dropped_; // debugger returns control back to user script.
FrameDropMode frame_drop_mode_;
// Top debugger entry. // Top debugger entry.
EnterDebugger* debugger_entry_; EnterDebugger* debugger_entry_;
......
...@@ -1187,7 +1187,12 @@ static bool FixTryCatchHandler(StackFrame* top_frame, ...@@ -1187,7 +1187,12 @@ static bool FixTryCatchHandler(StackFrame* top_frame,
// Returns error message or NULL. // Returns error message or NULL.
static const char* DropFrames(Vector<StackFrame*> frames, static const char* DropFrames(Vector<StackFrame*> frames,
int top_frame_index, int top_frame_index,
int bottom_js_frame_index) { int bottom_js_frame_index,
Debug::FrameDropMode* mode) {
if (Debug::kFrameDropperFrameSize < 0) {
return "Stack manipulations are not supported in this architecture.";
}
StackFrame* pre_top_frame = frames[top_frame_index - 1]; StackFrame* pre_top_frame = frames[top_frame_index - 1];
StackFrame* top_frame = frames[top_frame_index]; StackFrame* top_frame = frames[top_frame_index];
StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
...@@ -1198,12 +1203,18 @@ static const char* DropFrames(Vector<StackFrame*> frames, ...@@ -1198,12 +1203,18 @@ static const char* DropFrames(Vector<StackFrame*> frames,
if (pre_top_frame->code()->is_inline_cache_stub() && if (pre_top_frame->code()->is_inline_cache_stub() &&
pre_top_frame->code()->ic_state() == DEBUG_BREAK) { pre_top_frame->code()->ic_state() == DEBUG_BREAK) {
// OK, we can drop inline cache calls. // OK, we can drop inline cache calls.
*mode = Debug::FRAME_DROPPED_IN_IC_CALL;
} else if (pre_top_frame->code() == Debug::debug_break_slot()) {
// OK, we can drop debug break slot.
*mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
} else if (pre_top_frame->code() == } else if (pre_top_frame->code() ==
Builtins::builtin(Builtins::FrameDropper_LiveEdit)) { Builtins::builtin(Builtins::FrameDropper_LiveEdit)) {
// OK, we can drop our own code. // OK, we can drop our own code.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
} else if (pre_top_frame->code()->kind() == Code::STUB && } else if (pre_top_frame->code()->kind() == Code::STUB &&
pre_top_frame->code()->major_key()) { pre_top_frame->code()->major_key()) {
// Unit Test entry, it's fine, we support this case. // Entry from our unit tests, it's fine, we support this case.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
} else { } else {
return "Unknown structure of stack above changing function"; return "Unknown structure of stack above changing function";
} }
...@@ -1316,8 +1327,9 @@ static const char* DropActivationsInActiveThread( ...@@ -1316,8 +1327,9 @@ static const char* DropActivationsInActiveThread(
return NULL; return NULL;
} }
Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
const char* error_message = DropFrames(frames, top_frame_index, const char* error_message = DropFrames(frames, top_frame_index,
bottom_js_frame_index); bottom_js_frame_index, &drop_mode);
if (error_message != NULL) { if (error_message != NULL) {
return error_message; return error_message;
...@@ -1331,7 +1343,7 @@ static const char* DropActivationsInActiveThread( ...@@ -1331,7 +1343,7 @@ static const char* DropActivationsInActiveThread(
break; break;
} }
} }
Debug::FramesHaveBeenDropped(new_id); Debug::FramesHaveBeenDropped(new_id, drop_mode);
// Replace "blocked on active" with "replaced on active" status. // Replace "blocked on active" with "replaced on active" status.
for (int i = 0; i < array_len; i++) { for (int i = 0; i < array_len; i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment