diff --git a/include/hermes/VM/Runtime.h b/include/hermes/VM/Runtime.h index 8cae48286b2..f54d7391e37 100644 --- a/include/hermes/VM/Runtime.h +++ b/include/hermes/VM/Runtime.h @@ -96,6 +96,8 @@ using VMExperimentFlags = uint32_t; /// Type used to assign object unique integer identifiers. using ObjectID = uint32_t; +using DestructionCallback = std::function; + #define PROP_CACHE_IDS(V) V(RegExpLastIndex, Predefined::lastIndex) /// Fixed set of ids used by the property cache in Runtime. @@ -474,6 +476,12 @@ class Runtime : public HandleRootOwner, } #endif + /// Register \p callback which will be called + /// during runtime destruction. + void registerDestructionCallback(DestructionCallback callback) { + destructionCallbacks_.emplace_back(callback); + } + #ifdef HERMES_ENABLE_DEBUGGER /// Encapsulates useful information about a stack frame, needed by the /// debugger. It requres extra context and cannot be extracted from a @@ -978,6 +986,9 @@ class Runtime : public HandleRootOwner, /// we are sure it's safe to unregisterRuntime in destructor. std::shared_ptr samplingProfiler_; + /// A list of callbacks to call before runtime destruction. + std::vector destructionCallbacks_; + #if defined(HERMES_ENABLE_DEBUGGER) || defined(HERMESVM_TIMELIMIT) /// An atomic boolean set when an async pause is requested. /// This may be manipulated from multiple threads. diff --git a/lib/VM/Runtime.cpp b/lib/VM/Runtime.cpp index 7631d9de7eb..9b4728e927c 100644 --- a/lib/VM/Runtime.cpp +++ b/lib/VM/Runtime.cpp @@ -367,6 +367,10 @@ Runtime::~Runtime() { // Calling delete will automatically remove it from the list. delete &runtimeModuleList_.back(); } + + for (auto callback : destructionCallbacks_) { + callback(this); + } } /// A helper class used to measure the duration of GC marking different roots. diff --git a/lib/VM/TimeLimitMonitor.cpp b/lib/VM/TimeLimitMonitor.cpp index b1cd4ab63f3..482512ff31e 100644 --- a/lib/VM/TimeLimitMonitor.cpp +++ b/lib/VM/TimeLimitMonitor.cpp @@ -89,13 +89,20 @@ void TimeLimitMonitor::watchRuntime(Runtime *runtime, int timeoutInMs) { std::chrono::milliseconds(timeoutInMs); timeoutMap_[runtime] = deadline; } + + runtime->registerDestructionCallback( + [this](Runtime *runtime) { this->unwatchRuntime(runtime); }); + // There is only one thread anyway. newRequestCond_.notify_one(); } void TimeLimitMonitor::unwatchRuntime(Runtime *runtime) { std::lock_guard lock(timeoutMapMtx_); - timeoutMap_.erase(runtime); + // unwatchRuntime() may be called multiple times for the same runtime. + if (timeoutMap_.find(runtime) != timeoutMap_.end()) { + timeoutMap_.erase(runtime); + } } } // namespace vm