Implement issue 554 Add "ProcessDebuggerRequests" call to Debug Agent API
authorpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 15 Jan 2010 21:14:56 +0000 (21:14 +0000)
committerpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 15 Jan 2010 21:14:56 +0000 (21:14 +0000)
Review URL: http://codereview.chromium.org/549057

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

include/v8-debug.h
src/api.cc
src/execution.cc
src/execution.h
test/cctest/test-debug.cc

index 10b41e2..ff3182c 100644 (file)
@@ -263,6 +263,43 @@ class EXPORT Debug {
   */
   static bool EnableAgent(const char* name, int port,
                           bool wait_for_connection = false);
+
+  /**
+   * Makes V8 process all pending debug messages.
+   *
+   * From V8 point of view all debug messages come asynchronously (e.g. from
+   * remote debugger) but they all must be handled synchronously: V8 cannot
+   * do 2 things at one time so normal script execution must be interrupted
+   * for a while.
+   *
+   * Generally when message arrives V8 may be in one of 3 states:
+   * 1. V8 is running script; V8 will automatically interrupt and process all
+   * pending messages (however auto_break flag should be enabled);
+   * 2. V8 is suspended on debug breakpoint; in this state V8 is dedicated
+   * to reading and processing debug messages;
+   * 3. V8 is not running at all or has called some long-working C++ function;
+   * by default it means that processing of all debug message will be deferred
+   * until V8 gets control again; however, embedding application may improve
+   * this by manually calling this method.
+   *
+   * It makes sense to call this method whenever a new debug message arrived and
+   * V8 is not already running. Method v8::Debug::SetDebugMessageDispatchHandler
+   * should help with the former condition.
+   *
+   * Technically this method in many senses is equivalent to executing empty
+   * script:
+   * 1. It does nothing except for processing all pending debug messages.
+   * 2. It should be invoked with the same precautions and from the same context
+   * as V8 script would be invoked from, because:
+   *   a. with "evaluate" command it can do whatever normal script can do,
+   *   including all native calls;
+   *   b. no other thread should call V8 while this method is running
+   *   (v8::Locker may be used here).
+   *
+   * "Evaluate" debug command behavior currently is not specified in scope
+   * of this method.
+   */
+  static void ProcessDebugMessages();
 };
 
 
index ab5d0a5..2546101 100644 (file)
@@ -3744,6 +3744,11 @@ Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
 bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) {
   return i::Debugger::StartAgent(name, port, wait_for_connection);
 }
+
+void Debug::ProcessDebugMessages() {
+  i::Execution::ProcessDebugMesssages(true);
+}
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 namespace internal {
index 0f935ac..a79af23 100644 (file)
@@ -638,24 +638,32 @@ Object* Execution::DebugBreakHelper() {
   bool debug_command_only =
       StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak();
 
-  // Clear the debug request flags.
+  // Clear the debug break request flag.
   StackGuard::Continue(DEBUGBREAK);
+
+  ProcessDebugMesssages(debug_command_only);
+
+  // Return to continue execution.
+  return Heap::undefined_value();
+}
+
+void Execution::ProcessDebugMesssages(bool debug_command_only) {
+  // Clear the debug command request flag.
   StackGuard::Continue(DEBUGCOMMAND);
 
   HandleScope scope;
   // Enter the debugger. Just continue if we fail to enter the debugger.
   EnterDebugger debugger;
   if (debugger.FailedToEnter()) {
-    return Heap::undefined_value();
+    return;
   }
 
   // Notify the debug event listeners. Indicate auto continue if the break was
   // a debug command break.
   Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only);
-
-  // Return to continue execution.
-  return Heap::undefined_value();
 }
+
+
 #endif
 
 Object* Execution::HandleStackGuardInterrupt() {
index 52198c4..10683d6 100644 (file)
@@ -122,6 +122,7 @@ class Execution : public AllStatic {
                                           Handle<Object> is_global);
 #ifdef ENABLE_DEBUGGER_SUPPORT
   static Object* DebugBreakHelper();
+  static void ProcessDebugMesssages(bool debug_command_only);
 #endif
 
   // If the stack guard is triggered, but it is not an actual
index cad1ba3..918c7ec 100644 (file)
@@ -5655,6 +5655,51 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) {
 }
 
 
+static int counting_message_handler_counter;
+
+static void CountingMessageHandler(const v8::Debug::Message& message) {
+  counting_message_handler_counter++;
+}
+
+// Test that debug messages get processed when ProcessDebugMessages is called.
+TEST(ProcessDebugMessages) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  counting_message_handler_counter = 0;
+
+  v8::Debug::SetMessageHandler2(CountingMessageHandler);
+
+  const int kBufferSize = 1000;
+  uint16_t buffer[kBufferSize];
+  const char* scripts_command =
+    "{\"seq\":0,"
+     "\"type\":\"request\","
+     "\"command\":\"scripts\"}";
+
+  // Send scripts command.
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
+
+  CHECK_EQ(0, counting_message_handler_counter);
+  v8::Debug::ProcessDebugMessages();
+  // At least one message should come
+  CHECK_GE(counting_message_handler_counter, 1);
+
+  counting_message_handler_counter = 0;
+
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
+  CHECK_EQ(0, counting_message_handler_counter);
+  v8::Debug::ProcessDebugMessages();
+  // At least two messages should come
+  CHECK_GE(counting_message_handler_counter, 2);
+
+  // Get rid of the debug message handler.
+  v8::Debug::SetMessageHandler2(NULL);
+  CheckDebuggerUnloaded();
+}
+
+
 TEST(GetMirror) {
   v8::HandleScope scope;
   DebugLocalContext env;