Author: [EMAIL PROTECTED]
Date: Thu Nov 27 00:01:27 2008
New Revision: 854

Modified:
    branches/bleeding_edge/include/v8-debug.h
    branches/bleeding_edge/src/api.cc
    branches/bleeding_edge/src/debug.cc
    branches/bleeding_edge/src/debug.h
    branches/bleeding_edge/test/cctest/test-debug.cc

Log:
Added a debugger call to run a JavaScript function in the debugger. When  
called the debugger will be entered and the JavaScript function will be  
called with the debugger ExecutionState object as its first parameter.

This makes it possible to get information like current line number, current  
script resource, backtrace information etc. which is not part of the normal  
API.
Review URL: http://codereview.chromium.org/12472

Modified: branches/bleeding_edge/include/v8-debug.h
==============================================================================
--- branches/bleeding_edge/include/v8-debug.h   (original)
+++ branches/bleeding_edge/include/v8-debug.h   Thu Nov 27 00:01:27 2008
@@ -128,6 +128,26 @@
    // Message based interface. The message protocol is JSON.
    static void SetMessageHandler(DebugMessageHandler handler, void* data =  
NULL);
    static void SendCommand(const uint16_t* command, int length);
+
+ /**
+  * Run a JavaScript function in the debugger.
+  * \param fun the function to call
+  * \param data passed as second argument to the function
+  * With this call the debugger is entered and the function specified is  
called
+  * with the execution state as the first argument. This makes it possible  
to
+  * get access to information otherwise not available during normal  
JavaScript
+  * execution e.g. details on stack frames. The following example show a
+  * JavaScript function which when passed to v8::Debug::Call will return  
the
+  * current line of JavaScript execution.
+  *
+  * \code
+  *   function frame_source_line(exec_state) {
+  *     return exec_state.frame(0).sourceLine();
+  *   }
+  * \endcode
+  */
+  static Handle<Value> Call(v8::Handle<v8::Function> fun,
+                            Handle<Value> data = Handle<Value>());
  };



Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc   (original)
+++ branches/bleeding_edge/src/api.cc   Thu Nov 27 00:01:27 2008
@@ -2902,6 +2902,26 @@
  }


+Handle<Value> Debug::Call(v8::Handle<v8::Function> fun,
+                          v8::Handle<v8::Value> data) {
+  if (!i::V8::HasBeenSetup()) return Handle<Value>();
+  ON_BAILOUT("v8::Debug::Call()", return Handle<Value>());
+  i::Handle<i::Object> result;
+  EXCEPTION_PREAMBLE();
+  if (data.IsEmpty()) {
+    result = i::Debugger::Call(Utils::OpenHandle(*fun),
+                               i::Factory::undefined_value(),
+                               &has_pending_exception);
+  } else {
+    result = i::Debugger::Call(Utils::OpenHandle(*fun),
+                               Utils::OpenHandle(*data),
+                               &has_pending_exception);
+  }
+  EXCEPTION_BAILOUT_CHECK(Local<Value>());
+  return Utils::ToLocal(result);
+}
+
+
  namespace internal {



Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Thu Nov 27 00:01:27 2008
@@ -1650,6 +1650,30 @@
  }


+Handle<Object> Debugger::Call(Handle<JSFunction> fun,
+                              Handle<Object> data,
+                              bool* pending_exception) {
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
+    return Factory::undefined_value();
+  }
+
+  // Create the execution state.
+  bool caught_exception = false;
+  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
+  if (caught_exception) {
+    return Factory::undefined_value();
+  }
+
+  static const int kArgc = 2;
+  Object** argv[kArgc] = { exec_state.location(), data.location() };
+  Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
+                                          kArgc, argv, pending_exception);
+  return result;
+}
+
+
  DebugMessageThread::DebugMessageThread()
      : host_running_(true),
        command_queue_(kQueueInitialSize),

Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h  (original)
+++ branches/bleeding_edge/src/debug.h  Thu Nov 27 00:01:27 2008
@@ -358,6 +358,10 @@
    static void SendMessage(Vector<uint16_t> message);
    static void ProcessCommand(Vector<const uint16_t> command);
    static void UpdateActiveDebugger();
+  static Handle<Object> Call(Handle<JSFunction> fun,
+                             Handle<Object> data,
+                             bool* pending_exception);
+
    inline static bool EventActive(v8::DebugEvent event) {
      // Currently argument event is not used.
      return !Debugger::compiling_natives_ && Debugger::debugger_active_;
@@ -503,6 +507,9 @@

    // Check whether the debugger could be entered.
    inline bool FailedToEnter() { return load_failed_; }
+
+  // Check whether there are any JavaScript frames on the stack.
+  inline bool HasJavaScriptFrames() { return set_; }

   private:
    JavaScriptFrameIterator it_;

Modified: branches/bleeding_edge/test/cctest/test-debug.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-debug.cc    (original)
+++ branches/bleeding_edge/test/cctest/test-debug.cc    Thu Nov 27 00:01:27  
2008
@@ -3166,3 +3166,155 @@
    int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
    v8::Debug::SendCommand(dummy_buffer, dummy_length);
  }
