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) {
HandleScope scope;
ASSERT(args.length() == 0);
thread_local_.frames_are_dropped_ = false;
thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
// Get the top-most JavaScript frame.
JavaScriptFrameIterator it;
......@@ -932,12 +932,22 @@ Object* Debug::Break(Arguments args) {
PrepareStep(step_action, step_count);
}
if (thread_local_.frames_are_dropped_) {
// We must have been calling IC stub. Do not return there anymore.
if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
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);
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 {
SetAfterBreakTarget(frame);
UNREACHABLE();
}
return Heap::undefined_value();
......@@ -1749,8 +1759,9 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
}
void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id) {
thread_local_.frames_are_dropped_ = true;
void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
FrameDropMode mode) {
thread_local_.frame_drop_mode_ = mode;
thread_local_.break_frame_id_ = new_break_frame_id;
}
......
......@@ -400,7 +400,22 @@ class Debug {
// Called from stub-cache.cc.
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,
Handle<Code> code);
......@@ -471,8 +486,9 @@ class Debug {
// Storage location for jump when exiting debug break calls.
Address after_break_target_;
// Indicates that LiveEdit has patched the stack.
bool frames_are_dropped_;
// Stores the way how LiveEdit has patched the stack. It is used when
// debugger returns control back to user script.
FrameDropMode frame_drop_mode_;
// Top debugger entry.
EnterDebugger* debugger_entry_;
......
......@@ -1187,7 +1187,12 @@ static bool FixTryCatchHandler(StackFrame* top_frame,
// Returns error message or NULL.
static const char* DropFrames(Vector<StackFrame*> frames,
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* top_frame = frames[top_frame_index];
StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
......@@ -1198,12 +1203,18 @@ static const char* DropFrames(Vector<StackFrame*> frames,
if (pre_top_frame->code()->is_inline_cache_stub() &&
pre_top_frame->code()->ic_state() == DEBUG_BREAK) {
// 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() ==
Builtins::builtin(Builtins::FrameDropper_LiveEdit)) {
// OK, we can drop our own code.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
} else if (pre_top_frame->code()->kind() == Code::STUB &&
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 {
return "Unknown structure of stack above changing function";
}
......@@ -1316,8 +1327,9 @@ static const char* DropActivationsInActiveThread(
return NULL;
}
Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
const char* error_message = DropFrames(frames, top_frame_index,
bottom_js_frame_index);
bottom_js_frame_index, &drop_mode);
if (error_message != NULL) {
return error_message;
......@@ -1331,7 +1343,7 @@ static const char* DropActivationsInActiveThread(
break;
}
}
Debug::FramesHaveBeenDropped(new_id);
Debug::FramesHaveBeenDropped(new_id, drop_mode);
// Replace "blocked on active" with "replaced on active" status.
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