Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
IsolateDebugger C++
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny authored and bnoordhuis committed Jan 10, 2012
1 parent 44e7033 commit 99679c6
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 8 deletions.
17 changes: 11 additions & 6 deletions src/node.cc
Expand Up @@ -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);
Expand Down
208 changes: 207 additions & 1 deletion src/node_isolate.cc
Expand Up @@ -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>
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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
Expand All @@ -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();
}


Expand Down
53 changes: 53 additions & 0 deletions src/node_isolate.h
Expand Up @@ -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
Expand All @@ -42,16 +44,29 @@

namespace node {

template <class T>

class Channel;

class IsolateWrap;
class IsolateChannel;
class IsolateMessage;
class IsolateDebugger;
class IsolateDebuggerMessage;

class Isolate {
public:
char** argv_;
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();
Expand Down Expand Up @@ -125,6 +140,44 @@ class Isolate {
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_
3 changes: 3 additions & 0 deletions src/node_vars.h
Expand Up @@ -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;
Expand Down

0 comments on commit 99679c6

Please sign in to comment.