Author: [email protected]
Date: Wed Apr 29 01:23:58 2009
New Revision: 1811

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

Log:
Changed the debugger message API to receive an object instead of a JSON  
string.

The object delivered to the debug message handler contains additional  
information on the current break handling the messages.

Clients which require just JSON message parsing can simply get the JSON  
using the GetJSON message on the message object to still have the previous  
behaviour.

   NewMessageHangler(const v8::Debug::Message& message) {
     v8::String::Value val(message.GetJSON());
     OldMessageHandler(Vector<uint16_t>(const_cast<uint16_t*>(*val),  
val.length()));
   }

Refactored some of the debugger code to use internal handles instead of API  
handles. Also changed Object to JSObject is some places.

The access to the active context when the break occurred is still not  
implemented. I will add this in a new CL, as this one is quite big already.
Review URL: http://codereview.chromium.org/99122

Modified: branches/bleeding_edge/include/v8-debug.h
==============================================================================
--- branches/bleeding_edge/include/v8-debug.h   (original)
+++ branches/bleeding_edge/include/v8-debug.h   Wed Apr 29 01:23:58 2009
@@ -92,6 +92,55 @@


    /**
+   * A message object passed to the debug message handler.
+   */
+  class Message {
+   public:
+    /**
+     * Check type of message.
+     */
+    virtual bool IsEvent() const = 0;
+    virtual bool IsResponse() const = 0;
+    virtual DebugEvent GetEvent() const = 0;
+
+    /**
+     * Indicate whether this is a response to a continue command which will
+     * start the VM running after this is processed.
+     */
+    virtual bool WillStartRunning() const = 0;
+
+    /**
+     * Access to execution state and event data. Don't store these cross
+     * callbacks as their content becomes invalid. These objects are from  
the
+     * debugger event that started the debug message loop.
+     */
+    virtual Handle<Object> GetExecutionState() const = 0;
+    virtual Handle<Object> GetEventData() const = 0;
+       
+    /**
+     * Get the debugger protocol JSON.
+     */
+    virtual Handle<String> GetJSON() const = 0;
+
+    /**
+     * Get the context active when the debug event happened. Note this is  
not
+     * the current active context as the JavaScript part of the debugger is
+     * running in it's own context which is entered at this point.
+     */
+    virtual Handle<Context> GetEventContext() const = 0;
+
+    /**
+     * Client data passed with the corresponding request if any. This is  
the
+     * client_data data value passed into Debug::SendCommand along with the
+     * request that led to the message or NULL if the message is an event.  
The
+     * debugger takes ownership of the data and will delete it even if  
there is
+     * no message handler.
+     */
+    virtual ClientData* GetClientData() const = 0;
+  };
+
+
+  /**
     * Debug event callback function.
     *
     * \param event the type of the debug event that triggered the callback
@@ -101,26 +150,22 @@
     * \param data value passed by the user to SetDebugEventListener
     */
    typedef void (*EventCallback)(DebugEvent event,
-                                     Handle<Object> exec_state,
-                                     Handle<Object> event_data,
-                                     Handle<Value> data);
+                                Handle<Object> exec_state,
+                                Handle<Object> event_data,
+                                Handle<Value> data);


    /**
     * Debug message callback function.
     *
-   * \param message the debug message
+   * \param message the debug message handler message object
     * \param length length of the message
     * \param data the data value passed when registering the message handler
-   * \param client_data the data value passed into Debug::SendCommand along
-   *     with the request that led to the message or NULL if the message  
is an
-   *     asynchronous event. The debugger takes ownership of the data and  
will
-   *     delete it before dying even if there is no message handler.
+
     * A MessageHandler does not take posession of the message string,
     * and must not rely on the data persisting after the handler returns.
     */