+
+
+// Source for The JavaScript function which returns the number of frames.
+static const char* frame_count_source =
+    "function frame_count(exec_state) {"
+    "  return exec_state.frameCount();"
+    "}";
+v8::Handle<v8::Function> frame_count;
+
+
+// Source for a JavaScript function which returns the source line for the  
top
+// frame.
+static const char* frame_source_line_source =
+    "function frame_source_line(exec_state) {"
+    "  return exec_state.frame(0).sourceLine();"
+    "}";
+v8::Handle<v8::Function> frame_source_line;
+
+
+// Source for a JavaScript function which returns the data parameter of a
+// function called in the context of the debugger. If no data parameter is
+// passed it throws an exception.
+static const char* debugger_call_with_data_source =
+    "function debugger_call_with_data(exec_state, data) {"
+    "  if (data) return data;"
+    "  throw 'No data!'"
+    "}";
+v8::Handle<v8::Function> debugger_call_with_data;
+
+
+// Source for a JavaScript function which returns the data parameter of a
+// function called in the context of the debugger. If no data parameter is
+// passed it throws an exception.
+static const char* debugger_call_with_closure_source =
+    "var x = 3;"
+    "function (exec_state) {"
+    "  if (exec_state.y) return x - 1;"
+    "  exec_state.y = x;"
+    "  return exec_state.y"
+    "}";
+v8::Handle<v8::Function> debugger_call_with_closure;
+
+// Function to retrieve the number of JavaScript frames by calling a  
JavaScript
+// in the debugger.
+static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
+  CHECK(v8::Debug::Call(frame_count)->IsNumber());
+  CHECK_EQ(args[0]->Int32Value(),
+           v8::Debug::Call(frame_count)->Int32Value());
+  return v8::Undefined();
+}
+
+
+// Function to retrieve the source line of the top JavaScript frame by  
calling a
+// JavaScript function in the debugger.
+static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
+  CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
+  CHECK_EQ(args[0]->Int32Value(),
+           v8::Debug::Call(frame_source_line)->Int32Value());
+  return v8::Undefined();
+}
+
+
+// Function to test passing an additional parameter to a JavaScript  
function
+// called in the debugger. It also tests that functions called in the  
debugger
+// can throw exceptions.
+static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args)  
{
+  v8::Handle<v8::String> data = v8::String::New("Test");
+  CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
+
+  CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
+  CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
+
+  v8::TryCatch catcher;
+  v8::Debug::Call(debugger_call_with_data);
+  CHECK(catcher.HasCaught());
+  CHECK(catcher.Exception()->IsString());
+
+  return v8::Undefined();
+}
+
+
+// Function to test using a JavaScript with closure in the debugger.
+static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
+  CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
+  CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
+  return v8::Undefined();
+}
+
+
+// Test functions called through the debugger.
+TEST(CallFunctionInDebugger) {
+  // Create and enter a context with the functions CheckFrameCount,
+  // CheckSourceLine and CheckDataParameter installed.
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> global_template =  
v8::ObjectTemplate::New();
+  global_template->Set(v8::String::New("CheckFrameCount"),
+                       v8::FunctionTemplate::New(CheckFrameCount));
+  global_template->Set(v8::String::New("CheckSourceLine"),
+                       v8::FunctionTemplate::New(CheckSourceLine));
+  global_template->Set(v8::String::New("CheckDataParameter"),
+                       v8::FunctionTemplate::New(CheckDataParameter));
+  global_template->Set(v8::String::New("CheckClosure"),
+                       v8::FunctionTemplate::New(CheckClosure));
+  v8::Handle<v8::Context> context = v8::Context::New(NULL,  
global_template);
+  v8::Context::Scope context_scope(context);
+
+  // Compile a function for checking the number of JavaScript frames.
+  v8::Script::Compile(v8::String::New(frame_count_source))->Run();
+  frame_count = v8::Local<v8::Function>::Cast(
+      context->Global()->Get(v8::String::New("frame_count")));
+
+  // Compile a function for returning the source line for the top frame.
+  v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
+  frame_source_line = v8::Local<v8::Function>::Cast(
+      context->Global()->Get(v8::String::New("frame_source_line")));
+
+  // Compile a function returning the data parameter.
+   
v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
+  debugger_call_with_data = v8::Local<v8::Function>::Cast(
+      context->Global()->Get(v8::String::New("debugger_call_with_data")));
+
+  // Compile a function capturing closure.
+  debugger_call_with_closure = v8::Local<v8::Function>::Cast(
+      v8::Script::Compile(
+          v8::String::New(debugger_call_with_closure_source))->Run());
+
+  // Calling a function through the debugger returns undefined if there  
are no
+  // JavaScript frames.
+  CHECK(v8::Debug::Call(frame_count)->IsUndefined());
+  CHECK(v8::Debug::Call(frame_source_line)->IsUndefined());
+  CHECK(v8::Debug::Call(debugger_call_with_data)->IsUndefined());
+
+  // Test that the number of frames can be retrieved.
+  v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
+  v8::Script::Compile(v8::String::New("function f() {"
+                                      "  CheckFrameCount(2);"
+                                      "}; f()"))->Run();
+
+  // Test that the source line can be retrieved.
+  v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
+  v8::Script::Compile(v8::String::New("function f() {\n"
+                                      "  CheckSourceLine(1)\n"
+                                      "  CheckSourceLine(2)\n"
+                                      "  CheckSourceLine(3)\n"
+                                      "}; f()"))->Run();
+
+  // Test that a parameter can be passed to a function called in the  
debugger.
+  v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
+
+  // Test that a function with closure can be run in the debugger.
+  v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
+}

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to