From b2967e0276f326d40e525acc74b1db6432d6a531 Mon Sep 17 00:00:00 2001 From: Nick Lefever Date: Mon, 3 Jun 2024 15:10:53 -0700 Subject: [PATCH 1/2] Add feature flag for shadow node reference updates (#44769) Summary: Changelog: [Internal] Adding a feature flag to conditionally enable shadow node reference updates when cloning nodes within react native. Reviewed By: sammy-SC Differential Revision: D57860868 --- .../featureflags/ReactNativeFeatureFlags.kt | 8 ++++++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +++++++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +++- .../ReactNativeFeatureFlagsDefaults.kt | 4 +++- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++++++++++- .../ReactNativeFeatureFlagsProvider.kt | 4 +++- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +++++++++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 ++++- .../featureflags/ReactNativeFeatureFlags.cpp | 6 ++++- .../featureflags/ReactNativeFeatureFlags.h | 7 +++++- .../ReactNativeFeatureFlagsAccessor.cpp | 22 +++++++++++++++++-- .../ReactNativeFeatureFlagsAccessor.h | 6 +++-- .../ReactNativeFeatureFlagsDefaults.h | 6 ++++- .../ReactNativeFeatureFlagsProvider.h | 3 ++- .../NativeReactNativeFeatureFlags.cpp | 7 +++++- .../NativeReactNativeFeatureFlags.h | 4 +++- .../ReactNativeFeatureFlags.config.js | 5 +++++ .../featureflags/ReactNativeFeatureFlags.js | 7 +++++- .../specs/NativeReactNativeFeatureFlags.js | 3 ++- 19 files changed, 122 insertions(+), 20 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 48e065fd87b..0d621fa7563 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -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<<4e30b8a42dfe7e041ecb30a386b54e50>> + * @generated SignedSource<<987e450aa9db1b9da0e2a5a63deae4fe>> */ /** @@ -148,6 +148,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun useNativeViewConfigsInBridgelessMode(): Boolean = accessor.useNativeViewConfigsInBridgelessMode() + /** + * When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree. + */ + @JvmStatic + public fun useRuntimeShadowNodeReferenceUpdate(): Boolean = accessor.useRuntimeShadowNodeReferenceUpdate() + /** * When enabled, it uses optimised state reconciliation algorithm. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index d4411cb4465..d3b0d6f642c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -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<<944fabed27a371ce2e1a86e367312c1f>> + * @generated SignedSource<<1a6f57f6bc5b8efd35d6846c71166126>> */ /** @@ -40,6 +40,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var setAndroidLayoutDirectionCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null + private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null private var useStateAlignmentMechanismCache: Boolean? = null override fun commonTestFlag(): Boolean { @@ -222,6 +223,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun useRuntimeShadowNodeReferenceUpdate(): Boolean { + var cached = useRuntimeShadowNodeReferenceUpdateCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useRuntimeShadowNodeReferenceUpdate() + useRuntimeShadowNodeReferenceUpdateCache = cached + } + return cached + } + override fun useStateAlignmentMechanism(): Boolean { var cached = useStateAlignmentMechanismCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 32c41138a40..677ad63448d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -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<> + * @generated SignedSource<<1b8b3b8d140faefe9e5269b27770b235>> */ /** @@ -68,6 +68,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean + @DoNotStrip @JvmStatic public external fun useRuntimeShadowNodeReferenceUpdate(): Boolean + @DoNotStrip @JvmStatic public external fun useStateAlignmentMechanism(): Boolean @DoNotStrip @JvmStatic public external fun override(provider: Any) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 5c2f253babd..ebaaa298baf 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -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<> + * @generated SignedSource<<656d5e2feea3ec122516b75eaacc3323>> */ /** @@ -63,5 +63,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun useNativeViewConfigsInBridgelessMode(): Boolean = false + override fun useRuntimeShadowNodeReferenceUpdate(): Boolean = false + override fun useStateAlignmentMechanism(): Boolean = false } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 0a7fd0c8df5..2378a3569a4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -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<<3b94757d58e6adb2bccf4ddfb86e2080>> + * @generated SignedSource<<206771bdb2b95a893dd6a0dcba5dc48a>> */ /** @@ -44,6 +44,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var setAndroidLayoutDirectionCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null + private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null private var useStateAlignmentMechanismCache: Boolean? = null override fun commonTestFlag(): Boolean { @@ -246,6 +247,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun useRuntimeShadowNodeReferenceUpdate(): Boolean { + var cached = useRuntimeShadowNodeReferenceUpdateCache + if (cached == null) { + cached = currentProvider.useRuntimeShadowNodeReferenceUpdate() + accessedFeatureFlags.add("useRuntimeShadowNodeReferenceUpdate") + useRuntimeShadowNodeReferenceUpdateCache = cached + } + return cached + } + override fun useStateAlignmentMechanism(): Boolean { var cached = useStateAlignmentMechanismCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 6a197d336ec..e106df658ef 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -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<<68ec2c046868a2cb1d2d88e4fdd9d993>> + * @generated SignedSource<> */ /** @@ -63,5 +63,7 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean + @DoNotStrip public fun useRuntimeShadowNodeReferenceUpdate(): Boolean + @DoNotStrip public fun useStateAlignmentMechanism(): Boolean } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 4d13354e408..30d4d6277a5 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -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<<318ea35c5b58c968d7026dbe547200e4>> + * @generated SignedSource<> */ /** @@ -159,6 +159,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool useRuntimeShadowNodeReferenceUpdate() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useRuntimeShadowNodeReferenceUpdate"); + return method(javaProvider_); + } + bool useStateAlignmentMechanism() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useStateAlignmentMechanism"); @@ -269,6 +275,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode( return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode(); } +bool JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate(); +} + bool JReactNativeFeatureFlagsCxxInterop::useStateAlignmentMechanism( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useStateAlignmentMechanism(); @@ -351,6 +362,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "useNativeViewConfigsInBridgelessMode", JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode), + makeNativeMethod( + "useRuntimeShadowNodeReferenceUpdate", + JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate), makeNativeMethod( "useStateAlignmentMechanism", JReactNativeFeatureFlagsCxxInterop::useStateAlignmentMechanism), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 608ab6d64aa..1ca17c74405 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -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<<4d557dc4399d46888205165ee7ae4ab2>> + * @generated SignedSource<> */ /** @@ -90,6 +90,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool useNativeViewConfigsInBridgelessMode( facebook::jni::alias_ref); + static bool useRuntimeShadowNodeReferenceUpdate( + facebook::jni::alias_ref); + static bool useStateAlignmentMechanism( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 156b1c1a80b..e030eca18cd 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -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<<2a748a0a1b92cb0514fec83668ed8b0f>> + * @generated SignedSource<<5366e268a53215419a7271cd7fac76c9>> */ /** @@ -101,6 +101,10 @@ bool ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode() { return getAccessor().useNativeViewConfigsInBridgelessMode(); } +bool ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate() { + return getAccessor().useRuntimeShadowNodeReferenceUpdate(); +} + bool ReactNativeFeatureFlags::useStateAlignmentMechanism() { return getAccessor().useStateAlignmentMechanism(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 595b0fcd159..26b6e7e6dc5 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -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<> + * @generated SignedSource<<977b87c9478cea28cbb1aff61eef1fa4>> */ /** @@ -137,6 +137,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool useNativeViewConfigsInBridgelessMode(); + /** + * When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree. + */ + RN_EXPORT static bool useRuntimeShadowNodeReferenceUpdate(); + /** * When enabled, it uses optimised state reconciliation algorithm. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 4187f8b87ef..fbff9eab217 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -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<<3e5cb385f51ebc9f53010a901ccbb6a2>> + * @generated SignedSource<> */ /** @@ -389,6 +389,24 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { + auto flagValue = useRuntimeShadowNodeReferenceUpdate_.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(20, "useRuntimeShadowNodeReferenceUpdate"); + + flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); + useRuntimeShadowNodeReferenceUpdate_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { auto flagValue = useStateAlignmentMechanism_.load(); @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "useStateAlignmentMechanism"); + markFlagAsAccessed(21, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index e5d3b1eca90..ce16405bcd0 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -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<> + * @generated SignedSource<<7de49cd344ee15e49e2a1cf5e78e0139>> */ /** @@ -51,6 +51,7 @@ class ReactNativeFeatureFlagsAccessor { bool setAndroidLayoutDirection(); bool useModernRuntimeScheduler(); bool useNativeViewConfigsInBridgelessMode(); + bool useRuntimeShadowNodeReferenceUpdate(); bool useStateAlignmentMechanism(); void override(std::unique_ptr provider); @@ -62,7 +63,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 21> accessedFeatureFlags_; + std::array, 22> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowCollapsableChildren_; @@ -84,6 +85,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> setAndroidLayoutDirection_; std::atomic> useModernRuntimeScheduler_; std::atomic> useNativeViewConfigsInBridgelessMode_; + std::atomic> useRuntimeShadowNodeReferenceUpdate_; std::atomic> useStateAlignmentMechanism_; }; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 85a5fd0bef3..5b89126af4b 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -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<<5c78cdf7676d56996ea174f08bf4b8a6>> + * @generated SignedSource<<2466d6097301e3fa9d022cc8425c7b1c>> */ /** @@ -107,6 +107,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool useRuntimeShadowNodeReferenceUpdate() override { + return false; + } + bool useStateAlignmentMechanism() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 8bb300bce21..43c557e92bf 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -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<> + * @generated SignedSource<<6a05970506e696333c7480f6cf094642>> */ /** @@ -45,6 +45,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool setAndroidLayoutDirection() = 0; virtual bool useModernRuntimeScheduler() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; + virtual bool useRuntimeShadowNodeReferenceUpdate() = 0; virtual bool useStateAlignmentMechanism() = 0; }; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index b64fa4d22e2..b5476a9cc95 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -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<<4c02b68cc3b46ec214fe4552f136c5f0>> + * @generated SignedSource<> */ /** @@ -137,6 +137,11 @@ bool NativeReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode( return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode(); } +bool NativeReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate(); +} + bool NativeReactNativeFeatureFlags::useStateAlignmentMechanism( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useStateAlignmentMechanism(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 55bd107044e..bc0785fdfd0 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -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<> + * @generated SignedSource<> */ /** @@ -75,6 +75,8 @@ class NativeReactNativeFeatureFlags bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime); + bool useRuntimeShadowNodeReferenceUpdate(jsi::Runtime& runtime); + bool useStateAlignmentMechanism(jsi::Runtime& runtime); }; diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 0e972cc677f..b5db07593e7 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -132,6 +132,11 @@ const definitions: FeatureFlagDefinitions = { description: 'When enabled, the native view configs are used in bridgeless mode.', }, + useRuntimeShadowNodeReferenceUpdate: { + defaultValue: false, + description: + 'When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree.', + }, useStateAlignmentMechanism: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 9d8befdc35f..916e1cd99bd 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -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<<1cf3f0841a0523baddea551747c425ca>> + * @generated SignedSource<<98d5ac48b23f6422020b49ed5d8732d0>> * @flow strict-local */ @@ -60,6 +60,7 @@ export type ReactNativeFeatureFlags = { setAndroidLayoutDirection: Getter, useModernRuntimeScheduler: Getter, useNativeViewConfigsInBridgelessMode: Getter, + useRuntimeShadowNodeReferenceUpdate: Getter, useStateAlignmentMechanism: Getter, } @@ -183,6 +184,10 @@ export const useModernRuntimeScheduler: Getter = createNativeFlagGetter * When enabled, the native view configs are used in bridgeless mode. */ export const useNativeViewConfigsInBridgelessMode: Getter = createNativeFlagGetter('useNativeViewConfigsInBridgelessMode', false); +/** + * When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree. + */ +export const useRuntimeShadowNodeReferenceUpdate: Getter = createNativeFlagGetter('useRuntimeShadowNodeReferenceUpdate', false); /** * When enabled, it uses optimised state reconciliation algorithm. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 3d26ffbe380..88e19c6164a 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -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<<613d748b087fde71cc07a7cd5acf888e>> + * @generated SignedSource<> * @flow strict-local */ @@ -43,6 +43,7 @@ export interface Spec extends TurboModule { +setAndroidLayoutDirection?: () => boolean; +useModernRuntimeScheduler?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean; + +useRuntimeShadowNodeReferenceUpdate?: () => boolean; +useStateAlignmentMechanism?: () => boolean; } From e8117703e4f86d950f87e1b85384d297210ce545 Mon Sep 17 00:00:00 2001 From: Nick Lefever Date: Mon, 3 Jun 2024 15:10:53 -0700 Subject: [PATCH 2/2] Make runtime shadow node references updatable from native (#44742) Summary: Changelog: [Internal] React native clones shadow nodes internally without providing the new instances to the React renderer (current fiber tree). To support updating the shadow node references held by the JS side, this diff wraps the returned shadow nodes and adds a link to the runtime reference on the shadow node instance. This will allow for updating the shadow node references held within the JS runtime from the native side. Reviewed By: sammy-SC Differential Revision: D57860869 --- .../react/renderer/core/ShadowNode.cpp | 24 +++++++++++++ .../react/renderer/core/ShadowNode.h | 34 +++++++++++++++++++ .../react/renderer/core/ShadowNodeFragment.h | 1 + .../react/renderer/uimanager/primitives.h | 13 ++++--- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp index d84c512643a..5b60ac98428 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp @@ -309,6 +309,30 @@ bool ShadowNode::progressStateIfNecessary() { return false; } +void ShadowNode::setRuntimeShadowNodeReference( + ShadowNodeWrapper* runtimeShadowNodeReference) const { + runtimeShadowNodeReference_ = runtimeShadowNodeReference; +} + +void ShadowNode::transferRuntimeShadowNodeReference( + const Shared& destinationShadowNode) const { + destinationShadowNode->runtimeShadowNodeReference_ = + runtimeShadowNodeReference_; + + if (runtimeShadowNodeReference_ != nullptr) { + runtimeShadowNodeReference_->shadowNode = destinationShadowNode; + } +} + +void ShadowNode::transferRuntimeShadowNodeReference( + const Shared& destinationShadowNode, + const ShadowNodeFragment& fragment) const { + if (fragment.runtimeShadowNodeReference && + ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate()) { + transferRuntimeShadowNodeReference(destinationShadowNode); + } +} + const ShadowNodeFamily& ShadowNode::getFamily() const { return *family_; } diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h index 644159952bb..e40321c2574 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h @@ -26,6 +26,7 @@ namespace facebook::react { class ComponentDescriptor; struct ShadowNodeFragment; +struct ShadowNodeWrapper; class ShadowNode : public Sealable, public DebugStringConvertible, @@ -188,6 +189,27 @@ class ShadowNode : public Sealable, */ bool progressStateIfNecessary(); + /* + * Bind the runtime reference to this `ShadowNode` with a raw pointer, + * allowing to update the reference to this `ShadowNode` when cloned. + */ + void setRuntimeShadowNodeReference( + ShadowNodeWrapper* runtimeShadowNodeReference) const; + + /* + * Transfer the runtime reference to this `ShadowNode` to a new instance, + * updating the reference to point to the new `ShadowNode` referencing it. + */ + void transferRuntimeShadowNodeReference( + const Shared& destinationShadowNode) const; + + /* + * Transfer the runtime reference based on the fragment instructions. + */ + void transferRuntimeShadowNodeReference( + const Shared& destinationShadowNode, + const ShadowNodeFragment& fragment) const; + #pragma mark - DebugStringConvertible #if RN_DEBUG_STRING_CONVERTIBLE @@ -245,10 +267,22 @@ class ShadowNode : public Sealable, * that class. */ ShadowNodeTraits traits_; + + /* + * Pointer to the runtime reference to this `ShadowNode`. + */ + mutable ShadowNodeWrapper* runtimeShadowNodeReference_{}; }; static_assert( std::has_virtual_destructor::value, "ShadowNode must have a virtual destructor"); +struct ShadowNodeWrapper : public jsi::NativeState { + explicit ShadowNodeWrapper(ShadowNode::Shared shadowNode) + : shadowNode(std::move(shadowNode)) {} + + ShadowNode::Shared shadowNode; +}; + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFragment.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFragment.h index a521feac02a..e17f62aa5ab 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFragment.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFragment.h @@ -27,6 +27,7 @@ struct ShadowNodeFragment { const ShadowNode::SharedListOfShared& children = childrenPlaceholder(); const State::Shared& state = statePlaceholder(); const ShadowNodeTraits traits = {}; + const bool runtimeShadowNodeReference = true; /* * Placeholders. diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h index 03552d2b140..6c7e8b3dbaf 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h @@ -37,16 +37,21 @@ inline static ShadowNode::Shared shadowNodeFromValue( return nullptr; } - return value.getObject(runtime).getNativeState(runtime); + return value.getObject(runtime) + .getNativeState(runtime) + ->shadowNode; } inline static jsi::Value valueFromShadowNode( jsi::Runtime& runtime, ShadowNode::Shared shadowNode) { + // Wrap the shadow node so that we can update JS references from native + auto wrappedShadowNode = + std::make_shared(std::move(shadowNode)); + wrappedShadowNode->shadowNode->setRuntimeShadowNodeReference( + &*wrappedShadowNode); jsi::Object obj(runtime); - // Need to const_cast since JSI only allows non-const pointees - obj.setNativeState( - runtime, std::const_pointer_cast(std::move(shadowNode))); + obj.setNativeState(runtime, std::move(wrappedShadowNode)); return obj; }