-  typedef void (*MessageHandler)(const uint16_t* message, int length,
-                                      ClientData* client_data);
+  typedef void (*MessageHandler)(const Message& message);

    /**
     * Debug host dispatch callback function.

Modified: branches/bleeding_edge/src/debug-agent.cc
==============================================================================
--- branches/bleeding_edge/src/debug-agent.cc   (original)
+++ branches/bleeding_edge/src/debug-agent.cc   Wed Apr 29 01:23:58 2009
@@ -34,9 +34,8 @@

  // Public V8 debugger API message handler function. This function just  
delegates
  // to the debugger agent through it's data parameter.
-void DebuggerAgentMessageHandler(const uint16_t* message, int length,
-                                 v8::Debug::ClientData* client_data) {
-  DebuggerAgent::instance_->DebuggerMessage(message, length);
+void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
+  DebuggerAgent::instance_->DebuggerMessage(message);
  }

  // static
@@ -125,13 +124,14 @@
  }


-void DebuggerAgent::DebuggerMessage(const uint16_t* message, int length) {
+void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
    ScopedLock with(session_access_);

    // Forward the message handling to the session.
    if (session_ != NULL) {
-     
session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(message),
-                              length));
+    v8::String::Value val(message.GetJSON());
+    session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val),
+                              val.length()));
    }
  }


Modified: branches/bleeding_edge/src/debug-agent.h
==============================================================================
--- branches/bleeding_edge/src/debug-agent.h    (original)
+++ branches/bleeding_edge/src/debug-agent.h    Wed Apr 29 01:23:58 2009
@@ -60,7 +60,7 @@
   private:
    void Run();
    void CreateSession(Socket* socket);
-  void DebuggerMessage(const uint16_t* message, int length);
+  void DebuggerMessage(const v8::Debug::Message& message);
    void CloseSession();
    void OnSessionClosed(DebuggerAgentSession* session);

@@ -75,8 +75,7 @@
    static DebuggerAgent* instance_;

    friend class DebuggerAgentSession;
-  friend void DebuggerAgentMessageHandler(const uint16_t* message, int  
length,
-                                          v8::Debug::ClientData*  
client_data);
+  friend void DebuggerAgentMessageHandler(const v8::Debug::Message&  
message);

    DISALLOW_COPY_AND_ASSIGN(DebuggerAgent);
  };

Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Wed Apr 29 01:23:58 2009
@@ -41,6 +41,8 @@
  #include "stub-cache.h"
  #include "log.h"

+#include "../include/v8-debug.h"
+
  namespace v8 { namespace internal {

  #ifdef ENABLE_DEBUGGER_SUPPORT
@@ -377,7 +379,9 @@
      // is set the patching performed by the runtime system will take place  
in
      // the code copy and will therefore have no effect on the running code
      // keeping it from using the inlined code.
-    if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc());
+    if (code->is_keyed_load_stub() &&  
KeyedLoadIC::HasInlinedVersion(pc())) {
+      KeyedLoadIC::ClearInlinedVersion(pc());
+    }
    }
  }

@@ -1552,8 +1556,8 @@
      return;
    }

-  // Process debug event
-  ProcessDebugEvent(v8::Exception, event_data, false);
+  // Process debug event.
+  ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data),  
false);
    // Return to continue execution from where the exception was thrown.
  }

@@ -1584,8 +1588,10 @@
      return;
    }

-  // Process debug event
-  ProcessDebugEvent(v8::Break, event_data, auto_continue);
+  // Process debug event.
+  ProcessDebugEvent(v8::Break,
+                    Handle<JSObject>::cast(event_data),
+                    auto_continue);
  }


@@ -1609,8 +1615,10 @@
      return;
    }

-  // Process debug event
-  ProcessDebugEvent(v8::BeforeCompile, event_data, true);
+  // Process debug event.
+  ProcessDebugEvent(v8::BeforeCompile,
+                    Handle<JSObject>::cast(event_data),
+                    true);
  }


@@ -1670,8 +1678,10 @@
    if (caught_exception) {
      return;
    }
-  // Process debug event
-  ProcessDebugEvent(v8::AfterCompile, event_data, true);
+  // Process debug event.
+  ProcessDebugEvent(v8::AfterCompile,
+                    Handle<JSObject>::cast(event_data),
+                    true);
  }


@@ -1696,12 +1706,12 @@
      return;
    }
    // Process debug event.
-  ProcessDebugEvent(v8::NewFunction, event_data, true);
+  ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data),  
true);
  }


  void Debugger::ProcessDebugEvent(v8::DebugEvent event,
-                                 Handle<Object> event_data,
+                                 Handle<JSObject> event_data,
                                   bool auto_continue) {
    HandleScope scope;

@@ -1713,7 +1723,10 @@
    }
    // First notify the message handler if any.
    if (message_handler_ != NULL) {
-    NotifyMessageHandler(event, exec_state, event_data, auto_continue);
+    NotifyMessageHandler(event,
+                         Handle<JSObject>::cast(exec_state),
+                         event_data,
+                         auto_continue);
    }
    // Notify registered debug event listener. This can be either a C or a
    // JavaScript function.
@@ -1725,7 +1738,7 @@
              FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
        callback(event,
                 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
-               v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
+               v8::Utils::ToLocal(event_data),
                  
v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_)));
      } else {
        // JavaScript debug event listener.
@@ -1736,7 +1749,7 @@
        const int argc = 4;
        Object** argv[argc] = {  
Handle<Object>(Smi::FromInt(event)).location(),
                                exec_state.location(),
-                              event_data.location(),
+                              Handle<Object>::cast(event_data).location(),
                                event_listener_data_.location() };
        Handle<Object> result = Execution::TryCall(fun, Top::global(),
                                                   argc, argv,  
&caught_exception);
@@ -1766,8 +1779,8 @@


  void Debugger::NotifyMessageHandler(v8::DebugEvent event,
-                                    Handle<Object> exec_state,
-                                    Handle<Object> event_data,
+                                    Handle<JSObject> exec_state,
+                                    Handle<JSObject> event_data,
                                      bool auto_continue) {
    HandleScope scope;

@@ -1802,7 +1815,12 @@
    // Notify the debugger that a debug event has occurred unless auto  
continue is
    // active in which case no event is send.
    if (sendEventMessage) {
-    InvokeMessageHandlerWithEvent(event_data);
+    MessageImpl message = MessageImpl::NewEvent(
+        event,
+        auto_continue,
+        Handle<JSObject>::cast(exec_state),
+        Handle<JSObject>::cast(event_data));
+    InvokeMessageHandler(message);
    }
    if (auto_continue && !HasCommands()) {
      return;
@@ -1857,7 +1875,6 @@

      request = v8::String::New(command.text().start(),
                                command.text().length());
-    command.text().Dispose();
      static const int kArgc = 1;
      v8::Handle<Value> argv[kArgc] = { request };
      v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc,  
argv);
@@ -1894,7 +1911,15 @@
      }

      // Return the result.
-    InvokeMessageHandler(response, command.client_data());
+    MessageImpl message = MessageImpl::NewResponse(
+        event,
+        running,
+        Handle<JSObject>::cast(exec_state),
+        Handle<JSObject>::cast(event_data),
+        Handle<String>(Utils::OpenHandle(*response)),
+        command.client_data());
+    InvokeMessageHandler(message);
+    command.Dispose();

      // Return from debug event processing if either the VM is put into the
      // runnning state (through a continue command) or auto continue is  
active
@@ -1965,54 +1990,13 @@


  // Calls the registered debug message handler. This callback is part of the
-// public API. Messages are kept internally as Vector<uint16_t> strings,  
which
-// are allocated in various places and deallocated by the calling function
-// sometime after this call.
-void Debugger::InvokeMessageHandler(v8::Handle<v8::String> output,
-                                    v8::Debug::ClientData* data) {
+// public API.
+void Debugger::InvokeMessageHandler(MessageImpl message) {
    ScopedLock with(debugger_access_);

    if (message_handler_ != NULL) {
-    Vector<uint16_t> text = Vector<uint16_t>::New(output->Length());
-    output->Write(text.start(), 0, output->Length());
-
-    message_handler_(text.start(),
-                     text.length(),
-                     data);
-
-    text.Dispose();
-  }
-  delete data;
-}
-
-
-bool Debugger::InvokeMessageHandlerWithEvent(Handle<Object> event_data) {
-  v8::HandleScope scope;
-  // Call toJSONProtocol on the debug event object.
-  v8::Local<v8::Object> api_event_data =
-      v8::Utils::ToLocal(Handle<JSObject>::cast(event_data));
-  v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol");
-  v8::Local<v8::Function> fun =
-      v8::Function::Cast(*api_event_data->Get(fun_name));
-  v8::TryCatch try_catch;
-  v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL);
-  v8::Local<v8::String> json_event_string;
-  if (!try_catch.HasCaught()) {
-    if (!json_event->IsUndefined()) {
-      json_event_string = json_event->ToString();
-      if (FLAG_trace_debug_json) {
-        PrintLn(json_event_string);
-      }
-      InvokeMessageHandler(json_event_string,
-                           NULL /* no user data since there was no request  
*/);
-    } else {
-      InvokeMessageHandler(v8::String::Empty(), NULL);
-    }
-  } else {
-    PrintLn(try_catch.Exception());
-    return false;
+    message_handler_(message);
    }
