Skip to content
Permalink
Browse files

inspector: use inspector API for "break on start"

This change removes a need for using deprecated debug context for
breaking at the start of the main module.

PR-URL: #12076
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information...
eugeneo committed Mar 27, 2017
1 parent 4ddd23f commit 7954d2a4c7f47764643b0941635e093af6170f09
Showing with 73 additions and 6 deletions.
  1. +3 −1 lib/internal/bootstrap_node.js
  2. +27 −4 lib/module.js
  3. +42 −1 src/inspector_agent.cc
  4. +1 −0 src/inspector_agent.h
@@ -262,7 +262,9 @@
if (process.inspector) {
inspectorConsole = global.console;
wrapConsoleCall = process.inspector.wrapConsoleCall;
delete process.inspector;
delete process.inspector.wrapConsoleCall;
if (Object.keys(process.inspector).length === 0)
delete process.inspector;
}
var console;
Object.defineProperty(global, 'console', {
@@ -472,6 +472,19 @@ function tryModuleLoad(module, filename) {
}
}

function getInspectorCallWrapper() {
var inspector = process.inspector;
if (!inspector || !inspector.callAndPauseOnStart) {
return null;
}
var wrapper = inspector.callAndPauseOnStart.bind(inspector);
delete inspector.callAndPauseOnStart;
if (Object.keys(process.inspector).length === 0) {
delete process.inspector;
}
return wrapper;
}

Module._resolveFilename = function(request, parent, isMain) {
if (NativeModule.nonInternalExists(request)) {
return request;
@@ -561,6 +574,7 @@ Module.prototype._compile = function(content, filename) {
displayErrors: true
});

var inspectorWrapper = null;
if (process._debugWaitConnect && process._eval == null) {
if (!resolvedArgv) {
// we enter the repl if we're not given a filename argument.
@@ -574,16 +588,25 @@ Module.prototype._compile = function(content, filename) {
// Set breakpoint on module start
if (filename === resolvedArgv) {
delete process._debugWaitConnect;
const Debug = vm.runInDebugContext('Debug');
Debug.setBreakPoint(compiledWrapper, 0, 0);
inspectorWrapper = getInspectorCallWrapper();
if (!inspectorWrapper) {
const Debug = vm.runInDebugContext('Debug');
Debug.setBreakPoint(compiledWrapper, 0, 0);
}
}
}
var dirname = path.dirname(filename);
var require = internalModule.makeRequireFunction(this);
var depth = internalModule.requireDepth;
if (depth === 0) stat.cache = new Map();
var result = compiledWrapper.call(this.exports, this.exports, require, this,
filename, dirname);
var result;
if (inspectorWrapper) {
result = inspectorWrapper(compiledWrapper, this.exports, this.exports,
require, this, filename, dirname);
} else {
result = compiledWrapper.call(this.exports, this.exports, require, this,
filename, dirname);
}
if (depth === 0) stat.cache = null;
return result;
};
@@ -94,7 +94,6 @@ std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
utf16.length());
return StringBuffer::create(view);
}

} // namespace

class V8NodeInspector;
@@ -145,6 +144,8 @@ class AgentImpl {
void FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);

void SchedulePauseOnNextStatement(const std::string& reason);

void PostIncomingMessage(InspectorAction action, int session_id,
const std::string& message);
void ResumeStartup() {
@@ -160,6 +161,8 @@ class AgentImpl {
static void ThreadCbIO(void* agent);
static void WriteCbIO(uv_async_t* async);
static void MainThreadAsyncCb(uv_async_t* req);
static void CallAndPauseOnStart(
const v8::FunctionCallbackInfo<v8::Value>& args);

void InstallInspectorOnProcess();

@@ -310,6 +313,14 @@ class V8NodeInspector : public v8_inspector::V8InspectorClient {
session_->dispatchProtocolMessage(message);
}

void schedulePauseOnNextStatement(const std::string& reason) {
if (session_ != nullptr) {
std::unique_ptr<StringBuffer> buffer = Utf8ToStringView(reason);
session_->schedulePauseOnNextStatement(buffer->string(),
buffer->string());
}
}

v8::Local<v8::Context> ensureDefaultContextInGroup(int contextGroupId)
override {
return env_->context();
@@ -477,6 +488,28 @@ void AgentImpl::InstallInspectorOnProcess() {
v8::Local<v8::Object> inspector = v8::Object::New(env->isolate());
READONLY_PROPERTY(process, "inspector", inspector);
env->SetMethod(inspector, "wrapConsoleCall", InspectorWrapConsoleCall);
if (options_.wait_for_connect()) {
env->SetMethod(inspector, "callAndPauseOnStart", CallAndPauseOnStart);
}
}

// static
void AgentImpl::CallAndPauseOnStart(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_GT(args.Length(), 1);
CHECK(args[0]->IsFunction());
std::vector<v8::Local<v8::Value>> call_args;
for (int i = 2; i < args.Length(); i++) {
call_args.push_back(args[i]);
}

env->inspector_agent()->SchedulePauseOnNextStatement("Break on start");

v8::MaybeLocal<v8::Value> retval =
args[0].As<v8::Function>()->Call(env->context(), args[1],
call_args.size(), call_args.data());
args.GetReturnValue().Set(retval.ToLocalChecked());
}

std::unique_ptr<StringBuffer> ToProtocolString(v8::Local<v8::Value> value) {
@@ -682,6 +715,10 @@ void AgentImpl::Write(TransportAction action, int session_id,
CHECK_EQ(0, err);
}

void AgentImpl::SchedulePauseOnNextStatement(const std::string& reason) {
inspector_->schedulePauseOnNextStatement(reason);
}

// Exported class Agent
Agent::Agent(node::Environment* env) : impl(new AgentImpl(env)) {}

@@ -715,6 +752,10 @@ void Agent::FatalException(v8::Local<v8::Value> error,
impl->FatalException(error, message);
}

void Agent::SchedulePauseOnNextStatement(const std::string& reason) {
impl->SchedulePauseOnNextStatement(reason);
}

InspectorAgentDelegate::InspectorAgentDelegate(AgentImpl* agent,
const std::string& script_path,
const std::string& script_name,
@@ -43,6 +43,7 @@ class Agent {
void WaitForDisconnect();
void FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
void SchedulePauseOnNextStatement(const std::string& reason);
private:
AgentImpl* impl;
};

0 comments on commit 7954d2a

Please sign in to comment.
You can’t perform that action at this time.