From 8fb47215e3f984f6b3f939fc63719390cfef3c28 Mon Sep 17 00:00:00 2001 From: Gang Zhao Date: Wed, 25 Feb 2026 14:15:22 -0800 Subject: [PATCH] Allow HermesJSRuntime/HermesRuntimeTargetDelegate to take both jsi::Runtime and HermesRuntime arguments in ctor (#55732) Summary: Ideally we only need to pass jsi::Runtime, from which we can cast to IHermes for Hermes specific interface methods. But in some scenarios like instrumenting the runtime or tracing JSI calls, the passed runtime would be a decorator of the actual HermesRuntime, we can't do casting on the decoration type since it doesn't implement IHermes. So this diff changes it to pass both a shared_ptr of jsi::Runtime and HermesRuntime reference. It has no behavioral change. Changelog: [Internal] Differential Revision: D94258352 --- .../hermes/executor/HermesExecutorFactory.cpp | 2 +- .../chrome/HermesRuntimeTargetDelegate.cpp | 41 +++++++++++-------- .../chrome/HermesRuntimeTargetDelegate.h | 2 +- .../JsiIntegrationTestHermesEngineAdapter.cpp | 2 +- .../react/runtime/hermes/HermesInstance.cpp | 17 +++++--- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp index 951979499427..d83803fc4274 100644 --- a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp +++ b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp @@ -265,7 +265,7 @@ HermesExecutor::getRuntimeTargetDelegate() { if (!targetDelegate_) { targetDelegate_ = std::make_unique( - hermesRuntime_); + hermesRuntime_, *hermesRuntime_); } return *targetDelegate_; } diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.cpp index 493a786518e0..3fdedaa1c9e9 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.cpp @@ -36,8 +36,9 @@ const uint16_t HERMES_SAMPLING_FREQUENCY_HZ = 10000; class HermesRuntimeSamplingProfileDelegate { public: explicit HermesRuntimeSamplingProfileDelegate( - std::shared_ptr hermesRuntime) - : hermesRuntime_(std::move(hermesRuntime)) {} + std::shared_ptr runtime, + hermes::HermesRuntime& hermesRuntime) + : runtime_(std::move(runtime)), hermesRuntime_(hermesRuntime) {} void startSampling() { auto* hermesAPI = jsi::castInterface(makeHermesRootAPI()); @@ -52,11 +53,12 @@ class HermesRuntimeSamplingProfileDelegate { tracing::RuntimeSamplingProfile collectSamplingProfile() { return tracing::HermesRuntimeSamplingProfileSerializer:: serializeToTracingSamplingProfile( - hermesRuntime_->dumpSampledTraceToProfile()); + hermesRuntime_.dumpSampledTraceToProfile()); } private: - std::shared_ptr hermesRuntime_; + std::shared_ptr runtime_; + HermesRuntime& hermesRuntime_; }; } // namespace @@ -93,13 +95,16 @@ class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate { public: explicit Impl( HermesRuntimeTargetDelegate& delegate, - std::shared_ptr hermesRuntime) + std::shared_ptr runtime, + HermesRuntime& hermesRuntime) : delegate_(delegate), - runtime_(hermesRuntime), - cdpDebugAPI_(CDPDebugAPI::create(*runtime_)), + runtime_(runtime), + hermesRuntime_(hermesRuntime), + cdpDebugAPI_(CDPDebugAPI::create(hermesRuntime_)), samplingProfileDelegate_( std::make_unique( - std::move(hermesRuntime))) {} + std::move(runtime), + hermesRuntime_)) {} CDPDebugAPI& getCDPDebugAPI() { return *cdpDebugAPI_; @@ -119,7 +124,7 @@ class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate { sessionState, std::move(previouslyExportedState), executionContextDescription, - *runtime_, + hermesRuntime_, delegate_, std::move(runtimeExecutor))); } @@ -209,7 +214,7 @@ class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate { // properly representing the stack trace in other use cases, where native // frames aren't stripped on serialisation. return std::make_unique( - runtime_->getDebugger().captureStackTrace()); + hermesRuntime_.getDebugger().captureStackTrace()); } void enableSamplingProfiler() override { @@ -267,7 +272,8 @@ class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate { private: HermesRuntimeTargetDelegate& delegate_; - std::shared_ptr runtime_; + std::shared_ptr runtime_; + HermesRuntime& hermesRuntime_; const std::unique_ptr cdpDebugAPI_; std::unique_ptr samplingProfileDelegate_; @@ -284,11 +290,13 @@ class HermesRuntimeTargetDelegate::Impl final public: explicit Impl( HermesRuntimeTargetDelegate&, - std::shared_ptr hermesRuntime) - : FallbackRuntimeTargetDelegate{hermesRuntime->description()}, + std::shared_ptr runtime, + HermesRuntime& hermesRuntime) + : FallbackRuntimeTargetDelegate{hermesRuntime.description()}, samplingProfileDelegate_( std::make_unique( - std::move(hermesRuntime))) {} + std::move(runtime), + hermesRuntime)) {} void enableSamplingProfiler() override { samplingProfileDelegate_->startSampling(); @@ -310,8 +318,9 @@ class HermesRuntimeTargetDelegate::Impl final #endif // HERMES_ENABLE_DEBUGGER HermesRuntimeTargetDelegate::HermesRuntimeTargetDelegate( - std::shared_ptr hermesRuntime) - : impl_(std::make_unique(*this, std::move(hermesRuntime))) {} + std::shared_ptr runtime, + HermesRuntime& hermesRuntime) + : impl_(std::make_unique(*this, std::move(runtime), hermesRuntime)) {} HermesRuntimeTargetDelegate::~HermesRuntimeTargetDelegate() = default; diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.h b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.h index 07a63f2c47e4..7edb1bd14272 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.h +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.h @@ -29,7 +29,7 @@ class HermesRuntimeTargetDelegate : public RuntimeTargetDelegate { /** * Creates a HermesRuntimeTargetDelegate for the given runtime. */ - explicit HermesRuntimeTargetDelegate(std::shared_ptr hermesRuntime); + explicit HermesRuntimeTargetDelegate(std::shared_ptr runtime, hermes::HermesRuntime &hermesRuntime); ~HermesRuntimeTargetDelegate() override; diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/engines/JsiIntegrationTestHermesEngineAdapter.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tests/engines/JsiIntegrationTestHermesEngineAdapter.cpp index 19a8af8c5c61..fa7f10a2f36e 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/engines/JsiIntegrationTestHermesEngineAdapter.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/engines/JsiIntegrationTestHermesEngineAdapter.cpp @@ -17,7 +17,7 @@ JsiIntegrationTestHermesEngineAdapter::JsiIntegrationTestHermesEngineAdapter( ::hermes::vm::CompilationMode::ForceLazyCompilation) .build())}, jsExecutor_{jsExecutor}, - runtimeTargetDelegate_{runtime_} { + runtimeTargetDelegate_{runtime_, *runtime_} { // NOTE: In React Native, registerForProfiling is called by // HermesInstance::unstable_initializeOnJsThread, called from // ReactInstance::initializeRuntime. Ideally, we should figure out how to diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp index 4e12be7a6a90..b308cfd42082 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp @@ -98,8 +98,10 @@ class DecoratedRuntime : public jsi::RuntimeDecorator { class HermesJSRuntime : public JSRuntime { public: - HermesJSRuntime(std::unique_ptr runtime) - : runtime_(std::move(runtime)) {} + HermesJSRuntime( + std::shared_ptr runtime, + HermesRuntime& hermesRuntime) + : runtime_(std::move(runtime)), hermesRuntime_(hermesRuntime) {} jsi::Runtime& getRuntime() noexcept override { return *runtime_; @@ -108,17 +110,18 @@ class HermesJSRuntime : public JSRuntime { jsinspector_modern::RuntimeTargetDelegate& getRuntimeTargetDelegate() override { if (!targetDelegate_) { - targetDelegate_.emplace(runtime_); + targetDelegate_.emplace(runtime_, hermesRuntime_); } return *targetDelegate_; } void unstable_initializeOnJsThread() override { - runtime_->registerForProfiling(); + hermesRuntime_.registerForProfiling(); } private: - std::shared_ptr runtime_; + std::shared_ptr runtime_; + HermesRuntime& hermesRuntime_; std::optional targetDelegate_; }; @@ -173,7 +176,9 @@ std::unique_ptr HermesInstance::createJSRuntime( (void)msgQueueThread; #endif - return std::make_unique(std::move(hermesRuntime)); + HermesRuntime& hermesRuntimeRef = *hermesRuntime; + return std::make_unique( + std::move(hermesRuntime), hermesRuntimeRef); } } // namespace facebook::react