LiveEdit: Support debug break slots in frame dropping implementation
authorpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Jun 2010 17:29:00 +0000 (17:29 +0000)
committerpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Jun 2010 17:29:00 +0000 (17:29 +0000)
Review URL: http://codereview.chromium.org/2844030

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4995 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/debug.cc
src/debug.h
src/liveedit.cc

index d513b3121cc3b86f7df27d229b248738705c8417..f7c06f06ed0cce9ca172530a4b3b03e7f6328fb5 100644 (file)
@@ -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;
 }
 
index 6019294f22c4e54aa439a1c73be2b090b32b0038..fb9269272f1f2200b00cd9a20c5eba0d2e9f1a40 100644 (file)
@@ -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_;
index 950f8e0de2b46365bd03bc8291a0b8f15c2cd7e9..04631a3f7cae14a07ccf9b70b41c51f3eeadc383 100644 (file)
@@ -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++) {