From a6b69b309abf36b8a397c37b88a4add753e3988b Mon Sep 17 00:00:00 2001
From: Marc Rousavy <me@mrousavy.com>
Date: Sun, 23 Jun 2024 12:27:04 +0200
Subject: [PATCH] perf: Speed up Dispatcher get calls

---
 .../cpp/threading/Dispatcher.cpp                 | 16 ++++++++++++++++
 .../cpp/threading/Dispatcher.hpp                 |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/packages/react-native-nitro-modules/cpp/threading/Dispatcher.cpp b/packages/react-native-nitro-modules/cpp/threading/Dispatcher.cpp
index d3929f8c8..11e3ae4bc 100644
--- a/packages/react-native-nitro-modules/cpp/threading/Dispatcher.cpp
+++ b/packages/react-native-nitro-modules/cpp/threading/Dispatcher.cpp
@@ -7,15 +7,31 @@ using namespace facebook;
 
 static constexpr auto GLOBAL_DISPATCHER_HOLDER_NAME = "__nitroDispatcher";
 
+std::unordered_map<jsi::Runtime*, std::weak_ptr<Dispatcher>> Dispatcher::_globalCache;
+
 void Dispatcher::installRuntimeGlobalDispatcher(jsi::Runtime& runtime, std::shared_ptr<Dispatcher> dispatcher) {
   Logger::log(TAG, "Installing global Dispatcher Holder...");
+  
+  // Store a weak reference in global cache
+  _globalCache[&runtime] = std::weak_ptr(dispatcher);
 
+  // Inject the dispatcher into Runtime global (runtime will hold a strong reference)
   jsi::Object dispatcherHolder(runtime);
   dispatcherHolder.setNativeState(runtime, dispatcher);
   runtime.global().setProperty(runtime, GLOBAL_DISPATCHER_HOLDER_NAME, dispatcherHolder);
 }
 
 std::shared_ptr<Dispatcher> Dispatcher::getRuntimeGlobalDispatcher(jsi::Runtime& runtime) {
+  if (_globalCache.contains(&runtime)) [[likely]] {
+    // the runtime is known - we have something in cache
+    std::weak_ptr<Dispatcher> weakDispatcher = _globalCache[&runtime];
+    std::shared_ptr<Dispatcher> strongDispatcher = weakDispatcher.lock();
+    if (strongDispatcher) {
+      // the weak reference we cached is still valid - return it!
+      return strongDispatcher;
+    }
+  }
+  
   jsi::Value dispatcherHolderValue = getRuntimeGlobalDispatcherHolder(runtime);
   jsi::Object dispatcherHolder = dispatcherHolderValue.getObject(runtime);
   return dispatcherHolder.getNativeState<Dispatcher>(runtime);
diff --git a/packages/react-native-nitro-modules/cpp/threading/Dispatcher.hpp b/packages/react-native-nitro-modules/cpp/threading/Dispatcher.hpp
index 00db74759..59089b710 100644
--- a/packages/react-native-nitro-modules/cpp/threading/Dispatcher.hpp
+++ b/packages/react-native-nitro-modules/cpp/threading/Dispatcher.hpp
@@ -70,6 +70,9 @@ class Dispatcher : public jsi::NativeState {
     // 3. Return an open future that gets resolved later by the dispatcher Thread
     return future;
   }
+  
+private:
+  static std::unordered_map<jsi::Runtime*, std::weak_ptr<Dispatcher>> _globalCache;
 
 private:
   static constexpr auto TAG = "Dispatcher";