diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index bad634ddaf14b9..5841c58faf18d5 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -18,6 +18,11 @@ inline AsyncWrap::AsyncWrap(Environment* env, ProviderType provider, AsyncWrap* parent) : BaseObject(env, object), bits_(static_cast(provider) << 1) { + // Only set wrapper class id if object will be Wrap'd. + if (object->InternalFieldCount() > 0) + // Shift provider value over to prevent id collision. + persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider); + // Check user controlled flag to see if the init callback should run. if (!env->using_asyncwrap()) return; diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 2da6b102934fa7..454681e0c68dfa 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -6,6 +6,7 @@ #include "util-inl.h" #include "v8.h" +#include "v8-profiler.h" using v8::Array; using v8::Context; @@ -13,16 +14,95 @@ using v8::Function; using v8::FunctionCallbackInfo; using v8::Handle; using v8::HandleScope; +using v8::HeapProfiler; using v8::Integer; using v8::Isolate; using v8::Local; using v8::Object; +using v8::RetainedObjectInfo; using v8::TryCatch; using v8::Value; using v8::kExternalUint32Array; namespace node { +static const char* const provider_names[] = { +#define V(PROVIDER) \ + #PROVIDER, + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V +}; + + +class RetainedAsyncInfo: public RetainedObjectInfo { + public: + explicit RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap); + + virtual void Dispose() override; + virtual bool IsEquivalent(RetainedObjectInfo* other) override; + virtual intptr_t GetHash() override; + virtual const char* GetLabel() override; + virtual 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, Handle wrapper) { + // No class_id should be the provider type of NONE. + CHECK_NE(NODE_ASYNC_ID_OFFSET, class_id); + 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 EnableHooksJS(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); env->async_hooks()->set_enable_callbacks(1); @@ -71,6 +151,16 @@ static void Initialize(Handle target, } +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 +} + + Handle AsyncWrap::MakeCallback(const Handle cb, int argc, Handle* argv) { diff --git a/src/async-wrap.h b/src/async-wrap.h index 5e898fe4c24534..bb93872ff79656 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -8,6 +8,8 @@ namespace node { +#define NODE_ASYNC_ID_OFFSET 0xA1C + #define NODE_ASYNC_PROVIDER_TYPES(V) \ V(NONE) \ V(CARES) \ @@ -64,6 +66,8 @@ class AsyncWrap : public BaseObject { int argc, v8::Handle* argv); + virtual size_t self_size() const = 0; + private: inline AsyncWrap(); inline bool has_async_queue() const; @@ -74,6 +78,8 @@ class AsyncWrap : public BaseObject { uint32_t bits_; }; +void LoadAsyncWrapperInfo(Environment* env); + } // namespace node diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index c73f8c05cbc12d..d4be7c9b9bfa9b 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -51,6 +51,8 @@ using v8::Value; class GetAddrInfoReqWrap : public ReqWrap { public: GetAddrInfoReqWrap(Environment* env, Local req_wrap_obj); + + size_t self_size() const override { return sizeof(*this); } }; GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, @@ -66,8 +68,10 @@ static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo& args) { class GetNameInfoReqWrap : public ReqWrap { - public: - GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); + public: + GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); + + size_t self_size() const override { return sizeof(*this); } }; GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, @@ -385,6 +389,8 @@ class QueryAWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -422,6 +428,8 @@ class QueryAaaaWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -459,6 +467,8 @@ class QueryCnameWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -498,6 +508,8 @@ class QueryMxWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -547,6 +559,8 @@ class QueryNsWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -583,6 +597,8 @@ class QueryTxtWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -638,6 +654,8 @@ class QuerySrvWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -692,6 +710,8 @@ class QueryNaptrWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -754,6 +774,8 @@ class QuerySoaWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(unsigned char* buf, int len) override { HandleScope handle_scope(env()->isolate()); @@ -820,6 +842,8 @@ class GetHostByAddrWrap: public QueryWrap { return 0; } + size_t self_size() const override { return sizeof(*this); } + protected: void Parse(struct hostent* host) override { HandleScope handle_scope(env()->isolate()); diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index a6ceff2776db92..e17f9ce58ef5a3 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -31,6 +31,8 @@ class FSEventWrap: public HandleWrap { static void Start(const FunctionCallbackInfo& args); static void Close(const FunctionCallbackInfo& args); + size_t self_size() const override { return sizeof(*this); } + private: FSEventWrap(Environment* env, Handle object); virtual ~FSEventWrap() override; diff --git a/src/js_stream.h b/src/js_stream.h index 6bc763b36e2bd1..9f7ba7de27153c 100644 --- a/src/js_stream.h +++ b/src/js_stream.h @@ -28,6 +28,8 @@ class JSStream : public StreamBase, public AsyncWrap { size_t count, uv_stream_t* send_handle) override; + size_t self_size() const override { return sizeof(*this); } + protected: JSStream(Environment* env, v8::Handle obj, AsyncWrap* parent); diff --git a/src/node.cc b/src/node.cc index f47dd722056a8d..18d08504337e49 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3872,6 +3872,7 @@ Environment* CreateEnvironment(Isolate* isolate, env->set_process_object(process_object); SetupProcessObject(env, argc, argv, exec_argc, exec_argv); + LoadAsyncWrapperInfo(env); return env; } diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 48a75d30f76813..296ca0a6062839 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4546,6 +4546,8 @@ class PBKDF2Request : public AsyncWrap { error_ = err; } + size_t self_size() const override { return sizeof(*this); } + uv_work_t work_req_; private: @@ -4776,6 +4778,8 @@ class RandomBytesRequest : public AsyncWrap { error_ = err; } + size_t self_size() const override { return sizeof(*this); } + uv_work_t work_req_; private: diff --git a/src/node_crypto.h b/src/node_crypto.h index 0ef9c02273387e..3a00b519323d52 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -308,6 +308,8 @@ class Connection : public SSLWrap, public AsyncWrap { v8::Persistent servername_; #endif + size_t self_size() const override { return sizeof(*this); } + protected: static void New(const v8::FunctionCallbackInfo& args); static void EncIn(const v8::FunctionCallbackInfo& args); @@ -702,6 +704,8 @@ class Certificate : public AsyncWrap { const char* ExportPublicKey(const char* data, int len); const char* ExportChallenge(const char* data, int len); + size_t self_size() const override { return sizeof(*this); } + protected: static void New(const v8::FunctionCallbackInfo& args); static void VerifySpkac(const v8::FunctionCallbackInfo& args); diff --git a/src/node_file.cc b/src/node_file.cc index c8696f1295474b..0297b08e68d478 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -73,6 +73,8 @@ class FSReqWrap: public ReqWrap { const char* syscall() const { return syscall_; } const char* data() const { return data_; } + size_t self_size() const override { return sizeof(*this); } + private: FSReqWrap(Environment* env, Local req, diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h index bd214791048317..e0ef76601f6e90 100644 --- a/src/node_stat_watcher.h +++ b/src/node_stat_watcher.h @@ -22,6 +22,8 @@ class StatWatcher : public AsyncWrap { static void Start(const v8::FunctionCallbackInfo& args); static void Stop(const v8::FunctionCallbackInfo& args); + size_t self_size() const override { return sizeof(*this); } + private: static void Callback(uv_fs_poll_t* handle, int status, diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 58dfce397580ca..699d5c453c589c 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -535,6 +535,8 @@ class ZCtx : public AsyncWrap { } } + size_t self_size() const override { return sizeof(*this); } + private: void Ref() { if (++refs_ == 1) { diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 08fed68741f614..2e1ab5b2621c32 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -37,6 +37,8 @@ using v8::Value; class PipeConnectWrap : public ReqWrap { public: PipeConnectWrap(Environment* env, Local req_wrap_obj); + + size_t self_size() const override { return sizeof(*this); } }; diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index 6dc9a01bcd1687..6c74de984b34e6 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -16,6 +16,8 @@ class PipeWrap : public StreamWrap { v8::Handle unused, v8::Handle context); + size_t self_size() const override { return sizeof(*this); } + private: PipeWrap(Environment* env, v8::Handle object, diff --git a/src/process_wrap.cc b/src/process_wrap.cc index 56d1f28e4a2985..14bbb9c9e9a9eb 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -46,6 +46,8 @@ class ProcessWrap : public HandleWrap { constructor->GetFunction()); } + size_t self_size() const override { return sizeof(*this); } + private: static void New(const FunctionCallbackInfo& args) { // This constructor should not be exposed to public javascript. diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index 7cceb64560cf65..4811aca53a6183 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -40,6 +40,8 @@ class SignalWrap : public HandleWrap { constructor->GetFunction()); } + size_t self_size() const override { return sizeof(*this); } + private: static void New(const FunctionCallbackInfo& args) { // This constructor should not be exposed to public javascript. diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index 26ba54b3768afc..d74b47de6009f6 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -92,7 +92,7 @@ WriteWrap* WriteWrap::New(Environment* env, size_t storage_size = ROUND_UP(sizeof(WriteWrap), kAlignSize) + extra; char* storage = new char[storage_size]; - return new(storage) WriteWrap(env, obj, wrap, cb); + return new(storage) WriteWrap(env, obj, wrap, cb, storage_size); } diff --git a/src/stream_base.h b/src/stream_base.h index dfb0d31c66776d..31854b3435a337 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -48,6 +48,7 @@ class ShutdownWrap : public ReqWrap, } inline StreamBase* wrap() const { return wrap_; } + size_t self_size() const override { return sizeof(*this); } private: StreamBase* const wrap_; @@ -66,6 +67,8 @@ class WriteWrap: public ReqWrap, inline StreamBase* wrap() const { return wrap_; } + size_t self_size() const override { return storage_size_; } + static void NewWriteWrap(const v8::FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); } @@ -76,10 +79,12 @@ class WriteWrap: public ReqWrap, WriteWrap(Environment* env, v8::Local obj, StreamBase* wrap, - DoneCb cb) + DoneCb cb, + size_t storage_size) : ReqWrap(env, obj, AsyncWrap::PROVIDER_WRITEWRAP), StreamReq(cb), - wrap_(wrap) { + wrap_(wrap), + storage_size_(storage_size) { Wrap(obj, this); } @@ -96,6 +101,7 @@ class WriteWrap: public ReqWrap, void operator delete(void* ptr) { UNREACHABLE(); } StreamBase* const wrap_; + const size_t storage_size_; }; class StreamResource { diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index e16e14058332aa..6980f8b28ce028 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -37,6 +37,7 @@ using v8::Value; class TCPConnectWrap : public ReqWrap { public: TCPConnectWrap(Environment* env, Local req_wrap_obj); + size_t self_size() const override { return sizeof(*this); } }; diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index c41a36fbeb8ce6..ee1e9817b231e9 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -16,6 +16,8 @@ class TCPWrap : public StreamWrap { uv_tcp_t* UVHandle(); + size_t self_size() const override { return sizeof(*this); } + private: TCPWrap(Environment* env, v8::Handle object, AsyncWrap* parent); ~TCPWrap(); diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index f65290a5162398..d2c9a8c9ae27f6 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -51,6 +51,8 @@ class TimerWrap : public HandleWrap { constructor->GetFunction()); } + size_t self_size() const override { return sizeof(*this); } + private: static void New(const FunctionCallbackInfo& args) { // This constructor should not be exposed to public javascript. diff --git a/src/tls_wrap.h b/src/tls_wrap.h index a30447519083c2..b906d78de1ffb0 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -50,6 +50,8 @@ class TLSWrap : public crypto::SSLWrap, void NewSessionDoneCb(); + size_t self_size() const override { return sizeof(*this); } + protected: static const int kClearOutChunkSize = 1024; diff --git a/src/tty_wrap.h b/src/tty_wrap.h index 09cd71e7819e38..6d423e1ae5306b 100644 --- a/src/tty_wrap.h +++ b/src/tty_wrap.h @@ -15,6 +15,8 @@ class TTYWrap : public StreamWrap { uv_tty_t* UVHandle(); + size_t self_size() const override { return sizeof(*this); } + private: TTYWrap(Environment* env, v8::Handle object, diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 3183d1f9f5367c..fe0ed76dd5e68b 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -36,6 +36,7 @@ class SendWrap : public ReqWrap { public: SendWrap(Environment* env, Local req_wrap_obj, bool have_callback); inline bool have_callback() const; + size_t self_size() const override { return sizeof(*this); } private: const bool have_callback_; }; diff --git a/src/udp_wrap.h b/src/udp_wrap.h index 0a33ae8cb22530..3373cb9a2dfddb 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -37,6 +37,8 @@ class UDPWrap: public HandleWrap { static v8::Local Instantiate(Environment* env, AsyncWrap* parent); uv_udp_t* UVHandle(); + size_t self_size() const override { return sizeof(*this); } + private: UDPWrap(Environment* env, v8::Handle object, AsyncWrap* parent);