mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
32bfd7a857
Summary: ## Context Previously, when you'd call TurboModule methods with JavaScript callbacks, we'd [store the callbacks](https://www.internalfb.com/code/fbsource/[c503ff1b38621aebca87b2bbebeae088b01886c4]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModule.mm?lines=173%2C248-249) into [this global LongLivedObjectCollection collection](https://www.internalfb.com/code/fbsource/[c503ff1b38621aebca87b2bbebeae088b01886c4]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleUtils.h?lines=65). Then, when React Native's JavaScript VM got torn down, we'd [clear the global collection](https://www.internalfb.com/code/fbsource/[e26f476ce208c578f05b1edb7639d1dad5612c7d]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp?lines=49), which would ensure that we deleted all held jsi::Functions, before deleting the jsi::Runtime. ## Problem With bridgeless mode enabled, there can be two TurboModule systems. Further, it is possible to tear down bridgeless mode, or the bridge, without tearing down the other initialization infra. In this scenario, the jsi::Function for the other initialization infra would also get deleted, which could lead to mysterious problems. ## Fix In this diff, I refactored the jsi::Function cleanup in the TurboModule system. Now, there are 3 modes: - kGlobalScope: Everything works as it did before - kRCTGlobalScopeUsingRetainJSCallback: We still use the global LongLivedObjectCollection, but we do it through invoking a block passed to every ObjCTurboModule by the TurboModuleManager. This group exists to assess the impact of having each TurboModule retain/use the block. I suspect this will be negligible, but it'd be good to have actual data to back this claim. - kRCTTurboModuleManagerScope: Every TurboModule uses a LongLivedObjectCollection that is owned by its TurboModuleManager. This should effectively fix the problem I outlined above. Changelog: [Internal] Reviewed By: p-sun Differential Revision: D30019833 fbshipit-source-id: da50d884c7e37190107f570d8ed70eeda7d9ae83
129 lines
3.8 KiB
C++
129 lines
3.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "TurboModuleBinding.h"
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include <ReactCommon/LongLivedObject.h>
|
|
#include <cxxreact/SystraceSection.h>
|
|
|
|
using namespace facebook;
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
/**
|
|
* Public API to install the TurboModule system.
|
|
*/
|
|
|
|
TurboModuleBinding::TurboModuleBinding(
|
|
const TurboModuleProviderFunctionType &&moduleProvider)
|
|
: moduleProvider_(std::move(moduleProvider)),
|
|
longLivedObjectCollection_(nullptr),
|
|
disableGlobalLongLivedObjectCollection_(false) {}
|
|
|
|
TurboModuleBinding::TurboModuleBinding(
|
|
const TurboModuleProviderFunctionType &&moduleProvider,
|
|
std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection)
|
|
: moduleProvider_(std::move(moduleProvider)),
|
|
longLivedObjectCollection_(longLivedObjectCollection),
|
|
disableGlobalLongLivedObjectCollection_(true) {}
|
|
|
|
void TurboModuleBinding::install(
|
|
jsi::Runtime &runtime,
|
|
const TurboModuleProviderFunctionType &&moduleProvider) {
|
|
runtime.global().setProperty(
|
|
runtime,
|
|
"__turboModuleProxy",
|
|
jsi::Function::createFromHostFunction(
|
|
runtime,
|
|
jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
|
|
1,
|
|
|
|
// Create a TurboModuleBinding that uses the global
|
|
// LongLivedObjectCollection
|
|
[binding =
|
|
std::make_shared<TurboModuleBinding>(std::move(moduleProvider))](
|
|
jsi::Runtime &rt,
|
|
const jsi::Value &thisVal,
|
|
const jsi::Value *args,
|
|
size_t count) {
|
|
return binding->jsProxy(rt, thisVal, args, count);
|
|
}));
|
|
}
|
|
|
|
void TurboModuleBinding::install(
|
|
jsi::Runtime &runtime,
|
|
const TurboModuleProviderFunctionType &&moduleProvider,
|
|
std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection) {
|
|
runtime.global().setProperty(
|
|
runtime,
|
|
"__turboModuleProxy",
|
|
jsi::Function::createFromHostFunction(
|
|
runtime,
|
|
jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
|
|
1,
|
|
// Create a TurboModuleBinding that doesn't use the global
|
|
// LongLivedObjectCollection
|
|
[binding = std::make_shared<TurboModuleBinding>(
|
|
std::move(moduleProvider), longLivedObjectCollection)](
|
|
jsi::Runtime &rt,
|
|
const jsi::Value &thisVal,
|
|
const jsi::Value *args,
|
|
size_t count) {
|
|
return binding->jsProxy(rt, thisVal, args, count);
|
|
}));
|
|
}
|
|
|
|
TurboModuleBinding::~TurboModuleBinding() {
|
|
if (longLivedObjectCollection_ != nullptr) {
|
|
longLivedObjectCollection_->clear();
|
|
return;
|
|
}
|
|
|
|
if (disableGlobalLongLivedObjectCollection_) {
|
|
return;
|
|
}
|
|
|
|
LongLivedObjectCollection::get().clear();
|
|
}
|
|
|
|
std::shared_ptr<TurboModule> TurboModuleBinding::getModule(
|
|
const std::string &name) {
|
|
std::shared_ptr<TurboModule> module = nullptr;
|
|
{
|
|
SystraceSection s("TurboModuleBinding::getModule", "module", name);
|
|
module = moduleProvider_(name);
|
|
}
|
|
return module;
|
|
}
|
|
|
|
jsi::Value TurboModuleBinding::jsProxy(
|
|
jsi::Runtime &runtime,
|
|
const jsi::Value &thisVal,
|
|
const jsi::Value *args,
|
|
size_t count) {
|
|
if (count < 1) {
|
|
throw std::invalid_argument(
|
|
"__turboModuleProxy must be called with at least 1 argument");
|
|
}
|
|
std::string moduleName = args[0].getString(runtime).utf8(runtime);
|
|
jsi::Value nullSchema = jsi::Value::undefined();
|
|
|
|
std::shared_ptr<TurboModule> module = getModule(moduleName);
|
|
if (module == nullptr) {
|
|
return jsi::Value::null();
|
|
}
|
|
|
|
return jsi::Object::createFromHostObject(runtime, std::move(module));
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|