diff --git a/node.gyp b/node.gyp index e63e750414ee60..d290b2c941b08e 100644 --- a/node.gyp +++ b/node.gyp @@ -101,6 +101,7 @@ ], 'sources': [ + 'src/base-object.cc', 'src/debug-agent.cc', 'src/async-wrap.cc', 'src/env.cc', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index cac8175889dfbf..ed07410569afcb 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -4,58 +4,12 @@ #include "async-wrap.h" #include "base-object.h" #include "base-object-inl.h" -#include "env.h" -#include "env-inl.h" -#include "node_internals.h" #include "util.h" #include "util-inl.h" #include "v8.h" namespace node { -inline AsyncWrap::AsyncWrap(Environment* env, - v8::Local object, - ProviderType provider, - AsyncWrap* parent) - : BaseObject(env, object), bits_(static_cast(provider) << 1) { - 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); - - v8::Local init_fn = env->async_hooks_init_function(); - - // No init callback exists, no reason to go on. - if (init_fn.IsEmpty()) - return; - - // If async wrap callbacks are disabled and no parent was passed that has - // run the init callback then return. - if (!env->async_wrap_callbacks_enabled() && - (parent == nullptr || !parent->ran_init_callback())) - return; - - v8::HandleScope scope(env->isolate()); - - v8::Local argv[] = { - v8::Int32::New(env->isolate(), provider), - Null(env->isolate()) - }; - - if (parent != nullptr) - argv[1] = parent->object(); - - v8::MaybeLocal ret = - init_fn->Call(env->context(), object, ARRAY_SIZE(argv), argv); - - if (ret.IsEmpty()) - FatalError("node::AsyncWrap::AsyncWrap", "init hook threw"); - - bits_ |= 1; // ran_init_callback() is true now. -} - - inline bool AsyncWrap::ran_init_callback() const { return static_cast(bits_ & 1); } diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 4f27e5116dca8d..3ab55751a5fd2a 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -1,5 +1,7 @@ #include "async-wrap.h" #include "async-wrap-inl.h" +#include "base-object.h" +#include "base-object-inl.h" #include "env.h" #include "env-inl.h" #include "util.h" @@ -14,9 +16,11 @@ using v8::Function; using v8::FunctionCallbackInfo; using v8::HandleScope; using v8::HeapProfiler; +using v8::Int32; using v8::Integer; using v8::Isolate; using v8::Local; +using v8::MaybeLocal; using v8::Object; using v8::RetainedObjectInfo; using v8::TryCatch; @@ -101,6 +105,67 @@ RetainedObjectInfo* WrapperInfo(uint16_t class_id, Local wrapper) { // end RetainedAsyncInfo +void AsyncWrap::ConstructAsyncWrap(Environment* env, + Local object, + ProviderType provider, + AsyncWrap* parent) { + 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); + + Local init_fn = env->async_hooks_init_function(); + + // No init callback exists, no reason to go on. + if (init_fn.IsEmpty()) + return; + + // If async wrap callbacks are disabled and no parent was passed that has + // run the init callback then return. + if (!env->async_wrap_callbacks_enabled() && + (parent == nullptr || !parent->ran_init_callback())) + return; + + HandleScope scope(env->isolate()); + + Local argv[] = { + Int32::New(env->isolate(), provider), + Null(env->isolate()) + }; + + if (parent != nullptr) + argv[1] = parent->object(); + + MaybeLocal ret = + init_fn->Call(env->context(), object, ARRAY_SIZE(argv), argv); + + if (ret.IsEmpty()) + FatalError("node::AsyncWrap::AsyncWrap", "init hook threw"); + + bits_ |= 1; // ran_init_callback() is true now. +} + + +AsyncWrap::AsyncWrap(Environment* env, + Local object, + ProviderType provider, + AsyncWrap* parent) + : BaseObject(env, object), bits_(static_cast(provider) << 1) { + ConstructAsyncWrap(env, object, provider, parent); +} + + +AsyncWrap::AsyncWrap(Isolate* isolate, + Local object, + ProviderType provider, + AsyncWrap* parent) + : BaseObject(isolate, object), bits_(static_cast(provider) << 1) { + Environment* env = Environment::GetCurrent(isolate); + ConstructAsyncWrap(env, object, provider, parent); +} + + static void EnableHooksJS(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); env->async_hooks()->set_enable_callbacks(1); diff --git a/src/async-wrap.h b/src/async-wrap.h index 330f3454f42d2c..629a8d8f0830cb 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -33,7 +33,8 @@ namespace node { V(UDPWRAP) \ V(UDPSENDWRAP) \ V(WRITEWRAP) \ - V(ZLIB) + V(ZLIB) \ + V(USER) class Environment; @@ -46,10 +47,16 @@ class AsyncWrap : public BaseObject { #undef V }; - inline AsyncWrap(Environment* env, - v8::Local object, - ProviderType provider, - AsyncWrap* parent = nullptr); + AsyncWrap(v8::Isolate* isolate, + v8::Local object, + ProviderType provider, + AsyncWrap* parent = nullptr); + + // Private API. Users don't have access to Environment. + AsyncWrap(Environment* env, + v8::Local object, + ProviderType provider, + AsyncWrap* parent = nullptr); inline virtual ~AsyncWrap() override = default; @@ -66,11 +73,17 @@ class AsyncWrap : public BaseObject { int argc, v8::Local* argv); + inline bool ran_init_callback() const; + virtual size_t self_size() const = 0; private: inline AsyncWrap(); - inline bool ran_init_callback() const; + + void ConstructAsyncWrap(Environment* env, + v8::Local object, + ProviderType provider, + AsyncWrap* parent); // When the async hooks init JS function is called from the constructor it is // expected the context object will receive a _asyncQueue object property diff --git a/src/base-object-inl.h b/src/base-object-inl.h index db0daa1e82f559..cc007b0ef2b8e1 100644 --- a/src/base-object-inl.h +++ b/src/base-object-inl.h @@ -2,21 +2,18 @@ #define SRC_BASE_OBJECT_INL_H_ #include "base-object.h" -#include "env.h" -#include "env-inl.h" #include "util.h" #include "util-inl.h" #include "v8.h" namespace node { -inline BaseObject::BaseObject(Environment* env, v8::Local handle) - : handle_(env->isolate(), handle), - env_(env) { - CHECK_EQ(false, handle.IsEmpty()); +inline BaseObject::BaseObject(v8::Isolate* isolate, + v8::Local handle) + : handle_(isolate, handle), + isolate_(isolate) { } - inline BaseObject::~BaseObject() { CHECK(handle_.IsEmpty()); } @@ -28,7 +25,12 @@ inline v8::Persistent& BaseObject::persistent() { inline v8::Local BaseObject::object() { - return PersistentToLocal(env_->isolate(), handle_); + return PersistentToLocal(isolate(), handle_); +} + + +inline v8::Isolate* BaseObject::isolate() const { + return isolate_; } @@ -48,7 +50,7 @@ inline void BaseObject::WeakCallback( template inline void BaseObject::MakeWeak(Type* ptr) { - v8::HandleScope scope(env_->isolate()); + v8::HandleScope scope(isolate()); v8::Local handle = object(); CHECK_GT(handle->InternalFieldCount(), 0); Wrap(handle, ptr); diff --git a/src/base-object.cc b/src/base-object.cc new file mode 100644 index 00000000000000..f164eec4d95a52 --- /dev/null +++ b/src/base-object.cc @@ -0,0 +1,18 @@ +#include "base-object.h" +#include "base-object-inl.h" +#include "env.h" +#include "env-inl.h" + +namespace node { + +using v8::Local; +using v8::Object; + +BaseObject::BaseObject(Environment* env, Local handle) + : handle_(env->isolate(), handle), + isolate_(env->isolate()), + env_(env) { + CHECK_EQ(false, handle.IsEmpty()); +} + +} // namespace node diff --git a/src/base-object.h b/src/base-object.h index 5a7b95827e8f11..a6d54d1f3b80e0 100644 --- a/src/base-object.h +++ b/src/base-object.h @@ -10,6 +10,7 @@ class Environment; class BaseObject { public: BaseObject(Environment* env, v8::Local handle); + BaseObject(v8::Isolate* isolate, v8::Local handle); virtual ~BaseObject(); // Returns the wrapped object. Returns an empty handle when @@ -23,6 +24,8 @@ class BaseObject { // calling .Reset() again is harmless. inline v8::Persistent& persistent(); + inline v8::Isolate* isolate() const; + inline Environment* env() const; // The handle_ must have an internal field count > 0, and the first @@ -43,6 +46,7 @@ class BaseObject { const v8::WeakCallbackData& data); v8::Persistent handle_; + v8::Isolate* isolate_; Environment* env_; }; diff --git a/test/parallel/test-async-wrap-check-providers.js b/test/parallel/test-async-wrap-check-providers.js index 2d7d318885eb16..5dc889279d503a 100644 --- a/test/parallel/test-async-wrap-check-providers.js +++ b/test/parallel/test-async-wrap-check-providers.js @@ -14,10 +14,8 @@ const StreamWrap = require('_stream_wrap').StreamWrap; const async_wrap = process.binding('async_wrap'); const pkeys = Object.keys(async_wrap.Providers); -let keyList = pkeys.slice(); -// Drop NONE -keyList.splice(0, 1); - +// Remove the 'NONE' and 'USER' providers. +let keyList = pkeys.slice().filter(e => e != 'NONE' && e != 'USER'); function init(id) { keyList = keyList.filter(e => e != pkeys[id]);