From 78447666ea2e70b32b082267fd3a6965ac80f6c2 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 14 Nov 2017 13:34:52 +0100 Subject: src: rename async-wrap -> async_wrap This commit renames async-wrap to async_wrap for consitency with other c++ source files. PR-URL: https://github.com/nodejs/node/pull/17022 Reviewed-By: James M Snell Reviewed-By: Refael Ackermann Reviewed-By: Anatoli Papirovski --- node.gyp | 8 +- src/async-wrap-inl.h | 71 ---- src/async-wrap.cc | 831 ----------------------------------------------- src/async-wrap.h | 187 ----------- src/async_wrap-inl.h | 71 ++++ src/async_wrap.cc | 831 +++++++++++++++++++++++++++++++++++++++++++++++ src/async_wrap.h | 187 +++++++++++ src/cares_wrap.cc | 2 +- src/connect_wrap.h | 2 +- src/env.cc | 2 +- src/fs_event_wrap.cc | 2 +- src/handle_wrap.cc | 2 +- src/handle_wrap.h | 2 +- src/js_stream.cc | 2 +- src/js_stream.h | 2 +- src/node.cc | 2 +- src/node_crypto.cc | 2 +- src/node_crypto.h | 2 +- src/node_http_parser.cc | 2 +- src/node_stat_watcher.cc | 2 +- src/node_stat_watcher.h | 2 +- src/node_zlib.cc | 2 +- src/pipe_wrap.cc | 2 +- src/pipe_wrap.h | 2 +- src/req-wrap-inl.h | 2 +- src/req-wrap.h | 2 +- src/signal_wrap.cc | 2 +- src/stream_base.h | 2 +- src/tcp_wrap.h | 2 +- src/timer_wrap.cc | 2 +- src/tls_wrap.cc | 2 +- src/tls_wrap.h | 2 +- src/udp_wrap.h | 2 +- 33 files changed, 1119 insertions(+), 1119 deletions(-) delete mode 100644 src/async-wrap-inl.h delete mode 100644 src/async-wrap.cc delete mode 100644 src/async-wrap.h create mode 100644 src/async_wrap-inl.h create mode 100644 src/async_wrap.cc create mode 100644 src/async_wrap.h diff --git a/node.gyp b/node.gyp index 661e260e527..7212303460c 100644 --- a/node.gyp +++ b/node.gyp @@ -191,7 +191,7 @@ ], 'sources': [ - 'src/async-wrap.cc', + 'src/async_wrap.cc', 'src/cares_wrap.cc', 'src/connection_wrap.cc', 'src/connect_wrap.cc', @@ -245,8 +245,8 @@ 'src/uv.cc', # headers to make for a more pleasant IDE experience 'src/aliased_buffer.h', - 'src/async-wrap.h', - 'src/async-wrap-inl.h', + 'src/async_wrap.h', + 'src/async_wrap-inl.h', 'src/base-object.h', 'src/base-object-inl.h', 'src/connection_wrap.h', @@ -837,7 +837,7 @@ 'conditions': [ ['node_target_type!="static_library"', { 'libraries': [ - '<(OBJ_PATH)<(OBJ_SEPARATOR)async-wrap.<(OBJ_SUFFIX)', + '<(OBJ_PATH)<(OBJ_SEPARATOR)async_wrap.<(OBJ_SUFFIX)', '<(OBJ_PATH)<(OBJ_SEPARATOR)env.<(OBJ_SUFFIX)', '<(OBJ_PATH)<(OBJ_SEPARATOR)node.<(OBJ_SUFFIX)', '<(OBJ_PATH)<(OBJ_SEPARATOR)node_buffer.<(OBJ_SUFFIX)', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h deleted file mode 100644 index 617d51dc59f..00000000000 --- a/src/async-wrap-inl.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SRC_ASYNC_WRAP_INL_H_ -#define SRC_ASYNC_WRAP_INL_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "async-wrap.h" -#include "base-object-inl.h" -#include "node_internals.h" - -namespace node { - -inline AsyncWrap::ProviderType AsyncWrap::provider_type() const { - return provider_type_; -} - - -inline double AsyncWrap::get_async_id() const { - return async_id_; -} - - -inline double AsyncWrap::get_trigger_async_id() const { - return trigger_async_id_; -} - - -inline v8::MaybeLocal AsyncWrap::MakeCallback( - const v8::Local symbol, - int argc, - v8::Local* argv) { - v8::Local cb_v = object()->Get(symbol); - CHECK(cb_v->IsFunction()); - return MakeCallback(cb_v.As(), argc, argv); -} - - -inline v8::MaybeLocal AsyncWrap::MakeCallback( - uint32_t index, - int argc, - v8::Local* argv) { - v8::Local cb_v = object()->Get(index); - CHECK(cb_v->IsFunction()); - return MakeCallback(cb_v.As(), argc, argv); -} - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_ASYNC_WRAP_INL_H_ diff --git a/src/async-wrap.cc b/src/async-wrap.cc deleted file mode 100644 index 75af5c1a081..00000000000 --- a/src/async-wrap.cc +++ /dev/null @@ -1,831 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "async-wrap-inl.h" -#include "env-inl.h" -#include "util-inl.h" - -#include "uv.h" -#include "v8.h" -#include "v8-profiler.h" - -using v8::Array; -using v8::Context; -using v8::Float64Array; -using v8::Function; -using v8::FunctionCallbackInfo; -using v8::FunctionTemplate; -using v8::HandleScope; -using v8::HeapProfiler; -using v8::Integer; -using v8::Isolate; -using v8::Local; -using v8::MaybeLocal; -using v8::Number; -using v8::Object; -using v8::ObjectTemplate; -using v8::Promise; -using v8::PromiseHookType; -using v8::PropertyCallbackInfo; -using v8::RetainedObjectInfo; -using v8::String; -using v8::Symbol; -using v8::TryCatch; -using v8::Undefined; -using v8::Value; - -using AsyncHooks = node::Environment::AsyncHooks; - -namespace node { - -static const char* const provider_names[] = { -#define V(PROVIDER) \ - #PROVIDER, - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V -}; - - -// Report correct information in a heapdump. - -class RetainedAsyncInfo: public RetainedObjectInfo { - public: - explicit RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap); - - void Dispose() override; - bool IsEquivalent(RetainedObjectInfo* other) override; - intptr_t GetHash() override; - const char* GetLabel() override; - intptr_t GetSizeInBytes() override; - - private: - const char* label_; - const AsyncWrap* wrap_; - const int length_; -}; - - -RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap) - : label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]), - wrap_(wrap), - length_(wrap->self_size()) { -} - - -void RetainedAsyncInfo::Dispose() { - delete this; -} - - -bool RetainedAsyncInfo::IsEquivalent(RetainedObjectInfo* other) { - return label_ == other->GetLabel() && - wrap_ == static_cast(other)->wrap_; -} - - -intptr_t RetainedAsyncInfo::GetHash() { - return reinterpret_cast(wrap_); -} - - -const char* RetainedAsyncInfo::GetLabel() { - return label_; -} - - -intptr_t RetainedAsyncInfo::GetSizeInBytes() { - return length_; -} - - -RetainedObjectInfo* WrapperInfo(uint16_t class_id, Local wrapper) { - // No class_id should be the provider type of NONE. - CHECK_GT(class_id, NODE_ASYNC_ID_OFFSET); - // And make sure the class_id doesn't extend past the last provider. - CHECK_LE(class_id - NODE_ASYNC_ID_OFFSET, AsyncWrap::PROVIDERS_LENGTH); - CHECK(wrapper->IsObject()); - CHECK(!wrapper.IsEmpty()); - - Local object = wrapper.As(); - CHECK_GT(object->InternalFieldCount(), 0); - - AsyncWrap* wrap = Unwrap(object); - CHECK_NE(nullptr, wrap); - - return new RetainedAsyncInfo(class_id, wrap); -} - - -// end RetainedAsyncInfo - - -static void DestroyAsyncIdsCallback(uv_timer_t* handle) { - Environment* env = Environment::from_destroy_async_ids_timer_handle(handle); - - HandleScope handle_scope(env->isolate()); - Context::Scope context_scope(env->context()); - Local fn = env->async_hooks_destroy_function(); - - TryCatch try_catch(env->isolate()); - - do { - std::vector destroy_async_id_list; - destroy_async_id_list.swap(*env->destroy_async_id_list()); - for (auto async_id : destroy_async_id_list) { - // Want each callback to be cleaned up after itself, instead of cleaning - // them all up after the while() loop completes. - HandleScope scope(env->isolate()); - Local async_id_value = Number::New(env->isolate(), async_id); - MaybeLocal ret = fn->Call( - env->context(), Undefined(env->isolate()), 1, &async_id_value); - - if (ret.IsEmpty()) { - ClearFatalExceptionHandlers(env); - FatalException(env->isolate(), try_catch); - UNREACHABLE(); - } - } - } while (!env->destroy_async_id_list()->empty()); -} - - -void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) { - AsyncHooks* async_hooks = env->async_hooks(); - - if (async_hooks->fields()[AsyncHooks::kPromiseResolve] == 0) - return; - - Local async_id_value = Number::New(env->isolate(), async_id); - Local fn = env->async_hooks_promise_resolve_function(); - TryCatch try_catch(env->isolate()); - MaybeLocal ar = fn->Call( - env->context(), Undefined(env->isolate()), 1, &async_id_value); - if (ar.IsEmpty()) { - ClearFatalExceptionHandlers(env); - FatalException(env->isolate(), try_catch); - UNREACHABLE(); - } -} - - -void AsyncWrap::EmitTraceEventBefore() { - switch (provider_type()) { -#define V(PROVIDER) \ - case PROVIDER_ ## PROVIDER: \ - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("node.async_hooks", \ - #PROVIDER "_CALLBACK", static_cast(get_async_id())); \ - break; - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V - default: - UNREACHABLE(); - } -} - - -void AsyncWrap::EmitBefore(Environment* env, double async_id) { - AsyncHooks* async_hooks = env->async_hooks(); - - if (async_hooks->fields()[AsyncHooks::kBefore] == 0) - return; - - Local async_id_value = Number::New(env->isolate(), async_id); - Local fn = env->async_hooks_before_function(); - TryCatch try_catch(env->isolate()); - MaybeLocal ar = fn->Call( - env->context(), Undefined(env->isolate()), 1, &async_id_value); - if (ar.IsEmpty()) { - ClearFatalExceptionHandlers(env); - FatalException(env->isolate(), try_catch); - UNREACHABLE(); - } -} - - -void AsyncWrap::EmitTraceEventAfter() { - switch (provider_type()) { -#define V(PROVIDER) \ - case PROVIDER_ ## PROVIDER: \ - TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks", \ - #PROVIDER "_CALLBACK", static_cast(get_async_id())); \ - break; - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V - default: - UNREACHABLE(); - } -} - - -void AsyncWrap::EmitAfter(Environment* env, double async_id) { - AsyncHooks* async_hooks = env->async_hooks(); - - if (async_hooks->fields()[AsyncHooks::kAfter] == 0) - return; - - // If the user's callback failed then the after() hooks will be called at the - // end of _fatalException(). - Local async_id_value = Number::New(env->isolate(), async_id); - Local fn = env->async_hooks_after_function(); - TryCatch try_catch(env->isolate()); - MaybeLocal ar = fn->Call( - env->context(), Undefined(env->isolate()), 1, &async_id_value); - if (ar.IsEmpty()) { - ClearFatalExceptionHandlers(env); - FatalException(env->isolate(), try_catch); - UNREACHABLE(); - } -} - -class PromiseWrap : public AsyncWrap { - public: - PromiseWrap(Environment* env, Local object, bool silent) - : AsyncWrap(env, object, silent) { - MakeWeak(this); - } - size_t self_size() const override { return sizeof(*this); } - - static constexpr int kPromiseField = 1; - static constexpr int kParentAsyncIdField = 2; - static constexpr int kInternalFieldCount = 3; - - static PromiseWrap* New(Environment* env, - Local promise, - PromiseWrap* parent_wrap, - bool silent); - static void GetPromise(Local property, - const PropertyCallbackInfo& info); - static void getParentAsyncId(Local property, - const PropertyCallbackInfo& info); -}; - -PromiseWrap* PromiseWrap::New(Environment* env, - Local promise, - PromiseWrap* parent_wrap, - bool silent) { - Local object = env->promise_wrap_template() - ->NewInstance(env->context()).ToLocalChecked(); - object->SetInternalField(PromiseWrap::kPromiseField, promise); - if (parent_wrap != nullptr) { - object->SetInternalField(PromiseWrap::kParentAsyncIdField, - Number::New(env->isolate(), - parent_wrap->get_async_id())); - } - CHECK_EQ(promise->GetAlignedPointerFromInternalField(0), nullptr); - promise->SetInternalField(0, object); - return new PromiseWrap(env, object, silent); -} - -void PromiseWrap::GetPromise(Local property, - const PropertyCallbackInfo& info) { - info.GetReturnValue().Set(info.Holder()->GetInternalField(kPromiseField)); -} - -void PromiseWrap::getParentAsyncId(Local property, - const PropertyCallbackInfo& info) { - info.GetReturnValue().Set( - info.Holder()->GetInternalField(kParentAsyncIdField)); -} - -static void PromiseHook(PromiseHookType type, Local promise, - Local parent, void* arg) { - Environment* env = static_cast(arg); - Local resource_object_value = promise->GetInternalField(0); - PromiseWrap* wrap = nullptr; - if (resource_object_value->IsObject()) { - Local resource_object = resource_object_value.As(); - wrap = Unwrap(resource_object); - } - - if (type == PromiseHookType::kInit || wrap == nullptr) { - bool silent = type != PromiseHookType::kInit; - PromiseWrap* parent_wrap = nullptr; - - // 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 parent_promise = parent.As(); - Local parent_resource = parent_promise->GetInternalField(0); - if (parent_resource->IsObject()) { - parent_wrap = Unwrap(parent_resource.As()); - } - - if (parent_wrap == nullptr) { - parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true); - } - // get id from parentWrap - double trigger_async_id = parent_wrap->get_async_id(); - env->set_init_trigger_async_id(trigger_async_id); - } - - wrap = PromiseWrap::New(env, promise, parent_wrap, silent); - } - - CHECK_NE(wrap, nullptr); - if (type == PromiseHookType::kBefore) { - env->async_hooks()->push_async_ids( - wrap->get_async_id(), wrap->get_trigger_async_id()); - wrap->EmitTraceEventBefore(); - AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id()); - } else if (type == PromiseHookType::kAfter) { - wrap->EmitTraceEventAfter(); - 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 is 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_id(wrap->get_async_id()); - } - } else if (type == PromiseHookType::kResolve) { - AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id()); - } -} - - -static void SetupHooks(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - if (!args[0]->IsObject()) - return env->ThrowTypeError("first argument must be an object"); - - // All of init, before, after, destroy are supplied by async_hooks - // internally, so this should every only be called once. At which time all - // the functions should be set. Detect this by checking if init !IsEmpty(). - CHECK(env->async_hooks_init_function().IsEmpty()); - - Local fn_obj = args[0].As(); - -#define SET_HOOK_FN(name) \ - Local name##_v = fn_obj->Get( \ - env->context(), \ - FIXED_ONE_BYTE_STRING(env->isolate(), #name)).ToLocalChecked(); \ - CHECK(name##_v->IsFunction()); \ - env->set_async_hooks_##name##_function(name##_v.As()); - - SET_HOOK_FN(init); - SET_HOOK_FN(before); - SET_HOOK_FN(after); - SET_HOOK_FN(destroy); - SET_HOOK_FN(promise_resolve); -#undef SET_HOOK_FN - - { - Local ctor = - FunctionTemplate::New(env->isolate()); - ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap")); - Local promise_wrap_template = ctor->InstanceTemplate(); - promise_wrap_template->SetInternalFieldCount( - PromiseWrap::kInternalFieldCount); - promise_wrap_template->SetAccessor( - FIXED_ONE_BYTE_STRING(env->isolate(), "promise"), - PromiseWrap::GetPromise); - promise_wrap_template->SetAccessor( - FIXED_ONE_BYTE_STRING(env->isolate(), "parentId"), - PromiseWrap::getParentAsyncId); - env->set_promise_wrap_template(promise_wrap_template); - } -} - - -static void EnablePromiseHook(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - env->AddPromiseHook(PromiseHook, static_cast(env)); -} - - -static void DisablePromiseHook(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - // Delay the call to `RemovePromiseHook` because we might currently be - // between the `before` and `after` calls of a Promise. - env->isolate()->EnqueueMicrotask([](void* data) { - Environment* env = static_cast(data); - env->RemovePromiseHook(PromiseHook, data); - }, static_cast(env)); -} - - -class DestroyParam { - public: - double asyncId; - v8::Persistent target; - v8::Persistent propBag; -}; - - -void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { - HandleScope scope(info.GetIsolate()); - - Environment* env = Environment::GetCurrent(info.GetIsolate()); - DestroyParam* p = info.GetParameter(); - Local prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag); - - Local val = prop_bag->Get(env->destroyed_string()); - if (val->IsFalse()) { - AsyncWrap::EmitDestroy(env, p->asyncId); - } - p->target.Reset(); - p->propBag.Reset(); - delete p; -} - - -static void RegisterDestroyHook(const FunctionCallbackInfo& args) { - CHECK(args[0]->IsObject()); - CHECK(args[1]->IsNumber()); - CHECK(args[2]->IsObject()); - - Isolate* isolate = args.GetIsolate(); - DestroyParam* p = new DestroyParam(); - p->asyncId = args[1].As()->Value(); - p->target.Reset(isolate, args[0].As()); - p->propBag.Reset(isolate, args[2].As()); - p->target.SetWeak( - p, AsyncWrap::WeakCallback, v8::WeakCallbackType::kParameter); -} - - -void AsyncWrap::GetAsyncId(const FunctionCallbackInfo& args) { - AsyncWrap* wrap; - args.GetReturnValue().Set(-1); - ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); - args.GetReturnValue().Set(wrap->get_async_id()); -} - - -void AsyncWrap::PushAsyncIds(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail - // then the checks in push_async_ids() and pop_async_id() will. - double async_id = args[0]->NumberValue(env->context()).FromJust(); - double trigger_async_id = args[1]->NumberValue(env->context()).FromJust(); - env->async_hooks()->push_async_ids(async_id, trigger_async_id); -} - - -void AsyncWrap::PopAsyncIds(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - double async_id = args[0]->NumberValue(env->context()).FromJust(); - args.GetReturnValue().Set(env->async_hooks()->pop_async_id(async_id)); -} - - -void AsyncWrap::AsyncIdStackSize(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - args.GetReturnValue().Set( - static_cast(env->async_hooks()->stack_size())); -} - - -void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - env->async_hooks()->clear_async_id_stack(); -} - - -void AsyncWrap::AsyncReset(const FunctionCallbackInfo& args) { - AsyncWrap* wrap; - ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); - double execution_async_id = args[0]->IsNumber() ? args[0]->NumberValue() : -1; - wrap->AsyncReset(execution_async_id); -} - - -void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo& args) { - CHECK(args[0]->IsNumber()); - AsyncWrap::EmitDestroy( - Environment::GetCurrent(args), args[0]->NumberValue()); -} - -void AsyncWrap::AddWrapMethods(Environment* env, - Local constructor, - int flag) { - env->SetProtoMethod(constructor, "getAsyncId", AsyncWrap::GetAsyncId); - if (flag & kFlagHasReset) - env->SetProtoMethod(constructor, "asyncReset", AsyncWrap::AsyncReset); -} - -void AsyncWrap::Initialize(Local target, - Local unused, - Local context) { - Environment* env = Environment::GetCurrent(context); - Isolate* isolate = env->isolate(); - HandleScope scope(isolate); - - env->SetMethod(target, "setupHooks", SetupHooks); - env->SetMethod(target, "pushAsyncIds", PushAsyncIds); - env->SetMethod(target, "popAsyncIds", PopAsyncIds); - env->SetMethod(target, "asyncIdStackSize", AsyncIdStackSize); - env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack); - env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId); - env->SetMethod(target, "enablePromiseHook", EnablePromiseHook); - env->SetMethod(target, "disablePromiseHook", DisablePromiseHook); - env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook); - - v8::PropertyAttribute ReadOnlyDontDelete = - static_cast(v8::ReadOnly | v8::DontDelete); - -#define FORCE_SET_TARGET_FIELD(obj, str, field) \ - (obj)->DefineOwnProperty(context, \ - FIXED_ONE_BYTE_STRING(isolate, str), \ - field, \ - ReadOnlyDontDelete).FromJust() - - // Attach the uint32_t[] where each slot contains the count of the number of - // callbacks waiting to be called on a particular event. It can then be - // incremented/decremented from JS quickly to communicate to C++ if there are - // any callbacks waiting to be called. - FORCE_SET_TARGET_FIELD(target, - "async_hook_fields", - env->async_hooks()->fields().GetJSArray()); - - // The following v8::Float64Array has 5 fields. These fields are shared in - // this way to allow JS and C++ to read/write each value as quickly as - // possible. The fields are represented as follows: - // - // kAsyncUid: Maintains the state of the next unique id to be assigned. - // - // kInitTriggerAsyncId: Write the id of the resource responsible for a - // handle's creation just before calling the new handle's constructor. - // After the new handle is constructed kInitTriggerAsyncId is set back to 0. - FORCE_SET_TARGET_FIELD(target, - "async_id_fields", - env->async_hooks()->async_id_fields().GetJSArray()); - - Local constants = Object::New(isolate); -#define SET_HOOKS_CONSTANT(name) \ - FORCE_SET_TARGET_FIELD( \ - constants, #name, Integer::New(isolate, AsyncHooks::name)); - - SET_HOOKS_CONSTANT(kInit); - SET_HOOKS_CONSTANT(kBefore); - SET_HOOKS_CONSTANT(kAfter); - SET_HOOKS_CONSTANT(kDestroy); - SET_HOOKS_CONSTANT(kPromiseResolve); - SET_HOOKS_CONSTANT(kTotals); - SET_HOOKS_CONSTANT(kCheck); - SET_HOOKS_CONSTANT(kExecutionAsyncId); - SET_HOOKS_CONSTANT(kTriggerAsyncId); - SET_HOOKS_CONSTANT(kAsyncIdCounter); - SET_HOOKS_CONSTANT(kInitTriggerAsyncId); -#undef SET_HOOKS_CONSTANT - FORCE_SET_TARGET_FIELD(target, "constants", constants); - - Local async_providers = Object::New(isolate); -#define V(p) \ - FORCE_SET_TARGET_FIELD( \ - async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p)); - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V - FORCE_SET_TARGET_FIELD(target, "Providers", async_providers); - - // These Symbols are used throughout node so the stored values on each object - // can be accessed easily across files. - FORCE_SET_TARGET_FIELD( - target, - "async_id_symbol", - Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "asyncId"))); - FORCE_SET_TARGET_FIELD( - target, - "trigger_async_id_symbol", - Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "triggerAsyncId"))); - -#undef FORCE_SET_TARGET_FIELD - - env->set_async_hooks_init_function(Local()); - env->set_async_hooks_before_function(Local()); - env->set_async_hooks_after_function(Local()); - env->set_async_hooks_destroy_function(Local()); - env->set_async_hooks_promise_resolve_function(Local()); -} - - -void LoadAsyncWrapperInfo(Environment* env) { - HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler(); -#define V(PROVIDER) \ - heap_profiler->SetWrapperClassInfoProvider( \ - (NODE_ASYNC_ID_OFFSET + AsyncWrap::PROVIDER_ ## PROVIDER), WrapperInfo); - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V -} - - -AsyncWrap::AsyncWrap(Environment* env, - Local object, - ProviderType provider, - double execution_async_id) - : BaseObject(env, object), - provider_type_(provider) { - CHECK_NE(provider, PROVIDER_NONE); - CHECK_GE(object->InternalFieldCount(), 1); - - // Shift provider value over to prevent id collision. - persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider); - - // Use AsyncReset() call to execute the init() callbacks. - AsyncReset(execution_async_id); -} - - -// This is specifically used by the PromiseWrap constructor. -AsyncWrap::AsyncWrap(Environment* env, - Local object, - bool silent) - : BaseObject(env, object), - provider_type_(PROVIDER_PROMISE) { - CHECK_GE(object->InternalFieldCount(), 1); - - // Shift provider value over to prevent id collision. - persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider_type_); - - // Use AsyncReset() call to execute the init() callbacks. - AsyncReset(-1, silent); -} - - -AsyncWrap::~AsyncWrap() { - EmitTraceEventDestroy(); - EmitDestroy(env(), get_async_id()); -} - -void AsyncWrap::EmitTraceEventDestroy() { - switch (provider_type()) { - #define V(PROVIDER) \ - case PROVIDER_ ## PROVIDER: \ - TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks", \ - #PROVIDER, static_cast(get_async_id())); \ - break; - NODE_ASYNC_PROVIDER_TYPES(V) - #undef V - default: - UNREACHABLE(); - } -} - -void AsyncWrap::EmitDestroy(Environment* env, double async_id) { - if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0) - return; - - if (env->destroy_async_id_list()->empty()) { - uv_timer_start(env->destroy_async_ids_timer_handle(), - DestroyAsyncIdsCallback, 0, 0); - } - - env->destroy_async_id_list()->push_back(async_id); -} - - -// Generalized call for both the constructor and for handles that are pooled -// and reused over their lifetime. This way a new uid can be assigned when -// the resource is pulled out of the pool and put back into use. -void AsyncWrap::AsyncReset(double execution_async_id, bool silent) { - async_id_ = - execution_async_id == -1 ? env()->new_async_id() : execution_async_id; - trigger_async_id_ = env()->get_init_trigger_async_id(); - - switch (provider_type()) { -#define V(PROVIDER) \ - case PROVIDER_ ## PROVIDER: \ - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("node.async_hooks", \ - #PROVIDER, static_cast(get_async_id()), \ - "triggerAsyncId", static_cast(get_trigger_async_id())); \ - break; - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V - default: - UNREACHABLE(); - } - - if (silent) return; - - EmitAsyncInit(env(), object(), - env()->async_hooks()->provider_string(provider_type()), - async_id_, trigger_async_id_); -} - - -void AsyncWrap::EmitAsyncInit(Environment* env, - Local object, - Local type, - double async_id, - double trigger_async_id) { - CHECK(!object.IsEmpty()); - CHECK(!type.IsEmpty()); - AsyncHooks* async_hooks = env->async_hooks(); - - // Nothing to execute, so can continue normally. - if (async_hooks->fields()[AsyncHooks::kInit] == 0) { - return; - } - - HandleScope scope(env->isolate()); - Local init_fn = env->async_hooks_init_function(); - - Local argv[] = { - Number::New(env->isolate(), async_id), - type, - Number::New(env->isolate(), trigger_async_id), - object, - }; - - TryCatch try_catch(env->isolate()); - MaybeLocal ret = init_fn->Call( - env->context(), object, arraysize(argv), argv); - - if (ret.IsEmpty()) { - ClearFatalExceptionHandlers(env); - FatalException(env->isolate(), try_catch); - } -} - - -MaybeLocal AsyncWrap::MakeCallback(const Local cb, - int argc, - Local* argv) { - EmitTraceEventBefore(); - - async_context context { get_async_id(), get_trigger_async_id() }; - MaybeLocal ret = InternalMakeCallback( - env(), object(), cb, argc, argv, context); - - EmitTraceEventAfter(); - - return ret; -} - - -/* Public C++ embedder API */ - - -async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { - return Environment::GetCurrent(isolate)->execution_async_id(); -} - - -async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) { - return Environment::GetCurrent(isolate)->trigger_async_id(); -} - - -async_context EmitAsyncInit(Isolate* isolate, - Local resource, - const char* name, - async_id trigger_async_id) { - Local type = - String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized) - .ToLocalChecked(); - return EmitAsyncInit(isolate, resource, type, trigger_async_id); -} - -async_context EmitAsyncInit(Isolate* isolate, - Local resource, - v8::Local name, - async_id trigger_async_id) { - Environment* env = Environment::GetCurrent(isolate); - - // Initialize async context struct - if (trigger_async_id == -1) - trigger_async_id = env->get_init_trigger_async_id(); - - async_context context = { - env->new_async_id(), // async_id_ - trigger_async_id // trigger_async_id_ - }; - - // Run init hooks - AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id, - context.trigger_async_id); - - return context; -} - -void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) { - AsyncWrap::EmitDestroy( - Environment::GetCurrent(isolate), asyncContext.async_id); -} - -} // namespace node - -NODE_BUILTIN_MODULE_CONTEXT_AWARE(async_wrap, node::AsyncWrap::Initialize) diff --git a/src/async-wrap.h b/src/async-wrap.h deleted file mode 100644 index 222cda1fd7e..00000000000 --- a/src/async-wrap.h +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SRC_ASYNC_WRAP_H_ -#define SRC_ASYNC_WRAP_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "base-object.h" -#include "v8.h" - -#include - -namespace node { - -#define NODE_ASYNC_ID_OFFSET 0xA1C - -#define NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \ - V(NONE) \ - V(DNSCHANNEL) \ - V(FSEVENTWRAP) \ - V(FSREQWRAP) \ - V(GETADDRINFOREQWRAP) \ - V(GETNAMEINFOREQWRAP) \ - V(HTTP2SESSION) \ - V(HTTP2SESSIONSHUTDOWNWRAP) \ - V(HTTPPARSER) \ - V(JSSTREAM) \ - V(PIPECONNECTWRAP) \ - V(PIPEWRAP) \ - V(PROCESSWRAP) \ - V(PROMISE) \ - V(QUERYWRAP) \ - V(SHUTDOWNWRAP) \ - V(SIGNALWRAP) \ - V(STATWATCHER) \ - V(TCPCONNECTWRAP) \ - V(TCPWRAP) \ - V(TIMERWRAP) \ - V(TTYWRAP) \ - V(UDPSENDWRAP) \ - V(UDPWRAP) \ - V(WRITEWRAP) \ - V(ZLIB) - -#if HAVE_OPENSSL -#define NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) \ - V(SSLCONNECTION) \ - V(PBKDF2REQUEST) \ - V(RANDOMBYTESREQUEST) \ - V(TLSWRAP) -#else -#define NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) -#endif // HAVE_OPENSSL - -#if HAVE_INSPECTOR -#define NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) \ - V(INSPECTORJSBINDING) -#else -#define NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) -#endif // HAVE_INSPECTOR - -#define NODE_ASYNC_PROVIDER_TYPES(V) \ - NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \ - NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) \ - NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) - -class Environment; -class DestroyParam; - -class AsyncWrap : public BaseObject { - public: - enum ProviderType { -#define V(PROVIDER) \ - PROVIDER_ ## PROVIDER, - NODE_ASYNC_PROVIDER_TYPES(V) -#undef V - PROVIDERS_LENGTH, - }; - - enum Flags { - kFlagNone = 0x0, - kFlagHasReset = 0x1 - }; - - AsyncWrap(Environment* env, - v8::Local object, - ProviderType provider, - double execution_async_id = -1); - - virtual ~AsyncWrap(); - - static void AddWrapMethods(Environment* env, - v8::Local constructor, - int flags = kFlagNone); - - static void Initialize(v8::Local target, - v8::Local unused, - v8::Local context); - - static void GetAsyncId(const v8::FunctionCallbackInfo& args); - static void PushAsyncIds(const v8::FunctionCallbackInfo& args); - static void PopAsyncIds(const v8::FunctionCallbackInfo& args); - static void AsyncIdStackSize(const v8::FunctionCallbackInfo& args); - static void ClearAsyncIdStack( - const v8::FunctionCallbackInfo& args); - static void AsyncReset(const v8::FunctionCallbackInfo& args); - static void QueueDestroyAsyncId( - const v8::FunctionCallbackInfo& args); - - static void EmitAsyncInit(Environment* env, - v8::Local object, - v8::Local type, - double async_id, - double trigger_async_id); - - static void EmitDestroy(Environment* env, double async_id); - static void EmitBefore(Environment* env, double async_id); - static void EmitAfter(Environment* env, double async_id); - static void EmitPromiseResolve(Environment* env, double async_id); - - void EmitTraceEventBefore(); - void EmitTraceEventAfter(); - void EmitTraceEventDestroy(); - - - inline ProviderType provider_type() const; - - inline double get_async_id() const; - - inline double get_trigger_async_id() const; - - void AsyncReset(double execution_async_id = -1, bool silent = false); - - // Only call these within a valid HandleScope. - v8::MaybeLocal MakeCallback(const v8::Local cb, - int argc, - v8::Local* argv); - inline v8::MaybeLocal MakeCallback( - const v8::Local symbol, - int argc, - v8::Local* argv); - inline v8::MaybeLocal MakeCallback(uint32_t index, - int argc, - v8::Local* argv); - - virtual size_t self_size() const = 0; - - static void WeakCallback(const v8::WeakCallbackInfo &info); - - private: - friend class PromiseWrap; - - // This is specifically used by the PromiseWrap constructor. - AsyncWrap(Environment* env, v8::Local promise, bool silent); - inline AsyncWrap(); - const ProviderType provider_type_; - // Because the values may be Reset(), cannot be made const. - double async_id_; - double trigger_async_id_; -}; - -void LoadAsyncWrapperInfo(Environment* env); - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_ASYNC_WRAP_H_ diff --git a/src/async_wrap-inl.h b/src/async_wrap-inl.h new file mode 100644 index 00000000000..219dfa71b6c --- /dev/null +++ b/src/async_wrap-inl.h @@ -0,0 +1,71 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SRC_ASYNC_WRAP_INL_H_ +#define SRC_ASYNC_WRAP_INL_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "async_wrap.h" +#include "base-object-inl.h" +#include "node_internals.h" + +namespace node { + +inline AsyncWrap::ProviderType AsyncWrap::provider_type() const { + return provider_type_; +} + + +inline double AsyncWrap::get_async_id() const { + return async_id_; +} + + +inline double AsyncWrap::get_trigger_async_id() const { + return trigger_async_id_; +} + + +inline v8::MaybeLocal AsyncWrap::MakeCallback( + const v8::Local symbol, + int argc, + v8::Local* argv) { + v8::Local cb_v = object()->Get(symbol); + CHECK(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); +} + + +inline v8::MaybeLocal AsyncWrap::MakeCallback( + uint32_t index, + int argc, + v8::Local* argv) { + v8::Local cb_v = object()->Get(index); + CHECK(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); +} + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_ASYNC_WRAP_INL_H_ diff --git a/src/async_wrap.cc b/src/async_wrap.cc new file mode 100644 index 00000000000..7410557d2eb --- /dev/null +++ b/src/async_wrap.cc @@ -0,0 +1,831 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "async_wrap-inl.h" +#include "env-inl.h" +#include "util-inl.h" + +#include "uv.h" +#include "v8.h" +#include "v8-profiler.h" + +using v8::Array; +using v8::Context; +using v8::Float64Array; +using v8::Function; +using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; +using v8::HandleScope; +using v8::HeapProfiler; +using v8::Integer; +using v8::Isolate; +using v8::Local; +using v8::MaybeLocal; +using v8::Number; +using v8::Object; +using v8::ObjectTemplate; +using v8::Promise; +using v8::PromiseHookType; +using v8::PropertyCallbackInfo; +using v8::RetainedObjectInfo; +using v8::String; +using v8::Symbol; +using v8::TryCatch; +using v8::Undefined; +using v8::Value; + +using AsyncHooks = node::Environment::AsyncHooks; + +namespace node { + +static const char* const provider_names[] = { +#define V(PROVIDER) \ + #PROVIDER, + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V +}; + + +// Report correct information in a heapdump. + +class RetainedAsyncInfo: public RetainedObjectInfo { + public: + explicit RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap); + + void Dispose() override; + bool IsEquivalent(RetainedObjectInfo* other) override; + intptr_t GetHash() override; + const char* GetLabel() override; + intptr_t GetSizeInBytes() override; + + private: + const char* label_; + const AsyncWrap* wrap_; + const int length_; +}; + + +RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap) + : label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]), + wrap_(wrap), + length_(wrap->self_size()) { +} + + +void RetainedAsyncInfo::Dispose() { + delete this; +} + + +bool RetainedAsyncInfo::IsEquivalent(RetainedObjectInfo* other) { + return label_ == other->GetLabel() && + wrap_ == static_cast(other)->wrap_; +} + + +intptr_t RetainedAsyncInfo::GetHash() { + return reinterpret_cast(wrap_); +} + + +const char* RetainedAsyncInfo::GetLabel() { + return label_; +} + + +intptr_t RetainedAsyncInfo::GetSizeInBytes() { + return length_; +} + + +RetainedObjectInfo* WrapperInfo(uint16_t class_id, Local wrapper) { + // No class_id should be the provider type of NONE. + CHECK_GT(class_id, NODE_ASYNC_ID_OFFSET); + // And make sure the class_id doesn't extend past the last provider. + CHECK_LE(class_id - NODE_ASYNC_ID_OFFSET, AsyncWrap::PROVIDERS_LENGTH); + CHECK(wrapper->IsObject()); + CHECK(!wrapper.IsEmpty()); + + Local object = wrapper.As(); + CHECK_GT(object->InternalFieldCount(), 0); + + AsyncWrap* wrap = Unwrap(object); + CHECK_NE(nullptr, wrap); + + return new RetainedAsyncInfo(class_id, wrap); +} + + +// end RetainedAsyncInfo + + +static void DestroyAsyncIdsCallback(uv_timer_t* handle) { + Environment* env = Environment::from_destroy_async_ids_timer_handle(handle); + + HandleScope handle_scope(env->isolate()); + Context::Scope context_scope(env->context()); + Local fn = env->async_hooks_destroy_function(); + + TryCatch try_catch(env->isolate()); + + do { + std::vector destroy_async_id_list; + destroy_async_id_list.swap(*env->destroy_async_id_list()); + for (auto async_id : destroy_async_id_list) { + // Want each callback to be cleaned up after itself, instead of cleaning + // them all up after the while() loop completes. + HandleScope scope(env->isolate()); + Local async_id_value = Number::New(env->isolate(), async_id); + MaybeLocal ret = fn->Call( + env->context(), Undefined(env->isolate()), 1, &async_id_value); + + if (ret.IsEmpty()) { + ClearFatalExceptionHandlers(env); + FatalException(env->isolate(), try_catch); + UNREACHABLE(); + } + } + } while (!env->destroy_async_id_list()->empty()); +} + + +void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) { + AsyncHooks* async_hooks = env->async_hooks(); + + if (async_hooks->fields()[AsyncHooks::kPromiseResolve] == 0) + return; + + Local async_id_value = Number::New(env->isolate(), async_id); + Local fn = env->async_hooks_promise_resolve_function(); + TryCatch try_catch(env->isolate()); + MaybeLocal ar = fn->Call( + env->context(), Undefined(env->isolate()), 1, &async_id_value); + if (ar.IsEmpty()) { + ClearFatalExceptionHandlers(env); + FatalException(env->isolate(), try_catch); + UNREACHABLE(); + } +} + + +void AsyncWrap::EmitTraceEventBefore() { + switch (provider_type()) { +#define V(PROVIDER) \ + case PROVIDER_ ## PROVIDER: \ + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("node.async_hooks", \ + #PROVIDER "_CALLBACK", static_cast(get_async_id())); \ + break; + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + default: + UNREACHABLE(); + } +} + + +void AsyncWrap::EmitBefore(Environment* env, double async_id) { + AsyncHooks* async_hooks = env->async_hooks(); + + if (async_hooks->fields()[AsyncHooks::kBefore] == 0) + return; + + Local async_id_value = Number::New(env->isolate(), async_id); + Local fn = env->async_hooks_before_function(); + TryCatch try_catch(env->isolate()); + MaybeLocal ar = fn->Call( + env->context(), Undefined(env->isolate()), 1, &async_id_value); + if (ar.IsEmpty()) { + ClearFatalExceptionHandlers(env); + FatalException(env->isolate(), try_catch); + UNREACHABLE(); + } +} + + +void AsyncWrap::EmitTraceEventAfter() { + switch (provider_type()) { +#define V(PROVIDER) \ + case PROVIDER_ ## PROVIDER: \ + TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks", \ + #PROVIDER "_CALLBACK", static_cast(get_async_id())); \ + break; + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + default: + UNREACHABLE(); + } +} + + +void AsyncWrap::EmitAfter(Environment* env, double async_id) { + AsyncHooks* async_hooks = env->async_hooks(); + + if (async_hooks->fields()[AsyncHooks::kAfter] == 0) + return; + + // If the user's callback failed then the after() hooks will be called at the + // end of _fatalException(). + Local async_id_value = Number::New(env->isolate(), async_id); + Local fn = env->async_hooks_after_function(); + TryCatch try_catch(env->isolate()); + MaybeLocal ar = fn->Call( + env->context(), Undefined(env->isolate()), 1, &async_id_value); + if (ar.IsEmpty()) { + ClearFatalExceptionHandlers(env); + FatalException(env->isolate(), try_catch); + UNREACHABLE(); + } +} + +class PromiseWrap : public AsyncWrap { + public: + PromiseWrap(Environment* env, Local object, bool silent) + : AsyncWrap(env, object, silent) { + MakeWeak(this); + } + size_t self_size() const override { return sizeof(*this); } + + static constexpr int kPromiseField = 1; + static constexpr int kParentAsyncIdField = 2; + static constexpr int kInternalFieldCount = 3; + + static PromiseWrap* New(Environment* env, + Local promise, + PromiseWrap* parent_wrap, + bool silent); + static void GetPromise(Local property, + const PropertyCallbackInfo& info); + static void getParentAsyncId(Local property, + const PropertyCallbackInfo& info); +}; + +PromiseWrap* PromiseWrap::New(Environment* env, + Local promise, + PromiseWrap* parent_wrap, + bool silent) { + Local object = env->promise_wrap_template() + ->NewInstance(env->context()).ToLocalChecked(); + object->SetInternalField(PromiseWrap::kPromiseField, promise); + if (parent_wrap != nullptr) { + object->SetInternalField(PromiseWrap::kParentAsyncIdField, + Number::New(env->isolate(), + parent_wrap->get_async_id())); + } + CHECK_EQ(promise->GetAlignedPointerFromInternalField(0), nullptr); + promise->SetInternalField(0, object); + return new PromiseWrap(env, object, silent); +} + +void PromiseWrap::GetPromise(Local property, + const PropertyCallbackInfo& info) { + info.GetReturnValue().Set(info.Holder()->GetInternalField(kPromiseField)); +} + +void PromiseWrap::getParentAsyncId(Local property, + const PropertyCallbackInfo& info) { + info.GetReturnValue().Set( + info.Holder()->GetInternalField(kParentAsyncIdField)); +} + +static void PromiseHook(PromiseHookType type, Local promise, + Local parent, void* arg) { + Environment* env = static_cast(arg); + Local resource_object_value = promise->GetInternalField(0); + PromiseWrap* wrap = nullptr; + if (resource_object_value->IsObject()) { + Local resource_object = resource_object_value.As(); + wrap = Unwrap(resource_object); + } + + if (type == PromiseHookType::kInit || wrap == nullptr) { + bool silent = type != PromiseHookType::kInit; + PromiseWrap* parent_wrap = nullptr; + + // 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 parent_promise = parent.As(); + Local parent_resource = parent_promise->GetInternalField(0); + if (parent_resource->IsObject()) { + parent_wrap = Unwrap(parent_resource.As()); + } + + if (parent_wrap == nullptr) { + parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true); + } + // get id from parentWrap + double trigger_async_id = parent_wrap->get_async_id(); + env->set_init_trigger_async_id(trigger_async_id); + } + + wrap = PromiseWrap::New(env, promise, parent_wrap, silent); + } + + CHECK_NE(wrap, nullptr); + if (type == PromiseHookType::kBefore) { + env->async_hooks()->push_async_ids( + wrap->get_async_id(), wrap->get_trigger_async_id()); + wrap->EmitTraceEventBefore(); + AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id()); + } else if (type == PromiseHookType::kAfter) { + wrap->EmitTraceEventAfter(); + 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 is 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_id(wrap->get_async_id()); + } + } else if (type == PromiseHookType::kResolve) { + AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id()); + } +} + + +static void SetupHooks(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + if (!args[0]->IsObject()) + return env->ThrowTypeError("first argument must be an object"); + + // All of init, before, after, destroy are supplied by async_hooks + // internally, so this should every only be called once. At which time all + // the functions should be set. Detect this by checking if init !IsEmpty(). + CHECK(env->async_hooks_init_function().IsEmpty()); + + Local fn_obj = args[0].As(); + +#define SET_HOOK_FN(name) \ + Local name##_v = fn_obj->Get( \ + env->context(), \ + FIXED_ONE_BYTE_STRING(env->isolate(), #name)).ToLocalChecked(); \ + CHECK(name##_v->IsFunction()); \ + env->set_async_hooks_##name##_function(name##_v.As()); + + SET_HOOK_FN(init); + SET_HOOK_FN(before); + SET_HOOK_FN(after); + SET_HOOK_FN(destroy); + SET_HOOK_FN(promise_resolve); +#undef SET_HOOK_FN + + { + Local ctor = + FunctionTemplate::New(env->isolate()); + ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap")); + Local promise_wrap_template = ctor->InstanceTemplate(); + promise_wrap_template->SetInternalFieldCount( + PromiseWrap::kInternalFieldCount); + promise_wrap_template->SetAccessor( + FIXED_ONE_BYTE_STRING(env->isolate(), "promise"), + PromiseWrap::GetPromise); + promise_wrap_template->SetAccessor( + FIXED_ONE_BYTE_STRING(env->isolate(), "parentId"), + PromiseWrap::getParentAsyncId); + env->set_promise_wrap_template(promise_wrap_template); + } +} + + +static void EnablePromiseHook(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + env->AddPromiseHook(PromiseHook, static_cast(env)); +} + + +static void DisablePromiseHook(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + // Delay the call to `RemovePromiseHook` because we might currently be + // between the `before` and `after` calls of a Promise. + env->isolate()->EnqueueMicrotask([](void* data) { + Environment* env = static_cast(data); + env->RemovePromiseHook(PromiseHook, data); + }, static_cast(env)); +} + + +class DestroyParam { + public: + double asyncId; + v8::Persistent target; + v8::Persistent propBag; +}; + + +void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { + HandleScope scope(info.GetIsolate()); + + Environment* env = Environment::GetCurrent(info.GetIsolate()); + DestroyParam* p = info.GetParameter(); + Local prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag); + + Local val = prop_bag->Get(env->destroyed_string()); + if (val->IsFalse()) { + AsyncWrap::EmitDestroy(env, p->asyncId); + } + p->target.Reset(); + p->propBag.Reset(); + delete p; +} + + +static void RegisterDestroyHook(const FunctionCallbackInfo& args) { + CHECK(args[0]->IsObject()); + CHECK(args[1]->IsNumber()); + CHECK(args[2]->IsObject()); + + Isolate* isolate = args.GetIsolate(); + DestroyParam* p = new DestroyParam(); + p->asyncId = args[1].As()->Value(); + p->target.Reset(isolate, args[0].As()); + p->propBag.Reset(isolate, args[2].As()); + p->target.SetWeak( + p, AsyncWrap::WeakCallback, v8::WeakCallbackType::kParameter); +} + + +void AsyncWrap::GetAsyncId(const FunctionCallbackInfo& args) { + AsyncWrap* wrap; + args.GetReturnValue().Set(-1); + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); + args.GetReturnValue().Set(wrap->get_async_id()); +} + + +void AsyncWrap::PushAsyncIds(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail + // then the checks in push_async_ids() and pop_async_id() will. + double async_id = args[0]->NumberValue(env->context()).FromJust(); + double trigger_async_id = args[1]->NumberValue(env->context()).FromJust(); + env->async_hooks()->push_async_ids(async_id, trigger_async_id); +} + + +void AsyncWrap::PopAsyncIds(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + double async_id = args[0]->NumberValue(env->context()).FromJust(); + args.GetReturnValue().Set(env->async_hooks()->pop_async_id(async_id)); +} + + +void AsyncWrap::AsyncIdStackSize(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + args.GetReturnValue().Set( + static_cast(env->async_hooks()->stack_size())); +} + + +void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + env->async_hooks()->clear_async_id_stack(); +} + + +void AsyncWrap::AsyncReset(const FunctionCallbackInfo& args) { + AsyncWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); + double execution_async_id = args[0]->IsNumber() ? args[0]->NumberValue() : -1; + wrap->AsyncReset(execution_async_id); +} + + +void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo& args) { + CHECK(args[0]->IsNumber()); + AsyncWrap::EmitDestroy( + Environment::GetCurrent(args), args[0]->NumberValue()); +} + +void AsyncWrap::AddWrapMethods(Environment* env, + Local constructor, + int flag) { + env->SetProtoMethod(constructor, "getAsyncId", AsyncWrap::GetAsyncId); + if (flag & kFlagHasReset) + env->SetProtoMethod(constructor, "asyncReset", AsyncWrap::AsyncReset); +} + +void AsyncWrap::Initialize(Local target, + Local unused, + Local context) { + Environment* env = Environment::GetCurrent(context); + Isolate* isolate = env->isolate(); + HandleScope scope(isolate); + + env->SetMethod(target, "setupHooks", SetupHooks); + env->SetMethod(target, "pushAsyncIds", PushAsyncIds); + env->SetMethod(target, "popAsyncIds", PopAsyncIds); + env->SetMethod(target, "asyncIdStackSize", AsyncIdStackSize); + env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack); + env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId); + env->SetMethod(target, "enablePromiseHook", EnablePromiseHook); + env->SetMethod(target, "disablePromiseHook", DisablePromiseHook); + env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook); + + v8::PropertyAttribute ReadOnlyDontDelete = + static_cast(v8::ReadOnly | v8::DontDelete); + +#define FORCE_SET_TARGET_FIELD(obj, str, field) \ + (obj)->DefineOwnProperty(context, \ + FIXED_ONE_BYTE_STRING(isolate, str), \ + field, \ + ReadOnlyDontDelete).FromJust() + + // Attach the uint32_t[] where each slot contains the count of the number of + // callbacks waiting to be called on a particular event. It can then be + // incremented/decremented from JS quickly to communicate to C++ if there are + // any callbacks waiting to be called. + FORCE_SET_TARGET_FIELD(target, + "async_hook_fields", + env->async_hooks()->fields().GetJSArray()); + + // The following v8::Float64Array has 5 fields. These fields are shared in + // this way to allow JS and C++ to read/write each value as quickly as + // possible. The fields are represented as follows: + // + // kAsyncUid: Maintains the state of the next unique id to be assigned. + // + // kInitTriggerAsyncId: Write the id of the resource responsible for a + // handle's creation just before calling the new handle's constructor. + // After the new handle is constructed kInitTriggerAsyncId is set back to 0. + FORCE_SET_TARGET_FIELD(target, + "async_id_fields", + env->async_hooks()->async_id_fields().GetJSArray()); + + Local constants = Object::New(isolate); +#define SET_HOOKS_CONSTANT(name) \ + FORCE_SET_TARGET_FIELD( \ + constants, #name, Integer::New(isolate, AsyncHooks::name)); + + SET_HOOKS_CONSTANT(kInit); + SET_HOOKS_CONSTANT(kBefore); + SET_HOOKS_CONSTANT(kAfter); + SET_HOOKS_CONSTANT(kDestroy); + SET_HOOKS_CONSTANT(kPromiseResolve); + SET_HOOKS_CONSTANT(kTotals); + SET_HOOKS_CONSTANT(kCheck); + SET_HOOKS_CONSTANT(kExecutionAsyncId); + SET_HOOKS_CONSTANT(kTriggerAsyncId); + SET_HOOKS_CONSTANT(kAsyncIdCounter); + SET_HOOKS_CONSTANT(kInitTriggerAsyncId); +#undef SET_HOOKS_CONSTANT + FORCE_SET_TARGET_FIELD(target, "constants", constants); + + Local async_providers = Object::New(isolate); +#define V(p) \ + FORCE_SET_TARGET_FIELD( \ + async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p)); + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + FORCE_SET_TARGET_FIELD(target, "Providers", async_providers); + + // These Symbols are used throughout node so the stored values on each object + // can be accessed easily across files. + FORCE_SET_TARGET_FIELD( + target, + "async_id_symbol", + Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "asyncId"))); + FORCE_SET_TARGET_FIELD( + target, + "trigger_async_id_symbol", + Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "triggerAsyncId"))); + +#undef FORCE_SET_TARGET_FIELD + + env->set_async_hooks_init_function(Local()); + env->set_async_hooks_before_function(Local()); + env->set_async_hooks_after_function(Local()); + env->set_async_hooks_destroy_function(Local()); + env->set_async_hooks_promise_resolve_function(Local()); +} + + +void LoadAsyncWrapperInfo(Environment* env) { + HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler(); +#define V(PROVIDER) \ + heap_profiler->SetWrapperClassInfoProvider( \ + (NODE_ASYNC_ID_OFFSET + AsyncWrap::PROVIDER_ ## PROVIDER), WrapperInfo); + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V +} + + +AsyncWrap::AsyncWrap(Environment* env, + Local object, + ProviderType provider, + double execution_async_id) + : BaseObject(env, object), + provider_type_(provider) { + CHECK_NE(provider, PROVIDER_NONE); + CHECK_GE(object->InternalFieldCount(), 1); + + // Shift provider value over to prevent id collision. + persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider); + + // Use AsyncReset() call to execute the init() callbacks. + AsyncReset(execution_async_id); +} + + +// This is specifically used by the PromiseWrap constructor. +AsyncWrap::AsyncWrap(Environment* env, + Local object, + bool silent) + : BaseObject(env, object), + provider_type_(PROVIDER_PROMISE) { + CHECK_GE(object->InternalFieldCount(), 1); + + // Shift provider value over to prevent id collision. + persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider_type_); + + // Use AsyncReset() call to execute the init() callbacks. + AsyncReset(-1, silent); +} + + +AsyncWrap::~AsyncWrap() { + EmitTraceEventDestroy(); + EmitDestroy(env(), get_async_id()); +} + +void AsyncWrap::EmitTraceEventDestroy() { + switch (provider_type()) { + #define V(PROVIDER) \ + case PROVIDER_ ## PROVIDER: \ + TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks", \ + #PROVIDER, static_cast(get_async_id())); \ + break; + NODE_ASYNC_PROVIDER_TYPES(V) + #undef V + default: + UNREACHABLE(); + } +} + +void AsyncWrap::EmitDestroy(Environment* env, double async_id) { + if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0) + return; + + if (env->destroy_async_id_list()->empty()) { + uv_timer_start(env->destroy_async_ids_timer_handle(), + DestroyAsyncIdsCallback, 0, 0); + } + + env->destroy_async_id_list()->push_back(async_id); +} + + +// Generalized call for both the constructor and for handles that are pooled +// and reused over their lifetime. This way a new uid can be assigned when +// the resource is pulled out of the pool and put back into use. +void AsyncWrap::AsyncReset(double execution_async_id, bool silent) { + async_id_ = + execution_async_id == -1 ? env()->new_async_id() : execution_async_id; + trigger_async_id_ = env()->get_init_trigger_async_id(); + + switch (provider_type()) { +#define V(PROVIDER) \ + case PROVIDER_ ## PROVIDER: \ + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("node.async_hooks", \ + #PROVIDER, static_cast(get_async_id()), \ + "triggerAsyncId", static_cast(get_trigger_async_id())); \ + break; + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + default: + UNREACHABLE(); + } + + if (silent) return; + + EmitAsyncInit(env(), object(), + env()->async_hooks()->provider_string(provider_type()), + async_id_, trigger_async_id_); +} + + +void AsyncWrap::EmitAsyncInit(Environment* env, + Local object, + Local type, + double async_id, + double trigger_async_id) { + CHECK(!object.IsEmpty()); + CHECK(!type.IsEmpty()); + AsyncHooks* async_hooks = env->async_hooks(); + + // Nothing to execute, so can continue normally. + if (async_hooks->fields()[AsyncHooks::kInit] == 0) { + return; + } + + HandleScope scope(env->isolate()); + Local init_fn = env->async_hooks_init_function(); + + Local argv[] = { + Number::New(env->isolate(), async_id), + type, + Number::New(env->isolate(), trigger_async_id), + object, + }; + + TryCatch try_catch(env->isolate()); + MaybeLocal ret = init_fn->Call( + env->context(), object, arraysize(argv), argv); + + if (ret.IsEmpty()) { + ClearFatalExceptionHandlers(env); + FatalException(env->isolate(), try_catch); + } +} + + +MaybeLocal AsyncWrap::MakeCallback(const Local cb, + int argc, + Local* argv) { + EmitTraceEventBefore(); + + async_context context { get_async_id(), get_trigger_async_id() }; + MaybeLocal ret = InternalMakeCallback( + env(), object(), cb, argc, argv, context); + + EmitTraceEventAfter(); + + return ret; +} + + +/* Public C++ embedder API */ + + +async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { + return Environment::GetCurrent(isolate)->execution_async_id(); +} + + +async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) { + return Environment::GetCurrent(isolate)->trigger_async_id(); +} + + +async_context EmitAsyncInit(Isolate* isolate, + Local resource, + const char* name, + async_id trigger_async_id) { + Local type = + String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized) + .ToLocalChecked(); + return EmitAsyncInit(isolate, resource, type, trigger_async_id); +} + +async_context EmitAsyncInit(Isolate* isolate, + Local resource, + v8::Local name, + async_id trigger_async_id) { + Environment* env = Environment::GetCurrent(isolate); + + // Initialize async context struct + if (trigger_async_id == -1) + trigger_async_id = env->get_init_trigger_async_id(); + + async_context context = { + env->new_async_id(), // async_id_ + trigger_async_id // trigger_async_id_ + }; + + // Run init hooks + AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id, + context.trigger_async_id); + + return context; +} + +void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) { + AsyncWrap::EmitDestroy( + Environment::GetCurrent(isolate), asyncContext.async_id); +} + +} // namespace node + +NODE_BUILTIN_MODULE_CONTEXT_AWARE(async_wrap, node::AsyncWrap::Initialize) diff --git a/src/async_wrap.h b/src/async_wrap.h new file mode 100644 index 00000000000..222cda1fd7e --- /dev/null +++ b/src/async_wrap.h @@ -0,0 +1,187 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SRC_ASYNC_WRAP_H_ +#define SRC_ASYNC_WRAP_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "base-object.h" +#include "v8.h" + +#include + +namespace node { + +#define NODE_ASYNC_ID_OFFSET 0xA1C + +#define NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \ + V(NONE) \ + V(DNSCHANNEL) \ + V(FSEVENTWRAP) \ + V(FSREQWRAP) \ + V(GETADDRINFOREQWRAP) \ + V(GETNAMEINFOREQWRAP) \ + V(HTTP2SESSION) \ + V(HTTP2SESSIONSHUTDOWNWRAP) \ + V(HTTPPARSER) \ + V(JSSTREAM) \ + V(PIPECONNECTWRAP) \ + V(PIPEWRAP) \ + V(PROCESSWRAP) \ + V(PROMISE) \ + V(QUERYWRAP) \ + V(SHUTDOWNWRAP) \ + V(SIGNALWRAP) \ + V(STATWATCHER) \ + V(TCPCONNECTWRAP) \ + V(TCPWRAP) \ + V(TIMERWRAP) \ + V(TTYWRAP) \ + V(UDPSENDWRAP) \ + V(UDPWRAP) \ + V(WRITEWRAP) \ + V(ZLIB) + +#if HAVE_OPENSSL +#define NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) \ + V(SSLCONNECTION) \ + V(PBKDF2REQUEST) \ + V(RANDOMBYTESREQUEST) \ + V(TLSWRAP) +#else +#define NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) +#endif // HAVE_OPENSSL + +#if HAVE_INSPECTOR +#define NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) \ + V(INSPECTORJSBINDING) +#else +#define NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) +#endif // HAVE_INSPECTOR + +#define NODE_ASYNC_PROVIDER_TYPES(V) \ + NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \ + NODE_ASYNC_CRYPTO_PROVIDER_TYPES(V) \ + NODE_ASYNC_INSPECTOR_PROVIDER_TYPES(V) + +class Environment; +class DestroyParam; + +class AsyncWrap : public BaseObject { + public: + enum ProviderType { +#define V(PROVIDER) \ + PROVIDER_ ## PROVIDER, + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + PROVIDERS_LENGTH, + }; + + enum Flags { + kFlagNone = 0x0, + kFlagHasReset = 0x1 + }; + + AsyncWrap(Environment* env, + v8::Local object, + ProviderType provider, + double execution_async_id = -1); + + virtual ~AsyncWrap(); + + static void AddWrapMethods(Environment* env, + v8::Local constructor, + int flags = kFlagNone); + + static void Initialize(v8::Local target, + v8::Local unused, + v8::Local context); + + static void GetAsyncId(const v8::FunctionCallbackInfo& args); + static void PushAsyncIds(const v8::FunctionCallbackInfo& args); + static void PopAsyncIds(const v8::FunctionCallbackInfo& args); + static void AsyncIdStackSize(const v8::FunctionCallbackInfo& args); + static void ClearAsyncIdStack( + const v8::FunctionCallbackInfo& args); + static void AsyncReset(const v8::FunctionCallbackInfo& args); + static void QueueDestroyAsyncId( + const v8::FunctionCallbackInfo& args); + + static void EmitAsyncInit(Environment* env, + v8::Local object, + v8::Local type, + double async_id, + double trigger_async_id); + + static void EmitDestroy(Environment* env, double async_id); + static void EmitBefore(Environment* env, double async_id); + static void EmitAfter(Environment* env, double async_id); + static void EmitPromiseResolve(Environment* env, double async_id); + + void EmitTraceEventBefore(); + void EmitTraceEventAfter(); + void EmitTraceEventDestroy(); + + + inline ProviderType provider_type() const; + + inline double get_async_id() const; + + inline double get_trigger_async_id() const; + + void AsyncReset(double execution_async_id = -1, bool silent = false); + + // Only call these within a valid HandleScope. + v8::MaybeLocal MakeCallback(const v8::Local cb, + int argc, + v8::Local* argv); + inline v8::MaybeLocal MakeCallback( + const v8::Local symbol, + int argc, + v8::Local* argv); + inline v8::MaybeLocal MakeCallback(uint32_t index, + int argc, + v8::Local* argv); + + virtual size_t self_size() const = 0; + + static void WeakCallback(const v8::WeakCallbackInfo &info); + + private: + friend class PromiseWrap; + + // This is specifically used by the PromiseWrap constructor. + AsyncWrap(Environment* env, v8::Local promise, bool silent); + inline AsyncWrap(); + const ProviderType provider_type_; + // Because the values may be Reset(), cannot be made const. + double async_id_; + double trigger_async_id_; +}; + +void LoadAsyncWrapperInfo(Environment* env); + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_ASYNC_WRAP_H_ diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 27575fd8120..b7a6e47d53e 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -21,7 +21,7 @@ #define CARES_STATICLIB #include "ares.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "node.h" #include "req-wrap-inl.h" diff --git a/src/connect_wrap.h b/src/connect_wrap.h index 7b16a544874..59918078960 100644 --- a/src/connect_wrap.h +++ b/src/connect_wrap.h @@ -5,7 +5,7 @@ #include "env.h" #include "req-wrap.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "v8.h" namespace node { diff --git a/src/env.cc b/src/env.cc index c7bda013039..d4ca34aa74b 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1,5 +1,5 @@ #include "node_internals.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "v8-profiler.h" #include "node_buffer.h" #include "node_platform.h" diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 0a4d6452f51..934b9d545c6 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -19,7 +19,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "util-inl.h" #include "node.h" diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index 071f5ff8737..7dcafa2ce6e 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "handle_wrap.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "util-inl.h" #include "node.h" diff --git a/src/handle_wrap.h b/src/handle_wrap.h index f8be356e1a7..29e4f364603 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -24,7 +24,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "util.h" #include "uv.h" #include "v8.h" diff --git a/src/js_stream.cc b/src/js_stream.cc index 842fc3b711b..7d4ad7a4e97 100644 --- a/src/js_stream.cc +++ b/src/js_stream.cc @@ -1,6 +1,6 @@ #include "js_stream.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "env-inl.h" #include "node_buffer.h" #include "stream_base-inl.h" diff --git a/src/js_stream.h b/src/js_stream.h index a4a67ae3372..44bf7a06df7 100644 --- a/src/js_stream.h +++ b/src/js_stream.h @@ -3,7 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "stream_base.h" #include "v8.h" diff --git a/src/node.cc b/src/node.cc index 85fc23bbd93..30279a7f894 100644 --- a/src/node.cc +++ b/src/node.cc @@ -54,7 +54,7 @@ #endif #include "ares.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "handle_wrap.h" #include "http_parser.h" diff --git a/src/node_crypto.cc b/src/node_crypto.cc index cfab04b11ea..3acf5783428 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -28,7 +28,7 @@ #include "node_mutex.h" #include "tls_wrap.h" // TLSWrap -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "string_bytes.h" #include "util-inl.h" diff --git a/src/node_crypto.h b/src/node_crypto.h index a9719dec257..4034afab6f2 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -31,7 +31,7 @@ #include "node_buffer.h" #include "env.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "base-object-inl.h" #include "v8.h" diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 9974f566a8c..c990b763be3 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -22,7 +22,7 @@ #include "node.h" #include "node_buffer.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "http_parser.h" #include "stream_base-inl.h" diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index b8a395ef8de..cb48c652c97 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "node_stat_watcher.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "util-inl.h" diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h index df15f339d12..55f4307fdbc 100644 --- a/src/node_stat_watcher.h +++ b/src/node_stat_watcher.h @@ -25,7 +25,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "node.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "uv.h" #include "v8.h" diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 9d035030e82..08df3e97d79 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -22,7 +22,7 @@ #include "node.h" #include "node_buffer.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "util-inl.h" diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index d84458570d7..5ed8d304705 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -21,7 +21,7 @@ #include "pipe_wrap.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "connection_wrap.h" #include "env-inl.h" #include "handle_wrap.h" diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index 6db7f4561cb..6f22038b918 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -24,7 +24,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "connection_wrap.h" #include "env.h" diff --git a/src/req-wrap-inl.h b/src/req-wrap-inl.h index 4cf8e425de3..171160c2a15 100644 --- a/src/req-wrap-inl.h +++ b/src/req-wrap-inl.h @@ -4,7 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "req-wrap.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "util-inl.h" diff --git a/src/req-wrap.h b/src/req-wrap.h index 0fddae67460..83baf9d2a35 100644 --- a/src/req-wrap.h +++ b/src/req-wrap.h @@ -3,7 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "util.h" #include "v8.h" diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index 6d466f2cc3c..5117d3ab1d1 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -19,7 +19,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "handle_wrap.h" #include "util-inl.h" diff --git a/src/stream_base.h b/src/stream_base.h index 20cb0155c9d..94e4bfd7396 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -4,7 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "env.h" -#include "async-wrap.h" +#include "async_wrap.h" #include "req-wrap-inl.h" #include "node.h" #include "util.h" diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index 95c0b1c1e5b..fa6bac01386 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -24,7 +24,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "connection_wrap.h" diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index ba7f5b2d071..874c80d8d70 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -19,7 +19,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "env-inl.h" #include "handle_wrap.h" #include "util-inl.h" diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index d5b56ca9ba3..3b899ea12d5 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tls_wrap.h" -#include "async-wrap-inl.h" +#include "async_wrap-inl.h" #include "node_buffer.h" // Buffer #include "node_crypto.h" // SecureContext #include "node_crypto_bio.h" // NodeBIO diff --git a/src/tls_wrap.h b/src/tls_wrap.h index 99d2dc9121f..b782e7c3c23 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -27,7 +27,7 @@ #include "node.h" #include "node_crypto.h" // SSLWrap -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "stream_wrap.h" #include "util.h" diff --git a/src/udp_wrap.h b/src/udp_wrap.h index fe9256bcc63..50a7455beb6 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -24,7 +24,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "async-wrap.h" +#include "async_wrap.h" #include "env.h" #include "handle_wrap.h" #include "req-wrap-inl.h" -- cgit v1.2.3