Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 13 additions & 50 deletions packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,25 @@ const NativeModules = require('../BatchedBridge/NativeModules');

const turboModuleProxy = global.__turboModuleProxy;

const moduleLoadHistory = {
NativeModules: ([]: Array<string>),
TurboModules: ([]: Array<string>),
NotFound: ([]: Array<string>),
};
const useLegacyNativeModuleInterop =
global.RN$Bridgeless !== true || global.RN$TurboInterop === true;

function isBridgeless() {
return global.RN$Bridgeless === true;
}

function isTurboModuleInteropEnabled() {
return global.RN$TurboInterop === true;
}

// TODO(154308585): Remove "module not found" debug info logging
function shouldReportDebugInfo() {
return true;
}

// TODO(148943970): Consider reversing the lookup here:
// Lookup on __turboModuleProxy, then lookup on nativeModuleProxy
function requireModule<T: TurboModule>(name: string): ?T {
if (!isBridgeless() || isTurboModuleInteropEnabled()) {
// Backward compatibility layer during migration.
const legacyModule = NativeModules[name];
if (legacyModule != null) {
if (shouldReportDebugInfo()) {
moduleLoadHistory.NativeModules.push(name);
}
return ((legacyModule: $FlowFixMe): T);
}
}

if (turboModuleProxy != null) {
const module: ?T = turboModuleProxy(name);
if (module != null) {
if (shouldReportDebugInfo()) {
moduleLoadHistory.TurboModules.push(name);
}
return module;
}
}

if (shouldReportDebugInfo() && !moduleLoadHistory.NotFound.includes(name)) {
moduleLoadHistory.NotFound.push(name);
if (useLegacyNativeModuleInterop) {
// Backward compatibility layer during migration.
const legacyModule: ?T = NativeModules[name];
if (legacyModule != null) {
return legacyModule;
}
}

return null;
}

Expand All @@ -71,20 +44,10 @@ export function get<T: TurboModule>(name: string): ?T {

export function getEnforcing<T: TurboModule>(name: string): T {
const module = requireModule<T>(name);
let message =
invariant(
module != null,
`TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` +
'Verify that a module by this name is registered in the native binary.';

if (shouldReportDebugInfo()) {
message +=
' Bridgeless mode: ' + (isBridgeless() ? 'true' : 'false') + '. ';
message +=
'TurboModule interop: ' +
(isTurboModuleInteropEnabled() ? 'true' : 'false') +
'. ';
message += 'Modules loaded: ' + JSON.stringify(moduleLoadHistory);
}

invariant(module != null, message);
'Verify that a module by this name is registered in the native binary.',
);
return module;
}
2 changes: 0 additions & 2 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,6 @@ public abstract class com/facebook/react/ReactPackageTurboModuleManagerDelegate
public fun unstable_isLegacyModuleRegistered (Ljava/lang/String;)Z
public fun unstable_isModuleRegistered (Ljava/lang/String;)Z
public fun unstable_shouldEnableLegacyModuleInterop ()Z
public fun unstable_shouldRouteTurboModulesThroughLegacyModuleInterop ()Z
}

public abstract class com/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder {
Expand Down Expand Up @@ -1982,7 +1981,6 @@ public class com/facebook/react/config/ReactFeatureFlags {
public static field unstable_enableTurboModuleSyncVoidMethods Z
public static field unstable_useFabricInterop Z
public static field unstable_useTurboModuleInterop Z
public static field unstable_useTurboModuleInteropForAllTurboModules Z
public static field useTurboModules Z
public fun <init> ()V
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ interface ModuleProvider {
ReactFeatureFlags.enableBridgelessArchitecture
&& ReactFeatureFlags.unstable_useTurboModuleInterop;

private final boolean mShouldRouteTurboModulesThroughLegacyModuleInterop =
mShouldEnableLegacyModuleInterop
&& ReactFeatureFlags.unstable_useTurboModuleInteropForAllTurboModules;

private final boolean mEnableTurboModuleSyncVoidMethods =
ReactFeatureFlags.unstable_enableTurboModuleSyncVoidMethods;

Expand Down Expand Up @@ -147,11 +143,6 @@ public boolean unstable_shouldEnableLegacyModuleInterop() {
return mShouldEnableLegacyModuleInterop;
}

@Override
public boolean unstable_shouldRouteTurboModulesThroughLegacyModuleInterop() {
return mShouldRouteTurboModulesThroughLegacyModuleInterop;
}

public boolean unstable_enableSyncVoidMethods() {
return mEnableTurboModuleSyncVoidMethods;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ public class ReactFeatureFlags {
/** In Bridgeless mode, should legacy NativeModules use the TurboModule system? */
public static volatile boolean unstable_useTurboModuleInterop = false;

/**
* Temporary flag that will be used to validate the staibility of the TurboModule interop layer.
* Force all Java NativeModules that are TurboModule-compatible (that would have otherwise gone
* through the C++ codegen method dispatch path) instead through the TurboModule interop layer
* (i.e: the JavaInteropTurboModule method dispatch path).
*/
public static volatile boolean unstable_useTurboModuleInteropForAllTurboModules = false;

/**
* By default, native module methods that return void run asynchronously. This flag will make
* execution of void methods in TurboModules stay on the JS thread.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -990,10 +990,28 @@ public void updateLayout(
: layoutDirection == 2 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_INHERIT);
}

// Even though we have exact dimensions, we still call measure because some platform views (e.g.
// Switch) assume that method will always be called before onLayout and onDraw. They use it to
// calculate and cache information used in the draw pass. For most views, onMeasure can be
// stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed
// out to not recursively call layout on its children: React Native already handles doing
// that.
//
// Also, note measure and layout need to be called *after* all View properties have been updated
// because of caching and calculation that may occur in onMeasure and onLayout. Layout
// operations should also follow the native view hierarchy and go top to bottom for
// consistency with standard layout passes (some views may depend on this).
viewToUpdate.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));

// We update the layout of the RootView when there is a change in the layout of its child. This
// is required to re-measure the size of the native View container (usually a FrameLayout) that
// is configured with layout_height = WRAP_CONTENT or layout_width = WRAP_CONTENT
//
// This code is going to be executed ONLY when there is a change in the size of the root view
// defined in the JS side. Changes in the layout of inner views will not trigger an update on
// the layout of the root view.
ViewParent parent = viewToUpdate.getParent();
if (parent instanceof RootView) {
parent.requestLayout();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.CxxModuleWrapper;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactNoCrashSoftException;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.RuntimeExecutor;
import com.facebook.react.internal.turbomodule.core.interfaces.TurboModuleRegistry;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
Expand All @@ -27,6 +25,7 @@
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -37,6 +36,8 @@
* a Java module, that the C++ counterpart calls.
*/
public class TurboModuleManager implements TurboModuleRegistry {
private static final String TAG = "TurboModuleManager";

private final List<String> mEagerInitModuleNames;
private final ModuleProvider mTurboModuleProvider;
private final ModuleProvider mLegacyModuleProvider;
Expand Down Expand Up @@ -75,7 +76,7 @@ public TurboModuleManager(
installJSIBindings(shouldEnableLegacyModuleInterop(), enableSyncVoidMethods());

mEagerInitModuleNames =
delegate == null ? new ArrayList<>() : delegate.getEagerInitModuleNames();
delegate == null ? Collections.emptyList() : delegate.getEagerInitModuleNames();

ModuleProvider nullProvider = moduleName -> null;

Expand Down Expand Up @@ -112,11 +113,6 @@ private boolean shouldEnableLegacyModuleInterop() {
return mDelegate != null && mDelegate.unstable_shouldEnableLegacyModuleInterop();
}

private boolean shouldRouteTurboModulesThroughLegacyModuleInterop() {
return mDelegate != null
&& mDelegate.unstable_shouldRouteTurboModulesThroughLegacyModuleInterop();
}

private boolean enableSyncVoidMethods() {
return mDelegate != null && mDelegate.unstable_enableSyncVoidMethods();
}
Expand All @@ -140,11 +136,6 @@ private static List<TurboModuleInteropUtils.MethodDescriptor> getMethodDescripto
@DoNotStrip
@Nullable
private NativeModule getLegacyJavaModule(String moduleName) {
if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {
final NativeModule module = getModule(moduleName);
return !(module instanceof CxxModuleWrapper) ? module : null;
}

/*
* This API is invoked from global.nativeModuleProxy.
* Only call getModule if the native module is a legacy module.
Expand All @@ -164,11 +155,6 @@ private NativeModule getLegacyJavaModule(String moduleName) {
@DoNotStrip
@Nullable
private CxxModuleWrapper getLegacyCxxModule(String moduleName) {
if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {
final NativeModule module = getModule(moduleName);
return module instanceof CxxModuleWrapper ? (CxxModuleWrapper) module : null;
}

/*
* This API is invoked from global.nativeModuleProxy.
* Only call getModule if the native module is a legacy module.
Expand All @@ -188,10 +174,6 @@ private CxxModuleWrapper getLegacyCxxModule(String moduleName) {
@DoNotStrip
@Nullable
private CxxModuleWrapper getTurboLegacyCxxModule(String moduleName) {
if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {
return null;
}

/*
* This API is invoked from global.__turboModuleProxy.
* Only call getModule if the native module is a turbo module.
Expand All @@ -211,10 +193,6 @@ private CxxModuleWrapper getTurboLegacyCxxModule(String moduleName) {
@DoNotStrip
@Nullable
private TurboModule getTurboJavaModule(String moduleName) {
if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {
return null;
}

/*
* This API is invoked from global.__turboModuleProxy.
* Only call getModule if the native module is a turbo module.
Expand Down Expand Up @@ -244,14 +222,13 @@ public NativeModule getModule(String moduleName) {
/*
* Always return null after cleanup has started, so that getNativeModule(moduleName) returns null.
*/
logError(
"getModule(): Tried to get module \""
+ moduleName
+ "\", but TurboModuleManager was tearing down. Returning null. Was legacy: "
+ isLegacyModule(moduleName)
+ ". Was turbo: "
+ isTurboModule(moduleName)
+ ".");
FLog.e(
TAG,
"getModule(): Tried to get module \"%s\", but TurboModuleManager was tearing down"
+ " (legacy: %d, turbo: %d)",
moduleName,
isLegacyModule(moduleName),
isTurboModule(moduleName));
return null;
}

Expand Down Expand Up @@ -328,14 +305,12 @@ private NativeModule getOrCreateModule(
*/
nativeModule.initialize();
} else {
logError(
"getOrCreateModule(): Unable to create module \""
+ moduleName
+ "\". Was legacy: "
+ isLegacyModule(moduleName)
+ ". Was turbo: "
+ isTurboModule(moduleName)
+ ".");
FLog.e(
TAG,
"getOrCreateModule(): Unable to create module \"%s\" (legacy: %d, turbo: %d)",
moduleName,
isLegacyModule(moduleName),
isTurboModule(moduleName));
}

TurboModulePerfLogger.moduleCreateSetUpEnd(moduleName, moduleHolder.getModuleId());
Expand Down Expand Up @@ -408,14 +383,6 @@ public boolean hasModule(String moduleName) {
return false;
}

private void logError(String message) {
FLog.e("TurboModuleManager", message);
if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {
ReactSoftExceptionLogger.logSoftException(
"TurboModuleManager", new ReactNoCrashSoftException(message));
}
}

private native HybridData initHybrid(
RuntimeExecutor runtimeExecutor,
CallInvokerHolderImpl jsCallInvokerHolder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Nullsafe(Nullsafe.Mode.LOCAL)
Expand Down Expand Up @@ -62,22 +62,14 @@ public boolean unstable_isLegacyModuleRegistered(String moduleName) {
;

public List<String> getEagerInitModuleNames() {
return new ArrayList<>();
return Collections.emptyList();
}

/** Can the TurboModule system create legacy modules? */
public boolean unstable_shouldEnableLegacyModuleInterop() {
return false;
}

/**
* Should the TurboModule system treat all turbo native modules as though they were legacy
* modules? This method is for testing purposes only.
*/
public boolean unstable_shouldRouteTurboModulesThroughLegacyModuleInterop() {
return false;
}

/* Can TurboModule methods that return void execute on the JS thread? */
public boolean unstable_enableSyncVoidMethods() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1090,9 +1090,6 @@ private Task<ReactInstance> getOrCreateReactInstanceTask() {
getOrCreateReactHostInspectorTarget());
mReactInstance = instance;

// eagerly initailize turbo modules
instance.initializeEagerTurboModules();

MemoryPressureListener memoryPressureListener =
createMemoryPressureListener(instance);
mMemoryPressureListener = memoryPressureListener;
Expand All @@ -1101,6 +1098,10 @@ private Task<ReactInstance> getOrCreateReactInstanceTask() {
log(method, "Loading JS Bundle");
instance.loadJSBundle(bundleLoader);

// Eagerly initialize turbo modules in parallel with JS bundle execution
// as TurboModuleManager will handle any concurrent creation
instance.initializeEagerTurboModules();

log(
method,
"Calling DevSupportManagerBase.onNewReactContextCreated(reactContext)");
Expand Down
Loading