From dfb75eb430e01d7f338d2b86a88415b0a12a976a Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Wed, 5 Jun 2024 06:05:09 -0700 Subject: [PATCH] Add experiment to bypass background executor in bridgeless Summary: 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 featureflag to avoid additional background threads during execution Differential Revision: D58186090 --- .../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 5a6275d610c8..44b360ca562e 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3840,6 +3840,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 aac75718daf9..1d37426856c4 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 5292ebefde7a..25b762bd413d 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 82c1dd5b9bc0..947512885ac5 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 c3c01abccb8c..27cf09922f0d 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 702a8ebc9483..f73a9f3d2651 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 09b2170629f2..d4a63baf4d20 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 e58483008be6..437b7d939c56 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.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 @@ TaskInterface prerenderSurface(final ReactSurfaceImpl surface) { reactInstance -> { log(method, "Execute"); reactInstance.prerenderSurface(surface); - }); + }, + mBGExecutor); } /** @@ -235,7 +237,8 @@ TaskInterface startSurface(final ReactSurfaceImpl surface) { reactInstance -> { log(method, "Execute"); reactInstance.startSurface(surface); - }); + }, + mBGExecutor); } /** @@ -255,7 +258,8 @@ TaskInterface stopSurface(final ReactSurfaceImpl surface) { reactInstance -> { log(method, "Execute"); reactInstance.stopSurface(surface); - }) + }, + mBGExecutor) .makeVoid(); } @@ -756,7 +760,8 @@ DefaultHardwareBackBtnHandler getDefaultBackButtonHandler() { reactInstance -> { log(method, "Execute"); reactInstance.loadJSBundle(bundleLoader); - }); + }, + null); } /* package */ Task registerSegment( @@ -771,7 +776,8 @@ DefaultHardwareBackBtnHandler getDefaultBackButtonHandler() { log(method, "Execute"); reactInstance.registerSegment(segmentId, path); assertNotNull(callback).invoke(); - }); + }, + null); } /* package */ void handleHostException(Exception e) { @@ -800,7 +806,8 @@ DefaultHardwareBackBtnHandler getDefaultBackButtonHandler() { method, reactInstance -> { reactInstance.callFunctionOnModule(moduleName, methodName, args); - }); + }, + null); } /* package */ void attachSurface(ReactSurfaceImpl surface) { @@ -852,8 +859,8 @@ public void removeBeforeDestroyListener(@NonNull Function0 onBeforeDestroy } } - /* package */ interface VeniceThenable { - void then(T t); + private interface ReactInstanceCalback { + void then(ReactInstance reactInstance); } @ThreadConfined("ReactHost") @@ -909,9 +916,18 @@ private void raiseSoftException(String method, String message, @Nullable Throwab /** 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 = + ReactNativeFeatureFlags.useImmediateExecutorInAndroidBridgeless() + ? Task.IMMEDIATE_EXECUTOR + : mBGExecutor; + } + return mReactInstanceTaskRef .get() .onSuccess( @@ -925,14 +941,23 @@ private Task callWithExistingReactInstance( 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 = + ReactNativeFeatureFlags.useImmediateExecutorInAndroidBridgeless() + ? Task.IMMEDIATE_EXECUTOR + : mBGExecutor; + } + return getOrCreateReactInstance() .onSuccess( task -> { @@ -945,15 +970,14 @@ private Task callAfterGetOrCreateReactInstance( 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 86902f2ab5fc..107ada4b40ca 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 @@ public Collection getNativeModules() { } } + @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 38cdfb5a80aa..840d582a7b17 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 1cddc94e2d57..9eeab79065a2 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 0fc1b7eeaab4..1206b2215fb8 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 220b7c9413fc..0d291b1b9ecd 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 b73431522d9c..b809f8409f73 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 b7c574d3c510..8bca846e683b 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 e67bfd3bfa11..ac520127127c 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 171c8cd8a5f0..916ed06c2aa4 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 522fc6ae5701..3923d4b9e882 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 158cadd740f5..4d6a71669d17 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 3b12e4f8e167..0b16a9e99a01 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 45df9f5eea4c..3cd9aeabda89 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 ba219228c1fc..2554ebcc349c 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 3fe725e3e1f0..6d879790467c 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;