diff --git a/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.cpp b/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.cpp new file mode 100644 index 00000000000000..ebedfc0d01de44 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#include "HermesInstance.h" + +#include + +#ifdef HERMES_ENABLE_DEBUGGER +#include +#include +#include +#endif + +using namespace facebook::hermes; +using namespace facebook::jsi; + +namespace facebook { +namespace react { + +#ifdef HERMES_ENABLE_DEBUGGER + +// Wrapper that strongly retains the HermesRuntime for on device debugging. +// +// HermesInstanceRuntimeAdapter needs to strongly retain the HermesRuntime. Why: +// - facebook::hermes::inspector::chrome::Connection::Impl owns the Adapter +// - facebook::hermes::inspector::chrome::Connection::Impl also owns jsi:: +// objects +// - jsi:: objects need to be deleted before the Runtime. +// +// If Adapter doesn't share ownership over jsi::Runtime, the runtime can be +// deleted before Connection::Impl cleans up all its jsi:: Objects. This will +// lead to a runtime crash. +class HermesInstanceRuntimeAdapter : public inspector::RuntimeAdapter { + public: + HermesInstanceRuntimeAdapter(std::shared_ptr hermesRuntime) + : hermesRuntime_(hermesRuntime) {} + virtual ~HermesInstanceRuntimeAdapter() = default; + + HermesRuntime &getRuntime() override { + return *hermesRuntime_; + } + + private: + std::shared_ptr hermesRuntime_; +}; + +class DecoratedRuntime : public jsi::RuntimeDecorator { + public: + DecoratedRuntime(std::unique_ptr runtime) + : RuntimeDecorator(*runtime), runtime_(std::move(runtime)) { + auto adapter = std::make_unique(runtime_); + + debugToken_ = inspector::chrome::enableDebugging( + std::move(adapter), "Hermes Bridgeless React Native"); + } + + ~DecoratedRuntime() { + inspector::chrome::disableDebugging(debugToken_); + } + + private: + std::shared_ptr runtime_; + inspector::chrome::DebugSessionToken debugToken_; +}; + +#endif + +std::unique_ptr HermesInstance::createJSRuntime() noexcept { + return createJSRuntime(nullptr, nullptr); +} + +std::unique_ptr HermesInstance::createJSRuntime( + std::shared_ptr reactNativeConfig, + std::shared_ptr<::hermes::vm::CrashManager> cm) noexcept { + int64_t vmExperimentFlags = reactNativeConfig + ? reactNativeConfig->getInt64("ios_hermes:vm_experiment_flags") + : 0; + + int64_t heapSizeConfig = reactNativeConfig + ? reactNativeConfig->getInt64("ios_hermes:rn_heap_size_mb") + : 0; + // Default to 3GB if MobileConfigs is not available + auto heapSizeMB = heapSizeConfig > 0 + ? static_cast<::hermes::vm::gcheapsize_t>(heapSizeConfig) + : 3072; + ::hermes::vm::RuntimeConfig::Builder runtimeConfigBuilder = + ::hermes::vm::RuntimeConfig::Builder() + .withGCConfig(::hermes::vm::GCConfig::Builder() + .withMaxHeapSize(heapSizeMB << 20) + .withName("RNBridgeless") + // For the next two arguments: avoid GC before TTI + // by initializing the runtime to allocate directly + // in the old generation, but revert to normal + // operation when we reach the (first) TTI point. + .withAllocInYoung(false) + .withRevertToYGAtTTI(true) + .build()) + .withES6Proxy(false) + .withEnableSampleProfiling(true) + .withVMExperimentFlags(vmExperimentFlags); + + if (cm) { + runtimeConfigBuilder.withCrashMgr(cm); + } + + std::unique_ptr hermesRuntime = + hermes::makeHermesRuntime(runtimeConfigBuilder.build()); + +#ifdef HERMES_ENABLE_DEBUGGER + std::unique_ptr decoratedRuntime = + std::make_unique(std::move(hermesRuntime)); + return decoratedRuntime; +#endif + + return hermesRuntime; +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.h b/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.h new file mode 100644 index 00000000000000..35e8787880f305 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/hermes/HermesInstance.h @@ -0,0 +1,23 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include +#import + +namespace facebook { +namespace react { + +class HermesInstance { + public: + // This is only needed for Android. Consider removing. + static std::unique_ptr createJSRuntime() noexcept; + + static std::unique_ptr createJSRuntime( + std::shared_ptr reactNativeConfig, + std::shared_ptr<::hermes::vm::CrashManager> cm) noexcept; +}; + +} // namespace react +} // namespace facebook