diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java
index e0910b2fa91..a9961cb2f4d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java
@@ -116,6 +116,17 @@ public class ReactFeatureFlags {
/** Feature Flag to control RN Android scrollEventThrottle prop. */
public static boolean enableScrollEventThrottle = false;
+ /**
+ * Feature flag that controls how turbo modules are exposed to JS
+ *
+ *
+ * - 0 = as a HostObject
+ *
- 1 = as a plain object, backed with a HostObject as prototype
+ *
- 2 = as a plain object, with all methods eagerly configured
+ *
+ */
+ public static int turboModuleBindingMode = 0;
+
/**
* Feature Flag to enable View Recycling. When enabled, individual ViewManagers must still opt-in.
*/
diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ReactCommon/TurboModuleManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ReactCommon/TurboModuleManager.cpp
index 04238f8eb8f..a4d1c1289d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ReactCommon/TurboModuleManager.cpp
+++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ReactCommon/TurboModuleManager.cpp
@@ -20,6 +20,17 @@
namespace facebook {
namespace react {
+constexpr static auto ReactFeatureFlagsJavaDescriptor =
+ "com/facebook/react/config/ReactFeatureFlags";
+
+static int getFeatureFlagValue(const char *name) {
+ static const auto reactFeatureFlagsJavaDescriptor =
+ jni::findClassStatic(ReactFeatureFlagsJavaDescriptor);
+ const auto field =
+ reactFeatureFlagsJavaDescriptor->getStaticField(name);
+ return reactFeatureFlagsJavaDescriptor->getStaticFieldValue(field);
+}
+
TurboModuleManager::TurboModuleManager(
jni::alias_ref jThis,
RuntimeExecutor runtimeExecutor,
@@ -169,8 +180,13 @@ void TurboModuleManager::installJSIBindings() {
return nullptr;
};
+ TurboModuleBindingMode bindingMode = static_cast(
+ getFeatureFlagValue("turboModuleBindingMode"));
TurboModuleBinding::install(
- runtime, std::move(turboModuleProvider), longLivedObjectCollection_);
+ runtime,
+ std::move(turboModuleProvider),
+ bindingMode,
+ longLivedObjectCollection_);
});
}
diff --git a/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp b/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
index b73fdfd2207..03c65ef2890 100644
--- a/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
+++ b/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
@@ -24,13 +24,16 @@ namespace react {
TurboModuleBinding::TurboModuleBinding(
const TurboModuleProviderFunctionType &&moduleProvider,
+ TurboModuleBindingMode bindingMode,
std::shared_ptr longLivedObjectCollection)
: moduleProvider_(std::move(moduleProvider)),
- longLivedObjectCollection_(std::move(longLivedObjectCollection)) {}
+ longLivedObjectCollection_(std::move(longLivedObjectCollection)),
+ bindingMode_(bindingMode) {}
void TurboModuleBinding::install(
jsi::Runtime &runtime,
const TurboModuleProviderFunctionType &&moduleProvider,
+ TurboModuleBindingMode bindingMode,
std::shared_ptr longLivedObjectCollection) {
runtime.global().setProperty(
runtime,
@@ -41,6 +44,7 @@ void TurboModuleBinding::install(
1,
[binding = TurboModuleBinding(
std::move(moduleProvider),
+ bindingMode,
std::move(longLivedObjectCollection))](
jsi::Runtime &rt,
const jsi::Value &thisVal,
@@ -76,15 +80,28 @@ jsi::Value TurboModuleBinding::getModule(
module = moduleProvider_(moduleName);
}
if (module) {
+ // Default behaviour
+ if (bindingMode_ == TurboModuleBindingMode::HostObject) {
+ return jsi::Object::createFromHostObject(runtime, std::move(module));
+ }
+
auto &jsRepresentation = module->jsRepresentation_;
if (!jsRepresentation) {
jsRepresentation = std::make_unique(runtime);
- // Create plain object, with it's prototype mapped back to the hostobject.
- // Any properties accessed are cached on the plain object.
- auto hostObject =
- jsi::Object::createFromHostObject(runtime, std::move(module));
- jsRepresentation->setProperty(
- runtime, "__proto__", std::move(hostObject));
+ if (bindingMode_ == TurboModuleBindingMode::Prototype) {
+ // Option 1: create plain object, with it's prototype mapped back to the
+ // hostobject. Any properties accessed are stored on the plain object
+ auto hostObject =
+ jsi::Object::createFromHostObject(runtime, std::move(module));
+ jsRepresentation->setProperty(
+ runtime, "__proto__", std::move(hostObject));
+ } else {
+ // Option 2: eagerly install all hostfunctions at this point, avoids
+ // prototype
+ for (auto &propName : module->getPropertyNames(runtime)) {
+ module->get(runtime, propName);
+ }
+ }
}
return jsi::Value(runtime, *jsRepresentation);
} else {
diff --git a/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.h b/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.h
index 8d7742f3ff0..1791d4e272e 100644
--- a/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.h
+++ b/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.h
@@ -18,6 +18,12 @@ namespace react {
class JSCallInvoker;
+enum class TurboModuleBindingMode : uint8_t {
+ HostObject = 0,
+ Prototype = 1,
+ Eager = 2,
+};
+
/**
* Represents the JavaScript binding for the TurboModule system.
*/
@@ -30,11 +36,13 @@ class TurboModuleBinding {
static void install(
jsi::Runtime &runtime,
const TurboModuleProviderFunctionType &&moduleProvider,
+ TurboModuleBindingMode bindingMode,
std::shared_ptr longLivedObjectCollection);
private:
TurboModuleBinding(
const TurboModuleProviderFunctionType &&moduleProvider,
+ TurboModuleBindingMode bindingMode,
std::shared_ptr longLivedObjectCollection);
virtual ~TurboModuleBinding();
@@ -50,6 +58,7 @@ class TurboModuleBinding {
TurboModuleProviderFunctionType moduleProvider_;
std::shared_ptr longLivedObjectCollection_;
+ TurboModuleBindingMode bindingMode_;
};
} // namespace react
diff --git a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm
index bf0bdb1a06e..dffe85b24c0 100644
--- a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm
+++ b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm
@@ -777,12 +777,14 @@ static Class getFallbackClassFromName(const char *name)
if (RCTGetTurboModuleCleanupMode() == kRCTGlobalScope ||
RCTGetTurboModuleCleanupMode() == kRCTGlobalScopeUsingRetainJSCallback) {
runtimeExecutor([turboModuleProvider = std::move(turboModuleProvider)](jsi::Runtime &runtime) {
- react::TurboModuleBinding::install(runtime, std::move(turboModuleProvider), nullptr);
+ react::TurboModuleBinding::install(
+ runtime, std::move(turboModuleProvider), TurboModuleBindingMode::HostObject, nullptr);
});
} else if (RCTGetTurboModuleCleanupMode() == kRCTTurboModuleManagerScope) {
runtimeExecutor([turboModuleProvider = std::move(turboModuleProvider),
longLivedObjectCollection = _longLivedObjectCollection](jsi::Runtime &runtime) {
- react::TurboModuleBinding::install(runtime, std::move(turboModuleProvider), longLivedObjectCollection);
+ react::TurboModuleBinding::install(
+ runtime, std::move(turboModuleProvider), TurboModuleBindingMode::HostObject, longLivedObjectCollection);
});
}
}