Skip to content

Commit b45c22b

Browse files
addaleaxBridgeAR
authored andcommitted
src: use object to pass Environment to functions
Use a `v8::Object` with an internal field, rather than a `v8::External`. On a `GetReturnValue().Set(Environment::GetCurrent(args) == nullptr)` noop function, this benchmarks as a ~60 % speedup, as calls to `obj->GetAlignedPointerFromInternalField()` can be inlined and the field is stored with one level of indirection less. This also makes breaking up some pieces of the `Environment` class into per-native-binding data easier, if we want to pursue that path in the future. PR-URL: #26382 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent e79f0c2 commit b45c22b

11 files changed

+39
-20
lines changed

src/env-inl.h

+13-6
Original file line numberDiff line numberDiff line change
@@ -316,16 +316,23 @@ inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
316316

317317
inline Environment* Environment::GetCurrent(
318318
const v8::FunctionCallbackInfo<v8::Value>& info) {
319-
CHECK(info.Data()->IsExternal());
320-
return static_cast<Environment*>(info.Data().As<v8::External>()->Value());
319+
return GetFromCallbackData(info.Data());
321320
}
322321

323322
template <typename T>
324323
inline Environment* Environment::GetCurrent(
325324
const v8::PropertyCallbackInfo<T>& info) {
326-
CHECK(info.Data()->IsExternal());
327-
return static_cast<Environment*>(
328-
info.Data().template As<v8::External>()->Value());
325+
return GetFromCallbackData(info.Data());
326+
}
327+
328+
inline Environment* Environment::GetFromCallbackData(v8::Local<v8::Value> val) {
329+
DCHECK(val->IsObject());
330+
v8::Local<v8::Object> obj = val.As<v8::Object>();
331+
DCHECK_GE(obj->InternalFieldCount(), 1);
332+
Environment* env =
333+
static_cast<Environment*>(obj->GetAlignedPointerFromInternalField(0));
334+
DCHECK(env->as_callback_data_template()->HasInstance(obj));
335+
return env;
329336
}
330337

331338
inline Environment* Environment::GetThreadLocalEnv() {
@@ -857,7 +864,7 @@ inline v8::Local<v8::FunctionTemplate>
857864
v8::Local<v8::Signature> signature,
858865
v8::ConstructorBehavior behavior,
859866
v8::SideEffectType side_effect_type) {
860-
v8::Local<v8::External> external = as_external();
867+
v8::Local<v8::Object> external = as_callback_data();
861868
return v8::FunctionTemplate::New(isolate(), callback, external,
862869
signature, 0, behavior, side_effect_type);
863870
}