-  return true;
  }


@@ -2095,6 +2079,107 @@
      delete agent_;
      agent_ = NULL;
    }
+}
+
+
+MessageImpl MessageImpl::NewEvent(DebugEvent event,
+                                  bool running,
+                                  Handle<JSObject> exec_state,
+                                  Handle<JSObject> event_data) {
+  MessageImpl message(true, event, running,
+                      exec_state, event_data, Handle<String>(), NULL);
+  return message;
+}
+
+
+MessageImpl MessageImpl::NewResponse(DebugEvent event,
+                                     bool running,
+                                     Handle<JSObject> exec_state,
+                                     Handle<JSObject> event_data,
+                                     Handle<String> response_json,
+                                     v8::Debug::ClientData* client_data) {
+  MessageImpl message(false, event, running,
+                      exec_state, event_data, response_json, client_data);
+  return message;
+}
+
+
+MessageImpl::MessageImpl(bool is_event,
+                         DebugEvent event,
+                         bool running,
+                         Handle<JSObject> exec_state,
+                         Handle<JSObject> event_data,
+                         Handle<String> response_json,
+                         v8::Debug::ClientData* client_data)
+    : is_event_(is_event),
+      event_(event),
+      running_(running),
+      exec_state_(exec_state),
+      event_data_(event_data),
+      response_json_(response_json),
+      client_data_(client_data) {}
+
+
+bool MessageImpl::IsEvent() const {
+  return is_event_;
+}
+
+
+bool MessageImpl::IsResponse() const {
+  return !is_event_;
+}
+
+
+DebugEvent MessageImpl::GetEvent() const {
+  return event_;
+}
+
+
+bool MessageImpl::WillStartRunning() const {
+  return running_;
+}
+
+
+v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
+  return v8::Utils::ToLocal(exec_state_);
+}
+
+
+v8::Handle<v8::Object> MessageImpl::GetEventData() const {
+  return v8::Utils::ToLocal(event_data_);
+}
+
+
+v8::Handle<v8::String> MessageImpl::GetJSON() const {
+  v8::HandleScope scope;
+
+  if (IsEvent()) {
+    // Call toJSONProtocol on the debug event object.
+    Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
+    if (!fun->IsJSFunction()) {
+      return v8::Handle<v8::String>();
+    }
+    bool caught_exception;
+    Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
+                                             event_data_,
+                                             0, NULL, &caught_exception);
+    if (caught_exception || !json->IsString()) {
+      return v8::Handle<v8::String>();
+    }
+    return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
+  } else {
+    return v8::Utils::ToLocal(response_json_);
+  }
+}
+
+
+v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
+  return v8::Handle<v8::Context>();
+}
+
+
+v8::Debug::ClientData* MessageImpl::GetClientData() const {
+  return client_data_;
  }



Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h  (original)
+++ branches/bleeding_edge/src/debug.h  Wed Apr 29 01:23:58 2009
@@ -401,6 +401,54 @@
  };


