mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement mechanism to prevent ShadowTree commit exhaustion (#52645)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52645 Changelog: [internal] This add a new feature flag to test a fix for https://github.com/facebook/react-native/issues/51870 Reviewed By: cortinico, sammy-SC Differential Revision: D78418504 fbshipit-source-id: 2792026b6936393d196fd1e3162f8b2c61a38ed6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d00de31aef
commit
21cd09d4c0
+7
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<3212fc0e52bffab8e56359d207a22357>>
|
||||
* @generated SignedSource<<a90efac589511beb130c499e51150de8>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -306,6 +306,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun preparedTextCacheSize(): Double = accessor.preparedTextCacheSize()
|
||||
|
||||
/**
|
||||
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = accessor.preventShadowTreeCommitExhaustionWithLocking()
|
||||
|
||||
/**
|
||||
* Releases the cached image data when it is consumed by the observers.
|
||||
*/
|
||||
|
||||
+11
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<889f905c29a3558eb172782cccd521c4>>
|
||||
* @generated SignedSource<<b32f66fb09971e786dd1380bbf417720>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -66,6 +66,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
|
||||
private var releaseImageDataWhenConsumedCache: Boolean? = null
|
||||
private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
|
||||
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
|
||||
@@ -496,6 +497,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
|
||||
var cached = preventShadowTreeCommitExhaustionWithLockingCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.preventShadowTreeCommitExhaustionWithLocking()
|
||||
preventShadowTreeCommitExhaustionWithLockingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean {
|
||||
var cached = releaseImageDataWhenConsumedCache
|
||||
if (cached == null) {
|
||||
|
||||
+3
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<69a932d66b50ac8c059b0dab68313616>>
|
||||
* @generated SignedSource<<d1da48f826bc6a1793d1630cb89cb5c1>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -120,6 +120,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun releaseImageDataWhenConsumed(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun skipActivityIdentityAssertionOnHostPause(): Boolean
|
||||
|
||||
+3
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<90dadccf847e0f5fc24d3b1090bba82f>>
|
||||
* @generated SignedSource<<99019349a8f3642c42e6dac5f1476e7f>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -115,6 +115,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun preparedTextCacheSize(): Double = 200.0
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = false
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean = false
|
||||
|
||||
override fun skipActivityIdentityAssertionOnHostPause(): Boolean = false
|
||||
|
||||
+12
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<8663dc63e60ec71e7bf1d5645c39c77f>>
|
||||
* @generated SignedSource<<23605f090bfbebe911caa9d3d834d3e8>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -70,6 +70,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
|
||||
private var releaseImageDataWhenConsumedCache: Boolean? = null
|
||||
private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
|
||||
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
|
||||
@@ -546,6 +547,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
|
||||
var cached = preventShadowTreeCommitExhaustionWithLockingCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.preventShadowTreeCommitExhaustionWithLocking()
|
||||
accessedFeatureFlags.add("preventShadowTreeCommitExhaustionWithLocking")
|
||||
preventShadowTreeCommitExhaustionWithLockingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean {
|
||||
var cached = releaseImageDataWhenConsumedCache
|
||||
if (cached == null) {
|
||||
|
||||
+3
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<07caa03ff4d6e1e624a9a71d5aeceebe>>
|
||||
* @generated SignedSource<<780793412b76f101be1569d7a866c435>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -115,6 +115,8 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun preparedTextCacheSize(): Double
|
||||
|
||||
@DoNotStrip public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
|
||||
|
||||
@DoNotStrip public fun releaseImageDataWhenConsumed(): Boolean
|
||||
|
||||
@DoNotStrip public fun skipActivityIdentityAssertionOnHostPause(): Boolean
|
||||
|
||||
+15
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<8121b9fc632bb1db16a1554ea5dd0b87>>
|
||||
* @generated SignedSource<<f310a5dc27fd655eab4445cb25d4c85c>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -315,6 +315,12 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("preventShadowTreeCommitExhaustionWithLocking");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("releaseImageDataWhenConsumed");
|
||||
@@ -639,6 +645,11 @@ double JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize(
|
||||
return ReactNativeFeatureFlags::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::releaseImageDataWhenConsumed(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::releaseImageDataWhenConsumed();
|
||||
@@ -883,6 +894,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"preparedTextCacheSize",
|
||||
JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize),
|
||||
makeNativeMethod(
|
||||
"preventShadowTreeCommitExhaustionWithLocking",
|
||||
JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking),
|
||||
makeNativeMethod(
|
||||
"releaseImageDataWhenConsumed",
|
||||
JReactNativeFeatureFlagsCxxInterop::releaseImageDataWhenConsumed),
|
||||
|
||||
+4
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<1cfdc8abd4434d8b40d685b9beb79e3c>>
|
||||
* @generated SignedSource<<8c1da07c0b7d2053f7fdaac4326c3ac1>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -168,6 +168,9 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static double preparedTextCacheSize(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool preventShadowTreeCommitExhaustionWithLocking(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool releaseImageDataWhenConsumed(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<3e49ef5b83d57ba597a2675693046ec2>>
|
||||
* @generated SignedSource<<355265aa8f13e3f307d6e30db6b80d41>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -210,6 +210,10 @@ double ReactNativeFeatureFlags::preparedTextCacheSize() {
|
||||
return getAccessor().preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking() {
|
||||
return getAccessor().preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::releaseImageDataWhenConsumed() {
|
||||
return getAccessor().releaseImageDataWhenConsumed();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<191db129f17bcf82d2d133484124867b>>
|
||||
* @generated SignedSource<<c584290ce61ee78bdf843c19dd40c40d>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -269,6 +269,11 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static double preparedTextCacheSize();
|
||||
|
||||
/**
|
||||
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
|
||||
*/
|
||||
RN_EXPORT static bool preventShadowTreeCommitExhaustionWithLocking();
|
||||
|
||||
/**
|
||||
* Releases the cached image data when it is consumed by the observers.
|
||||
*/
|
||||
|
||||
+34
-16
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<26cc2b59099e4eb6bc97b0ea048d2e74>>
|
||||
* @generated SignedSource<<dc5c6b3273ef312426c4ac366cc13772>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -857,6 +857,24 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustionWithLocking() {
|
||||
auto flagValue = preventShadowTreeCommitExhaustionWithLocking_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(46, "preventShadowTreeCommitExhaustionWithLocking");
|
||||
|
||||
flagValue = currentProvider_->preventShadowTreeCommitExhaustionWithLocking();
|
||||
preventShadowTreeCommitExhaustionWithLocking_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() {
|
||||
auto flagValue = releaseImageDataWhenConsumed_.load();
|
||||
|
||||
@@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(46, "releaseImageDataWhenConsumed");
|
||||
markFlagAsAccessed(47, "releaseImageDataWhenConsumed");
|
||||
|
||||
flagValue = currentProvider_->releaseImageDataWhenConsumed();
|
||||
releaseImageDataWhenConsumed_ = flagValue;
|
||||
@@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause()
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(47, "skipActivityIdentityAssertionOnHostPause");
|
||||
markFlagAsAccessed(48, "skipActivityIdentityAssertionOnHostPause");
|
||||
|
||||
flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause();
|
||||
skipActivityIdentityAssertionOnHostPause_ = flagValue;
|
||||
@@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(48, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
markFlagAsAccessed(49, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
|
||||
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
|
||||
@@ -920,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit(
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(49, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
markFlagAsAccessed(50, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
|
||||
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
|
||||
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
|
||||
@@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(50, "useAlwaysAvailableJSErrorHandling");
|
||||
markFlagAsAccessed(51, "useAlwaysAvailableJSErrorHandling");
|
||||
|
||||
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
|
||||
useAlwaysAvailableJSErrorHandling_ = flagValue;
|
||||
@@ -956,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(51, "useFabricInterop");
|
||||
markFlagAsAccessed(52, "useFabricInterop");
|
||||
|
||||
flagValue = currentProvider_->useFabricInterop();
|
||||
useFabricInterop_ = flagValue;
|
||||
@@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroi
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(52, "useNativeEqualsInNativeReadableArrayAndroid");
|
||||
markFlagAsAccessed(53, "useNativeEqualsInNativeReadableArrayAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid();
|
||||
useNativeEqualsInNativeReadableArrayAndroid_ = flagValue;
|
||||
@@ -992,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(53, "useNativeTransformHelperAndroid");
|
||||
markFlagAsAccessed(54, "useNativeTransformHelperAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeTransformHelperAndroid();
|
||||
useNativeTransformHelperAndroid_ = flagValue;
|
||||
@@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(54, "useNativeViewConfigsInBridgelessMode");
|
||||
markFlagAsAccessed(55, "useNativeViewConfigsInBridgelessMode");
|
||||
|
||||
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
|
||||
useNativeViewConfigsInBridgelessMode_ = flagValue;
|
||||
@@ -1028,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(55, "useOptimizedEventBatchingOnAndroid");
|
||||
markFlagAsAccessed(56, "useOptimizedEventBatchingOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
|
||||
useOptimizedEventBatchingOnAndroid_ = flagValue;
|
||||
@@ -1046,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(56, "useRawPropsJsiValue");
|
||||
markFlagAsAccessed(57, "useRawPropsJsiValue");
|
||||
|
||||
flagValue = currentProvider_->useRawPropsJsiValue();
|
||||
useRawPropsJsiValue_ = flagValue;
|
||||
@@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(57, "useShadowNodeStateOnClone");
|
||||
markFlagAsAccessed(58, "useShadowNodeStateOnClone");
|
||||
|
||||
flagValue = currentProvider_->useShadowNodeStateOnClone();
|
||||
useShadowNodeStateOnClone_ = flagValue;
|
||||
@@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(58, "useTurboModuleInterop");
|
||||
markFlagAsAccessed(59, "useTurboModuleInterop");
|
||||
|
||||
flagValue = currentProvider_->useTurboModuleInterop();
|
||||
useTurboModuleInterop_ = flagValue;
|
||||
@@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(59, "useTurboModules");
|
||||
markFlagAsAccessed(60, "useTurboModules");
|
||||
|
||||
flagValue = currentProvider_->useTurboModules();
|
||||
useTurboModules_ = flagValue;
|
||||
@@ -1118,7 +1136,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(60, "virtualViewPrerenderRatio");
|
||||
markFlagAsAccessed(61, "virtualViewPrerenderRatio");
|
||||
|
||||
flagValue = currentProvider_->virtualViewPrerenderRatio();
|
||||
virtualViewPrerenderRatio_ = flagValue;
|
||||
|
||||
+4
-2
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<822091facf02e7a8e4d34e62881a1a7b>>
|
||||
* @generated SignedSource<<edfd880ca5034a683053dc95e177a7c2>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -78,6 +78,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool fuseboxNetworkInspectionEnabled();
|
||||
bool hideOffscreenVirtualViewsOnIOS();
|
||||
double preparedTextCacheSize();
|
||||
bool preventShadowTreeCommitExhaustionWithLocking();
|
||||
bool releaseImageDataWhenConsumed();
|
||||
bool skipActivityIdentityAssertionOnHostPause();
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid();
|
||||
@@ -104,7 +105,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
|
||||
bool wasOverridden_;
|
||||
|
||||
std::array<std::atomic<const char*>, 61> accessedFeatureFlags_;
|
||||
std::array<std::atomic<const char*>, 62> accessedFeatureFlags_;
|
||||
|
||||
std::atomic<std::optional<bool>> commonTestFlag_;
|
||||
std::atomic<std::optional<bool>> cxxNativeAnimatedEnabled_;
|
||||
@@ -152,6 +153,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> fuseboxNetworkInspectionEnabled_;
|
||||
std::atomic<std::optional<bool>> hideOffscreenVirtualViewsOnIOS_;
|
||||
std::atomic<std::optional<double>> preparedTextCacheSize_;
|
||||
std::atomic<std::optional<bool>> preventShadowTreeCommitExhaustionWithLocking_;
|
||||
std::atomic<std::optional<bool>> releaseImageDataWhenConsumed_;
|
||||
std::atomic<std::optional<bool>> skipActivityIdentityAssertionOnHostPause_;
|
||||
std::atomic<std::optional<bool>> traceTurboModulePromiseRejectionsOnAndroid_;
|
||||
|
||||
+5
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<efd96785ae3ffd19a4730e5f3eef76b2>>
|
||||
* @generated SignedSource<<d7534fe6e3b398e56c179da8233e3b0a>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -211,6 +211,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
+10
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<d8f58c2014535394a14199a38313c1d5>>
|
||||
* @generated SignedSource<<6502c090532e1d7d2ac67cf6e711d9f4>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -459,6 +459,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
auto value = values_["preventShadowTreeCommitExhaustionWithLocking"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
auto value = values_["releaseImageDataWhenConsumed"];
|
||||
if (!value.isNull()) {
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<094495d25071a77cbe2ee91d13b0415d>>
|
||||
* @generated SignedSource<<a26af781141939d35cff83bacf522bb0>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -71,6 +71,7 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool fuseboxNetworkInspectionEnabled() = 0;
|
||||
virtual bool hideOffscreenVirtualViewsOnIOS() = 0;
|
||||
virtual double preparedTextCacheSize() = 0;
|
||||
virtual bool preventShadowTreeCommitExhaustionWithLocking() = 0;
|
||||
virtual bool releaseImageDataWhenConsumed() = 0;
|
||||
virtual bool skipActivityIdentityAssertionOnHostPause() = 0;
|
||||
virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0;
|
||||
|
||||
+6
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<b553a8bf75d7047328c26c4b9029d509>>
|
||||
* @generated SignedSource<<cadb1f2c1c10a03593dc7c9a9a94747b>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -274,6 +274,11 @@ double NativeReactNativeFeatureFlags::preparedTextCacheSize(
|
||||
return ReactNativeFeatureFlags::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::releaseImageDataWhenConsumed(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::releaseImageDataWhenConsumed();
|
||||
|
||||
+3
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<d2506af091e796331f473dbb38aae518>>
|
||||
* @generated SignedSource<<de04d72490f2c09abdcea51e6f02796c>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -128,6 +128,8 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
double preparedTextCacheSize(jsi::Runtime& runtime);
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking(jsi::Runtime& runtime);
|
||||
|
||||
bool releaseImageDataWhenConsumed(jsi::Runtime& runtime);
|
||||
|
||||
bool skipActivityIdentityAssertionOnHostPause(jsi::Runtime& runtime);
|
||||
|
||||
@@ -25,6 +25,10 @@ namespace facebook::react {
|
||||
using CommitStatus = ShadowTree::CommitStatus;
|
||||
using CommitMode = ShadowTree::CommitMode;
|
||||
|
||||
namespace {
|
||||
const int MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates (possibly) a new tree where all nodes with non-obsolete `State`
|
||||
* objects. If all `State` objects in the tree are not obsolete for the moment
|
||||
@@ -241,17 +245,31 @@ CommitStatus ShadowTree::commit(
|
||||
const CommitOptions& commitOptions) const {
|
||||
[[maybe_unused]] int attempts = 0;
|
||||
|
||||
while (true) {
|
||||
attempts++;
|
||||
|
||||
auto status = tryCommit(transaction, commitOptions);
|
||||
if (status != CommitStatus::Failed) {
|
||||
return status;
|
||||
if (ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking()) {
|
||||
while (attempts < MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING) {
|
||||
auto status = tryCommit(transaction, commitOptions);
|
||||
if (status != CommitStatus::Failed) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// After multiple attempts, we failed to commit the transaction.
|
||||
// Something internally went terribly wrong.
|
||||
react_native_assert(attempts < 1024);
|
||||
{
|
||||
std::unique_lock lock(commitMutex_);
|
||||
return tryCommit(transaction, commitOptions);
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
attempts++;
|
||||
|
||||
auto status = tryCommit(transaction, commitOptions);
|
||||
if (status != CommitStatus::Failed) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// After multiple attempts, we failed to commit the transaction.
|
||||
// Something internally went terribly wrong.
|
||||
react_native_assert(attempts < 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,6 +534,17 @@ const definitions: FeatureFlagDefinitions = {
|
||||
},
|
||||
ossReleaseStage: 'none',
|
||||
},
|
||||
preventShadowTreeCommitExhaustionWithLocking: {
|
||||
defaultValue: false,
|
||||
metadata: {
|
||||
dateAdded: '2025-07-14',
|
||||
description:
|
||||
'Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.',
|
||||
expectedReleaseValue: true,
|
||||
purpose: 'experimentation',
|
||||
},
|
||||
ossReleaseStage: 'none',
|
||||
},
|
||||
releaseImageDataWhenConsumed: {
|
||||
defaultValue: false,
|
||||
metadata: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<9a7737303df151e91a4a6fdbec353e76>>
|
||||
* @generated SignedSource<<d30fc4e36ad600353c9b9098fd71430a>>
|
||||
* @flow strict
|
||||
* @noformat
|
||||
*/
|
||||
@@ -97,6 +97,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
|
||||
fuseboxNetworkInspectionEnabled: Getter<boolean>,
|
||||
hideOffscreenVirtualViewsOnIOS: Getter<boolean>,
|
||||
preparedTextCacheSize: Getter<number>,
|
||||
preventShadowTreeCommitExhaustionWithLocking: Getter<boolean>,
|
||||
releaseImageDataWhenConsumed: Getter<boolean>,
|
||||
skipActivityIdentityAssertionOnHostPause: Getter<boolean>,
|
||||
traceTurboModulePromiseRejectionsOnAndroid: Getter<boolean>,
|
||||
@@ -382,6 +383,10 @@ export const hideOffscreenVirtualViewsOnIOS: Getter<boolean> = createNativeFlagG
|
||||
* Number cached PreparedLayouts in TextLayoutManager cache
|
||||
*/
|
||||
export const preparedTextCacheSize: Getter<number> = createNativeFlagGetter('preparedTextCacheSize', 200);
|
||||
/**
|
||||
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
|
||||
*/
|
||||
export const preventShadowTreeCommitExhaustionWithLocking: Getter<boolean> = createNativeFlagGetter('preventShadowTreeCommitExhaustionWithLocking', false);
|
||||
/**
|
||||
* Releases the cached image data when it is consumed by the observers.
|
||||
*/
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<f0cb1821d25df02c6026a815eac4c076>>
|
||||
* @generated SignedSource<<45c98e5f4b5f3d3a8a0ded4c5148b549>>
|
||||
* @flow strict
|
||||
* @noformat
|
||||
*/
|
||||
@@ -71,6 +71,7 @@ export interface Spec extends TurboModule {
|
||||
+fuseboxNetworkInspectionEnabled?: () => boolean;
|
||||
+hideOffscreenVirtualViewsOnIOS?: () => boolean;
|
||||
+preparedTextCacheSize?: () => number;
|
||||
+preventShadowTreeCommitExhaustionWithLocking?: () => boolean;
|
||||
+releaseImageDataWhenConsumed?: () => boolean;
|
||||
+skipActivityIdentityAssertionOnHostPause?: () => boolean;
|
||||
+traceTurboModulePromiseRejectionsOnAndroid?: () => boolean;
|
||||
|
||||
Reference in New Issue
Block a user