Skip to content

Commit 3f48ab3

Browse files
author
Eugene Ostroukhov
committed
inspector: do not add 'inspector' property
'inspector' property is not an official API and should not be published on process object, where the user may discover it. This change was extracted from nodejs#12263 that will be focused on creating JS bindings. PR-URL: nodejs#12656 Reviewed-By: Aleksey Kozyatinskiy <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]>
1 parent 6ade7f3 commit 3f48ab3

File tree

6 files changed

+115
-161
lines changed

6 files changed

+115
-161
lines changed

lib/internal/bootstrap_node.js

+17-28
Original file line numberDiff line numberDiff line change
@@ -254,52 +254,41 @@
254254
}
255255

256256
function setupGlobalConsole() {
257-
var inspectorConsole;
258-
var wrapConsoleCall;
259-
if (process.inspector) {
260-
inspectorConsole = global.console;
261-
wrapConsoleCall = process.inspector.wrapConsoleCall;
262-
delete process.inspector.wrapConsoleCall;
263-
if (Object.keys(process.inspector).length === 0)
264-
delete process.inspector;
265-
}
266-
var console;
257+
const originalConsole = global.console;
258+
let console;
267259
Object.defineProperty(global, 'console', {
268260
configurable: true,
269261
enumerable: true,
270262
get: function() {
271263
if (!console) {
272-
console = NativeModule.require('console');
273-
installInspectorConsoleIfNeeded(console,
274-
inspectorConsole,
275-
wrapConsoleCall);
264+
console = installInspectorConsole(originalConsole);
276265
}
277266
return console;
278267
}
279268
});
280269
}
281270