+// Message delivered to the message handler callback. This is either a  
debugger
+// event or the response to a command.
+class MessageImpl: public v8::Debug::Message {
+ public:
+  // Create a message object for a debug event.
+  static MessageImpl NewEvent(DebugEvent event,
+                              bool running,
+                              Handle<JSObject> exec_state,
+                              Handle<JSObject> event_data);
+
+  // Create a message object for the response to a debug command.
+  static MessageImpl NewResponse(DebugEvent event,
+                                 bool running,
+                                 Handle<JSObject> exec_state,
+                                 Handle<JSObject> event_data,
+                                 Handle<String> response_json,
+                                 v8::Debug::ClientData* client_data);
+
+  // Implementation of interface v8::Debug::Message.
+  virtual bool IsEvent() const;
+  virtual bool IsResponse() const;
+  virtual DebugEvent GetEvent() const;
+  virtual bool WillStartRunning() const;
+  virtual v8::Handle<v8::Object> GetExecutionState() const;
+  virtual v8::Handle<v8::Object> GetEventData() const;
+  virtual v8::Handle<v8::String> GetJSON() const;
+  virtual v8::Handle<v8::Context> GetEventContext() const;
+  virtual v8::Debug::ClientData* GetClientData() const;
+
+ private:
+  MessageImpl(bool is_event,
+              DebugEvent event,
+              bool running,
+              Handle<JSObject> exec_state,
+              Handle<JSObject> event_data,
+              Handle<String> response_json,
+              v8::Debug::ClientData* client_data);
+
+  bool is_event_;  // Does this message represent a debug event?
+  DebugEvent event_;  // Debug event causing the break.
+  bool running_;  // Will the VM start running after this event?
+  Handle<JSObject> exec_state_;  // Current execution state.
+  Handle<JSObject> event_data_;  // Data associated with the event.
+  Handle<String> response_json_;  // Response JSON if message holds a  
response.
+  v8::Debug::ClientData* client_data_;  // Client data passed with the  
request.
+};
+
+
  // Message send by user to v8 debugger or debugger output message.
  // In addition to command text it may contain a pointer to some user data
  // which are expected to be passed along with the command reponse to  
