Skip to content

Commit faa4eaa

Browse files
committed
inspector: use BaseObject
Uses internal fields instead of the less efficient v8::External for storing the pointer to the C++ object. Refs: nodejs#13503
1 parent 11cb107 commit faa4eaa

File tree

3 files changed

+80
-69
lines changed

3 files changed

+80
-69
lines changed

lib/inspector.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
const EventEmitter = require('events');
44
const util = require('util');
5-
const { connect, open, url } = process.binding('inspector');
5+
const { Connection, open, url } = process.binding('inspector');
66

7-
if (!connect)
7+
if (!Connection)
88
throw new Error('Inspector is not available');
99

1010
const connectionSymbol = Symbol('connectionProperty');
@@ -23,8 +23,7 @@ class Session extends EventEmitter {
2323
connect() {
2424
if (this[connectionSymbol])
2525
throw new Error('Already connected');
26-
this[connectionSymbol] =
27-
connect((message) => this[onMessageSymbol](message));
26+
this[connectionSymbol] = new Connection(this[onMessageSymbol], this);
2827
}
2928

3029
[onMessageSymbol](message) {

src/env.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ namespace node {
7676
V(arrow_message_private_symbol, "node:arrowMessage") \
7777
V(contextify_context_private_symbol, "node:contextify:context") \
7878
V(contextify_global_private_symbol, "node:contextify:global") \
79-
V(inspector_delegate_private_symbol, "node:inspector:delegate") \
8079
V(decorated_private_symbol, "node:decorated") \
8180
V(npn_buffer_private_symbol, "node:npnBuffer") \
8281
V(processed_private_symbol, "node:processed") \

src/inspector_agent.cc

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "inspector_agent.h"
22

33
#include "inspector_io.h"
4+
#include "base-object.h"
5+
#include "base-object-inl.h"
46
#include "env.h"
57
#include "env-inl.h"
68
#include "node.h"
@@ -27,6 +29,7 @@ using v8::Context;
2729
using v8::External;
2830
using v8::Function;
2931
using v8::FunctionCallbackInfo;
32+
using v8::FunctionTemplate;
3033
using v8::HandleScope;
3134
using v8::Isolate;
3235
using v8::Local;
@@ -250,79 +253,81 @@ class JsBindingsSessionDelegate : public InspectorSessionDelegate {
250253
Persistent<Function> callback_;
251254
};
252255

253-
void SetDelegate(Environment* env, Local<Object> inspector,
254-
JsBindingsSessionDelegate* delegate) {
255-
inspector->SetPrivate(env->context(),
256-
env->inspector_delegate_private_symbol(),
257-
v8::External::New(env->isolate(), delegate));
258-
}
259-
260-
Maybe<JsBindingsSessionDelegate*> GetDelegate(
261-
const FunctionCallbackInfo<Value>& info) {
262-
Environment* env = Environment::GetCurrent(info);
263-
Local<Value> delegate;
264-
MaybeLocal<Value> maybe_delegate =
265-
info.This()->GetPrivate(env->context(),
266-
env->inspector_delegate_private_symbol());
267-
268-
if (maybe_delegate.ToLocal(&delegate)) {
269-
CHECK(delegate->IsExternal());
270-
void* value = delegate.As<External>()->Value();
271-
if (value != nullptr) {
272-
return v8::Just(static_cast<JsBindingsSessionDelegate*>(value));
256+
class JSBindingsConnection : public BaseObject {
257+
public:
258+
JSBindingsConnection(Environment* env,
259+
Local<Object> wrap,
260+
Local<Object> receiver,
261+
Local<Function> callback)
262+
: BaseObject(env, wrap) {
263+
MakeWeak<JSBindingsConnection>(this);
264+
Wrap(wrap, this);
265+
266+
Agent* inspector = env->inspector_agent();
267+
if (inspector->delegate() != nullptr) {
268+
env->ThrowTypeError("Session is already attached");
269+
return;
273270
}
271+
delegate_ = new JsBindingsSessionDelegate(env, wrap, receiver, callback);
272+
inspector->Connect(delegate_);
274273
}
275-
env->ThrowError("Inspector is not connected");
276-
return v8::Nothing<JsBindingsSessionDelegate*>();
277-
}
278274

279-
void Dispatch(const FunctionCallbackInfo<Value>& info) {
280-
Environment* env = Environment::GetCurrent(info);
281-
if (!info[0]->IsString()) {
282-
env->ThrowError("Inspector message must be a string");
283-
return;
275+
~JSBindingsConnection() override {
276+
Disconnect();
284277
}
285-
Maybe<JsBindingsSessionDelegate*> maybe_delegate = GetDelegate(info);
286-
if (maybe_delegate.IsNothing())
287-
return;
288-
Agent* inspector = env->inspector_agent();
289-
CHECK_EQ(maybe_delegate.ToChecked(), inspector->delegate());
290-
inspector->Dispatch(ToProtocolString(env->isolate(), info[0])->string());
291-
}
292278

293-
void Disconnect(const FunctionCallbackInfo<Value>& info) {
294-
Environment* env = Environment::GetCurrent(info);
295-
Maybe<JsBindingsSessionDelegate*> delegate = GetDelegate(info);
296-
if (delegate.IsNothing()) {
297-
return;
279+
JsBindingsSessionDelegate* delegate() {
280+
return delegate_;
298281
}
299-
delegate.ToChecked()->Disconnect();
300-
SetDelegate(env, info.This(), nullptr);
301-
delete delegate.ToChecked();
302-
}
303282

304-
void ConnectJSBindingsSession(const FunctionCallbackInfo<Value>& info) {
305-
Environment* env = Environment::GetCurrent(info);
306-
if (!info[0]->IsFunction()) {
307-
env->ThrowError("Message callback is required");
308-
return;
283+
static void New(const FunctionCallbackInfo<Value>& info) {
284+
Environment* env = Environment::GetCurrent(info);
285+
if (!info[0]->IsFunction()) {
286+
env->ThrowTypeError("Message callback is required");
287+
return;
288+
}
289+
Local<Function> callback = info[0].As<Function>();
290+
Local<Object> receiver =
291+
info[1]->IsObject() ? info[1].As<Object>() : info.This();
292+
new JSBindingsConnection(env, info.This(), receiver, callback);
309293
}
310-
Agent* inspector = env->inspector_agent();
311-
if (inspector->delegate() != nullptr) {
312-
env->ThrowError("Session is already attached");
313-
return;
294+
295+
void Disconnect() {
296+
if (!delegate_)
297+
return;
298+
delegate_->Disconnect();
299+
delete delegate_;
300+
delegate_ = nullptr;
314301
}
315-
Local<Object> session = Object::New(env->isolate());
316-
env->SetMethod(session, "dispatch", Dispatch);
317-
env->SetMethod(session, "disconnect", Disconnect);
318-
info.GetReturnValue().Set(session);
319302

320-
JsBindingsSessionDelegate* delegate =
321-
new JsBindingsSessionDelegate(env, session, info.Holder(),
322-
info[0].As<Function>());
323-
inspector->Connect(delegate);
324-
SetDelegate(env, session, delegate);
325-
}
303+
static void Disconnect(const FunctionCallbackInfo<Value>& info) {
304+
JSBindingsConnection* session;
305+
ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
306+
session->Disconnect();
307+
}
308+
309+
static void Dispatch(const FunctionCallbackInfo<Value>& info) {
310+
Environment* env = Environment::GetCurrent(info);
311+
JSBindingsConnection* session;
312+
ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
313+
if (!info[0]->IsString()) {
314+
env->ThrowTypeError("Inspector message must be a string");
315+
return;
316+
}
317+
318+
auto delegate = session->delegate();
319+
if (!delegate) {
320+
env->ThrowTypeError("Inspector is not connected");
321+
return;
322+
}
323+
Agent* inspector = env->inspector_agent();
324+
CHECK_EQ(delegate, inspector->delegate());
325+
inspector->Dispatch(ToProtocolString(env->isolate(), info[0])->string());
326+
}
327+
328+
private:
329+
JsBindingsSessionDelegate* delegate_;
330+
};
326331

327332
void InspectorConsoleCall(const v8::FunctionCallbackInfo<Value>& info) {
328333
Isolate* isolate = info.GetIsolate();
@@ -825,9 +830,17 @@ void Agent::InitInspector(Local<Object> target, Local<Value> unused,
825830
env->SetMethod(target, "addCommandLineAPI", AddCommandLineAPI);
826831
if (agent->debug_options_.wait_for_connect())
827832
env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
828-
env->SetMethod(target, "connect", ConnectJSBindingsSession);
829833
env->SetMethod(target, "open", Open);
830834
env->SetMethod(target, "url", Url);
835+
836+
auto conn_str = FIXED_ONE_BYTE_STRING(env->isolate(), "Connection");
837+
Local<FunctionTemplate> tmpl =
838+
env->NewFunctionTemplate(JSBindingsConnection::New);
839+
tmpl->InstanceTemplate()->SetInternalFieldCount(1);
840+
env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
841+
env->SetProtoMethod(tmpl, "disconnect", JSBindingsConnection::Disconnect);
842+
tmpl->SetClassName(conn_str);
843+
target->Set(env->context(), conn_str, tmpl->GetFunction()).ToChecked();
831844
}
832845

833846
void Agent::RequestIoThreadStart() {

0 commit comments

Comments
 (0)