282-
function installInspectorConsoleIfNeeded(console,
283-
inspectorConsole,
284-
wrapConsoleCall) {
285-
if (!inspectorConsole)
286-
return;
271+
function installInspectorConsole(globalConsole) {
272+
const wrappedConsole = NativeModule.require('console');
273+
const inspector = process.binding('inspector');
287274
const config = {};
288-
for (const key of Object.keys(console)) {
289-
if (!inspectorConsole.hasOwnProperty(key))
275+
for (const key of Object.keys(wrappedConsole)) {
276+
if (!globalConsole.hasOwnProperty(key))
290277
continue;
291-
// If node console has the same method as inspector console,
278+
// If global console has the same method as inspector console,
292279
// then wrap these two methods into one. Native wrapper will preserve
293280
// the original stack.
294-
console[key] = wrapConsoleCall(inspectorConsole[key],
295-
console[key],
296-
config);
281+
wrappedConsole[key] = inspector.consoleCall.bind(wrappedConsole,
282+
globalConsole[key],
283+
wrappedConsole[key],
284+
config);
297285
}
298-
for (const key of Object.keys(inspectorConsole)) {
299-
if (console.hasOwnProperty(key))
286+
for (const key of Object.keys(globalConsole)) {
287+
if (wrappedConsole.hasOwnProperty(key))
300288
continue;
301-
console[key] = inspectorConsole[key];
289+
wrappedConsole[key] = globalConsole[key];
302290
}
291+
return wrappedConsole;
303292
}
304293

305294
function setupProcessFatal() {

lib/module.js

+1-14
Original file line numberDiff line numberDiff line change
@@ -472,19 +472,6 @@ function tryModuleLoad(module, filename) {
472472
}
473473
}
474474

475-
function getInspectorCallWrapper() {
476-
var inspector = process.inspector;
477-
if (!inspector || !inspector.callAndPauseOnStart) {
478-
return null;
479-
}
480-
var wrapper = inspector.callAndPauseOnStart.bind(inspector);
481-
delete inspector.callAndPauseOnStart;
482-
if (Object.keys(process.inspector).length === 0) {
483-
delete process.inspector;
484-
}
485-
return wrapper;
486-
}
487-
488475
Module._resolveFilename = function(request, parent, isMain) {
489476
if (NativeModule.nonInternalExists(request)) {
490477
return request;
@@ -563,7 +550,7 @@ Module.prototype._compile = function(content, filename) {
563550
// Set breakpoint on module start
564551
if (filename === resolvedArgv) {
565552
delete process._debugWaitConnect;
566-
inspectorWrapper = getInspectorCallWrapper();
553+
inspectorWrapper = process.binding('inspector').callAndPauseOnStart;
567554
if (!inspectorWrapper) {
568555
const Debug = vm.runInDebugContext('Debug');
569556
Debug.setBreakPoint(compiledWrapper, 0, 0);

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ namespace node {
7272
V(arrow_message_private_symbol, "node:arrowMessage") \
7373
V(contextify_context_private_symbol, "node:contextify:context") \
7474
V(contextify_global_private_symbol, "node:contextify:global") \
75+
V(inspector_delegate_private_symbol, "node:inspector:delegate") \
7576
V(decorated_private_symbol, "node:decorated") \
7677
V(npn_buffer_private_symbol, "node:npnBuffer") \
7778
V(processed_private_symbol, "node:processed") \

src/inspector_agent.cc

+79-112
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,61 @@ static int RegisterDebugSignalHandler() {
154154
return 0;
155155
}
156156
#endif // _WIN32
157-
} // namespace
158157

158+
void InspectorConsoleCall(const v8::FunctionCallbackInfo<Value>& info) {
159+
Isolate* isolate = info.GetIsolate();
160+
HandleScope handle_scope(isolate);
161+
Local<Context> context = isolate->GetCurrentContext();
162+
CHECK_LT(2, info.Length());
163+
std::vector<Local<Value>> call_args;
164+
for (int i = 3; i < info.Length(); ++i) {
165+
call_args.push_back(info[i]);
166+
}
167+
Environment* env = Environment::GetCurrent(isolate);
168+
if (env->inspector_agent()->enabled()) {
169+
Local<Value> inspector_method = info[0];
170+
CHECK(inspector_method->IsFunction());
171+
Local<Value> config_value = info[2];
172+
CHECK(config_value->IsObject());
173+
Local<Object> config_object = config_value.As<Object>();
174+
Local<String> in_call_key = FIXED_ONE_BYTE_STRING(isolate, "in_call");
175+
if (!config_object->Has(context, in_call_key).FromMaybe(false)) {
176+
CHECK(config_object->Set(context,
177+
in_call_key,
178+
v8::True(isolate)).FromJust());
179+
CHECK(!inspector_method.As<Function>()->Call(context,
180+
info.Holder(),
181+
call_args.size(),
182+
call_args.data()).IsEmpty());
183+
}
184+
CHECK(config_object->Delete(context, in_call_key).FromJust());
185+
}
186+
187+
Local<Value> node_method = info[1];
188+
CHECK(node_method->IsFunction());
189+
static_cast<void>(node_method.As<Function>()->Call(context,
190+
info.Holder(),
191+
call_args.size(),
192+
call_args.data()));
193+
}
194+
195+
void CallAndPauseOnStart(
196+
const v8::FunctionCallbackInfo<v8::Value>& args) {
197+
Environment* env = Environment::GetCurrent(args);
198+
CHECK_GT(args.Length(), 1);
199+
CHECK(args[0]->IsFunction());
200+
std::vector<v8::Local<v8::Value>> call_args;
201+
for (int i = 2; i < args.Length(); i++) {
202+
call_args.push_back(args[i]);
203+
}
204+
205+
env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
206+
v8::MaybeLocal<v8::Value> retval =
207+
args[0].As<v8::Function>()->Call(env->context(), args[1],
208+
call_args.size(), call_args.data());
209+
args.GetReturnValue().Set(retval.ToLocalChecked());
210+
}
211+
} // namespace
159212

160213
// Used in NodeInspectorClient::currentTimeMS() below.
161214
const int NANOS_PER_MSEC = 1000000;
@@ -263,12 +316,6 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
263316
channel_->dispatchProtocolMessage(message);
264317
}
265318

266-
void schedulePauseOnNextStatement(const std::string& reason) {
267-
if (channel_ != nullptr) {
268-
channel_->schedulePauseOnNextStatement(reason);
269-
}
270-
}
271-
272319
Local<Context> ensureDefaultContextInGroup(int contextGroupId) override {
273320
return env_->context();
274321
}
@@ -302,10 +349,8 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
302349
script_id);
303350
}
304351

305-
InspectorSessionDelegate* delegate() {
306-
if (channel_ == nullptr)
307-
return nullptr;
308-
return channel_->delegate();
352+
ChannelImpl* channel() {
353+
return channel_.get();
309354
}
310355

311356
private:
@@ -320,98 +365,22 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
320365
Agent::Agent(Environment* env) : parent_env_(env),
321366
inspector_(nullptr),
322367
platform_(nullptr),
323-
inspector_console_(false) {}
368+
enabled_(false) {}
324369

325-
// Header has unique_ptr to some incomplete types - this definition tells
326-
// the compiler to figure out destruction here, were those types are complete
370+
// Destructor needs to be defined here in implementation file as the header
371+
// does not have full definition of some classes.
327372
Agent::~Agent() {
328373
}
329374

330-
// static
331-
void Agent::InspectorConsoleCall(const v8::FunctionCallbackInfo<Value>& info) {
332-
Isolate* isolate = info.GetIsolate();
333-
Local<Context> context = isolate->GetCurrentContext();
334-
335-
CHECK(info.Data()->IsArray());
336-
Local<v8::Array> args = info.Data().As<v8::Array>();
337-
CHECK_EQ(args->Length(), 3);
338-
339-
std::vector<Local<Value>> call_args(info.Length());
340-
for (int i = 0; i < info.Length(); ++i) {
341-
call_args[i] = info[i];
342-
}
343-
344-
Environment* env = Environment::GetCurrent(isolate);
345-
if (env->inspector_agent()->inspector_console_) {
346-
Local<Value> inspector_method = args->Get(context, 0).ToLocalChecked();
347-
CHECK(inspector_method->IsFunction());
348-
Local<Value> config_value = args->Get(context, 2).ToLocalChecked();
349-
CHECK(config_value->IsObject());
350-
Local<Object> config_object = config_value.As<Object>();
351-
Local<String> in_call_key = FIXED_ONE_BYTE_STRING(isolate, "in_call");
352-
if (!config_object->Has(context, in_call_key).FromMaybe(false)) {
353-
CHECK(config_object->Set(context,
354-
in_call_key,
355-
v8::True(isolate)).FromJust());
356-
CHECK(!inspector_method.As<Function>()->Call(context,
357-
info.Holder(),
358-
call_args.size(),
359-
call_args.data()).IsEmpty());
360-
}
361-
CHECK(config_object->Delete(context, in_call_key).FromJust());
362-
}
363-
364-
Local<Value> node_method =
365-
args->Get(context, 1).ToLocalChecked();
366-
CHECK(node_method->IsFunction());
367-
static_cast<void>(node_method.As<Function>()->Call(context,
368-
info.Holder(),
369-
call_args.size(),
370-
call_args.data()));
371-
}
372-
373-
// static
374-
void Agent::InspectorWrapConsoleCall(const FunctionCallbackInfo<Value>& info) {
375-
Environment* env = Environment::GetCurrent(info);
376-
if (info.Length() != 3 || !info[0]->IsFunction() ||
377-
!info[1]->IsFunction() || !info[2]->IsObject()) {
378-
return env->ThrowError("inspector.wrapConsoleCall takes exactly 3 "
379-
"arguments: two functions and an object.");
380-
}
381-
382-
Local<v8::Array> array = v8::Array::New(env->isolate(), info.Length());
383-
CHECK(array->Set(env->context(), 0, info[0]).FromJust());
384-
CHECK(array->Set(env->context(), 1, info[1]).FromJust());
385-
CHECK(array->Set(env->context(), 2, info[2]).FromJust());
386-
info.GetReturnValue().Set(Function::New(env->context(),
387-
InspectorConsoleCall,
388-
array).ToLocalChecked());
389-
}
390-
391375
bool Agent::Start(v8::Platform* platform, const char* path,
392376
const DebugOptions& options) {
393377
path_ = path == nullptr ? "" : path;
394378
debug_options_ = options;
395-
inspector_console_ = false;
396379
inspector_ =
397380
std::unique_ptr<NodeInspectorClient>(
398381
new NodeInspectorClient(parent_env_, platform));
399382
platform_ = platform;
400-
Local<Object> process = parent_env_->process_object();
401-
Local<Object> inspector = Object::New(parent_env_->isolate());
402-
Local<String> name =
403-
FIXED_ONE_BYTE_STRING(parent_env_->isolate(), "inspector");
404-
process->DefineOwnProperty(parent_env_->context(),
405-
name,
406-
inspector,
407-
v8::ReadOnly).FromJust();
408-
parent_env_->SetMethod(inspector, "wrapConsoleCall",
409-
InspectorWrapConsoleCall);
410383
if (options.inspector_enabled()) {
411-
if (options.wait_for_connect()) {
412-
parent_env_->SetMethod(inspector, "callAndPauseOnStart",
413-
CallAndPauseOnStart);
414-
}
415384
return StartIoThread();
416385
} else {
417386
CHECK_EQ(0, uv_async_init(uv_default_loop(),
@@ -431,7 +400,7 @@ bool Agent::StartIoThread() {
431400

432401
CHECK_NE(inspector_, nullptr);
433402

434-
inspector_console_ = true;
403+
enabled_ = true;
435404
io_ = std::unique_ptr<InspectorIo>(
436405
new InspectorIo(parent_env_, platform_, path_, debug_options_));
437406
if (!io_->Start()) {
@@ -469,7 +438,7 @@ void Agent::Stop() {
469438
}
470439

471440
void Agent::Connect(InspectorSessionDelegate* delegate) {
472-
inspector_console_ = true;
441+
enabled_ = true;
473442
inspector_->connectFrontend(delegate);
474443
}
475444

@@ -481,26 +450,6 @@ bool Agent::IsStarted() {
481450
return !!inspector_;
482451
}
483452

484-
// static
485-
void Agent::CallAndPauseOnStart(
486-
const v8::FunctionCallbackInfo<v8::Value>& args) {
487-
Environment* env = Environment::GetCurrent(args);
488-
CHECK_GT(args.Length(), 1);
489-
CHECK(args[0]->IsFunction());
490-
std::vector<v8::Local<v8::Value>> call_args;
491-
for (int i = 2; i < args.Length(); i++) {
492-
call_args.push_back(args[i]);
493-
}
494-
495-
Agent* agent = env->inspector_agent();
496-
agent->inspector_->schedulePauseOnNextStatement("Break on start");
497-
498-
v8::MaybeLocal<v8::Value> retval =
499-
args[0].As<v8::Function>()->Call(env->context(), args[1],
500-
call_args.size(), call_args.data());
501-
args.GetReturnValue().Set(retval.ToLocalChecked());
502-
}
503-
504453
void Agent::WaitForDisconnect() {
505454
if (io_ != nullptr) {
506455
io_->WaitForDisconnect();
@@ -529,5 +478,23 @@ void Agent::RunMessageLoop() {
529478
inspector_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
530479
}
531480

481+
void Agent::PauseOnNextJavascriptStatement(const std::string& reason) {
482+
ChannelImpl* channel = inspector_->channel();
483+
if (channel != nullptr)
484+
channel->schedulePauseOnNextStatement(reason);
485+
}
486+
487+
// static
488+
void Agent::InitJSBindings(Local<Object> target, Local<Value> unused,
489+
Local<Context> context, void* priv) {
490+
Environment* env = Environment::GetCurrent(context);
491+
Agent* agent = env->inspector_agent();
492+
env->SetMethod(target, "consoleCall", InspectorConsoleCall);
493+
if (agent->debug_options_.wait_for_connect())
494+
env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
495+
}
532496
} // namespace inspector
533497
} // namespace node
498+
499+
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector,
500+
node::inspector::Agent::InitJSBindings);

0 commit comments

Comments
 (0)