summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2020-04-20 03:51:05 +0800
committerShelley Vohr <shelley.vohr@gmail.com>2020-05-07 08:24:55 -0700
commita292630baf0dc21fde11c9fd6a5eaf018e2b7eb5 (patch)
tree650d6a185133db583e73b972d28976332df5f6a2
parent07372e9d5b785793706728299f9a92e330e084e3 (diff)
downloadnode-new-a292630baf0dc21fde11c9fd6a5eaf018e2b7eb5.tar.gz
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. This makes the function templates more context-independent, and makes it possible to embed binding data in non-main contexts. Co-authored-by: Anna Henningsen <anna@addaleax.net> PR-URL: https://github.com/nodejs/node/pull/33139 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
-rw-r--r--src/README.md24
-rw-r--r--src/env-inl.h78
-rw-r--r--src/env.cc18
-rw-r--r--src/env.h35
-rw-r--r--src/fs_event_wrap.cc2
-rw-r--r--src/node.cc3
-rw-r--r--src/node_binding.cc6
-rw-r--r--src/node_context_data.h5
-rw-r--r--src/node_crypto.cc4
-rw-r--r--src/node_env_var.cc6
-rw-r--r--src/node_file-inl.h2
-rw-r--r--src/node_file.cc21
-rw-r--r--src/node_file.h8
-rw-r--r--src/node_http2.cc14
-rw-r--r--src/node_http2_state.h67
-rw-r--r--src/node_http_parser.cc15
-rw-r--r--src/node_native_module_env.cc2
-rw-r--r--src/node_process.h3
-rw-r--r--src/node_process_object.cc4
-rw-r--r--src/node_stat_watcher.cc3
-rw-r--r--src/node_v8.cc16
-rw-r--r--src/stream_wrap.cc2
-rw-r--r--src/tls_wrap.cc2
-rw-r--r--src/udp_wrap.cc2
-rw-r--r--src/util-inl.h31
-rw-r--r--src/util.h21
26 files changed, 233 insertions, 161 deletions
diff --git a/src/README.md b/src/README.md
index e2b256fba2..f940da3fe2 100644
--- a/src/README.md
+++ b/src/README.md
@@ -400,16 +400,23 @@ NODE_MODULE_CONTEXT_AWARE_INTERNAL(cares_wrap, Initialize)
Some internal bindings, such as the HTTP parser, maintain internal state that
only affects that particular binding. In that case, one common way to store
-that state is through the use of `Environment::BindingScope`, which gives all
-new functions created within it access to an object for storing such state.
+that state is through the use of `Environment::AddBindingData`, which gives
+binding functions access to an object for storing such state.
That object is always a [`BaseObject`][].
+Its class needs to have a static `binding_data_name` field that based on a
+constant string, in order to disambiguate it from other classes of this type,
+and which could e.g. match the binding’s name (in the example above, that would
+be `cares_wrap`).
+
```c++
// In the HTTP parser source code file:
class BindingData : public BaseObject {
public:
BindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
+ static constexpr FastStringKey binding_data_name { "http_parser" };
+
std::vector<char> parser_buffer;
bool parser_buffer_in_use = false;
@@ -418,22 +425,21 @@ class BindingData : public BaseObject {
// Available for binding functions, e.g. the HTTP Parser constructor:
static void New(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
new Parser(binding_data, args.This());
}
-// ... because the initialization function told the Environment to use this
-// BindingData class for all functions created by it:
+// ... because the initialization function told the Environment to store the
+// BindingData object:
void InitializeHttpParser(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
- Environment::BindingScope<BindingData> binding_scope(env);
- if (!binding_scope) return;
- BindingData* binding_data = binding_scope.data;
+ BindingData* const binding_data =
+ env->AddBindingData<BindingData>(context, target);
+ if (binding_data == nullptr) return;
- // Created within the Environment::BindingScope
Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
...
}
diff --git a/src/env-inl.h b/src/env-inl.h
index 9ba5bebe00..237a46ca84 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -287,6 +287,10 @@ inline void Environment::AssignToContext(v8::Local<v8::Context> context,
// Used by Environment::GetCurrent to know that we are on a node context.
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kContextTag, Environment::kNodeContextTagPtr);
+ // Used to retrieve bindings
+ context->SetAlignedPointerInEmbedderData(
+ ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));
+
#if HAVE_INSPECTOR
inspector_agent()->ContextCreated(context, info);
#endif // HAVE_INSPECTOR
@@ -318,55 +322,55 @@ inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
inline Environment* Environment::GetCurrent(
const v8::FunctionCallbackInfo<v8::Value>& info) {
- return GetFromCallbackData(info.Data());
+ return GetCurrent(info.GetIsolate()->GetCurrentContext());
}
template <typename T>
inline Environment* Environment::GetCurrent(
const v8::PropertyCallbackInfo<T>& info) {
- return GetFromCallbackData(info.Data());
+ return GetCurrent(info.GetIsolate()->GetCurrentContext());
}
-Environment* Environment::GetFromCallbackData(v8::Local<v8::Value> val) {
- DCHECK(val->IsObject());
- v8::Local<v8::Object> obj = val.As<v8::Object>();
- DCHECK_GE(obj->InternalFieldCount(),
- BaseObject::kInternalFieldCount);
- Environment* env = Unwrap<BaseObject>(obj)->env();
- DCHECK(env->as_callback_data_template()->HasInstance(obj));
- return env;
+template <typename T, typename U>
+inline T* Environment::GetBindingData(const v8::PropertyCallbackInfo<U>& info) {
+ return GetBindingData<T>(info.GetIsolate()->GetCurrentContext());
}
template <typename T>
-Environment::BindingScope<T>::BindingScope(Environment* env) : env(env) {
- v8::Local<v8::Object> callback_data;
- if (!env->MakeBindingCallbackData<T>().ToLocal(&callback_data))
- return;
- data = Unwrap<T>(callback_data);
-
- // No nesting allowed currently.
- CHECK_EQ(env->current_callback_data(), env->as_callback_data());
- env->set_current_callback_data(callback_data);
+inline T* Environment::GetBindingData(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ return GetBindingData<T>(info.GetIsolate()->GetCurrentContext());
}
template <typename T>
-Environment::BindingScope<T>::~BindingScope() {
- env->set_current_callback_data(env->as_callback_data());
+inline T* Environment::GetBindingData(v8::Local<v8::Context> context) {
+ BindingDataStore* map = static_cast<BindingDataStore*>(
+ context->GetAlignedPointerFromEmbedderData(
+ ContextEmbedderIndex::kBindingListIndex));
+ DCHECK_NOT_NULL(map);
+ auto it = map->find(T::binding_data_name);
+ if (UNLIKELY(it == map->end())) return nullptr;
+ T* result = static_cast<T*>(it->second.get());
+ DCHECK_NOT_NULL(result);
+ DCHECK_EQ(result->env(), GetCurrent(context));
+ return result;
}
template <typename T>
-v8::MaybeLocal<v8::Object> Environment::MakeBindingCallbackData() {
- v8::Local<v8::Function> ctor;
- v8::Local<v8::Object> obj;
- if (!as_callback_data_template()->GetFunction(context()).ToLocal(&ctor) ||
- !ctor->NewInstance(context()).ToLocal(&obj)) {
- return v8::MaybeLocal<v8::Object>();
- }
- T* data = new T(this, obj);
+inline T* Environment::AddBindingData(
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Object> target) {
+ DCHECK_EQ(GetCurrent(context), this);
// This won't compile if T is not a BaseObject subclass.
- CHECK_EQ(data, static_cast<BaseObject*>(data));
- data->MakeWeak();
- return obj;
+ BaseObjectPtr<T> item = MakeDetachedBaseObject<T>(this, target);
+ BindingDataStore* map = static_cast<BindingDataStore*>(
+ context->GetAlignedPointerFromEmbedderData(
+ ContextEmbedderIndex::kBindingListIndex));
+ DCHECK_NOT_NULL(map);
+ auto result = map->emplace(T::binding_data_name, item);
+ CHECK(result.second);
+ DCHECK_EQ(GetBindingData<T>(context), item.get());
+ return item.get();
}
inline Environment* Environment::GetThreadLocalEnv() {
@@ -1077,8 +1081,7 @@ inline v8::Local<v8::FunctionTemplate>
v8::Local<v8::Signature> signature,
v8::ConstructorBehavior behavior,
v8::SideEffectType side_effect_type) {
- v8::Local<v8::Object> external = current_callback_data();
- return v8::FunctionTemplate::New(isolate(), callback, external,
+ return v8::FunctionTemplate::New(isolate(), callback, v8::Local<v8::Value>(),
signature, 0, behavior, side_effect_type);
}
@@ -1270,9 +1273,10 @@ void Environment::set_process_exit_handler(
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
#undef V
- inline v8::Local<v8::Context> Environment::context() const {
- return PersistentToLocal::Strong(context_);
- }
+v8::Local<v8::Context> Environment::context() const {
+ return PersistentToLocal::Strong(context_);
+}
+
} // namespace node
// These two files depend on each other. Including base_object-inl.h after this
diff --git a/src/env.cc b/src/env.cc
index f966bfba1e..3efa5c3b9c 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -261,29 +261,17 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
USE(cb->Call(env_->context(), Undefined(isolate), arraysize(args), args));
}
-class NoBindingData : public BaseObject {
- public:
- NoBindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
-
- SET_NO_MEMORY_INFO()
- SET_MEMORY_INFO_NAME(NoBindingData)
- SET_SELF_SIZE(NoBindingData)
-};
-
void Environment::CreateProperties() {
HandleScope handle_scope(isolate_);
Local<Context> ctx = context();
+
{
Context::Scope context_scope(ctx);
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
templ->InstanceTemplate()->SetInternalFieldCount(
BaseObject::kInternalFieldCount);
- set_as_callback_data_template(templ);
- Local<Object> obj = MakeBindingCallbackData<NoBindingData>()
- .ToLocalChecked();
- set_as_callback_data(obj);
- set_current_callback_data(obj);
+ set_binding_data_ctor_template(templ);
}
// Store primordials setup by the per-context script in the environment.
@@ -674,6 +662,8 @@ void Environment::RunCleanup() {
started_cleanup_ = true;
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunCleanup", this);
+ bindings_.clear();
+ initial_base_object_count_ = 0;
CleanupHandles();
while (!cleanup_hooks_.empty()) {
diff --git a/src/env.h b/src/env.h
index 48f8a83aad..8047ac0fce 100644
--- a/src/env.h
+++ b/src/env.h
@@ -390,9 +390,9 @@ constexpr size_t kFsStatsBufferLength =
V(zero_return_string, "ZERO_RETURN")
#define ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) \
- V(as_callback_data_template, v8::FunctionTemplate) \
V(async_wrap_ctor_template, v8::FunctionTemplate) \
V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
+ V(binding_data_ctor_template, v8::FunctionTemplate) \
V(compiled_fn_entry_template, v8::ObjectTemplate) \
V(dir_instance_template, v8::ObjectTemplate) \
V(fd_constructor_template, v8::ObjectTemplate) \
@@ -420,7 +420,6 @@ constexpr size_t kFsStatsBufferLength =
V(worker_heap_snapshot_taker_template, v8::ObjectTemplate)
#define ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \
- V(as_callback_data, v8::Object) \
V(async_hooks_after_function, v8::Function) \
V(async_hooks_before_function, v8::Function) \
V(async_hooks_binding, v8::Object) \
@@ -429,7 +428,6 @@ constexpr size_t kFsStatsBufferLength =
V(async_hooks_promise_resolve_function, v8::Function) \
V(buffer_prototype_object, v8::Object) \
V(crypto_key_object_constructor, v8::Function) \
- V(current_callback_data, v8::Object) \
V(domain_callback, v8::Function) \
V(domexception_function, v8::Function) \
V(enhance_fatal_stack_after_inspector, v8::Function) \
@@ -864,25 +862,24 @@ class Environment : public MemoryRetainer {
static inline Environment* GetCurrent(
const v8::PropertyCallbackInfo<T>& info);
- static inline Environment* GetFromCallbackData(v8::Local<v8::Value> val);
-
// Methods created using SetMethod(), SetPrototypeMethod(), etc. inside
// this scope can access the created T* object using
- // Unwrap<T>(args.Data()) later.
+ // GetBindingData<T>(args) later.
template <typename T>
- struct BindingScope {
- explicit inline BindingScope(Environment* env);
- inline ~BindingScope();
-
- T* data = nullptr;
- Environment* env;
-
- inline operator bool() const { return data != nullptr; }
- inline bool operator !() const { return data == nullptr; }
- };
-
+ T* AddBindingData(v8::Local<v8::Context> context,
+ v8::Local<v8::Object> target);
+ template <typename T, typename U>
+ static inline T* GetBindingData(const v8::PropertyCallbackInfo<U>& info);
template <typename T>
- inline v8::MaybeLocal<v8::Object> MakeBindingCallbackData();
+ static inline T* GetBindingData(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+ template <typename T>
+ static inline T* GetBindingData(v8::Local<v8::Context> context);
+
+ typedef std::unordered_map<
+ FastStringKey,
+ BaseObjectPtr<BaseObject>,
+ FastStringKey::Hash> BindingDataStore;
static uv_key_t thread_local_env;
static inline Environment* GetThreadLocalEnv();
@@ -1425,6 +1422,8 @@ class Environment : public MemoryRetainer {
void RequestInterruptFromV8();
static void CheckImmediate(uv_check_t* handle);
+ BindingDataStore bindings_;
+
// Use an unordered_set, so that we have efficient insertion and removal.
std::unordered_set<CleanupHookCallback,
CleanupHookCallback::Hash,
diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc
index b4b110cc2c..9b6c553a63 100644
--- a/src/fs_event_wrap.cc
+++ b/src/fs_event_wrap.cc
@@ -108,7 +108,7 @@ void FSEventWrap::Initialize(Local<Object> target,
Local<FunctionTemplate> get_initialized_templ =
FunctionTemplate::New(env->isolate(),
GetInitialized,
- env->current_callback_data(),
+ Local<Value>(),
Signature::New(env->isolate(), t));
t->PrototypeTemplate()->SetAccessorProperty(
diff --git a/src/node.cc b/src/node.cc
index 649ac43fbe..240f1f2e3b 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -331,8 +331,7 @@ MaybeLocal<Value> Environment::BootstrapNode() {
Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
Local<Object> env_var_proxy;
- if (!CreateEnvVarProxy(context(), isolate_, current_callback_data())
- .ToLocal(&env_var_proxy) ||
+ if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
return MaybeLocal<Value>();
}
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 592d0ca2a3..fdd84c39a2 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -230,6 +230,7 @@ namespace node {
using v8::Context;
using v8::Exception;
+using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::NewStringType;
@@ -556,8 +557,11 @@ inline struct node_module* FindModule(struct node_module* list,
static Local<Object> InitModule(Environment* env,
node_module* mod,
Local<String> module) {
- Local<Object> exports = Object::New(env->isolate());
// Internal bindings don't have a "module" object, only exports.
+ Local<Function> ctor = env->binding_data_ctor_template()
+ ->GetFunction(env->context())
+ .ToLocalChecked();
+ Local<Object> exports = ctor->NewInstance(env->context()).ToLocalChecked();
CHECK_NULL(mod->nm_register_func);
CHECK_NOT_NULL(mod->nm_context_register_func);
Local<Value> unused = Undefined(env->isolate());
diff --git a/src/node_context_data.h b/src/node_context_data.h
index 807ba56c7c..912e65b427 100644
--- a/src/node_context_data.h
+++ b/src/node_context_data.h
@@ -25,11 +25,16 @@ namespace node {
#define NODE_CONTEXT_TAG 35
#endif
+#ifndef NODE_BINDING_LIST
+#define NODE_BINDING_LIST_INDEX 36
+#endif
+
enum ContextEmbedderIndex {
kEnvironment = NODE_CONTEXT_EMBEDDER_DATA_INDEX,
kSandboxObject = NODE_CONTEXT_SANDBOX_OBJECT_INDEX,
kAllowWasmCodeGeneration = NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX,
kContextTag = NODE_CONTEXT_TAG,
+ kBindingListIndex = NODE_BINDING_LIST_INDEX
};
} // namespace node
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index afdb2e3c27..d53a6d2f23 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -505,7 +505,7 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> ctx_getter_templ =
FunctionTemplate::New(env->isolate(),
CtxGetter,
- env->current_callback_data(),
+ Local<Value>(),
Signature::New(env->isolate(), t));
@@ -5103,7 +5103,7 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> verify_error_getter_templ =
FunctionTemplate::New(env->isolate(),
DiffieHellman::VerifyErrorGetter,
- env->current_callback_data(),
+ Local<Value>(),
Signature::New(env->isolate(), t),
/* length */ 0,
ConstructorBehavior::kThrow,
diff --git a/src/node_env_var.cc b/src/node_env_var.cc
index 8eaf79538a..23eaad4858 100644
--- a/src/node_env_var.cc
+++ b/src/node_env_var.cc
@@ -377,13 +377,11 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
env->env_vars()->Enumerate(env->isolate()));
}
-MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
- Isolate* isolate,
- Local<Object> data) {
+MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context, Isolate* isolate) {
EscapableHandleScope scope(isolate);
Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(
- EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, data,
+ EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, Local<Value>(),
PropertyHandlerFlags::kHasNoSideEffect));
return scope.EscapeMaybe(env_proxy_template->NewInstance(context));
}
diff --git a/src/node_file-inl.h b/src/node_file-inl.h
index d30d773010..2ad8c73f05 100644
--- a/src/node_file-inl.h
+++ b/src/node_file-inl.h
@@ -227,7 +227,7 @@ FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
return Unwrap<FSReqBase>(value.As<v8::Object>());
}
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
if (value->StrictEquals(env->fs_use_promises_symbol())) {
if (use_bigint) {
diff --git a/src/node_file.cc b/src/node_file.cc
index 203ec5c8ca..be18b18fdd 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -158,7 +158,7 @@ FileHandle* FileHandle::New(BindingData* binding_data,
}
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
CHECK(args.IsConstructCall());
CHECK(args[0]->IsInt32());
@@ -543,7 +543,7 @@ void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
}
@@ -948,7 +948,7 @@ static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
}
static void Stat(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
const int argc = args.Length();
@@ -979,7 +979,7 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
}
static void LStat(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
const int argc = args.Length();
@@ -1011,7 +1011,7 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
}
static void FStat(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
const int argc = args.Length();
@@ -1674,7 +1674,7 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
}
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
Isolate* isolate = env->isolate();
@@ -2303,15 +2303,18 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const {
file_handle_read_wrap_freelist);
}
+// TODO(addaleax): Remove once we're on C++17.
+constexpr FastStringKey BindingData::binding_data_name;
+
void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
Isolate* isolate = env->isolate();
- Environment::BindingScope<BindingData> binding_scope(env);
- if (!binding_scope) return;
- BindingData* binding_data = binding_scope.data;
+ BindingData* const binding_data =
+ env->AddBindingData<BindingData>(context, target);
+ if (binding_data == nullptr) return;
env->SetMethod(target, "access", Access);
env->SetMethod(target, "close", Close);
diff --git a/src/node_file.h b/src/node_file.h
index 1fda81361f..7690f27284 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -16,9 +16,9 @@ class FileHandleReadWrap;
class BindingData : public BaseObject {
public:
explicit BindingData(Environment* env, v8::Local<v8::Object> wrap)
- : BaseObject(env, wrap),
- stats_field_array(env->isolate(), kFsStatsBufferLength),
- stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {}
+ : BaseObject(env, wrap),
+ stats_field_array(env->isolate(), kFsStatsBufferLength),
+ stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {}
AliasedFloat64Array stats_field_array;
AliasedBigUint64Array stats_field_bigint_array;
@@ -26,6 +26,8 @@ class BindingData : public BaseObject {
std::vector<BaseObjectPtr<FileHandleReadWrap>>
file_handle_read_wrap_freelist;
+ static constexpr FastStringKey binding_data_name { "fs" };
+
void MemoryInfo(MemoryTracker* tracker) const override;
SET_SELF_SIZE(BindingData)
SET_MEMORY_INFO_NAME(BindingData)
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 6637166e95..25f353bb14 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -2351,7 +2351,7 @@ void HttpErrorString(const FunctionCallbackInfo<Value>& args) {
// would be suitable, for instance, for creating the Base64
// output for an HTTP2-Settings header field.
void PackSettings(const FunctionCallbackInfo<Value>& args) {
- Http2State* state = Unwrap<Http2State>(args.Data());
+ Http2State* state = Environment::GetBindingData<Http2State>(args);
args.GetReturnValue().Set(Http2Settings::Pack(state));
}
@@ -2359,7 +2359,7 @@ void PackSettings(const FunctionCallbackInfo<Value>& args) {
// default SETTINGS. RefreshDefaultSettings updates that TypedArray with the
// default values.
void RefreshDefaultSettings(const FunctionCallbackInfo<Value>& args) {
- Http2State* state = Unwrap<Http2State>(args.Data());
+ Http2State* state = Environment::GetBindingData<Http2State>(args);
Http2Settings::RefreshDefaults(state);
}
@@ -2423,7 +2423,7 @@ void Http2Session::RefreshState(const FunctionCallbackInfo<Value>& args) {
// Constructor for new Http2Session instances.
void Http2Session::New(const FunctionCallbackInfo<Value>& args) {
- Http2State* state = Unwrap<Http2State>(args.Data());
+ Http2State* state = Environment::GetBindingData<Http2State>(args);
Environment* env = state->env();
CHECK(args.IsConstructCall());
SessionType type =
@@ -2941,6 +2941,9 @@ void Http2State::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("root_buffer", root_buffer);
}
+// TODO(addaleax): Remove once we're on C++17.
+constexpr FastStringKey Http2State::binding_data_name;
+
// Set up the process.binding('http2') binding.
void Initialize(Local<Object> target,
Local<Value> unused,
@@ -2950,9 +2953,8 @@ void Initialize(Local<Object> target,
Isolate* isolate = env->isolate();
HandleScope handle_scope(isolate);
- Environment::BindingScope<Http2State> binding_scope(env);
- if (!binding_scope) return;
- Http2State* state = binding_scope.data;
+ Http2State* const state = env->AddBindingData<Http2State>(context, target);
+ if (state == nullptr) return;
#define SET_STATE_TYPEDARRAY(name, field) \
target->Set(context, \
diff --git a/src/node_http2_state.h b/src/node_http2_state.h
index 80efb40cd2..2e9d3e5d6b 100644
--- a/src/node_http2_state.h
+++ b/src/node_http2_state.h
@@ -83,41 +83,36 @@ namespace http2 {
class Http2State : public BaseObject {
public:
Http2State(Environment* env, v8::Local<v8::Object> obj)
- : BaseObject(env, obj),
- root_buffer(
- env->isolate(),
- sizeof(http2_state_internal)),
- session_state_buffer(
- env->isolate(),
- offsetof(http2_state_internal, session_state_buffer),
- IDX_SESSION_STATE_COUNT,
- root_buffer),
- stream_state_buffer(
- env->isolate(),
- offsetof(http2_state_internal, stream_state_buffer),
- IDX_STREAM_STATE_COUNT,
- root_buffer),
- stream_stats_buffer(
- env->isolate(),
- offsetof(http2_state_internal, stream_stats_buffer),
- IDX_STREAM_STATS_COUNT,
- root_buffer),
- session_stats_buffer(
- env->isolate(),
- offsetof(http2_state_internal, session_stats_buffer),
- IDX_SESSION_STATS_COUNT,
- root_buffer),
- options_buffer(
- env->isolate(),
- offsetof(http2_state_internal, options_buffer),
- IDX_OPTIONS_FLAGS + 1,
- root_buffer),
- settings_buffer(
- env->isolate(),
- offsetof(http2_state_internal, settings_buffer),
- IDX_SETTINGS_COUNT + 1,
- root_buffer) {
- }
+ : BaseObject(env, obj),
+ root_buffer(env->isolate(), sizeof(http2_state_internal)),
+ session_state_buffer(
+ env->isolate(),
+ offsetof(http2_state_internal, session_state_buffer),
+ IDX_SESSION_STATE_COUNT,
+ root_buffer),
+ stream_state_buffer(
+ env->isolate(),
+ offsetof(http2_state_internal, stream_state_buffer),
+ IDX_STREAM_STATE_COUNT,
+ root_buffer),
+ stream_stats_buffer(
+ env->isolate(),
+ offsetof(http2_state_internal, stream_stats_buffer),
+ IDX_STREAM_STATS_COUNT,
+ root_buffer),
+ session_stats_buffer(
+ env->isolate(),
+ offsetof(http2_state_internal, session_stats_buffer),
+ IDX_SESSION_STATS_COUNT,
+ root_buffer),
+ options_buffer(env->isolate(),
+ offsetof(http2_state_internal, options_buffer),
+ IDX_OPTIONS_FLAGS + 1,
+ root_buffer),
+ settings_buffer(env->isolate(),
+ offsetof(http2_state_internal, settings_buffer),
+ IDX_SETTINGS_COUNT + 1,
+ root_buffer) {}
AliasedUint8Array root_buffer;
AliasedFloat64Array session_state_buffer;
@@ -131,6 +126,8 @@ class Http2State : public BaseObject {
SET_SELF_SIZE(Http2State)
SET_MEMORY_INFO_NAME(Http2State)
+ static constexpr FastStringKey binding_data_name { "http2" };
+
private:
struct http2_state_internal {
// doubles first so that they are always sizeof(double)-aligned
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc
index f98e9f5c7b..c7a3df8d06 100644
--- a/src/node_http_parser.cc
+++ b/src/node_http_parser.cc
@@ -84,7 +84,10 @@ inline bool IsOWS(char c) {
class BindingData : public BaseObject {
public:
- BindingData(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
+ BindingData(Environment* env, Local<Object> obj)
+ : BaseObject(env, obj) {}
+
+ static constexpr FastStringKey binding_data_name { "http_parser" };
std::vector<char> parser_buffer;
bool parser_buffer_in_use = false;
@@ -96,6 +99,9 @@ class BindingData : public BaseObject {
SET_MEMORY_INFO_NAME(BindingData)
};
+// TODO(addaleax): Remove once we're on C++17.
+constexpr FastStringKey BindingData::binding_data_name;
+
// helper class for the Parser
struct StringPtr {
StringPtr() {
@@ -444,7 +450,7 @@ class Parser : public AsyncWrap, public StreamListener {
}
static void New(const FunctionCallbackInfo<Value>& args) {
- BindingData* binding_data = Unwrap<BindingData>(args.Data());
+ BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
new Parser(binding_data, args.This());
}
@@ -920,8 +926,9 @@ void InitializeHttpParser(Local<Object> target,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
- Environment::BindingScope<BindingData> binding_scope(env);
- if (!binding_scope) return;
+ BindingData* const binding_data =
+ env->AddBindingData<BindingData>(context, target);
+ if (binding_data == nullptr) return;
Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount);
diff --git a/src/node_native_module_env.cc b/src/node_native_module_env.cc
index b48ae962dd..be647b01c6 100644
--- a/src/node_native_module_env.cc
+++ b/src/node_native_module_env.cc
@@ -190,7 +190,7 @@ void NativeModuleEnv::Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"),
GetModuleCategories,
nullptr,
- env->as_callback_data(),
+ Local<Value>(),
DEFAULT,
None,
SideEffectType::kHasNoSideEffect)
diff --git a/src/node_process.h b/src/node_process.h
index ad86b449f9..2e87385348 100644
--- a/src/node_process.h
+++ b/src/node_process.h
@@ -8,8 +8,7 @@
namespace node {
v8::MaybeLocal<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
- v8::Isolate* isolate,
- v8::Local<v8::Object> data);
+ v8::Isolate* isolate);
// Most of the time, it's best to use `console.error` to write
// to the process.stderr stream. However, in some cases, such as
diff --git a/src/node_process_object.cc b/src/node_process_object.cc
index ee7d771c71..ca17da9583 100644
--- a/src/node_process_object.cc
+++ b/src/node_process_object.cc
@@ -147,7 +147,7 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) {
FIXED_ONE_BYTE_STRING(isolate, "title"),
ProcessTitleGetter,
env->owns_process_state() ? ProcessTitleSetter : nullptr,
- env->current_callback_data(),
+ Local<Value>(),
DEFAULT,
None,
SideEffectType::kHasNoSideEffect)
@@ -198,7 +198,7 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) {
FIXED_ONE_BYTE_STRING(isolate, "debugPort"),
DebugPortGetter,
env->owns_process_state() ? DebugPortSetter : nullptr,
- env->current_callback_data())
+ Local<Value>())
.FromJust());
}
diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc
index af23affc41..70903525ba 100644
--- a/src/node_stat_watcher.cc
+++ b/src/node_stat_watcher.cc
@@ -95,7 +95,8 @@ void StatWatcher::Callback(uv_fs_poll_t* handle,
void StatWatcher::New(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
- fs::BindingData* binding_data = Unwrap<fs::BindingData>(args.Data());
+ fs::BindingData* binding_data =
+ Environment::GetBindingData<fs::BindingData>(args);
new StatWatcher(binding_data, args.This(), args[0]->IsTrue());
}
diff --git a/src/node_v8.cc b/src/node_v8.cc
index 7174d9ae7f..047ca59409 100644
--- a/src/node_v8.cc
+++ b/src/node_v8.cc
@@ -96,6 +96,8 @@ class BindingData : public BaseObject {
heap_code_statistics_buffer(env->isolate(),
kHeapCodeStatisticsPropertiesCount) {}
+ static constexpr FastStringKey binding_data_name { "v8" };
+
AliasedFloat64Array heap_statistics_buffer;
AliasedFloat64Array heap_space_statistics_buffer;
AliasedFloat64Array heap_code_statistics_buffer;
@@ -111,6 +113,8 @@ class BindingData : public BaseObject {
SET_MEMORY_INFO_NAME(BindingData)
};
+// TODO(addaleax): Remove once we're on C++17.
+constexpr FastStringKey BindingData::binding_data_name;
void CachedDataVersionTag(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -121,7 +125,7 @@ void CachedDataVersionTag(const FunctionCallbackInfo<Value>& args) {
}
void UpdateHeapStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
- BindingData* data = Unwrap<BindingData>(args.Data());
+ BindingData* data = Environment::GetBindingData<BindingData>(args);
HeapStatistics s;
args.GetIsolate()->GetHeapStatistics(&s);
AliasedFloat64Array& buffer = data->heap_statistics_buffer;
@@ -132,7 +136,7 @@ void UpdateHeapStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
void UpdateHeapSpaceStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
- BindingData* data = Unwrap<BindingData>(args.Data());
+ BindingData* data = Environment::GetBindingData<BindingData>(args);
HeapSpaceStatistics s;
Isolate* const isolate = args.GetIsolate();
CHECK(args[0]->IsUint32());
@@ -147,7 +151,7 @@ void UpdateHeapSpaceStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
}
void UpdateHeapCodeStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
- BindingData* data = Unwrap<BindingData>(args.Data());
+ BindingData* data = Environment::GetBindingData<BindingData>(args);
HeapCodeStatistics s;
args.GetIsolate()->GetHeapCodeAndMetadataStatistics(&s);
AliasedFloat64Array& buffer = data->heap_code_statistics_buffer;
@@ -170,9 +174,9 @@ void Initialize(Local<Object> target,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
- Environment::BindingScope<BindingData> binding_scope(env);
- if (!binding_scope) return;
- BindingData* binding_data = binding_scope.data;
+ BindingData* const binding_data =
+ env->AddBindingData<BindingData>(context, target);
+ if (binding_data == nullptr) return;
env->SetMethodNoSideEffect(target, "cachedDataVersionTag",
CachedDataVersionTag);
diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc
index 90b2bb9341..bd396110fc 100644
--- a/src/stream_wrap.cc
+++ b/src/stream_wrap.cc
@@ -142,7 +142,7 @@ Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
Local<FunctionTemplate> get_write_queue_size =
FunctionTemplate::New(env->isolate(),
GetWriteQueueSize,
- env->current_callback_data(),
+ Local<Value>(),
Signature::New(env->isolate(), tmpl));
tmpl->PrototypeTemplate()->SetAccessorProperty(
env->write_queue_size_string(),
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
index df6a989dfb..0c2c2bbc01 100644
--- a/src/tls_wrap.cc
+++ b/src/tls_wrap.cc
@@ -1276,7 +1276,7 @@ void TLSWrap::Initialize(Local<Object> target,
Local<FunctionTemplate> get_write_queue_size =
FunctionTemplate::New(env->isolate(),
GetWriteQueueSize,
- env->current_callback_data(),
+ Local<Value>(),
Signature::New(env->isolate(), t));
t->PrototypeTemplate()->SetAccessorProperty(
env->write_queue_size_string(),
diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc
index 1c42481f17..9013bc9fe3 100644
--- a/src/udp_wrap.cc
+++ b/src/udp_wrap.cc
@@ -145,7 +145,7 @@ void UDPWrap::Initialize(Local<Object> target,
Local<FunctionTemplate> get_fd_templ =
FunctionTemplate::New(env->isolate(),
UDPWrap::GetFD,
- env->current_callback_data(),
+ Local<Value>(),
signature);
t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),
diff --git a/src/util-inl.h b/src/util-inl.h
index d44ee09fef..6b4bdfe034 100644
--- a/src/util-inl.h
+++ b/src/util-inl.h
@@ -533,6 +533,37 @@ inline bool IsSafeJsInt(v8::Local<v8::Value> v) {
return false;
}
+constexpr size_t FastStringKey::HashImpl(const char* str) {
+ // Low-quality hash (djb2), but just fine for current use cases.
+ size_t h = 5381;
+ do {
+ h = h * 33 + *str; // NOLINT(readability/pointer_notation)
+ } while (*(str++) != '\0');
+ return h;
+}
+
+constexpr size_t FastStringKey::Hash::operator()(
+ const FastStringKey& key) const {
+ return key.cached_hash_;
+}
+
+constexpr bool FastStringKey::operator==(const FastStringKey& other) const {
+ const char* p1 = name_;
+ const char* p2 = other.name_;
+ if (p1 == p2) return true;
+ do {
+ if (*(p1++) != *(p2++)) return false;
+ } while (*p1 != '\0');
+ return true;
+}
+
+constexpr FastStringKey::FastStringKey(const char* name)
+ : name_(name), cached_hash_(HashImpl(name)) {}
+
+constexpr const char* FastStringKey::c_str() const {
+ return name_;
+}
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/src/util.h b/src/util.h
index 5eaa20b760..979091e6d6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -764,6 +764,27 @@ class PersistentToLocal {
}
};
+// Can be used as a key for std::unordered_map when lookup performance is more
+// important than size and the keys are statically used to avoid redundant hash
+// computations.
+class FastStringKey {
+ public:
+ constexpr explicit FastStringKey(const char* name);
+
+ struct Hash {
+ constexpr size_t operator()(const FastStringKey& key) const;
+ };
+ constexpr bool operator==(const FastStringKey& other) const;
+
+ constexpr const char* c_str() const;
+
+ private:
+ static constexpr size_t HashImpl(const char* str);
+
+ const char* name_;
+ size_t cached_hash_;
+};
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS