Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFedor Indutny <fedor.indutny@gmail.com>2012-01-06 22:27:55 +0400
committerBen Noordhuis <info@bnoordhuis.nl>2012-01-10 05:28:42 +0400
commit99679c643028eba79b81d0a3eaa204af1cce2d15 (patch)
treed0244c670817aee797ee8a0817be6349f2bf3c3b /src
parent44e703327970be080877ad7c02f57f0713b553b8 (diff)
IsolateDebugger C++
Diffstat (limited to 'src')
-rw-r--r--src/node.cc17
-rw-r--r--src/node_isolate.cc208
-rw-r--r--src/node_isolate.h53
-rw-r--r--src/node_vars.h3
4 files changed, 274 insertions, 7 deletions
diff --git a/src/node.cc b/src/node.cc
index c6efa89f2bf..ab24990029a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -2624,15 +2624,20 @@ void StartThread(node::Isolate* isolate,
// even when we need it to access it from another (debugger) thread.
node_isolate = v8::Isolate::GetCurrent();
- // If the --debug flag was specified then initialize the debug thread.
- if (use_debug_agent) {
- EnableDebug(debug_wait_connect);
- } else {
+ // Only main isolate is allowed to run a debug agent and listen for signals
+ if (isolate->id_ == 1) {
+ // If the --debug flag was specified then initialize the debug thread.
+ if (use_debug_agent) {
+ EnableDebug(debug_wait_connect);
+ } else {
#ifdef _WIN32
- RegisterDebugSignalHandler();
+ RegisterDebugSignalHandler();
#else // Posix
- RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
+ RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
#endif // __POSIX__
+ }
+ } else if (isolate->debug_state != Isolate::kNone) {
+ isolate->debugger_instance->Init();
}
Handle<Object> process_l = SetupProcessObject(argc, argv);
diff --git a/src/node_isolate.cc b/src/node_isolate.cc
index 47e5b66e3ca..ede131faf01 100644
--- a/src/node_isolate.cc
+++ b/src/node_isolate.cc
@@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <v8.h>
+#include <v8-debug.h>
#include <node.h>
#include <node_buffer.h>
#include <node_isolate.h>
@@ -31,11 +32,16 @@
#include <assert.h>
+#define isolate_debugger_constructor NODE_VAR(isolate_debugger_constructor)
+
+
namespace node {
using v8::Arguments;
using v8::Array;
+using v8::Context;
using v8::False;
+using v8::Function;
using v8::FunctionTemplate;
using v8::Handle;
using v8::HandleScope;
@@ -47,6 +53,7 @@ using v8::ObjectTemplate;
using v8::Persistent;
using v8::String;
using v8::True;
+using v8::Undefined;
using v8::Value;
using v8::Undefined;
@@ -252,6 +259,9 @@ Isolate::Isolate() {
loop_ = uv_loop_new();
}
+ debug_state = kNone;
+ debugger_instance = NULL;
+
ngx_queue_init(&at_exit_callbacks_);
v8_isolate_ = v8::Isolate::New();
@@ -290,7 +300,7 @@ void Isolate::Enter() {
v8_isolate_->Enter();
if (v8_context_.IsEmpty()) {
- v8_context_ = v8::Context::New();
+ v8_context_ = Context::New();
}
v8_context_->Enter();
@@ -476,6 +486,22 @@ static Handle<Value> CreateIsolate(const Arguments& args) {
}
isolate->argv_[isolate->argc_] = NULL;
+ // If options object was provided
+ if (args.Length() > 1) {
+ Local<Object> options = args[1].As<Object>();
+ Local<Value> opt_debug = options->Get(String::New("debug"));
+ Local<Value> opt_debug_brk = options->Get(String::New("debugBrk"));
+
+ // Handle .debug = true case
+ if (opt_debug->IsFunction()) {
+ isolate->debug_state = opt_debug_brk->IsTrue() ?
+ Isolate::kDebugBrk
+ :
+ Isolate::kDebug;
+ isolate->debugger_instance = IsolateDebugger::New(opt_debug);
+ }
+ }
+
if (uv_thread_create(&isolate->tid_, RunIsolate, isolate))
return Null(); // wrap is collected by the GC
else
@@ -493,6 +519,186 @@ void InitIsolates(Handle<Object> target) {
HandleScope scope;
NODE_SET_METHOD(target, "create", CreateIsolate);
NODE_SET_METHOD(target, "count", CountIsolate);
+
+ IsolateDebugger::Initialize();
+}
+
+
+class IsolateDebuggerMessage {
+ public:
+ IsolateDebugger* d_;
+ uint16_t* value_;
+ int len_;
+
+ IsolateDebuggerMessage(IsolateDebugger* d, uint16_t* value, int len) {
+ d_ = d;
+ value_ = new uint16_t[len];
+ len_ = len;
+ memcpy(value_, value, len * sizeof(value_[0]));
+ }
+
+ ~IsolateDebuggerMessage() {
+ delete[] value_;
+ }
+};
+
+
+void IsolateDebugger::Initialize() {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(IsolateDebugger::New);
+ isolate_debugger_constructor = Persistent<FunctionTemplate>::New(t);
+
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ t->SetClassName(String::NewSymbol("IsolateDebugger"));
+
+ NODE_SET_PROTOTYPE_METHOD(t, "write", IsolateDebugger::Write);
+}
+
+
+IsolateDebugger::IsolateDebugger(Handle<Value> init) {
+ debuggee_ = NULL;
+ initialized_ = false;
+ host_ = Isolate::GetCurrent();
+ host_loop_ = host_->GetLoop();
+ init_callback_fn_ = Persistent<Value>::New(init);
+
+ // Init async handle to invoke js callback once
+ // debugger will be initialized
+ uv_async_init(host_loop_,
+ &init_callback_,
+ IsolateDebugger::InitCallback);
+ init_callback_.data = reinterpret_cast<void*>(this);
+
+ msg_channel_ = new Channel<IsolateDebuggerMessage*>(
+ host_loop_, MessageCallback, NULL);
+}
+
+
+IsolateDebugger::~IsolateDebugger() {
+ init_callback_fn_.Clear();
+ init_callback_fn_.Dispose();
+ delete msg_channel_;
+}
+
+
+void IsolateDebugger::Init(void) {
+ HandleScope scope;
+
+ Isolate* isolate = Isolate::GetCurrent();
+
+ debuggee_ = isolate;
+ debuggee_v8_ = isolate->GetV8Isolate();
+ v8::Debug::SetMessageHandler2(IsolateDebugger::DebugMessageHandler);
+
+ // Expose v8debug for isolate
+
+ if (isolate->debug_state == Isolate::kDebugBrk) {
+ Local<Context> debugContext = v8::Debug::GetDebugContext();
+
+ debugContext->SetSecurityToken(
+ isolate->GetV8Context()->GetSecurityToken()
+ );
+ isolate->GetV8Context()->Global()->Set(
+ String::New("v8debug"),
+ debugContext->Global()
+ );
+ }
+
+ initialized_ = true;
+
+ uv_async_send(&init_callback_);
+}
+
+
+void IsolateDebugger::InitCallback(uv_async_t* c, int status) {
+ assert(c->data != NULL);
+
+ IsolateDebugger* d = reinterpret_cast<IsolateDebugger*>(c->data);
+
+ d->host_->Enter();
+ HandleScope scope;
+
+ Handle<Value> argv[1] = { d->handle_ };
+ Function::Cast(*d->init_callback_fn_)->Call(d->handle_, 1, argv);
+
+ d->host_->Exit();
+
+ // Unreference loop
+ uv_unref(d->host_loop_);
+}
+
+
+Handle<Value> IsolateDebugger::New(const Arguments& args) {
+ HandleScope scope;
+
+ IsolateDebugger* d = new IsolateDebugger(args[0]);
+ d->Wrap(args.Holder());
+
+ return args.This();
+}
+
+
+IsolateDebugger* IsolateDebugger::New(Handle<Value> init) {
+ HandleScope scope;
+
+ Handle<Value> argv[1] = { init };
+ Handle<Object> i = isolate_debugger_constructor->GetFunction()->NewInstance(
+ 1,
+ argv
+ );
+
+ return ObjectWrap::Unwrap<IsolateDebugger>(i);
+}
+
+
+Handle<Value> IsolateDebugger::Write(const Arguments& args) {
+ HandleScope scope;
+
+ if (args.Length() != 1) {
+ return ThrowException(String::New(
+ "IsolateDebugger::Write requires one argument"
+ ));
+ }
+
+ IsolateDebugger* d = ObjectWrap::Unwrap<IsolateDebugger>(args.This());
+ assert(d->initialized_);
+
+ String::Value v(args[0]->ToString());
+ v8::Debug::SendCommand(*v,
+ v.length(),
+ NULL,
+ d->debuggee_v8_);
+
+ return Undefined();
+}
+
+
+void IsolateDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
+ IsolateDebugger* d = Isolate::GetCurrent()->debugger_instance;
+
+ String::Value v(message.GetJSON());
+ d->msg_channel_->Send(new IsolateDebuggerMessage(d, *v, v.length()));
+}
+
+
+void IsolateDebugger::MessageCallback(IsolateDebuggerMessage* msg, void*) {
+ assert(msg != NULL);
+
+ IsolateDebugger *d = msg->d_;
+ // Enter parent isolate context
+ d->host_->Enter();
+ HandleScope scope;
+
+ // debugger.onmessage should be a function!
+ Handle<Value> argv[] = { String::New(msg->value_, msg->len_) };
+ MakeCallback(d->handle_, "onmessage", ARRAY_SIZE(argv), argv);
+
+ // Free memory allocated for message
+ delete msg;
+
+ // And leave isolate
+ d->host_->Exit();
}
diff --git a/src/node_isolate.h b/src/node_isolate.h
index ccfc8343332..667ee24ad1a 100644
--- a/src/node_isolate.h
+++ b/src/node_isolate.h
@@ -23,8 +23,10 @@
#define SRC_NODE_ISOLATE_H_
#include "v8.h"
+#include "v8-debug.h"
#include "uv.h"
#include "node_vars.h"
+#include "node_object_wrap.h"
#include "ngx-queue.h"
#ifdef NDEBUG
@@ -42,9 +44,15 @@
namespace node {
+template <class T>
+
+class Channel;
+
class IsolateWrap;
class IsolateChannel;
class IsolateMessage;
+class IsolateDebugger;
+class IsolateDebuggerMessage;
class Isolate {
public:
@@ -52,6 +60,13 @@ public:
int argc_;
uv_thread_t tid_;
+ enum {
+ kNone,
+ kDebug,
+ kDebugBrk
+ } debug_state;
+ IsolateDebugger* debugger_instance;
+
// Call this before instantiating any Isolate
static void Initialize();
static int Count();
@@ -125,6 +140,44 @@ private:
bool globals_init_;
};
+class IsolateDebugger : ObjectWrap {
+public:
+ static void Initialize();
+ void Init();
+ static void InitCallback(uv_async_t* c, int status);
+
+ static v8::Handle<v8::Value> New(const v8::Arguments& args);
+ static IsolateDebugger* New(v8::Handle<v8::Value> init);
+
+ static v8::Handle<v8::Value> Write(const v8::Arguments& args);
+
+ static void DebugMessageHandler(const v8::Debug::Message& message);
+ static void MessageCallback(IsolateDebuggerMessage* msg, void*);
+
+ IsolateDebugger(v8::Handle<v8::Value> init);
+ ~IsolateDebugger();
+
+protected:
+ Isolate* host_;
+ uv_loop_t* host_loop_;
+
+ uv_async_t init_callback_;
+ v8::Persistent<v8::Value> init_callback_fn_;
+
+ bool initialized_;
+ Isolate* debuggee_;
+ v8::Isolate* debuggee_v8_;
+
+ struct debug_msg_s {
+ uint16_t* value;
+ int len;
+
+ IsolateDebugger* d;
+ };
+
+ Channel<IsolateDebuggerMessage*>* msg_channel_;
+};
+
} // namespace node
#endif // SRC_NODE_ISOLATE_H_
diff --git a/src/node_vars.h b/src/node_vars.h
index 4ec628497c2..f50938ab984 100644
--- a/src/node_vars.h
+++ b/src/node_vars.h
@@ -171,6 +171,9 @@ struct globals {
v8::Persistent<v8::FunctionTemplate> wrapped_context_constructor;
v8::Persistent<v8::FunctionTemplate> wrapped_script_constructor;
+ // node_isolate.cc
+ v8::Persistent<v8::FunctionTemplate> isolate_debugger_constructor;
+
// node_signal_watcher.cc
v8::Persistent<v8::String> callback_symbol;
v8::Persistent<v8::FunctionTemplate> signal_watcher_constructor_template;