Skip to content

Commit 029567a

Browse files
eugeneoaddaleax
authored andcommitted
inspector: support extra contexts
This enables inspector support for contexts created using the vm module. PR-URL: #14465 Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Aleksey Kozyatinskiy <[email protected]>
1 parent 2d806f4 commit 029567a

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed

src/env-inl.h

+3
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ inline void Environment::TickInfo::set_index(uint32_t value) {
259259

260260
inline void Environment::AssignToContext(v8::Local<v8::Context> context) {
261261
context->SetAlignedPointerInEmbedderData(kContextEmbedderDataIndex, this);
262+
#if HAVE_INSPECTOR
263+
inspector_agent()->ContextCreated(context);
264+
#endif // HAVE_INSPECTOR
262265
}
263266

264267
inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {

src/inspector_agent.cc

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "libplatform/libplatform.h"
1313

1414
#include <string.h>
15+
#include <sstream>
1516
#include <unordered_map>
1617
#include <vector>
1718

@@ -500,6 +501,7 @@ class NodeInspectorClient : public V8InspectorClient {
500501
terminated_(false),
501502
running_nested_loop_(false) {
502503
client_ = V8Inspector::create(env->isolate(), this);
504+
contextCreated(env->context(), "Node.js Main Context");
503505
}
504506

505507
void runMessageLoopOnPause(int context_group_id) override {
@@ -627,7 +629,8 @@ class NodeInspectorClient : public V8InspectorClient {
627629
Agent::Agent(Environment* env) : parent_env_(env),
628630
client_(nullptr),
629631
platform_(nullptr),
630-
enabled_(false) {}
632+
enabled_(false),
633+
next_context_number_(1) {}
631634

632635
// Destructor needs to be defined here in implementation file as the header
633636
// does not have full definition of some classes.
@@ -641,7 +644,6 @@ bool Agent::Start(v8::Platform* platform, const char* path,
641644
client_ =
642645
std::unique_ptr<NodeInspectorClient>(
643646
new NodeInspectorClient(parent_env_, platform));
644-
client_->contextCreated(parent_env_->context(), "Node.js Main Context");
645647
platform_ = platform;
646648
CHECK_EQ(0, uv_async_init(uv_default_loop(),
647649
&start_io_thread_async,
@@ -841,6 +843,14 @@ void Agent::RequestIoThreadStart() {
841843
uv_async_send(&start_io_thread_async);
842844
}
843845

846+
void Agent::ContextCreated(Local<Context> context) {
847+
if (client_ == nullptr) // This happens for a main context
848+
return;
849+
std::ostringstream name;
850+
name << "VM Context " << next_context_number_++;
851+
client_->contextCreated(context, name.str());
852+
}
853+
844854
} // namespace inspector
845855
} // namespace node
846856

src/inspector_agent.h

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class Agent {
9696
void RequestIoThreadStart();
9797

9898
DebugOptions& options() { return debug_options_; }
99+
void ContextCreated(v8::Local<v8::Context> context);
99100

100101
private:
101102
node::Environment* parent_env_;
@@ -105,6 +106,7 @@ class Agent {
105106
bool enabled_;
106107
std::string path_;
107108
DebugOptions debug_options_;
109+
int next_context_number_;
108110
};
109111

110112
} // namespace inspector

test/inspector/test-contexts.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
'use strict';
2+
3+
// Flags: --expose-gc
4+
5+
const common = require('../common');
6+
common.skipIfInspectorDisabled();
7+
8+
const { strictEqual } = require('assert');
9+
const { runInNewContext } = require('vm');
10+
const { Session } = require('inspector');
11+
12+
const session = new Session();
13+
session.connect();
14+
15+
function notificationPromise(method) {
16+
return new Promise((resolve) => session.once(method, resolve));
17+
}
18+
19+
async function testContextCreatedAndDestroyed() {
20+
console.log('Testing context created/destroyed notifications');
21+
const mainContextPromise =
22+
notificationPromise('Runtime.executionContextCreated');
23+
24+
session.post('Runtime.enable');
25+
let contextCreated = await mainContextPromise;
26+
strictEqual('Node.js Main Context',
27+
contextCreated.params.context.name,
28+
JSON.stringify(contextCreated));
29+
30+
const secondContextCreatedPromise =
31+
notificationPromise('Runtime.executionContextCreated');
32+
33+
let contextDestroyed = null;
34+
session.once('Runtime.executionContextDestroyed',
35+
(notification) => contextDestroyed = notification);
36+
37+
runInNewContext('1 + 1', {});
38+
39+
contextCreated = await secondContextCreatedPromise;
40+
strictEqual('VM Context 1',
41+
contextCreated.params.context.name,
42+
JSON.stringify(contextCreated));
43+
44+
// GC is unpredictable...
45+
while (!contextDestroyed)
46+
global.gc();
47+
48+
strictEqual(contextCreated.params.context.id,
49+
contextDestroyed.params.executionContextId,
50+
JSON.stringify(contextDestroyed));
51+
}
52+
53+
async function testBreakpointHit() {
54+
console.log('Testing breakpoint is hit in a new context');
55+
session.post('Debugger.enable');
56+
57+
const pausedPromise = notificationPromise('Debugger.paused');
58+
runInNewContext('debugger', {});
59+
await pausedPromise;
60+
}
61+
62+
common.crashOnUnhandledRejection();
63+
testContextCreatedAndDestroyed().then(testBreakpointHit);

0 commit comments

Comments
 (0)