Do not disable AllocInYoung for Hermes by default (#46314)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/46314

In Bridgeless's version of the Hermes JVM init path, we defaulted an internal GC option to allocate memory in Hermes' OldGen, and revert that behaviour once an internal API was called which marked the app as loaded.

This is an unsuitable default behaviour, since we can't rely on that internal API to be called on every launch. We're also moving to implicit performance instrumentation, which makes it harder to reliably call this API at the right time.

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D61937427

fbshipit-source-id: 95e43fc093b56aee6362f43b6b0832d1f439fb3f
This commit is contained in:
Pieter De Baets
2024-09-03 16:01:30 -07:00
committed by Facebook GitHub Bot
parent 83489de271
commit db375ab449
10 changed files with 70 additions and 43 deletions
@@ -283,7 +283,8 @@ static NSDictionary *updateInitialProps(NSDictionary *initialProps, BOOL isFabri
- (std::shared_ptr<facebook::react::JSRuntimeFactory>)createJSRuntimeFactory
{
#if USE_HERMES
return std::make_shared<facebook::react::RCTHermesInstance>(_reactNativeConfig, nullptr);
return std::make_shared<facebook::react::RCTHermesInstance>(
_reactNativeConfig, nullptr, /* allocInOldGenBeforeTTI */ false);
#else
return std::make_shared<facebook::react::RCTJscInstance>();
#endif
@@ -3971,7 +3971,7 @@ public final class com/facebook/react/runtime/ReactSurfaceView : com/facebook/re
public final class com/facebook/react/runtime/hermes/HermesInstance : com/facebook/react/runtime/JSRuntimeFactory {
public static final field Companion Lcom/facebook/react/runtime/hermes/HermesInstance$Companion;
public fun <init> ()V
public fun <init> (Lcom/facebook/react/fabric/ReactNativeConfig;)V
public fun <init> (Lcom/facebook/react/fabric/ReactNativeConfig;Z)V
}
public final class com/facebook/react/runtime/hermes/HermesInstance$Companion {
@@ -13,13 +13,20 @@ import com.facebook.react.fabric.ReactNativeConfig
import com.facebook.react.runtime.JSRuntimeFactory
import com.facebook.soloader.SoLoader
public class HermesInstance(reactNativeConfig: ReactNativeConfig?) :
JSRuntimeFactory(initHybrid(reactNativeConfig as Any?)) {
public class HermesInstance(
reactNativeConfig: ReactNativeConfig?,
allocInOldGenBeforeTTI: Boolean
) : JSRuntimeFactory(initHybrid(reactNativeConfig as Any?, allocInOldGenBeforeTTI)) {
public constructor() : this(null)
public constructor() : this(null, false)
public companion object {
@JvmStatic @DoNotStrip protected external fun initHybrid(reactNativeConfig: Any?): HybridData
@JvmStatic
@DoNotStrip
protected external fun initHybrid(
reactNativeConfig: Any?,
allocInOldGenBeforeTTI: Boolean
): HybridData
init {
SoLoader.loadLibrary("hermesinstancejni")
@@ -14,12 +14,13 @@ namespace facebook::react {
jni::local_ref<JHermesInstance::jhybriddata> JHermesInstance::initHybrid(
jni::alias_ref<jclass> /* unused */,
jni::alias_ref<jobject> reactNativeConfig) {
jni::alias_ref<jobject> reactNativeConfig,
bool allocInOldGenBeforeTTI) {
std::shared_ptr<const ReactNativeConfig> config = reactNativeConfig != nullptr
? std::make_shared<const ReactNativeConfigHolder>(reactNativeConfig)
: nullptr;
return makeCxxInstance(config);
return makeCxxInstance(config, allocInOldGenBeforeTTI);
}
void JHermesInstance::registerNatives() {
@@ -31,7 +32,7 @@ void JHermesInstance::registerNatives() {
std::unique_ptr<JSRuntime> JHermesInstance::createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
return HermesInstance::createJSRuntime(
reactNativeConfig_, nullptr, msgQueueThread);
reactNativeConfig_, nullptr, msgQueueThread, allocInOldGenBeforeTTI_);
}
} // namespace facebook::react
@@ -28,12 +28,16 @@ class JHermesInstance
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass> /* unused */,
jni::alias_ref<jobject> reactNativeConfig);
jni::alias_ref<jobject> reactNativeConfig,
bool allocInOldGenBeforeTTI);
static void registerNatives();
JHermesInstance(std::shared_ptr<const ReactNativeConfig> reactNativeConfig)
: reactNativeConfig_(reactNativeConfig){};
JHermesInstance(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
bool allocInOldGenBeforeTTI)
: reactNativeConfig_(std::move(reactNativeConfig)),
allocInOldGenBeforeTTI_(allocInOldGenBeforeTTI){};
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept;
@@ -44,6 +48,7 @@ class JHermesInstance
friend HybridBase;
std::shared_ptr<const ReactNativeConfig> reactNativeConfig_;
bool allocInOldGenBeforeTTI_;
};
} // namespace facebook::react
@@ -51,7 +51,8 @@ void ReactInstanceIntegrationTest::SetUp() {
auto jsRuntimeFactory = std::make_unique<react::HermesInstance>();
std::unique_ptr<react::JSRuntime> runtime_ =
jsRuntimeFactory->createJSRuntime(nullptr, nullptr, messageQueueThread);
jsRuntimeFactory->createJSRuntime(
nullptr, nullptr, messageQueueThread, false);
jsi::Runtime* jsiRuntime = &runtime_->getRuntime();
// Error handler:
@@ -121,32 +121,37 @@ class HermesJSRuntime : public JSRuntime {
std::unique_ptr<JSRuntime> HermesInstance::createJSRuntime(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
std::shared_ptr<::hermes::vm::CrashManager> cm,
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
std::shared_ptr<::hermes::vm::CrashManager> crashManager,
std::shared_ptr<MessageQueueThread> msgQueueThread,
bool allocInOldGenBeforeTTI) noexcept {
assert(msgQueueThread != nullptr);
auto gcConfig = ::hermes::vm::GCConfig::Builder()
// Default to 3GB
.withMaxHeapSize(3072 << 20)
.withName("RNBridgeless");
if (allocInOldGenBeforeTTI) {
// 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.
gcConfig.withAllocInYoung(false).withRevertToYGAtTTI(true);
}
int64_t vmExperimentFlags = reactNativeConfig
? reactNativeConfig->getInt64("ios_hermes:vm_experiment_flags")
: 0;
::hermes::vm::RuntimeConfig::Builder runtimeConfigBuilder =
::hermes::vm::RuntimeConfig::Builder()
.withGCConfig(::hermes::vm::GCConfig::Builder()
// Default to 3GB
.withMaxHeapSize(3072 << 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())
.withGCConfig(gcConfig.build())
.withEnableSampleProfiling(true)
.withMicrotaskQueue(ReactNativeFeatureFlags::enableMicrotasks())
.withVMExperimentFlags(vmExperimentFlags);
if (cm) {
runtimeConfigBuilder.withCrashMgr(cm);
if (crashManager) {
runtimeConfigBuilder.withCrashMgr(crashManager);
}
std::unique_ptr<HermesRuntime> hermesRuntime =
@@ -19,8 +19,9 @@ class HermesInstance {
public:
static std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
std::shared_ptr<::hermes::vm::CrashManager> cm,
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept;
std::shared_ptr<::hermes::vm::CrashManager> crashManager,
std::shared_ptr<MessageQueueThread> msgQueueThread,
bool allocInOldGenBeforeTTI) noexcept;
};
} // namespace facebook::react
@@ -13,8 +13,8 @@
#import <react/runtime/JSRuntimeFactory.h>
#import <react/runtime/hermes/HermesInstance.h>
namespace facebook {
namespace react {
namespace facebook::react {
using CrashManagerProvider =
std::function<std::shared_ptr<::hermes::vm::CrashManager>()>;
@@ -24,7 +24,8 @@ class RCTHermesInstance : public JSRuntimeFactory {
RCTHermesInstance();
RCTHermesInstance(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
CrashManagerProvider crashManagerProvider);
CrashManagerProvider crashManagerProvider,
bool allocInOldGenBeforeTTI);
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept override;
@@ -35,6 +36,7 @@ class RCTHermesInstance : public JSRuntimeFactory {
std::shared_ptr<const ReactNativeConfig> _reactNativeConfig;
CrashManagerProvider _crashManagerProvider;
std::unique_ptr<HermesInstance> _hermesInstance;
bool _allocInOldGenBeforeTTI;
};
} // namespace react
} // namespace facebook
} // namespace facebook::react
@@ -7,16 +7,18 @@
#import "RCTHermesInstance.h"
namespace facebook {
namespace react {
RCTHermesInstance::RCTHermesInstance() : RCTHermesInstance(nullptr, nullptr) {}
namespace facebook::react {
RCTHermesInstance::RCTHermesInstance() : RCTHermesInstance(nullptr, nullptr, false) {}
RCTHermesInstance::RCTHermesInstance(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
CrashManagerProvider crashManagerProvider)
CrashManagerProvider crashManagerProvider,
bool allocInOldGenBeforeTTI)
: _reactNativeConfig(std::move(reactNativeConfig)),
_crashManagerProvider(std::move(crashManagerProvider)),
_hermesInstance(std::make_unique<HermesInstance>())
_hermesInstance(std::make_unique<HermesInstance>()),
_allocInOldGenBeforeTTI(allocInOldGenBeforeTTI)
{
}
@@ -24,8 +26,10 @@ std::unique_ptr<JSRuntime> RCTHermesInstance::createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept
{
return _hermesInstance->createJSRuntime(
_reactNativeConfig, _crashManagerProvider ? _crashManagerProvider() : nullptr, msgQueueThread);
_reactNativeConfig,
_crashManagerProvider ? _crashManagerProvider() : nullptr,
std::move(msgQueueThread),
_allocInOldGenBeforeTTI);
}
} // namespace react
} // namespace facebook
} // namespace facebook::react