mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Use WeakObject for new turbomodule binding mechanism
Summary: A previous version of this experiment saw crashes on iOS once rolled out. Switching to WeakObject to make sure we're not accessing invalid references, and setting up the ability to experiment with this on iOS. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D41552667 fbshipit-source-id: dc0c54edc2ad18c1947941119ffd50038a47c5f6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c28c6f2531
commit
b73dd6726d
@@ -111,7 +111,12 @@ jsi::Value TurboCxxModule::get(
|
||||
|
||||
// If we have a JS wrapper, cache the result of this lookup
|
||||
if (jsRepresentation_) {
|
||||
jsRepresentation_->setProperty(runtime, propName, result);
|
||||
auto jsRepresentation = jsRepresentation_->lock(runtime);
|
||||
if (!jsRepresentation.isUndefined()) {
|
||||
std::move(jsRepresentation)
|
||||
.asObject(runtime)
|
||||
.setProperty(runtime, propName, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -31,7 +31,8 @@ jsi::Value TurboModule::get(
|
||||
// If we have a JS wrapper, cache the result of this lookup
|
||||
// We don't cache misses, to allow for methodMap_ to dynamically be extended
|
||||
if (jsRepresentation_) {
|
||||
jsRepresentation_->setProperty(runtime, propName, result);
|
||||
jsRepresentation_->lock(runtime).asObject(runtime).setProperty(
|
||||
runtime, propName, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class JSI_EXPORT TurboModule : public facebook::jsi::HostObject {
|
||||
private:
|
||||
friend class TurboCxxModule;
|
||||
friend class TurboModuleBinding;
|
||||
std::unique_ptr<jsi::Object> jsRepresentation_;
|
||||
std::unique_ptr<jsi::WeakObject> jsRepresentation_;
|
||||
|
||||
facebook::jsi::Value get(
|
||||
facebook::jsi::Runtime &runtime,
|
||||
|
||||
@@ -43,7 +43,7 @@ void TurboModuleBinding::install(
|
||||
jsi::Runtime &rt,
|
||||
const jsi::Value &thisVal,
|
||||
const jsi::Value *args,
|
||||
size_t count) mutable {
|
||||
size_t count) {
|
||||
return binding.getModule(rt, thisVal, args, count);
|
||||
}));
|
||||
}
|
||||
@@ -56,7 +56,7 @@ jsi::Value TurboModuleBinding::getModule(
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &thisVal,
|
||||
const jsi::Value *args,
|
||||
size_t count) {
|
||||
size_t count) const {
|
||||
if (count < 1) {
|
||||
throw std::invalid_argument(
|
||||
"__turboModuleProxy must be called with at least 1 argument");
|
||||
@@ -75,25 +75,33 @@ jsi::Value TurboModuleBinding::getModule(
|
||||
return jsi::Object::createFromHostObject(runtime, std::move(module));
|
||||
}
|
||||
|
||||
auto &jsRepresentation = module->jsRepresentation_;
|
||||
if (!jsRepresentation) {
|
||||
jsRepresentation = std::make_unique<jsi::Object>(runtime);
|
||||
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);
|
||||
}
|
||||
auto &weakJsRepresentation = module->jsRepresentation_;
|
||||
if (weakJsRepresentation) {
|
||||
auto jsRepresentation = weakJsRepresentation->lock(runtime);
|
||||
if (!jsRepresentation.isUndefined()) {
|
||||
return jsRepresentation;
|
||||
}
|
||||
}
|
||||
return jsi::Value(runtime, *jsRepresentation);
|
||||
|
||||
// No JS representation found, or object has been collected
|
||||
jsi::Object jsRepresentation(runtime);
|
||||
weakJsRepresentation =
|
||||
std::make_unique<jsi::WeakObject>(runtime, jsRepresentation);
|
||||
|
||||
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 jsRepresentation;
|
||||
} else {
|
||||
return jsi::Value::null();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class TurboModuleBinding {
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &thisVal,
|
||||
const jsi::Value *args,
|
||||
size_t count);
|
||||
size_t count) const;
|
||||
|
||||
TurboModuleProviderFunctionType moduleProvider_;
|
||||
TurboModuleBindingMode bindingMode_;
|
||||
|
||||
+5
-1
@@ -9,10 +9,14 @@
|
||||
|
||||
#import <memory>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTTurboModuleRegistry.h>
|
||||
#import <ReactCommon/RuntimeExecutor.h>
|
||||
#import <ReactCommon/TurboModuleBinding.h>
|
||||
#import "RCTTurboModule.h"
|
||||
|
||||
RCT_EXTERN void RCTTurboModuleSetBindingMode(facebook::react::TurboModuleBindingMode bindingMode);
|
||||
|
||||
@protocol RCTTurboModuleManagerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
@@ -44,7 +48,7 @@
|
||||
delegate:(id<RCTTurboModuleManagerDelegate>)delegate
|
||||
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker;
|
||||
|
||||
- (void)installJSBindingWithRuntimeExecutor:(facebook::react::RuntimeExecutor)runtimeExecutor;
|
||||
- (void)installJSBindingWithRuntimeExecutor:(facebook::react::RuntimeExecutor &)runtimeExecutor;
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
|
||||
+9
-4
@@ -25,13 +25,18 @@
|
||||
#import <React/RCTUtils.h>
|
||||
#import <ReactCommon/RuntimeExecutor.h>
|
||||
#import <ReactCommon/TurboCxxModule.h>
|
||||
#import <ReactCommon/TurboModuleBinding.h>
|
||||
#import <ReactCommon/TurboModulePerfLogger.h>
|
||||
#import <ReactCommon/TurboModuleUtils.h>
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::react;
|
||||
|
||||
static TurboModuleBindingMode sTurboModuleBindingMode = TurboModuleBindingMode::HostObject;
|
||||
void RCTTurboModuleSetBindingMode(TurboModuleBindingMode bindingMode)
|
||||
{
|
||||
sTurboModuleBindingMode = bindingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A global variable whose address we use to associate method queues to id<RCTTurboModule> objects.
|
||||
*/
|
||||
@@ -181,7 +186,7 @@ static Class getFallbackClassFromName(const char *name)
|
||||
jsInvoker:(std::shared_ptr<CallInvoker>)jsInvoker
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_jsInvoker = jsInvoker;
|
||||
_jsInvoker = std::move(jsInvoker);
|
||||
_delegate = delegate;
|
||||
_bridge = bridge;
|
||||
_invalidating = false;
|
||||
@@ -691,7 +696,7 @@ static Class getFallbackClassFromName(const char *name)
|
||||
return requiresMainQueueSetup;
|
||||
}
|
||||
|
||||
- (void)installJSBindingWithRuntimeExecutor:(facebook::react::RuntimeExecutor)runtimeExecutor
|
||||
- (void)installJSBindingWithRuntimeExecutor:(facebook::react::RuntimeExecutor &)runtimeExecutor
|
||||
{
|
||||
if (!runtimeExecutor) {
|
||||
// jsi::Runtime doesn't exist when attached to Chrome debugger.
|
||||
@@ -736,7 +741,7 @@ static Class getFallbackClassFromName(const char *name)
|
||||
};
|
||||
|
||||
runtimeExecutor([turboModuleProvider = std::move(turboModuleProvider)](jsi::Runtime &runtime) {
|
||||
TurboModuleBinding::install(runtime, std::move(turboModuleProvider), TurboModuleBindingMode::HostObject);
|
||||
TurboModuleBinding::install(runtime, std::move(turboModuleProvider), sTurboModuleBindingMode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user