Skip to content

Commit de409d8

Browse files
joyeecheungaddaleax
authored andcommitted
src: retrieve binding data from the context
Instead of passing them through the data bound to function templates, store references to them in a list embedded inside the context, and store the integer index (which is context-independent) in the function template data. This makes the function templates more context-independent, and makes it possible to embed binding data in non-main contexts.
1 parent 8f87d25 commit de409d8

17 files changed

+181
-121
lines changed

src/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,13 @@ Some internal bindings, such as the HTTP parser, maintain internal state that
402402
only affects that particular binding. In that case, one common way to store
403403
that state is through the use of `Environment::BindingScope`, which gives all
404404
new functions created within it access to an object for storing such state.
405-
That object is always a [`BaseObject`][].
405+
That object is always a `BindingDataBase`.
406406
407407
```c++
408408
// In the HTTP parser source code file:
409-
class BindingData : public BaseObject {
409+
class BindingData : public BindingDataBase {
410410
public:
411-
BindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
411+
BindingData(Environment* env, Local<Object> obj) : BindingDataBase(env, obj) {}
412412
413413
std::vector<char> parser_buffer;
414414
bool parser_buffer_in_use = false;
@@ -418,7 +418,7 @@ class BindingData : public BaseObject {
418418
419419
// Available for binding functions, e.g. the HTTP Parser constructor:
420420
static void New(const FunctionCallbackInfo<Value>& args) {
421-
BindingData* binding_data = Unwrap<BindingData>(args.Data());
421+
BindingData* binding_data = BindingDataBase::Unwrap<BindingData>(args);
422422
new Parser(binding_data, args.This());
423423
}
424424
@@ -429,7 +429,7 @@ void InitializeHttpParser(Local<Object> target,
429429
Local<Context> context,
430430
void* priv) {
431431
Environment* env = Environment::GetCurrent(context);
432-
Environment::BindingScope<BindingData> binding_scope(env);
432+
Environment::BindingScope<BindingData> binding_scope(env, context, target);
433433
if (!binding_scope) return;
434434
BindingData* binding_data = binding_scope.data;
435435

src/env-inl.h

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ inline void Environment::AssignToContext(v8::Local<v8::Context> context,
287287
// Used by Environment::GetCurrent to know that we are on a node context.
288288
context->SetAlignedPointerInEmbedderData(
289289
ContextEmbedderIndex::kContextTag, Environment::kNodeContextTagPtr);
290+
// Used to retrieve bindings
291+
context->SetAlignedPointerInEmbedderData(
292+
ContextEmbedderIndex::KBindingListIndex, &(this->bindings_));
293+
290294
#if HAVE_INSPECTOR
291295
inspector_agent()->ContextCreated(context, info);
292296
#endif // HAVE_INSPECTOR
@@ -318,55 +322,74 @@ inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
318322

319323
inline Environment* Environment::GetCurrent(
320324
const v8::FunctionCallbackInfo<v8::Value>& info) {
321-
return GetFromCallbackData(info.Data());
325+
return BindingDataBase::Unwrap<BindingDataBase>(info)->env();
322326
}
323327

324328
template <typename T>
325329
inline Environment* Environment::GetCurrent(
326330
const v8::PropertyCallbackInfo<T>& info) {
327-
return GetFromCallbackData(info.Data());
331+
return BindingDataBase::Unwrap<BindingDataBase>(info)->env();
328332
}
329333

330-
Environment* Environment::GetFromCallbackData(v8::Local<v8::Value> val) {
331-
DCHECK(val->IsObject());
332-
v8::Local<v8::Object> obj = val.As<v8::Object>();
333-
DCHECK_GE(obj->InternalFieldCount(),
334-
BaseObject::kInternalFieldCount);
335-
Environment* env = Unwrap<BaseObject>(obj)->env();
336-
DCHECK(env->as_callback_data_template()->HasInstance(obj));
337-
return env;
334+
inline BindingDataBase::BindingDataBase(Environment* env,
335+
v8::Local<v8::Object> target)
336+
: BaseObject(env, target) {}
337+
338+
template <typename T, typename U>
339+
inline T* BindingDataBase::Unwrap(const v8::PropertyCallbackInfo<U>& info) {
340+
return Unwrap<T>(info.GetIsolate()->GetCurrentContext(), info.Data());
338341
}
339342

340343
template <typename T>
341-
Environment::BindingScope<T>::BindingScope(Environment* env) : env(env) {
342-
v8::Local<v8::Object> callback_data;
343-
if (!env->MakeBindingCallbackData<T>().ToLocal(&callback_data))
344-
return;
345-
data = Unwrap<T>(callback_data);
344+
inline T* BindingDataBase::Unwrap(
345+
const v8::FunctionCallbackInfo<v8::Value>& info) {
346+
return Unwrap<T>(info.GetIsolate()->GetCurrentContext(), info.Data());
347+
}
346348

347-
// No nesting allowed currently.
348-
CHECK_EQ(env->current_callback_data(), env->as_callback_data());
349-
env->set_current_callback_data(callback_data);
349+
template <typename T>
350+
inline T* BindingDataBase::Unwrap(v8::Local<v8::Context> context,
351+
v8::Local<v8::Value> val) {
352+
CHECK(val->IsUint32());
353+
uint32_t index = val.As<v8::Uint32>()->Value();
354+
std::vector<BindingDataBase*>* list =
355+
static_cast<std::vector<BindingDataBase*>*>(
356+
context->GetAlignedPointerFromEmbedderData(
357+
ContextEmbedderIndex::KBindingListIndex));
358+
CHECK_GT(list->size(), index);
359+
T* result = static_cast<T*>(list->at(index));
360+
return result;
350361
}
351362

352363
template <typename T>
353-
Environment::BindingScope<T>::~BindingScope() {
354-
env->set_current_callback_data(env->as_callback_data());
364+
inline v8::Local<v8::Uint32> BindingDataBase::New(
365+
Environment* env,
366+
v8::Local<v8::Context> context,
367+
v8::Local<v8::Object> target) {
368+
T* data = new T(env, target);
369+
// This won't compile if T is not a BindingDataBase subclass.
370+
BindingDataBase* item = static_cast<BindingDataBase*>(data);
371+
std::vector<BindingDataBase*>* list =
372+
static_cast<std::vector<BindingDataBase*>*>(
373+
context->GetAlignedPointerFromEmbedderData(
374+
ContextEmbedderIndex::KBindingListIndex));
375+
size_t index = list->size();
376+
list->push_back(item);
377+
return v8::Integer::NewFromUnsigned(env->isolate(), index).As<v8::Uint32>();
355378
}
356379

357380
template <typename T>
358-
v8::MaybeLocal<v8::Object> Environment::MakeBindingCallbackData() {
359-
v8::Local<v8::Function> ctor;
360-
v8::Local<v8::Object> obj;
361-
if (!as_callback_data_template()->GetFunction(context()).ToLocal(&ctor) ||
362-
!ctor->NewInstance(context()).ToLocal(&obj)) {
363-
return v8::MaybeLocal<v8::Object>();
364-
}
365-
T* data = new T(this, obj);
366-
// This won't compile if T is not a BaseObject subclass.
367-
CHECK_EQ(data, static_cast<BaseObject*>(data));
368-
data->MakeWeak();
369-
return obj;
381+
Environment::BindingScope<T>::BindingScope(Environment* env,
382+
v8::Local<v8::Context> context,
383+
v8::Local<v8::Object> target)
384+
: env(env) {
385+
v8::Local<v8::Uint32> index = BindingDataBase::New<T>(env, context, target);
386+
data = BindingDataBase::Unwrap<T>(context, index);
387+
env->set_current_callback_data(index);
388+
}
389+
390+
template <typename T>
391+
Environment::BindingScope<T>::~BindingScope() {
392+
env->set_current_callback_data(env->default_callback_data());
370393
}
371394

372395
inline Environment* Environment::GetThreadLocalEnv() {
@@ -1085,7 +1108,7 @@ inline v8::Local<v8::FunctionTemplate>
10851108
v8::Local<v8::Signature> signature,
10861109
v8::ConstructorBehavior behavior,
10871110
v8::SideEffectType side_effect_type) {
1088-
v8::Local<v8::Object> external = current_callback_data();
1111+
v8::Local<v8::Value> external = current_callback_data();
10891112
return v8::FunctionTemplate::New(isolate(), callback, external,
10901113
signature, 0, behavior, side_effect_type);
10911114
}
@@ -1276,6 +1299,7 @@ void Environment::set_process_exit_handler(
12761299
}
12771300
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
12781301
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
1302+
ENVIRONMENT_CALLBACK_DATA(V)
12791303
#undef V
12801304

12811305
inline v8::Local<v8::Context> Environment::context() const {

src/env.cc

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ using v8::String;
5050
using v8::Symbol;
5151
using v8::TracingController;
5252
using v8::TryCatch;
53+
using v8::Uint32;
5354
using v8::Undefined;
5455
using v8::Value;
5556
using worker::Worker;
@@ -261,9 +262,10 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
261262
USE(cb->Call(env_->context(), Undefined(isolate), arraysize(args), args));
262263
}
263264

264-
class NoBindingData : public BaseObject {
265+
class NoBindingData : public BindingDataBase {
265266
public:
266-
NoBindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
267+
NoBindingData(Environment* env, Local<Object> obj)
268+
: BindingDataBase(env, obj) {}
267269

268270
SET_NO_MEMORY_INFO()
269271
SET_MEMORY_INFO_NAME(NoBindingData)
@@ -273,17 +275,19 @@ class NoBindingData : public BaseObject {
273275
void Environment::CreateProperties() {
274276
HandleScope handle_scope(isolate_);
275277
Local<Context> ctx = context();
278+
276279
{
277280
Context::Scope context_scope(ctx);
278281
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
279282
templ->InstanceTemplate()->SetInternalFieldCount(
280283
BaseObject::kInternalFieldCount);
281-
set_as_callback_data_template(templ);
282284

283-
Local<Object> obj = MakeBindingCallbackData<NoBindingData>()
284-
.ToLocalChecked();
285-
set_as_callback_data(obj);
286-
set_current_callback_data(obj);
285+
set_binding_data_ctor_template(templ);
286+
Local<Function> ctor = templ->GetFunction(ctx).ToLocalChecked();
287+
Local<Object> obj = ctor->NewInstance(ctx).ToLocalChecked();
288+
Local<Uint32> index = BindingDataBase::New<NoBindingData>(this, ctx, obj);
289+
set_default_callback_data(index);
290+
set_current_callback_data(index);
287291
}
288292

289293
// Store primordials setup by the per-context script in the environment.
@@ -1133,6 +1137,7 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const {
11331137
#define V(PropertyName, TypeName) \
11341138
tracker->TrackField(#PropertyName, PropertyName());
11351139
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
1140+
ENVIRONMENT_CALLBACK_DATA(V)
11361141
#undef V
11371142

11381143
// FIXME(joyeecheung): track other fields in Environment.

src/env.h

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,9 @@ constexpr size_t kFsStatsBufferLength =
390390
V(zero_return_string, "ZERO_RETURN")
391391

392392
#define ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) \
393-
V(as_callback_data_template, v8::FunctionTemplate) \
394393
V(async_wrap_ctor_template, v8::FunctionTemplate) \
395394
V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
395+
V(binding_data_ctor_template, v8::FunctionTemplate) \
396396
V(compiled_fn_entry_template, v8::ObjectTemplate) \
397397
V(dir_instance_template, v8::ObjectTemplate) \
398398
V(fd_constructor_template, v8::ObjectTemplate) \
@@ -419,8 +419,11 @@ constexpr size_t kFsStatsBufferLength =
419419
V(write_wrap_template, v8::ObjectTemplate) \
420420
V(worker_heap_snapshot_taker_template, v8::ObjectTemplate)
421421

422+
#define ENVIRONMENT_CALLBACK_DATA(V) \
423+
V(default_callback_data, v8::Uint32) \
424+
V(current_callback_data, v8::Uint32)
425+
422426
#define ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \
423-
V(as_callback_data, v8::Object) \
424427
V(async_hooks_after_function, v8::Function) \
425428
V(async_hooks_before_function, v8::Function) \
426429
V(async_hooks_binding, v8::Object) \
@@ -429,7 +432,6 @@ constexpr size_t kFsStatsBufferLength =
429432
V(async_hooks_promise_resolve_function, v8::Function) \
430433
V(buffer_prototype_object, v8::Object) \
431434
V(crypto_key_object_constructor, v8::Function) \
432-
V(current_callback_data, v8::Object) \
433435
V(domain_callback, v8::Function) \
434436
V(domexception_function, v8::Function) \
435437
V(enhance_fatal_stack_after_inspector, v8::Function) \
@@ -824,6 +826,28 @@ class CleanupHookCallback {
824826
uint64_t insertion_order_counter_;
825827
};
826828

829+
class BindingDataBase : public BaseObject {
830+
public:
831+
// Exposed for subclasses
832+
inline BindingDataBase(Environment* env, v8::Local<v8::Object> target);
833+
// Unwrap a subclass T object from a v8::Value which needs to be an
834+
// v8::Uint32
835+
template <typename T, typename U>
836+
static inline T* Unwrap(const v8::PropertyCallbackInfo<U>& info);
837+
template <typename T>
838+
static inline T* Unwrap(const v8::FunctionCallbackInfo<v8::Value>& info);
839+
840+
template <typename T>
841+
static inline T* Unwrap(v8::Local<v8::Context> context,
842+
v8::Local<v8::Value> val);
843+
// Create a BindingData of subclass T, put it into the context binding list,
844+
// return the index as v8::Integer
845+
template <typename T>
846+
static inline v8::Local<v8::Uint32> New(Environment* env,
847+
v8::Local<v8::Context> context,
848+
v8::Local<v8::Object> target);
849+
};
850+
827851
class Environment : public MemoryRetainer {
828852
public:
829853
Environment(const Environment&) = delete;
@@ -864,14 +888,14 @@ class Environment : public MemoryRetainer {
864888
static inline Environment* GetCurrent(
865889
const v8::PropertyCallbackInfo<T>& info);
866890

867-
static inline Environment* GetFromCallbackData(v8::Local<v8::Value> val);
868-
869891
// Methods created using SetMethod(), SetPrototypeMethod(), etc. inside
870892
// this scope can access the created T* object using
871893
// Unwrap<T>(args.Data()) later.
872894
template <typename T>
873895
struct BindingScope {
874-
explicit inline BindingScope(Environment* env);
896+
explicit inline BindingScope(Environment* env,
897+
v8::Local<v8::Context> context,
898+
v8::Local<v8::Object> target);
875899
inline ~BindingScope();
876900

877901
T* data = nullptr;
@@ -881,9 +905,6 @@ class Environment : public MemoryRetainer {
881905
inline bool operator !() const { return data == nullptr; }
882906
};
883907

884-
template <typename T>
885-
inline v8::MaybeLocal<v8::Object> MakeBindingCallbackData();
886-
887908
static uv_key_t thread_local_env;
888909
static inline Environment* GetThreadLocalEnv();
889910

@@ -1128,6 +1149,7 @@ class Environment : public MemoryRetainer {
11281149
#define V(PropertyName, TypeName) \
11291150
inline v8::Local<TypeName> PropertyName() const; \
11301151
inline void set_ ## PropertyName(v8::Local<TypeName> value);
1152+
ENVIRONMENT_CALLBACK_DATA(V)
11311153
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
11321154
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
11331155
#undef V
@@ -1428,6 +1450,8 @@ class Environment : public MemoryRetainer {
14281450
void RequestInterruptFromV8();
14291451
static void CheckImmediate(uv_check_t* handle);
14301452

1453+
std::vector<BindingDataBase*> bindings_;
1454+
14311455
// Use an unordered_set, so that we have efficient insertion and removal.
14321456
std::unordered_set<CleanupHookCallback,
14331457
CleanupHookCallback::Hash,
@@ -1446,6 +1470,7 @@ class Environment : public MemoryRetainer {
14461470
void ForEachBaseObject(T&& iterator);
14471471

14481472
#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName ## _;
1473+
ENVIRONMENT_CALLBACK_DATA(V)
14491474
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
14501475
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
14511476
#undef V

src/node_binding.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ namespace node {
230230

231231
using v8::Context;
232232
using v8::Exception;
233+
using v8::Function;
233234
using v8::FunctionCallbackInfo;
234235
using v8::Local;
235236
using v8::NewStringType;
@@ -556,8 +557,11 @@ inline struct node_module* FindModule(struct node_module* list,
556557
static Local<Object> InitModule(Environment* env,
557558
node_module* mod,
558559
Local<String> module) {
559-
Local<Object> exports = Object::New(env->isolate());
560560
// Internal bindings don't have a "module" object, only exports.
561+
Local<Function> ctor = env->binding_data_ctor_template()
562+
->GetFunction(env->context())
563+
.ToLocalChecked();
564+
Local<Object> exports = ctor->NewInstance(env->context()).ToLocalChecked();
561565
CHECK_NULL(mod->nm_register_func);
562566
CHECK_NOT_NULL(mod->nm_context_register_func);
563567
Local<Value> unused = Undefined(env->isolate());

src/node_context_data.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ namespace node {
2525
#define NODE_CONTEXT_TAG 35
2626
#endif
2727

28+
#ifndef NODE_BINDING_LIST
29+
#define NODE_BINDING_LIST_INDEX 36
30+
#endif
31+
2832
enum ContextEmbedderIndex {
2933
kEnvironment = NODE_CONTEXT_EMBEDDER_DATA_INDEX,
3034
kSandboxObject = NODE_CONTEXT_SANDBOX_OBJECT_INDEX,
3135
kAllowWasmCodeGeneration = NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX,
3236
kContextTag = NODE_CONTEXT_TAG,
37+
KBindingListIndex = NODE_BINDING_LIST_INDEX
3338
};
3439

3540
} // namespace node

src/node_env_var.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
379379

380380
MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
381381
Isolate* isolate,
382-
Local<Object> data) {
382+
Local<Value> data) {
383383
EscapableHandleScope scope(isolate);
384384
Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
385385
env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(

src/node_file-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
227227
return Unwrap<FSReqBase>(value.As<v8::Object>());
228228
}
229229

230-
BindingData* binding_data = Unwrap<BindingData>(args.Data());
230+
BindingData* binding_data = BindingDataBase::Unwrap<BindingData>(args);
231231
Environment* env = binding_data->env();
232232
if (value->StrictEquals(env->fs_use_promises_symbol())) {
233233
if (use_bigint) {

0 commit comments

Comments
 (0)