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;
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();
}
-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;
}
// 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);
// 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_;
// 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];
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";
}
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;
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++) {