diff --git a/node.gyp b/node.gyp index d89296246c3f84..1ee29f18647990 100644 --- a/node.gyp +++ b/node.gyp @@ -423,6 +423,8 @@ 'src/node_revert.h', 'src/node_i18n.h', 'src/node_worker.h', + 'src/memory_tracker.h', + 'src/memory_tracker-inl.h', 'src/pipe_wrap.h', 'src/tty_wrap.h', 'src/tcp_wrap.h', diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 89e82b9ce364b6..e98dca3c56651b 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -76,14 +76,22 @@ class RetainedAsyncInfo: public RetainedObjectInfo { private: const char* label_; const AsyncWrap* wrap_; - const int length_; + const size_t length_; }; +static int OwnMemory(AsyncWrap* async_wrap) { + MemoryTracker tracker; + tracker.set_track_only_self(true); + tracker.Track(async_wrap); + return tracker.accumulated_size(); +} + + RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap) : label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]), wrap_(wrap), - length_(wrap->self_size()) { + length_(OwnMemory(wrap)) { } @@ -147,7 +155,9 @@ struct AsyncWrapObject : public AsyncWrap { inline AsyncWrapObject(Environment* env, Local object, ProviderType type) : AsyncWrap(env, object, type) {} - inline size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } }; @@ -252,7 +262,10 @@ class PromiseWrap : public AsyncWrap { : AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) { MakeWeak(); } - size_t self_size() const override { return sizeof(*this); } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } static constexpr int kPromiseField = 1; static constexpr int kIsChainedPromiseField = 2; diff --git a/src/async_wrap.h b/src/async_wrap.h index 64b74ac209607b..ef3a5934893d7f 100644 --- a/src/async_wrap.h +++ b/src/async_wrap.h @@ -173,7 +173,6 @@ class AsyncWrap : public BaseObject { int argc, v8::Local* argv); - virtual size_t self_size() const = 0; virtual std::string diagnostic_name() const; static void WeakCallback(const v8::WeakCallbackInfo &info); diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 06a29223973c5d..d067a807cb8e14 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -61,11 +61,11 @@ Persistent& BaseObject::persistent() { } -v8::Local BaseObject::object() { +v8::Local BaseObject::object() const { return PersistentToLocal(env_->isolate(), persistent_handle_); } -v8::Local BaseObject::object(v8::Isolate* isolate) { +v8::Local BaseObject::object(v8::Isolate* isolate) const { v8::Local handle = object(); #ifdef DEBUG CHECK_EQ(handle->CreationContext()->GetIsolate(), isolate); @@ -91,12 +91,6 @@ T* BaseObject::FromJSObject(v8::Local object) { } -void BaseObject::DeleteMe(void* data) { - BaseObject* self = static_cast(data); - delete self; -} - - void BaseObject::MakeWeak() { persistent_handle_.SetWeak( this, diff --git a/src/base_object.h b/src/base_object.h index 38291d598feb1c..e0f3f27950e7d0 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -25,6 +25,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "node_persistent.h" +#include "memory_tracker-inl.h" #include "v8.h" #include // std::remove_reference @@ -32,7 +33,7 @@ namespace node { class Environment; -class BaseObject { +class BaseObject : public MemoryRetainer { public: // Associates this object with `object`. It uses the 0th internal field for // that, and in particular aborts if there is no such field. @@ -41,11 +42,11 @@ class BaseObject { // Returns the wrapped object. Returns an empty handle when // persistent.IsEmpty() is true. - inline v8::Local object(); + inline v8::Local object() const; // Same as the above, except it additionally verifies that this object // is associated with the passed Isolate in debug mode. - inline v8::Local object(v8::Isolate* isolate); + inline v8::Local object(v8::Isolate* isolate) const; inline Persistent& persistent(); @@ -75,7 +76,9 @@ class BaseObject { private: BaseObject(); - static inline void DeleteMe(void* data); + v8::Local WrappedObject() const override; + bool IsRootNode() const override; + static void DeleteMe(void* data); // persistent_handle_ needs to be at a fixed offset from the start of the // class because it is used by src/node_postmortem_metadata.cc to calculate @@ -83,6 +86,8 @@ class BaseObject { // position of members in memory are predictable. For more information please // refer to `doc/guides/node-postmortem-support.md` friend int GenDebugSymbols(); + friend class Environment; + Persistent persistent_handle_; Environment* env_; }; diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 3cf1d434d3ca71..69a3d46668193a 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -121,10 +121,12 @@ inline const char* ToErrorCodeString(int status) { class ChannelWrap; -struct node_ares_task { +struct node_ares_task : public MemoryRetainer { ChannelWrap* channel; ares_socket_t sock; uv_poll_t poll_watcher; + + void MemoryInfo(MemoryTracker* tracker) const override; }; struct TaskHash { @@ -167,7 +169,12 @@ class ChannelWrap : public AsyncWrap { inline int active_query_count() { return active_query_count_; } inline node_ares_task_list* task_list() { return &task_list_; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + if (timer_handle_ != nullptr) + tracker->TrackFieldWithSize("timer handle", sizeof(*timer_handle_)); + tracker->TrackField("task list", task_list_); + } static void AresTimeout(uv_timer_t* handle); @@ -181,6 +188,11 @@ class ChannelWrap : public AsyncWrap { node_ares_task_list task_list_; }; +void node_ares_task::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackThis(this); + tracker->TrackField("channel", channel); +} + ChannelWrap::ChannelWrap(Environment* env, Local object) : AsyncWrap(env, object, PROVIDER_DNSCHANNEL), @@ -209,7 +221,10 @@ class GetAddrInfoReqWrap : public ReqWrap { Local req_wrap_obj, bool verbatim); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + bool verbatim() const { return verbatim_; } private: @@ -228,7 +243,9 @@ class GetNameInfoReqWrap : public ReqWrap { public: GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } }; GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, @@ -270,13 +287,13 @@ void ares_poll_cb(uv_poll_t* watcher, int status, int events) { void ares_poll_close_cb(uv_poll_t* watcher) { node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher); - free(task); + delete task; } /* Allocates and returns a new node_ares_task */ node_ares_task* ares_task_create(ChannelWrap* channel, ares_socket_t sock) { - auto task = node::UncheckedMalloc(1); + auto task = new node_ares_task(); if (task == nullptr) { /* Out of memory. */ @@ -1172,7 +1189,9 @@ class QueryAnyWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1349,7 +1368,9 @@ class QueryAWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1393,7 +1414,9 @@ class QueryAaaaWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1437,7 +1460,9 @@ class QueryCnameWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1468,7 +1493,9 @@ class QueryMxWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1499,7 +1526,9 @@ class QueryNsWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1530,7 +1559,9 @@ class QueryTxtWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1560,7 +1591,9 @@ class QuerySrvWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1589,7 +1622,9 @@ class QueryPtrWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1620,7 +1655,9 @@ class QueryNaptrWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1650,7 +1687,9 @@ class QuerySoaWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(unsigned char* buf, int len) override { @@ -1729,7 +1768,9 @@ class GetHostByAddrWrap: public QueryWrap { return 0; } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: void Parse(struct hostent* host) override { diff --git a/src/connect_wrap.h b/src/connect_wrap.h index 80eae7f9bb8290..587e4c6b0593e5 100644 --- a/src/connect_wrap.h +++ b/src/connect_wrap.h @@ -16,7 +16,9 @@ class ConnectWrap : public ReqWrap { v8::Local req_wrap_obj, AsyncWrap::ProviderType provider); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } }; } // namespace node diff --git a/src/env.cc b/src/env.cc index 4d7008df36d41b..30bc85559a9a0a 100644 --- a/src/env.cc +++ b/src/env.cc @@ -734,4 +734,18 @@ void Environment::stop_sub_worker_contexts() { } } +// Not really any better place than env.cc at this moment. +void BaseObject::DeleteMe(void* data) { + BaseObject* self = static_cast(data); + delete self; +} + +Local BaseObject::WrappedObject() const { + return object(); +} + +bool BaseObject::IsRootNode() const { + return !persistent_handle_.IsWeak(); +} + } // namespace node diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 164614ae81145f..7587ace8e3ce70 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -56,7 +56,10 @@ class FSEventWrap: public HandleWrap { static void New(const FunctionCallbackInfo& args); static void Start(const FunctionCallbackInfo& args); static void GetInitialized(const FunctionCallbackInfo& args); - size_t self_size() const override { return sizeof(*this); } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: static const encoding kDefaultEncoding = UTF8; diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 96b064e495a01a..9a74f4d1098c29 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -103,7 +103,11 @@ class JSBindingsConnection : public AsyncWrap { } } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("callback", callback_); + tracker->TrackFieldWithSize("session", sizeof(*session_)); + } private: std::unique_ptr session_; diff --git a/src/js_stream.h b/src/js_stream.h index b47a91a653ba7e..f3406ae83ee560 100644 --- a/src/js_stream.h +++ b/src/js_stream.h @@ -27,7 +27,9 @@ class JSStream : public AsyncWrap, public StreamBase { size_t count, uv_stream_t* send_handle) override; - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } protected: JSStream(Environment* env, v8::Local obj); diff --git a/src/memory_tracker-inl.h b/src/memory_tracker-inl.h new file mode 100644 index 00000000000000..758223492f6e71 --- /dev/null +++ b/src/memory_tracker-inl.h @@ -0,0 +1,107 @@ +#ifndef SRC_MEMORY_TRACKER_INL_H_ +#define SRC_MEMORY_TRACKER_INL_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "memory_tracker.h" + +namespace node { + +template +void MemoryTracker::TrackThis(const T* obj) { + accumulated_size_ += sizeof(T); +} + +void MemoryTracker::TrackFieldWithSize(const char* name, size_t size) { + accumulated_size_ += size; +} + +void MemoryTracker::TrackField(const char* name, const MemoryRetainer& value) { + TrackField(name, &value); +} + +void MemoryTracker::TrackField(const char* name, const MemoryRetainer* value) { + if (track_only_self_ || value == nullptr || seen_.count(value) > 0) return; + seen_.insert(value); + Track(value); +} + +template +void MemoryTracker::TrackField(const char* name, + const std::unique_ptr& value) { + TrackField(name, value.get()); +} + +template +void MemoryTracker::TrackField(const char* name, const T& value) { + if (value.begin() == value.end()) return; + size_t index = 0; + for (Iterator it = value.begin(); it != value.end(); ++it) + TrackField(std::to_string(index++).c_str(), *it); +} + +template +void MemoryTracker::TrackField(const char* name, const std::queue& value) { + struct ContainerGetter : public std::queue { + static const typename std::queue::container_type& Get( + const std::queue& value) { + return value.*&ContainerGetter::c; + } + }; + + const auto& container = ContainerGetter::Get(value); + TrackField(name, container); +} + +template +void MemoryTracker::TrackField(const char* name, const T& value) { + // For numbers, creating new nodes is not worth the overhead. + TrackFieldWithSize(name, sizeof(T)); +} + +template +void MemoryTracker::TrackField(const char* name, const std::pair& value) { + TrackField("first", value.first); + TrackField("second", value.second); +} + +template +void MemoryTracker::TrackField(const char* name, + const std::basic_string& value) { + TrackFieldWithSize(name, value.size() * sizeof(T)); +} + +template +void MemoryTracker::TrackField(const char* name, + const v8::Persistent& value) { +} + +template +void MemoryTracker::TrackField(const char* name, const v8::Local& value) { +} + +template +void MemoryTracker::TrackField(const char* name, + const MallocedBuffer& value) { + TrackFieldWithSize(name, value.size); +} + +void MemoryTracker::TrackField(const char* name, const uv_buf_t& value) { + TrackFieldWithSize(name, value.len); +} + +template +void MemoryTracker::TrackField(const char* name, + const AliasedBuffer& value) { + TrackField(name, value.GetJSArray()); +} + +void MemoryTracker::Track(const MemoryRetainer* value) { + value->MemoryInfo(this); +} + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_MEMORY_TRACKER_INL_H_ diff --git a/src/memory_tracker.h b/src/memory_tracker.h new file mode 100644 index 00000000000000..18822651f67873 --- /dev/null +++ b/src/memory_tracker.h @@ -0,0 +1,87 @@ +#ifndef SRC_MEMORY_TRACKER_H_ +#define SRC_MEMORY_TRACKER_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include +#include +#include +#include +#include + +namespace node { + +class MemoryTracker; + +namespace crypto { +class NodeBIO; +} + +class MemoryRetainer { + public: + virtual ~MemoryRetainer() {} + + // Subclasses should implement this to provide information for heap snapshots. + virtual void MemoryInfo(MemoryTracker* tracker) const = 0; + + virtual v8::Local WrappedObject() const { + return v8::Local(); + } + + virtual bool IsRootNode() const { return false; } +}; + +class MemoryTracker { + public: + template + inline void TrackThis(const T* obj); + + inline void TrackFieldWithSize(const char* name, size_t size); + + inline void TrackField(const char* name, const MemoryRetainer& value); + inline void TrackField(const char* name, const MemoryRetainer* value); + template + inline void TrackField(const char* name, const std::unique_ptr& value); + template + inline void TrackField(const char* name, const T& value); + template + inline void TrackField(const char* name, const std::queue& value); + template + inline void TrackField(const char* name, const std::basic_string& value); + template ::is_specialized, bool>::type, + typename dummy = bool> + inline void TrackField(const char* name, const T& value); + template + inline void TrackField(const char* name, const std::pair& value); + template + inline void TrackField(const char* name, + const v8::Persistent& value); + template + inline void TrackField(const char* name, const v8::Local& value); + template + inline void TrackField(const char* name, const MallocedBuffer& value); + inline void TrackField(const char* name, const uv_buf_t& value); + template + inline void TrackField(const char* name, + const AliasedBuffer& value); + + inline void Track(const MemoryRetainer* value); + inline size_t accumulated_size() const { return accumulated_size_; } + + inline void set_track_only_self(bool value) { track_only_self_ = value; } + + inline MemoryTracker() {} + + private: + bool track_only_self_ = false; + size_t accumulated_size_ = 0; + std::unordered_set seen_; +}; + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_MEMORY_TRACKER_H_ diff --git a/src/module_wrap.h b/src/module_wrap.h index 3969e2a37878fc..2d6f5c49d88988 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -33,6 +33,12 @@ class ModuleWrap : public BaseObject { v8::Local module, v8::Local meta); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("url", url_); + tracker->TrackField("resolve_cache", resolve_cache_); + } + private: ModuleWrap(Environment* env, v8::Local object, diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 61c686ba001a3f..e4b4fef3dca989 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -588,6 +588,10 @@ class ContextifyScript : public BaseObject { private: Persistent script_; + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + public: static void Init(Environment* env, Local target) { HandleScope scope(env->isolate()); diff --git a/src/node_contextify.h b/src/node_contextify.h index 2ebfef7f27374d..3d94fbc5c47947 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -49,6 +49,7 @@ class ContextifyContext { context()->GetEmbedderData(ContextEmbedderIndex::kSandboxObject)); } + template static ContextifyContext* Get(const v8::PropertyCallbackInfo& args); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3df00baf659f53..5bceae0ce00c8b 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4582,6 +4582,8 @@ bool ECDH::IsKeyPairValid() { } +// TODO(addaleax): If there is an `AsyncWrap`, it currently has no access to +// this object. This makes proper reporting of memory usage impossible. struct CryptoJob : public ThreadPoolWork { Environment* const env; std::unique_ptr async_wrap; diff --git a/src/node_crypto.h b/src/node_crypto.h index 4587a96e725f86..7df2660c779760 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -105,6 +105,10 @@ class SecureContext : public BaseObject { static void Initialize(Environment* env, v8::Local target); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + SSLCtxPointer ctx_; X509Pointer cert_; X509Pointer issuer_; @@ -337,6 +341,10 @@ class CipherBase : public BaseObject { public: static void Initialize(Environment* env, v8::Local target); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + protected: enum CipherKind { kCipher, @@ -407,6 +415,10 @@ class Hmac : public BaseObject { public: static void Initialize(Environment* env, v8::Local target); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + protected: void HmacInit(const char* hash_type, const char* key, int key_len); bool HmacUpdate(const char* data, int len); @@ -430,6 +442,10 @@ class Hash : public BaseObject { public: static void Initialize(Environment* env, v8::Local target); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + bool HashInit(const char* hash_type); bool HashUpdate(const char* data, int len); @@ -469,6 +485,10 @@ class SignBase : public BaseObject { Error Init(const char* sign_type); Error Update(const char* data, int len); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + protected: void CheckThrow(Error error); @@ -581,6 +601,10 @@ class DiffieHellman : public BaseObject { MakeWeak(); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + private: static void GetField(const v8::FunctionCallbackInfo& args, const BIGNUM* (*get_field)(const DH*), @@ -606,6 +630,10 @@ class ECDH : public BaseObject { char* data, size_t len); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + protected: ECDH(Environment* env, v8::Local wrap, ECKeyPointer&& key) : BaseObject(env, wrap), diff --git a/src/node_crypto_bio.h b/src/node_crypto_bio.h index 380a3a6b4c64f5..dea010fa0158b4 100644 --- a/src/node_crypto_bio.h +++ b/src/node_crypto_bio.h @@ -32,7 +32,7 @@ namespace node { namespace crypto { -class NodeBIO { +class NodeBIO : public MemoryRetainer { public: NodeBIO() : env_(nullptr), initial_(kInitialBufferLength), @@ -110,6 +110,11 @@ class NodeBIO { static NodeBIO* FromBIO(BIO* bio); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackFieldWithSize("buffer", length_); + } + private: static int New(BIO* bio); static int Free(BIO* bio); diff --git a/src/node_file.h b/src/node_file.h index a14a1b0f85e108..6b45dc881750a7 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -66,7 +66,6 @@ class FSReqBase : public ReqWrap { const char* data() const { return has_data_ ? *buffer_ : nullptr; } enum encoding encoding() const { return encoding_; } - size_t self_size() const override { return sizeof(*this); } bool use_bigint() const { return use_bigint_; } private: @@ -92,6 +91,10 @@ class FSReqWrap : public FSReqBase { void ResolveStat(const uv_stat_t* stat) override; void SetReturnValue(const FunctionCallbackInfo& args) override; + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + private: DISALLOW_COPY_AND_ASSIGN(FSReqWrap); }; @@ -150,6 +153,11 @@ class FSReqPromise : public FSReqBase { args.GetReturnValue().Set(resolver->GetPromise()); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("stats_field_array", stats_field_array_); + } + private: bool finished_ = false; AliasedBuffer stats_field_array_; @@ -184,7 +192,10 @@ class FileHandleReadWrap : public ReqWrap { return static_cast(ReqWrap::from_req(req)); } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("buffer", buffer_); + } private: FileHandle* file_handle_; @@ -205,7 +216,6 @@ class FileHandle : public AsyncWrap, public StreamBase { static void New(const v8::FunctionCallbackInfo& args); int fd() const { return fd_; } - size_t self_size() const override { return sizeof(*this); } // Will asynchronously close the FD and return a Promise that will // be resolved once closing is complete. @@ -233,6 +243,11 @@ class FileHandle : public AsyncWrap, public StreamBase { return UV_ENOSYS; // Not implemented (yet). } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("current_read", current_read_); + } + private: // Synchronous close that emits a warning void Close(); @@ -259,7 +274,11 @@ class FileHandle : public AsyncWrap, public StreamBase { FileHandle* file_handle(); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("promise", promise_); + tracker->TrackField("ref", ref_); + } void Resolve(); diff --git a/src/node_http2.cc b/src/node_http2.cc index 0251777644115a..7a5e9ba23e99b3 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -737,7 +737,7 @@ inline void Http2Session::AddStream(Http2Stream* stream) { size_t size = streams_.size(); if (size > statistics_.max_concurrent_streams) statistics_.max_concurrent_streams = size; - IncrementCurrentSessionMemory(stream->self_size()); + IncrementCurrentSessionMemory(sizeof(*stream)); } @@ -745,7 +745,7 @@ inline void Http2Session::RemoveStream(Http2Stream* stream) { if (streams_.empty() || stream == nullptr) return; // Nothing to remove, item was never added? streams_.erase(stream->id()); - DecrementCurrentSessionMemory(stream->self_size()); + DecrementCurrentSessionMemory(sizeof(*stream)); } // Used as one of the Padding Strategy functions. Will attempt to ensure @@ -2694,7 +2694,7 @@ Http2Session::Http2Ping* Http2Session::PopPing() { if (!outstanding_pings_.empty()) { ping = outstanding_pings_.front(); outstanding_pings_.pop(); - DecrementCurrentSessionMemory(ping->self_size()); + DecrementCurrentSessionMemory(sizeof(*ping)); } return ping; } @@ -2703,7 +2703,7 @@ bool Http2Session::AddPing(Http2Session::Http2Ping* ping) { if (outstanding_pings_.size() == max_outstanding_pings_) return false; outstanding_pings_.push(ping); - IncrementCurrentSessionMemory(ping->self_size()); + IncrementCurrentSessionMemory(sizeof(*ping)); return true; } @@ -2712,7 +2712,7 @@ Http2Session::Http2Settings* Http2Session::PopSettings() { if (!outstanding_settings_.empty()) { settings = outstanding_settings_.front(); outstanding_settings_.pop(); - DecrementCurrentSessionMemory(settings->self_size()); + DecrementCurrentSessionMemory(sizeof(*settings)); } return settings; } @@ -2721,7 +2721,7 @@ bool Http2Session::AddSettings(Http2Session::Http2Settings* settings) { if (outstanding_settings_.size() == max_outstanding_settings_) return false; outstanding_settings_.push(settings); - IncrementCurrentSessionMemory(settings->self_size()); + IncrementCurrentSessionMemory(sizeof(*settings)); return true; } @@ -2766,6 +2766,21 @@ void Http2Session::Http2Ping::Done(bool ack, const uint8_t* payload) { } +void nghttp2_stream_write::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackThis(this); + if (req_wrap != nullptr) + tracker->TrackField("req_wrap", req_wrap->GetAsyncWrap()); + tracker->TrackField("buf", buf); +} + + +void nghttp2_header::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackThis(this); + tracker->TrackFieldWithSize("name", nghttp2_rcbuf_get_buf(name).len); + tracker->TrackFieldWithSize("value", nghttp2_rcbuf_get_buf(value).len); +} + + // Set up the process.binding('http2') binding. void Initialize(Local target, Local unused, diff --git a/src/node_http2.h b/src/node_http2.h index d90c3aed66b0a0..cbed2a267d171e 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -83,19 +83,23 @@ enum nghttp2_stream_options { STREAM_OPTION_GET_TRAILERS = 0x2, }; -struct nghttp2_stream_write { +struct nghttp2_stream_write : public MemoryRetainer { WriteWrap* req_wrap = nullptr; uv_buf_t buf; inline explicit nghttp2_stream_write(uv_buf_t buf_) : buf(buf_) {} inline nghttp2_stream_write(WriteWrap* req, uv_buf_t buf_) : req_wrap(req), buf(buf_) {} + + void MemoryInfo(MemoryTracker* tracker) const override; }; -struct nghttp2_header { +struct nghttp2_header : public MemoryRetainer { nghttp2_rcbuf* name = nullptr; nghttp2_rcbuf* value = nullptr; uint8_t flags = 0; + + void MemoryInfo(MemoryTracker* tracker) const override; }; @@ -617,7 +621,12 @@ class Http2Stream : public AsyncWrap, int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count, uv_stream_t* send_handle) override; - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("current_headers", current_headers_); + tracker->TrackField("queue", queue_); + } + std::string diagnostic_name() const override; // JavaScript API @@ -793,7 +802,17 @@ class Http2Session : public AsyncWrap, public StreamListener { // Write data to the session ssize_t Write(const uv_buf_t* bufs, size_t nbufs); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("streams", streams_); + tracker->TrackField("outstanding_pings", outstanding_pings_); + tracker->TrackField("outstanding_settings", outstanding_settings_); + tracker->TrackField("outgoing_buffers", outgoing_buffers_); + tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size()); + tracker->TrackFieldWithSize("pending_rst_streams", + pending_rst_streams_.size() * sizeof(int32_t)); + } + std::string diagnostic_name() const override; // Schedule an RstStream for after the current write finishes. @@ -1109,7 +1128,10 @@ class Http2Session::Http2Ping : public AsyncWrap { public: explicit Http2Ping(Http2Session* session); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("session", session_); + } void Send(uint8_t* payload); void Done(bool ack, const uint8_t* payload = nullptr); @@ -1129,7 +1151,10 @@ class Http2Session::Http2Settings : public AsyncWrap { explicit Http2Settings(Environment* env); explicit Http2Settings(Http2Session* session); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("session", session_); + } void Send(); void Done(bool ack); diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 7d96466c3933fc..e8fc1f22e4938a 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -155,8 +155,9 @@ class Parser : public AsyncWrap, public StreamListener { } - size_t self_size() const override { - return sizeof(*this); + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("current_buffer", current_buffer_); } diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 4ace513810f1b8..288ad77f619188 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -250,6 +250,10 @@ class ConverterObject : public BaseObject, Converter { } } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + protected: ConverterObject(Environment* env, v8::Local wrap, diff --git a/src/node_messaging.cc b/src/node_messaging.cc index 712add06d3e2bc..c28d0d4ea66560 100644 --- a/src/node_messaging.cc +++ b/src/node_messaging.cc @@ -325,6 +325,14 @@ Maybe Message::Serialize(Environment* env, return Just(true); } +void Message::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackThis(this); + tracker->TrackField("array_buffer_contents", array_buffer_contents_); + tracker->TrackFieldWithSize("shared_array_buffers", + shared_array_buffers_.size() * sizeof(shared_array_buffers_[0])); + tracker->TrackField("message_ports", message_ports_); +} + MessagePortData::MessagePortData(MessagePort* owner) : owner_(owner) { } MessagePortData::~MessagePortData() { @@ -332,6 +340,12 @@ MessagePortData::~MessagePortData() { Disentangle(); } +void MessagePortData::MemoryInfo(MemoryTracker* tracker) const { + Mutex::ScopedLock lock(mutex_); + tracker->TrackThis(this); + tracker->TrackField("incoming_messages", incoming_messages_); +} + void MessagePortData::AddToIncomingQueue(Message&& message) { // This function will be called by other threads. Mutex::ScopedLock lock(mutex_); @@ -688,14 +702,6 @@ void MessagePort::Drain(const FunctionCallbackInfo& args) { port->OnMessage(); } -size_t MessagePort::self_size() const { - Mutex::ScopedLock lock(data_->mutex_); - size_t sz = sizeof(*this) + sizeof(*data_); - for (const Message& msg : data_->incoming_messages_) - sz += sizeof(msg) + msg.main_message_buf_.size; - return sz; -} - void MessagePort::Entangle(MessagePort* a, MessagePort* b) { Entangle(a, b->data_.get()); } diff --git a/src/node_messaging.h b/src/node_messaging.h index 62ae633b9e0b8d..da10300aedbd42 100644 --- a/src/node_messaging.h +++ b/src/node_messaging.h @@ -15,7 +15,7 @@ class MessagePortData; class MessagePort; // Represents a single communication message. -class Message { +class Message : public MemoryRetainer { public: explicit Message(MallocedBuffer&& payload = MallocedBuffer()); @@ -55,6 +55,8 @@ class Message { return message_ports_; } + void MemoryInfo(MemoryTracker* tracker) const override; + private: MallocedBuffer main_message_buf_; std::vector> array_buffer_contents_; @@ -66,7 +68,7 @@ class Message { // This contains all data for a `MessagePort` instance that is not tied to // a specific Environment/Isolate/event loop, for easier transfer between those. -class MessagePortData { +class MessagePortData : public MemoryRetainer { public: explicit MessagePortData(MessagePort* owner); ~MessagePortData(); @@ -94,6 +96,8 @@ class MessagePortData { // which can happen on either side of a worker. void Disentangle(); + void MemoryInfo(MemoryTracker* tracker) const override; + private: // After disentangling this message port, the owner handle (if any) // is asynchronously triggered, so that it can close down naturally. @@ -178,7 +182,10 @@ class MessagePort : public HandleWrap { // NULL pointer to the C++ MessagePort object is also detached. inline bool IsDetached() const; - size_t self_size() const override; + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("data", data_); + } private: void OnClose() override; diff --git a/src/node_serdes.cc b/src/node_serdes.cc index 520b350199245a..4b2cc60b3f7584 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -52,6 +52,11 @@ class SerializerContext : public BaseObject, static void WriteUint64(const FunctionCallbackInfo& args); static void WriteDouble(const FunctionCallbackInfo& args); static void WriteRawBytes(const FunctionCallbackInfo& args); + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + private: ValueSerializer serializer_; }; @@ -76,6 +81,11 @@ class DeserializerContext : public BaseObject, static void ReadUint64(const FunctionCallbackInfo& args); static void ReadDouble(const FunctionCallbackInfo& args); static void ReadRawBytes(const FunctionCallbackInfo& args); + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + private: const uint8_t* data_; const size_t length_; diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h index 45150de785f9d1..baf6bdc14ee317 100644 --- a/src/node_stat_watcher.h +++ b/src/node_stat_watcher.h @@ -44,7 +44,9 @@ class StatWatcher : public HandleWrap { static void New(const v8::FunctionCallbackInfo& args); static void Start(const v8::FunctionCallbackInfo& args); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: static void Callback(uv_fs_poll_t* handle, diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index 985c706dc4a2f1..0904311dad865b 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -27,6 +27,11 @@ class NodeCategorySet : public BaseObject { const std::set& GetCategories() { return categories_; } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackField("categories", categories_); + } + private: NodeCategorySet(Environment* env, Local wrap, diff --git a/src/node_worker.cc b/src/node_worker.cc index 6f325668b86921..3768d80a9c58d4 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -403,10 +403,6 @@ void Worker::Exit(int code) { } } -size_t Worker::self_size() const { - return sizeof(*this); -} - namespace { // Return the MessagePort that is global for this Environment and communicates diff --git a/src/node_worker.h b/src/node_worker.h index d802b5cfefdf77..bd737d4800fd79 100644 --- a/src/node_worker.h +++ b/src/node_worker.h @@ -25,7 +25,14 @@ class Worker : public AsyncWrap { // Wait for the worker thread to stop (in a blocking manner). void JoinThread(); - size_t self_size() const override; + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackFieldWithSize("isolate_data", sizeof(IsolateData)); + tracker->TrackFieldWithSize("env", sizeof(Environment)); + tracker->TrackFieldWithSize("thread_exit_async", sizeof(uv_async_t)); + tracker->TrackField("parent_port", parent_port_); + } + bool is_stopped() const; static void New(const v8::FunctionCallbackInfo& args); diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 169816d16f48b6..031666e19ad29c 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -646,7 +646,12 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork { } } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackFieldWithSize("dictionary", dictionary_len_); + tracker->TrackFieldWithSize("zlib memory", + zlib_memory_ + unreported_allocations_); + } private: void Ref() { diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index d6e45c28ff7822..9ed4f153ae5c4c 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -45,7 +45,9 @@ class PipeWrap : public ConnectionWrap { v8::Local unused, v8::Local context); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: PipeWrap(Environment* env, diff --git a/src/process_wrap.cc b/src/process_wrap.cc index 54345b231bccce..3219b1a40b9c16 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -71,7 +71,9 @@ class ProcessWrap : public HandleWrap { target->Set(processString, constructor->GetFunction()); } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: static void New(const FunctionCallbackInfo& args) { diff --git a/src/sharedarraybuffer_metadata.cc b/src/sharedarraybuffer_metadata.cc index 86476a9f12c38b..95fed87c8d4ea0 100644 --- a/src/sharedarraybuffer_metadata.cc +++ b/src/sharedarraybuffer_metadata.cc @@ -47,6 +47,10 @@ class SABLifetimePartner : public BaseObject { MakeWeak(); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + SharedArrayBufferMetadataReference reference; }; diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index 5117d3ab1d1988..346f442f61df0f 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -62,7 +62,9 @@ class SignalWrap : public HandleWrap { target->Set(signalString, constructor->GetFunction()); } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: static void New(const FunctionCallbackInfo& args) { diff --git a/src/stream_base.h b/src/stream_base.h index 405780619856ba..bbb20e52e1a8de 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -346,7 +346,10 @@ class SimpleShutdownWrap : public ShutdownWrap, public OtherBase { v8::Local req_wrap_obj); AsyncWrap* GetAsyncWrap() override { return this; } - size_t self_size() const override { return sizeof(*this); } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } }; template @@ -356,7 +359,11 @@ class SimpleWriteWrap : public WriteWrap, public OtherBase { v8::Local req_wrap_obj); AsyncWrap* GetAsyncWrap() override { return this; } - size_t self_size() const override { return sizeof(*this) + StorageSize(); } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + tracker->TrackFieldWithSize("storage", StorageSize()); + } }; } // namespace node diff --git a/src/stream_pipe.h b/src/stream_pipe.h index 98d6dae11be841..b72a60941b610a 100644 --- a/src/stream_pipe.h +++ b/src/stream_pipe.h @@ -18,7 +18,9 @@ class StreamPipe : public AsyncWrap { static void Start(const v8::FunctionCallbackInfo& args); static void Unpipe(const v8::FunctionCallbackInfo& args); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: StreamBase* source(); diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index 2ab50f1fdcdfab..d6ca9306099e37 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -44,7 +44,9 @@ class TCPWrap : public ConnectionWrap { v8::Local unused, v8::Local context); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: typedef uv_tcp_t HandleType; diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index b87430dad8adc7..df3e34090baf6c 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -71,7 +71,9 @@ class TimerWrap : public HandleWrap { ->GetFunction(env->context()).ToLocalChecked()).FromJust(); } - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: static void SetupTimers(const FunctionCallbackInfo& args) { diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index e731c0c130216b..0d0791b710c860 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -864,6 +864,15 @@ void TLSWrap::GetWriteQueueSize(const FunctionCallbackInfo& info) { } +void TLSWrap::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackThis(this); + tracker->TrackField("error", error_); + tracker->TrackField("pending_cleartext_input", pending_cleartext_input_); + tracker->TrackField("enc_in", crypto::NodeBIO::FromBIO(enc_in_)); + tracker->TrackField("enc_out", crypto::NodeBIO::FromBIO(enc_out_)); +} + + void TLSWrap::Initialize(Local target, Local unused, Local context) { diff --git a/src/tls_wrap.h b/src/tls_wrap.h index 1603d8919a472c..b45e379ca3f61c 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -76,7 +76,7 @@ class TLSWrap : public AsyncWrap, void NewSessionDoneCb(); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override; protected: inline StreamBase* underlying_stream() { diff --git a/src/tty_wrap.h b/src/tty_wrap.h index 91b07a570e9b50..cca5650ddb3964 100644 --- a/src/tty_wrap.h +++ b/src/tty_wrap.h @@ -38,7 +38,9 @@ class TTYWrap : public LibuvStreamWrap { uv_tty_t* UVHandle(); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: TTYWrap(Environment* env, diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 1d1ded449bd221..49f66914e2aa81 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -55,7 +55,11 @@ class SendWrap : public ReqWrap { SendWrap(Environment* env, Local req_wrap_obj, bool have_callback); inline bool have_callback() const; size_t msg_size; - size_t self_size() const override { return sizeof(*this); } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } + private: const bool have_callback_; }; diff --git a/src/udp_wrap.h b/src/udp_wrap.h index 01eb8b961f0cf2..3792bcc459da23 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -64,7 +64,9 @@ class UDPWrap: public HandleWrap { SocketType type); uv_udp_t* UVHandle(); - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } private: typedef uv_udp_t HandleType; diff --git a/test/cctest/test_node_postmortem_metadata.cc b/test/cctest/test_node_postmortem_metadata.cc index b911a92c0de10b..e9acd629f35f91 100644 --- a/test/cctest/test_node_postmortem_metadata.cc +++ b/test/cctest/test_node_postmortem_metadata.cc @@ -34,7 +34,9 @@ class DebugSymbolsTest : public EnvironmentTestFixture {}; class TestHandleWrap : public node::HandleWrap { public: - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(node::MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } TestHandleWrap(node::Environment* env, v8::Local object, @@ -48,7 +50,9 @@ class TestHandleWrap : public node::HandleWrap { class TestReqWrap : public node::ReqWrap { public: - size_t self_size() const override { return sizeof(*this); } + void MemoryInfo(node::MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } TestReqWrap(node::Environment* env, v8::Local object) : node::ReqWrap(env, @@ -67,6 +71,16 @@ TEST_F(DebugSymbolsTest, ExternalStringDataOffset) { NODE_OFF_EXTSTR_DATA); } +class DummyBaseObject : public node::BaseObject { + public: + DummyBaseObject(node::Environment* env, v8::Local obj) : + BaseObject(env, obj) {} + + void MemoryInfo(node::MemoryTracker* tracker) const override { + tracker->TrackThis(this); + } +}; + TEST_F(DebugSymbolsTest, BaseObjectPersistentHandle) { const v8::HandleScope handle_scope(isolate_); const Argv argv; @@ -77,7 +91,7 @@ TEST_F(DebugSymbolsTest, BaseObjectPersistentHandle) { v8::Local object = obj_templ->NewInstance(env.context()).ToLocalChecked(); - node::BaseObject obj(*env, object); + DummyBaseObject obj(*env, object); auto expected = reinterpret_cast(&obj.persistent()); auto calculated = reinterpret_cast(&obj) +