Browse Source

async_wrap,src: wrap promises directly

Promises do not have any internal fields by default. V8 recently added
the capability of configuring the number of internal fields on promises.
This change adds an internal field to promises allowing promises to be
wrapped directly by the PromiseWrap object. In addition to cleaner code
this avoids an extra object allocation per promise and speeds up promise
creation with async_hooks enabled by ~2x.

PR-URL: https://github.com/nodejs/node/pull/13242
Ref: https://github.com/nodejs/node/pull/13224
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
v6
Matt Loring 8 years ago
committed by Anna Henningsen
parent
commit
849f22309a
No known key found for this signature in database GPG Key ID: D8B9F5AEAE84E4CF
  1. 1
      configure
  2. 31
      src/async-wrap.cc
  3. 3
      src/env.h

1
configure

@ -954,6 +954,7 @@ def configure_v8(o):
o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs. o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs.
o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds. o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds.
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables. o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks.
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true' o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform) o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8) o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)

31
src/async-wrap.cc

@ -294,32 +294,12 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,
Local<Context> context = promise->CreationContext(); Local<Context> context = promise->CreationContext();
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
if (type == PromiseHookType::kInit) { if (type == PromiseHookType::kInit) {
// Unfortunately, promises don't have internal fields. Need a surrogate that PromiseWrap* wrap = new PromiseWrap(env, promise);
// async wrap can wrap. wrap->MakeWeak(wrap);
Local<Object> obj =
env->async_hooks_promise_object()->NewInstance(context).ToLocalChecked();
PromiseWrap* wrap = new PromiseWrap(env, obj);
v8::PropertyAttribute hidden =
static_cast<v8::PropertyAttribute>(v8::ReadOnly
| v8::DontDelete
| v8::DontEnum);
promise->DefineOwnProperty(context,
env->promise_wrap(),
v8::External::New(env->isolate(), wrap),
hidden).FromJust();
// The async tag will be destroyed at the same time as the promise as the
// only reference to it is held by the promise. This allows the promise
// wrap instance to be notified when the promise is destroyed.
promise->DefineOwnProperty(context,
env->promise_async_tag(),
obj, hidden).FromJust();
} else if (type == PromiseHookType::kResolve) { } else if (type == PromiseHookType::kResolve) {
// TODO(matthewloring): need to expose this through the async hooks api. // TODO(matthewloring): need to expose this through the async hooks api.
} }
Local<v8::Value> external_wrap = PromiseWrap* wrap = Unwrap<PromiseWrap>(promise);
promise->Get(context, env->promise_wrap()).ToLocalChecked();
PromiseWrap* wrap =
static_cast<PromiseWrap*>(external_wrap.As<v8::External>()->Value());
CHECK_NE(wrap, nullptr); CHECK_NE(wrap, nullptr);
if (type == PromiseHookType::kBefore) { if (type == PromiseHookType::kBefore) {
PreCallbackExecution(wrap, false); PreCallbackExecution(wrap, false);
@ -415,11 +395,6 @@ void AsyncWrap::Initialize(Local<Object> target,
env->SetMethod(target, "clearIdStack", ClearIdStack); env->SetMethod(target, "clearIdStack", ClearIdStack);
env->SetMethod(target, "addIdToDestroyList", QueueDestroyId); env->SetMethod(target, "addIdToDestroyList", QueueDestroyId);
Local<v8::ObjectTemplate> promise_object_template =
v8::ObjectTemplate::New(env->isolate());
promise_object_template->SetInternalFieldCount(1);
env->set_async_hooks_promise_object(promise_object_template);
v8::PropertyAttribute ReadOnlyDontDelete = v8::PropertyAttribute ReadOnlyDontDelete =
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);

3
src/env.h

@ -195,8 +195,6 @@ namespace node {
V(preference_string, "preference") \ V(preference_string, "preference") \
V(priority_string, "priority") \ V(priority_string, "priority") \
V(produce_cached_data_string, "produceCachedData") \ V(produce_cached_data_string, "produceCachedData") \
V(promise_wrap, "_promise_async_wrap") \
V(promise_async_tag, "_promise_async_wrap_tag") \
V(raw_string, "raw") \ V(raw_string, "raw") \
V(read_host_object_string, "_readHostObject") \ V(read_host_object_string, "_readHostObject") \
V(readable_string, "readable") \ V(readable_string, "readable") \
@ -258,7 +256,6 @@ namespace node {
V(async_hooks_init_function, v8::Function) \ V(async_hooks_init_function, v8::Function) \
V(async_hooks_before_function, v8::Function) \ V(async_hooks_before_function, v8::Function) \
V(async_hooks_after_function, v8::Function) \ V(async_hooks_after_function, v8::Function) \
V(async_hooks_promise_object, v8::ObjectTemplate) \
V(binding_cache_object, v8::Object) \ V(binding_cache_object, v8::Object) \
V(buffer_constructor_function, v8::Function) \ V(buffer_constructor_function, v8::Function) \
V(buffer_prototype_object, v8::Object) \ V(buffer_prototype_object, v8::Object) \

Loading…
Cancel
Save