diff options
| author | Stephen Belanger <stephen.belanger@datadoghq.com> | 2021-06-23 22:35:46 -0700 |
|---|---|---|
| committer | Node.js GitHub Bot <github-bot@iojs.org> | 2021-07-23 03:54:31 +0000 |
| commit | 84dfa1f3e315b8016264dce46e6782bb55693917 (patch) | |
| tree | 9726eb6f8728cdaac49c4760d15810d8ef8ceb90 /src/async_wrap.cc | |
| parent | 44ee6c26232622c286d7b221f07b7014b031e064 (diff) | |
| download | node-new-84dfa1f3e315b8016264dce46e6782bb55693917.tar.gz | |
async_hooks: eliminate native PromiseHook
PR-URL: https://github.com/nodejs/node/pull/39135
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Diffstat (limited to 'src/async_wrap.cc')
| -rw-r--r-- | src/async_wrap.cc | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 1bca27d6a0..3fb2f8c309 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -39,19 +39,12 @@ using v8::Global; using v8::HandleScope; using v8::Integer; using v8::Isolate; -using v8::Just; using v8::Local; -using v8::Maybe; using v8::MaybeLocal; -using v8::Name; using v8::Nothing; using v8::Number; using v8::Object; -using v8::ObjectTemplate; -using v8::Promise; -using v8::PromiseHookType; using v8::PropertyAttribute; -using v8::PropertyCallbackInfo; using v8::ReadOnly; using v8::String; using v8::Undefined; @@ -161,255 +154,6 @@ void AsyncWrap::EmitAfter(Environment* env, double async_id) { // TODO(addaleax): Remove once we're on C++17. constexpr double AsyncWrap::kInvalidAsyncId; -static Maybe<double> GetAssignedPromiseAsyncId(Environment* env, - Local<Promise> promise, - Local<Value> id_symbol) { - Local<Value> maybe_async_id; - if (!promise->Get(env->context(), id_symbol).ToLocal(&maybe_async_id)) { - return Nothing<double>(); - } - return maybe_async_id->IsNumber() - ? maybe_async_id->NumberValue(env->context()) - : Just(AsyncWrap::kInvalidAsyncId); -} - -class PromiseWrap : public AsyncWrap { - public: - PromiseWrap(Environment* env, Local<Object> object, bool silent) - : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) { - MakeWeak(); - } - - PromiseWrap(Environment* env, Local<Object> object, double asyncId, - double triggerAsyncId) - : AsyncWrap(env, object, PROVIDER_PROMISE, asyncId, triggerAsyncId) { - MakeWeak(); - } - - SET_NO_MEMORY_INFO() - SET_MEMORY_INFO_NAME(PromiseWrap) - SET_SELF_SIZE(PromiseWrap) - - static PromiseWrap* New(Environment* env, - Local<Promise> promise, - bool silent); - static void GetAsyncId(Local<Name> property, - const PropertyCallbackInfo<Value>& args); - static void GetTriggerAsyncId(Local<Name> property, - const PropertyCallbackInfo<Value>& args); - - static void Initialize(Environment* env); -}; - -PromiseWrap* PromiseWrap::New(Environment* env, - Local<Promise> promise, - bool silent) { - Local<Context> context = env->context(); - - Local<Object> obj; - if (!env->promise_wrap_template()->NewInstance(context).ToLocal(&obj)) - return nullptr; - - CHECK_NULL(promise->GetAlignedPointerFromInternalField(0)); - promise->SetInternalField(0, obj); - - // Skip for init events - if (silent) { - double async_id; - double trigger_async_id; - if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol()) - .To(&async_id)) return nullptr; - if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol()) - .To(&trigger_async_id)) return nullptr; - - if (async_id != AsyncWrap::kInvalidAsyncId && - trigger_async_id != AsyncWrap::kInvalidAsyncId) { - return new PromiseWrap( - env, obj, async_id, trigger_async_id); - } - } - - return new PromiseWrap(env, obj, silent); -} - -void PromiseWrap::GetAsyncId(Local<Name> property, - const PropertyCallbackInfo<Value>& info) { - Isolate* isolate = info.GetIsolate(); - HandleScope scope(isolate); - - PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder()); - double value = wrap->get_async_id(); - - info.GetReturnValue().Set(Number::New(isolate, value)); -} - -void PromiseWrap::GetTriggerAsyncId(Local<Name> property, - const PropertyCallbackInfo<Value>& info) { - Isolate* isolate = info.GetIsolate(); - HandleScope scope(isolate); - - PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder()); - double value = wrap->get_trigger_async_id(); - - info.GetReturnValue().Set(Number::New(isolate, value)); -} - -void PromiseWrap::Initialize(Environment* env) { - Isolate* isolate = env->isolate(); - HandleScope scope(isolate); - - Local<FunctionTemplate> ctor = FunctionTemplate::New(isolate); - ctor->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "PromiseWrap")); - - Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate(); - env->set_promise_wrap_template(promise_wrap_template); - - promise_wrap_template->SetInternalFieldCount( - PromiseWrap::kInternalFieldCount); - - promise_wrap_template->SetAccessor( - env->async_id_symbol(), - PromiseWrap::GetAsyncId); - - promise_wrap_template->SetAccessor( - env->trigger_async_id_symbol(), - PromiseWrap::GetTriggerAsyncId); -} - -static PromiseWrap* extractPromiseWrap(Local<Promise> promise) { - // This check is imperfect. If the internal field is set, it should - // be an object. If it's not, we just ignore it. Ideally v8 would - // have had GetInternalField returning a MaybeLocal but this works - // for now. - Local<Value> obj = promise->GetInternalField(0); - return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr; -} - -static uint16_t ToAsyncHooksType(PromiseHookType type) { - switch (type) { - case PromiseHookType::kInit: return AsyncHooks::kInit; - case PromiseHookType::kBefore: return AsyncHooks::kBefore; - case PromiseHookType::kAfter: return AsyncHooks::kAfter; - case PromiseHookType::kResolve: return AsyncHooks::kPromiseResolve; - } - UNREACHABLE(); -} - -// Simplified JavaScript hook fast-path for when there is no destroy hook -static void FastPromiseHook(PromiseHookType type, Local<Promise> promise, - Local<Value> parent) { - Local<Context> context = promise->GetCreationContext().ToLocalChecked(); - Environment* env = Environment::GetCurrent(context); - if (env == nullptr) return; - - if (type == PromiseHookType::kBefore && - env->async_hooks()->fields()[AsyncHooks::kBefore] == 0) { - double async_id; - double trigger_async_id; - if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol()) - .To(&async_id)) return; - if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol()) - .To(&trigger_async_id)) return; - - if (async_id != AsyncWrap::kInvalidAsyncId && - trigger_async_id != AsyncWrap::kInvalidAsyncId) { - env->async_hooks()->push_async_context( - async_id, trigger_async_id, promise); - return; - } - } - - if (type == PromiseHookType::kAfter && - env->async_hooks()->fields()[AsyncHooks::kAfter] == 0) { - double async_id; - if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol()) - .To(&async_id)) return; - - if (async_id != AsyncWrap::kInvalidAsyncId) { - if (env->execution_async_id() == async_id) { - // This condition might not be true if async_hooks was enabled during - // the promise callback execution. - env->async_hooks()->pop_async_context(async_id); - } - return; - } - } - - if (type == PromiseHookType::kResolve && - env->async_hooks()->fields()[AsyncHooks::kPromiseResolve] == 0) { - return; - } - - // Getting up to this point means either init type or - // that there are active hooks of another type. - // In both cases fast-path JS hook should be called. - - Local<Value> argv[] = { - Integer::New(env->isolate(), ToAsyncHooksType(type)), - promise, - parent - }; - - TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); - Local<Function> promise_hook = env->promise_hook_handler(); - USE(promise_hook->Call(context, Undefined(env->isolate()), 3, argv)); -} - -static void FullPromiseHook(PromiseHookType type, Local<Promise> promise, - Local<Value> parent) { - Local<Context> context = promise->GetCreationContext().ToLocalChecked(); - - Environment* env = Environment::GetCurrent(context); - if (env == nullptr) return; - TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment), - "EnvPromiseHook", env); - - PromiseWrap* wrap = extractPromiseWrap(promise); - if (type == PromiseHookType::kInit || wrap == nullptr) { - bool silent = type != PromiseHookType::kInit; - - // set parent promise's async Id as this promise's triggerAsyncId - if (parent->IsPromise()) { - // parent promise exists, current promise - // is a chained promise, so we set parent promise's id as - // current promise's triggerAsyncId - Local<Promise> parent_promise = parent.As<Promise>(); - PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise); - if (parent_wrap == nullptr) { - parent_wrap = PromiseWrap::New(env, parent_promise, true); - if (parent_wrap == nullptr) return; - } - - AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap); - wrap = PromiseWrap::New(env, promise, silent); - } else { - wrap = PromiseWrap::New(env, promise, silent); - } - } - - if (wrap == nullptr) return; - - if (type == PromiseHookType::kBefore) { - env->async_hooks()->push_async_context(wrap->get_async_id(), - wrap->get_trigger_async_id(), wrap->object()); - wrap->EmitTraceEventBefore(); - AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id()); - } else if (type == PromiseHookType::kAfter) { - wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id()); - AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id()); - if (env->execution_async_id() == wrap->get_async_id()) { - // This condition might not be true if async_hooks was enabled during - // the promise callback execution. - // Popping it off the stack can be skipped in that case, because it is - // known that it would correspond to exactly one call with - // PromiseHookType::kBefore that was not witnessed by the PromiseHook. - env->async_hooks()->pop_async_context(wrap->get_async_id()); - } - } else if (type == PromiseHookType::kResolve) { - AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id()); - } -} - static void SetupHooks(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); @@ -441,17 +185,6 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) { #undef SET_HOOK_FN } -static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) { - Environment* env = Environment::GetCurrent(args); - - if (args[0]->IsFunction()) { - env->set_promise_hook_handler(args[0].As<Function>()); - args.GetIsolate()->SetPromiseHook(FastPromiseHook); - } else { - args.GetIsolate()->SetPromiseHook(FullPromiseHook); - } -} - static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); @@ -462,17 +195,6 @@ static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) { args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>()); } -static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) { - Environment* env = Environment::GetCurrent(args); - env->set_promise_hook_handler(Local<Function>()); - - // The per-Isolate API provides no way of knowing whether there are multiple - // users of the PromiseHook. That hopefully goes away when V8 introduces - // a per-context API. - args.GetIsolate()->SetPromiseHook(nullptr); -} - - class DestroyParam { public: double asyncId; @@ -639,9 +361,7 @@ void AsyncWrap::Initialize(Local<Object> target, env->SetMethod(target, "executionAsyncResource", ExecutionAsyncResource); env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack); env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId); - env->SetMethod(target, "enablePromiseHook", EnablePromiseHook); env->SetMethod(target, "setPromiseHooks", SetPromiseHooks); - env->SetMethod(target, "disablePromiseHook", DisablePromiseHook); env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook); PropertyAttribute ReadOnlyDontDelete = @@ -720,9 +440,6 @@ void AsyncWrap::Initialize(Local<Object> target, env->set_async_hooks_destroy_function(Local<Function>()); env->set_async_hooks_promise_resolve_function(Local<Function>()); env->set_async_hooks_binding(target); - - // TODO(qard): maybe this should be GetConstructorTemplate instead? - PromiseWrap::Initialize(env); } void AsyncWrap::RegisterExternalReferences( @@ -734,15 +451,11 @@ void AsyncWrap::RegisterExternalReferences( registry->Register(ExecutionAsyncResource); registry->Register(ClearAsyncIdStack); registry->Register(QueueDestroyAsyncId); - registry->Register(EnablePromiseHook); registry->Register(SetPromiseHooks); - registry->Register(DisablePromiseHook); registry->Register(RegisterDestroyHook); registry->Register(AsyncWrap::GetAsyncId); registry->Register(AsyncWrap::AsyncReset); registry->Register(AsyncWrap::GetProviderType); - registry->Register(PromiseWrap::GetAsyncId); - registry->Register(PromiseWrap::GetTriggerAsyncId); } AsyncWrap::AsyncWrap(Environment* env, |