message
@@ -491,11 +539,11 @@
                             Handle<JSFunction> fun);
    static void OnNewFunction(Handle<JSFunction> fun);
    static void ProcessDebugEvent(v8::DebugEvent event,
-                                Handle<Object> event_data,
+                                Handle<JSObject> event_data,
                                  bool auto_continue);
    static void NotifyMessageHandler(v8::DebugEvent event,
-                                   Handle<Object> exec_state,
-                                   Handle<Object> event_data,
+                                   Handle<JSObject> exec_state,
+                                   Handle<JSObject> event_data,
                                     bool auto_continue);
    static void SetEventListener(Handle<Object> callback, Handle<Object>  
data);
    static void SetMessageHandler(v8::Debug::MessageHandler handler);
@@ -503,11 +551,7 @@
                                       int period);

    // Invoke the message handler function.
-  static void InvokeMessageHandler(v8::Handle<v8::String> output,
-                                   v8::Debug::ClientData* data);
-
-  // Send the JSON message for a debug event.
-  static bool InvokeMessageHandlerWithEvent(Handle<Object> event_data);
+  static void InvokeMessageHandler(MessageImpl message);

    // Add a debugger command to the command queue.
    static void ProcessCommand(Vector<const uint16_t> command,

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    Wed Apr 29 01:23:58  
2009
@@ -3427,10 +3427,10 @@
    void Run();
  };