src/env.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ using v8::ArrayBuffer;
2525
using v8::Boolean;
2626
using v8::Context;
2727
using v8::EmbedderGraph;
28-
using v8::External;
2928
using v8::Function;
29+
using v8::FunctionTemplate;
3030
using v8::HandleScope;
3131
using v8::Integer;
3232
using v8::Isolate;
@@ -195,7 +195,16 @@ Environment::Environment(IsolateData* isolate_data,
195195
// We'll be creating new objects so make sure we've entered the context.
196196
HandleScope handle_scope(isolate());
197197
Context::Scope context_scope(context);
198-
set_as_external(External::New(isolate(), this));
198+
{
199+
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
200+
templ->InstanceTemplate()->SetInternalFieldCount(1);
201+
Local<Object> obj =
202+
templ->GetFunction(context).ToLocalChecked()->NewInstance(
203+
context).ToLocalChecked();
204+
obj->SetAlignedPointerInInternalField(0, this);
205+
set_as_callback_data(obj);
206+
set_as_callback_data_template(templ);
207+
}
199208

200209
// We create new copies of the per-Environment option sets, so that it is
201210
// easier to modify them after Environment creation. The defaults are

src/env.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
319319
V(zero_return_string, "ZERO_RETURN")
320320

321321
#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
322-
V(as_external, v8::External) \
322+
V(as_callback_data, v8::Object) \
323+
V(as_callback_data_template, v8::FunctionTemplate) \
323324
V(async_hooks_after_function, v8::Function) \
324325
V(async_hooks_before_function, v8::Function) \
325326
V(async_hooks_binding, v8::Object) \
@@ -661,6 +662,8 @@ class Environment {
661662
static inline Environment* GetCurrent(
662663
const v8::PropertyCallbackInfo<T>& info);
663664

665+
static inline Environment* GetFromCallbackData(v8::Local<v8::Value> val);
666+
664667
static uv_key_t thread_local_env;
665668
static inline Environment* GetThreadLocalEnv();
666669

src/fs_event_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ void FSEventWrap::Initialize(Local<Object> target,
111111
Local<FunctionTemplate> get_initialized_templ =
112112
FunctionTemplate::New(env->isolate(),
113113
GetInitialized,
114-
env->as_external(),
114+
env->as_callback_data(),
115115
Signature::New(env->isolate(), t));
116116

117117
t->PrototypeTemplate()->SetAccessorProperty(

src/node_crypto.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
369369
Local<FunctionTemplate> ctx_getter_templ =
370370
FunctionTemplate::New(env->isolate(),
371371
CtxGetter,
372-
env->as_external(),
372+
env->as_callback_data(),
373373
Signature::New(env->isolate(), t));
374374

375375

@@ -4762,7 +4762,7 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
47624762
Local<FunctionTemplate> verify_error_getter_templ =
47634763
FunctionTemplate::New(env->isolate(),
47644764
DiffieHellman::VerifyErrorGetter,
4765-
env->as_external(),
4765+
env->as_callback_data(),
47664766
Signature::New(env->isolate(), t),
47674767
/* length */ 0,
47684768
ConstructorBehavior::kThrow,

src/node_env_var.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
212212

213213
MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
214214
Isolate* isolate,
215-
Local<Value> data) {
215+
Local<Object> data) {
216216
EscapableHandleScope scope(isolate);
217217
Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
218218
env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(

src/node_process.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace node {
99

1010
v8::MaybeLocal<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
1111
v8::Isolate* isolate,
12-
v8::Local<v8::Value> data);
12+
v8::Local<v8::Object> data);
1313

1414
// Most of the time, it's best to use `console.error` to write
1515
// to the process.stderr stream. However, in some cases, such as

src/node_process_object.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ MaybeLocal<Object> CreateProcessObject(
9292
title_string,
9393
ProcessTitleGetter,
9494
env->owns_process_state() ? ProcessTitleSetter : nullptr,
95-
env->as_external(),
95+
env->as_callback_data(),
9696
DEFAULT,
9797
None,
9898
SideEffectType::kHasNoSideEffect)
@@ -152,7 +152,7 @@ MaybeLocal<Object> CreateProcessObject(
152152
.ToLocalChecked()).FromJust();
153153

154154
Local<Object> env_var_proxy;
155-
if (!CreateEnvVarProxy(context, isolate, env->as_external())
155+
if (!CreateEnvVarProxy(context, isolate, env->as_callback_data())
156156
.ToLocal(&env_var_proxy))
157157
return MaybeLocal<Object>();
158158

@@ -322,7 +322,7 @@ MaybeLocal<Object> CreateProcessObject(
322322
debug_port_string,
323323
DebugPortGetter,
324324
env->owns_process_state() ? DebugPortSetter : nullptr,
325-
env->as_external())
325+
env->as_callback_data())
326326
.FromJust());
327327

328328
// process._rawDebug: may be overwritten later in JS land, but should be

src/stream_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
137137
Local<FunctionTemplate> get_write_queue_size =
138138
FunctionTemplate::New(env->isolate(),
139139
GetWriteQueueSize,
140-
env->as_external(),
140+
env->as_callback_data(),
141141
Signature::New(env->isolate(), tmpl));
142142
tmpl->PrototypeTemplate()->SetAccessorProperty(
143143
env->write_queue_size_string(),

src/tls_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ void TLSWrap::Initialize(Local<Object> target,
927927
Local<FunctionTemplate> get_write_queue_size =
928928
FunctionTemplate::New(env->isolate(),
929929
GetWriteQueueSize,
930-
env->as_external(),
930+
env->as_callback_data(),
931931
Signature::New(env->isolate(), t));
932932
t->PrototypeTemplate()->SetAccessorProperty(
933933
env->write_queue_size_string(),

src/udp_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void UDPWrap::Initialize(Local<Object> target,
105105
Local<FunctionTemplate> get_fd_templ =
106106
FunctionTemplate::New(env->isolate(),
107107
UDPWrap::GetFD,
108-
env->as_external(),
108+
env->as_callback_data(),
109109
signature);
110110

111111
t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),

0 commit comments

Comments
 (0)