From 4324f08749433cc175f85246791bf8946b6ef04a Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 6 Jun 2024 13:15:45 -0700 Subject: [PATCH] Add experiment to bypass bridgeless background executor (#44797) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44797 Noticed when profiling bridgeless that that every call into JS would be passed via a (default priority) background thread first. This is inefficient from a scheduling perspective. Instead use the Task's default/immediate executor to immediately execute the success callback on the current thread and avoid a thread change. This diff adds a new feature flag, to use the immediate executor for any ReactInstance method that doesn't require further synchronization within ReactInstance. For most methods, this is indeed unnecessary as ReactInstance will synchronize internally by scheduling work on the JS thread. Changelog: [Android][Added] Added featureflag to avoid additional background threads during execution Reviewed By: cortinico Differential Revision: D58186090 fbshipit-source-id: 67ffed2d34083a6b6e7871160a2f3d6f1967d630 --- .../ReactAndroid/api/ReactAndroid.api | 1 + .../featureflags/ReactNativeFeatureFlags.kt | 8 ++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 ++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../facebook/react/runtime/ReactHostImpl.java | 52 ++++++++++++++----- .../facebook/react/runtime/ReactInstance.java | 1 + .../react/runtime/internal/bolts/Task.java | 2 +- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 ++- .../featureflags/ReactNativeFeatureFlags.h | 7 ++- .../ReactNativeFeatureFlagsAccessor.cpp | 30 ++++++++--- .../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 +- 23 files changed, 167 insertions(+), 39 deletions(-) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index e5967fc6c3f..f4c3f3e7dc5 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3848,6 +3848,7 @@ public abstract interface class com/facebook/react/runtime/internal/bolts/Contin } public class com/facebook/react/runtime/internal/bolts/Task : com/facebook/react/interfaces/TaskInterface { + public static final field IMMEDIATE_EXECUTOR Ljava/util/concurrent/Executor; public static final field UI_THREAD_EXECUTOR Ljava/util/concurrent/Executor; public static fun call (Ljava/util/concurrent/Callable;)Lcom/facebook/react/runtime/internal/bolts/Task; public static fun call (Ljava/util/concurrent/Callable;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task; 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 aac75718daf..1d37426856c 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<> + * @generated SignedSource<<177f05d7b2fadcfffa32cb5a7a21c76b>> */ /** @@ -136,6 +136,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun setAndroidLayoutDirection(): Boolean = accessor.setAndroidLayoutDirection() + /** + * Invoke callbacks immediately on the ReactInstance rather than going through a background thread for synchronization + */ + @JvmStatic + public fun useImmediateExecutorInAndroidBridgeless(): Boolean = accessor.useImmediateExecutorInAndroidBridgeless() + /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ 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 5292ebefde7..25b762bd413 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<<546c981f0b56bb022ad4e96e6a6ddb17>> + * @generated SignedSource<<492902f307361b8f7b7d42973561a3b4>> */ /** @@ -38,6 +38,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var lazyAnimationCallbacksCache: Boolean? = null private var preventDoubleTextMeasureCache: Boolean? = null private var setAndroidLayoutDirectionCache: Boolean? = null + private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null @@ -206,6 +207,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun useImmediateExecutorInAndroidBridgeless(): Boolean { + var cached = useImmediateExecutorInAndroidBridgelessCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useImmediateExecutorInAndroidBridgeless() + useImmediateExecutorInAndroidBridgelessCache = cached + } + return cached + } + override fun useModernRuntimeScheduler(): Boolean { var cached = useModernRuntimeSchedulerCache 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 82c1dd5b9bc..947512885ac 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<<05bf91e1b2a64cdc48615137deec627a>> */ /** @@ -64,6 +64,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun setAndroidLayoutDirection(): Boolean + @DoNotStrip @JvmStatic public external fun useImmediateExecutorInAndroidBridgeless(): Boolean + @DoNotStrip @JvmStatic public external fun useModernRuntimeScheduler(): Boolean @DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean 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 c3c01abccb8..27cf09922f0 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<<8cb9343bf5aa9a7ec1940720ce253c5b>> + * @generated SignedSource<<7c95ebf976344317cd8904d71ea22fe5>> */ /** @@ -59,6 +59,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun setAndroidLayoutDirection(): Boolean = false + override fun useImmediateExecutorInAndroidBridgeless(): Boolean = false + override fun useModernRuntimeScheduler(): Boolean = false override fun useNativeViewConfigsInBridgelessMode(): 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 702a8ebc948..f73a9f3d265 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<<3b6ad9b32518e319bb7d11da4eaa262c>> + * @generated SignedSource<> */ /** @@ -42,6 +42,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var lazyAnimationCallbacksCache: Boolean? = null private var preventDoubleTextMeasureCache: Boolean? = null private var setAndroidLayoutDirectionCache: Boolean? = null + private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null @@ -228,6 +229,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun useImmediateExecutorInAndroidBridgeless(): Boolean { + var cached = useImmediateExecutorInAndroidBridgelessCache + if (cached == null) { + cached = currentProvider.useImmediateExecutorInAndroidBridgeless() + accessedFeatureFlags.add("useImmediateExecutorInAndroidBridgeless") + useImmediateExecutorInAndroidBridgelessCache = cached + } + return cached + } + override fun useModernRuntimeScheduler(): Boolean { var cached = useModernRuntimeSchedulerCache 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 09b2170629f..d4a63baf4d2 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<> + * @generated SignedSource<> */ /** @@ -59,6 +59,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun setAndroidLayoutDirection(): Boolean + @DoNotStrip public fun useImmediateExecutorInAndroidBridgeless(): Boolean + @DoNotStrip public fun useModernRuntimeScheduler(): Boolean @DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java index d37e4ffde1c..baa00162754 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java @@ -59,6 +59,7 @@ import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.interfaces.TaskInterface; import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler; import com.facebook.react.interfaces.fabric.ReactSurface; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.appearance.AppearanceModule; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -215,7 +216,8 @@ public class ReactHostImpl implements ReactHost { reactInstance -> { log(method, "Execute"); reactInstance.prerenderSurface(surface); - }); + }, + mBGExecutor); } /** @@ -235,7 +237,8 @@ public class ReactHostImpl implements ReactHost { reactInstance -> { log(method, "Execute"); reactInstance.startSurface(surface); - }); + }, + mBGExecutor); } /** @@ -255,7 +258,8 @@ public class ReactHostImpl implements ReactHost { reactInstance -> { log(method, "Execute"); reactInstance.stopSurface(surface); - }) + }, + mBGExecutor) .makeVoid(); } @@ -756,7 +760,8 @@ public class ReactHostImpl implements ReactHost { reactInstance -> { log(method, "Execute"); reactInstance.loadJSBundle(bundleLoader); - }); + }, + null); } /* package */ Task registerSegment( @@ -771,7 +776,8 @@ public class ReactHostImpl implements ReactHost { log(method, "Execute"); reactInstance.registerSegment(segmentId, path); assertNotNull(callback).invoke(); - }); + }, + null); } /* package */ void handleHostException(Exception e) { @@ -800,7 +806,8 @@ public class ReactHostImpl implements ReactHost { method, reactInstance -> { reactInstance.callFunctionOnModule(moduleName, methodName, args); - }); + }, + null); } /* package */ void attachSurface(ReactSurfaceImpl surface) { @@ -852,8 +859,8 @@ public class ReactHostImpl implements ReactHost { } } - /* package */ interface VeniceThenable { - void then(T t); + private interface ReactInstanceCalback { + void then(ReactInstance reactInstance); } @ThreadConfined("ReactHost") @@ -911,11 +918,23 @@ public class ReactHostImpl implements ReactHost { TAG, new ReactNoCrashSoftException(method + ": " + message)); } + private Executor getDefaultReactInstanceExecutor() { + return ReactNativeFeatureFlags.useImmediateExecutorInAndroidBridgeless() + ? Task.IMMEDIATE_EXECUTOR + : mBGExecutor; + } + /** Schedule work on a ReactInstance that is already created. */ private Task callWithExistingReactInstance( - final String callingMethod, final VeniceThenable continuation) { + final String callingMethod, + final ReactInstanceCalback continuation, + @Nullable Executor executor) { final String method = "callWithExistingReactInstance(" + callingMethod + ")"; + if (executor == null) { + executor = getDefaultReactInstanceExecutor(); + } + return mReactInstanceTaskRef .get() .onSuccess( @@ -929,14 +948,20 @@ public class ReactHostImpl implements ReactHost { continuation.then(reactInstance); return TRUE; }, - mBGExecutor); + executor); } /** Create a ReactInstance if it doesn't exist already, and schedule work on it. */ private Task callAfterGetOrCreateReactInstance( - final String callingMethod, final VeniceThenable runnable) { + final String callingMethod, + final ReactInstanceCalback runnable, + @Nullable Executor executor) { final String method = "callAfterGetOrCreateReactInstance(" + callingMethod + ")"; + if (executor == null) { + executor = getDefaultReactInstanceExecutor(); + } + return getOrCreateReactInstance() .onSuccess( task -> { @@ -949,15 +974,14 @@ public class ReactHostImpl implements ReactHost { runnable.then(reactInstance); return null; }, - mBGExecutor) + executor) .continueWith( task -> { if (task.isFaulted()) { handleHostException(task.getError()); } return null; - }, - mBGExecutor); + }); } private BridgelessReactContext getOrCreateReactContext() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java index 86902f2ab5f..107ada4b40c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java @@ -369,6 +369,7 @@ final class ReactInstance { } } + @ThreadConfined("ReactHost") /* package */ void prerenderSurface(ReactSurfaceImpl surface) { Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstance.prerenderSurface"); FLog.d(TAG, "call prerenderSurface with surface: " + surface.getModuleName()); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/internal/bolts/Task.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/internal/bolts/Task.java index 38cdfb5a80a..840d582a7b1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/internal/bolts/Task.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/internal/bolts/Task.java @@ -27,7 +27,7 @@ public class Task implements TaskInterface { * stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in * order to trim the stack. */ - private static final Executor IMMEDIATE_EXECUTOR = Executors.IMMEDIATE; + public static final Executor IMMEDIATE_EXECUTOR = Executors.IMMEDIATE; /** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */ public static final Executor UI_THREAD_EXECUTOR = Executors.UI_THREAD; 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 1cddc94e2d5..9eeab79065a 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<<43b256d5f58743df52f579dc69721083>> + * @generated SignedSource<<2af7a8ae4860f81b46e48afb17ee54b6>> */ /** @@ -147,6 +147,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool useImmediateExecutorInAndroidBridgeless() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useImmediateExecutorInAndroidBridgeless"); + return method(javaProvider_); + } + bool useModernRuntimeScheduler() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useModernRuntimeScheduler"); @@ -271,6 +277,11 @@ bool JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection( return ReactNativeFeatureFlags::setAndroidLayoutDirection(); } +bool JReactNativeFeatureFlagsCxxInterop::useImmediateExecutorInAndroidBridgeless( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useImmediateExecutorInAndroidBridgeless(); +} + bool JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useModernRuntimeScheduler(); @@ -367,6 +378,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "setAndroidLayoutDirection", JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection), + makeNativeMethod( + "useImmediateExecutorInAndroidBridgeless", + JReactNativeFeatureFlagsCxxInterop::useImmediateExecutorInAndroidBridgeless), makeNativeMethod( "useModernRuntimeScheduler", JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler), 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 0fc1b7eeaab..1206b2215fb 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<<19fe3642ec462c23d361e0f036da887a>> + * @generated SignedSource<<1d1422d073ae40ee4bbc788dc222cc28>> */ /** @@ -84,6 +84,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool setAndroidLayoutDirection( facebook::jni::alias_ref); + static bool useImmediateExecutorInAndroidBridgeless( + facebook::jni::alias_ref); + static bool useModernRuntimeScheduler( 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 220b7c9413f..0d291b1b9ec 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<> + * @generated SignedSource<> */ /** @@ -93,6 +93,10 @@ bool ReactNativeFeatureFlags::setAndroidLayoutDirection() { return getAccessor().setAndroidLayoutDirection(); } +bool ReactNativeFeatureFlags::useImmediateExecutorInAndroidBridgeless() { + return getAccessor().useImmediateExecutorInAndroidBridgeless(); +} + bool ReactNativeFeatureFlags::useModernRuntimeScheduler() { return getAccessor().useModernRuntimeScheduler(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index b73431522d9..b809f8409f7 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<<5f1ae3edfe01ee0545bd89137c5cb3e9>> */ /** @@ -127,6 +127,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool setAndroidLayoutDirection(); + /** + * Invoke callbacks immediately on the ReactInstance rather than going through a background thread for synchronization + */ + RN_EXPORT static bool useImmediateExecutorInAndroidBridgeless(); + /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index b7c574d3c51..8bca846e683 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<<5f27dd10824706ea065dc0340d46c409>> + * @generated SignedSource<<6d08fc8ff31f1db50cb4b14edb6b690f>> */ /** @@ -353,6 +353,24 @@ bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() { + auto flagValue = useImmediateExecutorInAndroidBridgeless_.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(18, "useImmediateExecutorInAndroidBridgeless"); + + flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); + useImmediateExecutorInAndroidBridgeless_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { auto flagValue = useModernRuntimeScheduler_.load(); @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "useModernRuntimeScheduler"); + markFlagAsAccessed(19, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -380,7 +398,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(19, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(20, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // 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"); + markFlagAsAccessed(21, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdateOnLayou // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "useRuntimeShadowNodeReferenceUpdateOnLayout"); + markFlagAsAccessed(22, "useRuntimeShadowNodeReferenceUpdateOnLayout"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdateOnLayout(); useRuntimeShadowNodeReferenceUpdateOnLayout_ = flagValue; @@ -434,7 +452,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(22, "useStateAlignmentMechanism"); + markFlagAsAccessed(23, "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 e67bfd3bfa1..ac520127127 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<<8837dd1578561f205e6f682afd98c450>> + * @generated SignedSource<<3be4d7eb8694603de9fb5885562d5a78>> */ /** @@ -49,6 +49,7 @@ class ReactNativeFeatureFlagsAccessor { bool lazyAnimationCallbacks(); bool preventDoubleTextMeasure(); bool setAndroidLayoutDirection(); + bool useImmediateExecutorInAndroidBridgeless(); bool useModernRuntimeScheduler(); bool useNativeViewConfigsInBridgelessMode(); bool useRuntimeShadowNodeReferenceUpdate(); @@ -64,7 +65,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 23> accessedFeatureFlags_; + std::array, 24> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowCollapsableChildren_; @@ -84,6 +85,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> lazyAnimationCallbacks_; std::atomic> preventDoubleTextMeasure_; std::atomic> setAndroidLayoutDirection_; + std::atomic> useImmediateExecutorInAndroidBridgeless_; std::atomic> useModernRuntimeScheduler_; std::atomic> useNativeViewConfigsInBridgelessMode_; std::atomic> useRuntimeShadowNodeReferenceUpdate_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 171c8cd8a5f..916ed06c2aa 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<<2a0324c7b8009e906b18db11c5d2beb9>> + * @generated SignedSource<<97c824bb63734389fae8eea61b92d440>> */ /** @@ -99,6 +99,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool useImmediateExecutorInAndroidBridgeless() override { + return false; + } + bool useModernRuntimeScheduler() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 522fc6ae570..3923d4b9e88 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<<7cd3889fcccc029925651f7ef406ff40>> + * @generated SignedSource<<454a55db4c97f9c28c0a8427d4c0bd57>> */ /** @@ -43,6 +43,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool lazyAnimationCallbacks() = 0; virtual bool preventDoubleTextMeasure() = 0; virtual bool setAndroidLayoutDirection() = 0; + virtual bool useImmediateExecutorInAndroidBridgeless() = 0; virtual bool useModernRuntimeScheduler() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; virtual bool useRuntimeShadowNodeReferenceUpdate() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 158cadd740f..4d6a71669d1 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<<914fa03d71af61b82f05f005d3f3973d>> + * @generated SignedSource<<81d9543c4231939f31dc5c9bb06c942c>> */ /** @@ -127,6 +127,11 @@ bool NativeReactNativeFeatureFlags::setAndroidLayoutDirection( return ReactNativeFeatureFlags::setAndroidLayoutDirection(); } +bool NativeReactNativeFeatureFlags::useImmediateExecutorInAndroidBridgeless( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useImmediateExecutorInAndroidBridgeless(); +} + bool NativeReactNativeFeatureFlags::useModernRuntimeScheduler( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useModernRuntimeScheduler(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 3b12e4f8e16..0b16a9e99a0 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<<1458397650db55d5a985685fa4998e41>> + * @generated SignedSource<> */ /** @@ -71,6 +71,8 @@ class NativeReactNativeFeatureFlags bool setAndroidLayoutDirection(jsi::Runtime& runtime); + bool useImmediateExecutorInAndroidBridgeless(jsi::Runtime& runtime); + bool useModernRuntimeScheduler(jsi::Runtime& runtime); bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 45df9f5eea4..3cd9aeabda8 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -122,6 +122,11 @@ const definitions: FeatureFlagDefinitions = { defaultValue: false, description: 'Propagate layout direction to Android views.', }, + useImmediateExecutorInAndroidBridgeless: { + defaultValue: false, + description: + 'Invoke callbacks immediately on the ReactInstance rather than going through a background thread for synchronization', + }, useModernRuntimeScheduler: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index ba219228c1f..2554ebcc349 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<> + * @generated SignedSource<<870e25c844e692bb04ee49fe20cd3baf>> * @flow strict-local */ @@ -58,6 +58,7 @@ export type ReactNativeFeatureFlags = { lazyAnimationCallbacks: Getter, preventDoubleTextMeasure: Getter, setAndroidLayoutDirection: Getter, + useImmediateExecutorInAndroidBridgeless: Getter, useModernRuntimeScheduler: Getter, useNativeViewConfigsInBridgelessMode: Getter, useRuntimeShadowNodeReferenceUpdate: Getter, @@ -177,6 +178,10 @@ export const preventDoubleTextMeasure: Getter = createNativeFlagGetter( * Propagate layout direction to Android views. */ export const setAndroidLayoutDirection: Getter = createNativeFlagGetter('setAndroidLayoutDirection', false); +/** + * Invoke callbacks immediately on the ReactInstance rather than going through a background thread for synchronization + */ +export const useImmediateExecutorInAndroidBridgeless: Getter = createNativeFlagGetter('useImmediateExecutorInAndroidBridgeless', false); /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 3fe725e3e1f..6d879790467 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<<4a30969e69164b149af42698f94c3b28>> + * @generated SignedSource<<6922b452333fc62a263bd77d42afbbbe>> * @flow strict-local */ @@ -41,6 +41,7 @@ export interface Spec extends TurboModule { +lazyAnimationCallbacks?: () => boolean; +preventDoubleTextMeasure?: () => boolean; +setAndroidLayoutDirection?: () => boolean; + +useImmediateExecutorInAndroidBridgeless?: () => boolean; +useModernRuntimeScheduler?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean; +useRuntimeShadowNodeReferenceUpdate?: () => boolean;