Browse Source

IsolateDebugger C++

v0.7.4-release
Fedor Indutny 13 years ago
committed by Ben Noordhuis
parent
commit
99679c6430
  1. 5
      src/node.cc
  2. 208
      src/node_isolate.cc
  3. 53
      src/node_isolate.h
  4. 3
      src/node_vars.h
  5. 15
      test/simple/test-isolates.js

5
src/node.cc

@ -2624,6 +2624,8 @@ void StartThread(node::Isolate* isolate,
// even when we need it to access it from another (debugger) thread.
node_isolate = v8::Isolate::GetCurrent();
// 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);
@ -2634,6 +2636,9 @@ void StartThread(node::Isolate* isolate,
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
#endif // __POSIX__
}
} else if (isolate->debug_state != Isolate::kNone) {
isolate->debugger_instance->Init();
}
Handle<Object> process_l = SetupProcessObject(argc, argv);

208
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();
}

53
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_

3
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;

15
test/simple/test-isolates.js

@ -5,7 +5,20 @@ var isolates = process.binding('isolates');
console.log("count: %d", isolates.count());
if (process.tid === 1) {
var isolate = isolates.create(process.argv);
var isolate = isolates.create(process.argv, {
debug: function init(d) {
d.onmessage = function(data) {
data = JSON.parse(data);
if (data.event === 'break') {
d.write(JSON.stringify({
type: 'request',
seq: 1,
command: 'continue'
}));
}
};
}
});
isolate.onmessage = function() {
console.error("onmessage");

Loading…
Cancel
Save