-static void MessageHandler(const uint16_t* message, int length,
-                           v8::Debug::ClientData* client_data) {
+static void MessageHandler(const v8::Debug::Message& message) {
    static char print_buffer[1000];
-  Utf16ToAscii(message, length, print_buffer);
+  v8::String::Value json(message.GetJSON());
+  Utf16ToAscii(*json, json.length(), print_buffer);
    if (IsBreakEventMessage(print_buffer)) {
      // Lets test script wait until break occurs to send commands.
      // Signals when a break is reported.
@@ -3612,10 +3612,8 @@

  static int handled_client_data_instances_count = 0;
  static void MessageHandlerCountingClientData(
-    const uint16_t* message,
-    int length,
-    v8::Debug::ClientData* client_data) {
-  if (client_data) {
+    const v8::Debug::Message& message) {
+  if (message.GetClientData() != NULL) {
      handled_client_data_instances_count++;
    }
  }
@@ -3691,10 +3689,10 @@
  }


-static void ThreadedMessageHandler(const uint16_t* message, int length,
-                                   v8::Debug::ClientData* client_data) {
+static void ThreadedMessageHandler(const v8::Debug::Message& message) {
    static char print_buffer[1000];
-  Utf16ToAscii(message, length, print_buffer);
+  v8::String::Value json(message.GetJSON());
+  Utf16ToAscii(*json, json.length(), print_buffer);
    if (IsBreakEventMessage(print_buffer)) {
      threaded_debugging_barriers.barrier_2.Wait();
    }
@@ -3788,11 +3786,10 @@

  Barriers* breakpoints_barriers;

-static void BreakpointsMessageHandler(const uint16_t* message,
-                                      int length,
-                                      v8::Debug::ClientData* client_data) {
+static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
    static char print_buffer[1000];
-  Utf16ToAscii(message, length, print_buffer);
+  v8::String::Value json(message.GetJSON());
+  Utf16ToAscii(*json, json.length(), print_buffer);
    printf("%s\n", print_buffer);
    fflush(stdout);

@@ -3935,9 +3932,7 @@
  }


-static void DummyMessageHandler(const uint16_t* message,
-                                int length,
-                                v8::Debug::ClientData* client_data) {
+static void DummyMessageHandler(const v8::Debug::Message& message) {
  }


@@ -4162,9 +4157,7 @@

  // Debugger message handler which counts the number of times it is called.
  static int message_handler_hit_count = 0;
-static void MessageHandlerHitCount(const uint16_t* message,
-                                   int length,
-                                   v8::Debug::ClientData* client_data) {
+static void MessageHandlerHitCount(const v8::Debug::Message& message) {
    message_handler_hit_count++;

    const int kBufferSize = 1000;
@@ -4213,9 +4206,7 @@

  // Debugger message handler which clears the message handler while active.
  static void MessageHandlerClearingMessageHandler(
-    const uint16_t* message,
-    int length,
-    v8::Debug::ClientData* client_data) {
+    const v8::Debug::Message& message) {
    message_handler_hit_count++;

    // Clear debug message handler.
@@ -4262,11 +4253,10 @@

  Barriers* host_dispatch_barriers;

-static void HostDispatchMessageHandler(const uint16_t* message,
-                                       int length,
-                                       v8::Debug::ClientData* client_data)  
{
+static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
    static char print_buffer[1000];
-  Utf16ToAscii(message, length, print_buffer);
+  v8::String::Value json(message.GetJSON());
+  Utf16ToAscii(*json, json.length(), print_buffer);
    printf("%s\n", print_buffer);
    fflush(stdout);
  }

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

Reply via email to