diff --git a/src/env.cc b/src/env.cc index 4a67c80f1a99bd..4c8cb75945d825 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1279,6 +1279,11 @@ void Environment::RunCleanup() { // Defer the BaseObject cleanup after handles are cleaned up. CleanupHandles(); + while (!cleanable_queue_.IsEmpty()) { + Cleanable* cleanable = cleanable_queue_.PopFront(); + cleanable->Clean(); + } + while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() || native_immediates_.size() > 0 || native_immediates_threadsafe_.size() > 0 || diff --git a/src/env.h b/src/env.h index 772cbb26108665..2d8af8335d7d61 100644 --- a/src/env.h +++ b/src/env.h @@ -594,6 +594,18 @@ void DefaultProcessExitHandlerInternal(Environment* env, ExitCode exit_code); v8::Maybe SpinEventLoopInternal(Environment* env); v8::Maybe EmitProcessExitInternal(Environment* env); +class Cleanable { + public: + virtual ~Cleanable() = default; + + protected: + ListNode cleanable_queue_; + + private: + virtual void Clean() = 0; + friend class Environment; +}; + /** * Environment is a per-isolate data structure that represents an execution * environment. Each environment has a principal realm. An environment can @@ -902,8 +914,12 @@ class Environment final : public MemoryRetainer { typedef ListHead HandleWrapQueue; typedef ListHead ReqWrapQueue; + typedef ListHead CleanableQueue; inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; } + inline CleanableQueue* cleanable_queue() { + return &cleanable_queue_; + } inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; } // https://w3c.github.io/hr-time/#dfn-time-origin @@ -1192,6 +1208,7 @@ class Environment final : public MemoryRetainer { // memory are predictable. For more information please refer to // `doc/contributing/node-postmortem-support.md` friend int GenDebugSymbols(); + CleanableQueue cleanable_queue_; HandleWrapQueue handle_wrap_queue_; ReqWrapQueue req_wrap_queue_; std::list handle_cleanup_queue_; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 42bd7b42d398ec..2302e8d94da325 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -84,7 +84,7 @@ using v8::Value; namespace { -class CallbackInfo { +class CallbackInfo : public Cleanable { public: static inline Local CreateTrackedArrayBuffer( Environment* env, @@ -97,7 +97,7 @@ class CallbackInfo { CallbackInfo& operator=(const CallbackInfo&) = delete; private: - static void CleanupHook(void* data); + void Clean(); inline void OnBackingStoreFree(); inline void CallAndResetCallback(); inline CallbackInfo(Environment* env, @@ -112,7 +112,6 @@ class CallbackInfo { Environment* const env_; }; - Local CallbackInfo::CreateTrackedArrayBuffer( Environment* env, char* data, @@ -152,25 +151,23 @@ CallbackInfo::CallbackInfo(Environment* env, data_(data), hint_(hint), env_(env) { - env->AddCleanupHook(CleanupHook, this); + env->cleanable_queue()->PushFront(this); env->isolate()->AdjustAmountOfExternalAllocatedMemory(sizeof(*this)); } -void CallbackInfo::CleanupHook(void* data) { - CallbackInfo* self = static_cast(data); - +void CallbackInfo::Clean() { { - HandleScope handle_scope(self->env_->isolate()); - Local ab = self->persistent_.Get(self->env_->isolate()); + HandleScope handle_scope(env_->isolate()); + Local ab = persistent_.Get(env_->isolate()); if (!ab.IsEmpty() && ab->IsDetachable()) { ab->Detach(Local()).Check(); - self->persistent_.Reset(); + persistent_.Reset(); } } // Call the callback in this case, but don't delete `this` yet because the // BackingStore deleter callback will do so later. - self->CallAndResetCallback(); + CallAndResetCallback(); } void CallbackInfo::CallAndResetCallback() { @@ -182,7 +179,7 @@ void CallbackInfo::CallAndResetCallback() { } if (callback != nullptr) { // Clean up all Environment-related state and run the callback. - env_->RemoveCleanupHook(CleanupHook, this); + cleanable_queue_.Remove(); int64_t change_in_bytes = -static_cast(sizeof(*this)); env_->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);