Skip to content

Commit 9ae9558

Browse files
RSNarafacebook-github-bot
authored andcommitted
Clear all held jsi::Functions when jsi::Runtime is deleted
Summary: ## Description You're not supposed to hold on to JSI objects (ex: `jsi::Function`) past the point where their `jsi::Runtime` is deleted. Otherwise, we get a dangling pointer crash, like this: T60262810! Historically, this cleanup problem has always been really tricky to get right. With this diff, I hope to fix that problem once and for all by deleting all `jsi::Function`s when we delete the global `__turboModuleProxy` function. ## Current Setup - The TurboModules infra uses weak references to `CallbackWrapper`s to hold on to the `jsi::Function`s passed from JS to ObjC. - The LongLivedObjectCollection holds on to strong references to `CallbackWrapper`s. This ensures that the `jsi::Function`s aren't deleted prematurely. This also means that we can use `LongLivedObjectCollection` to delete all `CallbackWrappers`. - `TurboModuleBinding` is the abstraction we use to install the global `__turboModuleProxy` function. It is owned by `TurboModuleManager`, and `TurboModuleManager` uses it to clear all references to `jsi::Function`s, when we delete all NativeModules. ## Solution 1. Transfer ownership of `TurboModuleBinding` from `TurboModuleManager` to the `__turboModuleProxy` function. 2. Clear the `LongLivedObjectCollection` when `TurboModuleBinding` is deleted. Changelog: [iOS][Fixed] - Clear all held jsi::Functions when jsi::Runtime is deleted Reviewed By: JoshuaGross Differential Revision: D19565499 fbshipit-source-id: e3510ea04e72f6bda363a8fc3ee2be60303b70a6
1 parent 7001dc3 commit 9ae9558

File tree

5 files changed

+94
-116
lines changed

5 files changed

+94
-116
lines changed

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ReactCommon/TurboModuleManager.cpp

+56-59
Original file line numberDiff line numberDiff line change
@@ -65,65 +65,62 @@ void TurboModuleManager::installJSIBindings() {
6565

6666
TurboModuleBinding::install(
6767
*runtime_,
68-
std::make_shared<TurboModuleBinding>(
69-
[turboModuleCache_ =
70-
std::weak_ptr<TurboModuleCache>(turboModuleCache_),
71-
jsCallInvoker_ = std::weak_ptr<CallInvoker>(jsCallInvoker_),
72-
nativeCallInvoker_ = std::weak_ptr<CallInvoker>(nativeCallInvoker_),
73-
delegate_ = jni::make_weak(delegate_),
74-
javaPart_ = jni::make_weak(javaPart_)](
75-
const std::string &name) -> std::shared_ptr<TurboModule> {
76-
auto turboModuleCache = turboModuleCache_.lock();
77-
auto jsCallInvoker = jsCallInvoker_.lock();
78-
auto nativeCallInvoker = nativeCallInvoker_.lock();
79-
auto delegate = delegate_.lockLocal();
80-
auto javaPart = javaPart_.lockLocal();
81-
82-
if (!turboModuleCache || !jsCallInvoker || !nativeCallInvoker ||
83-
!delegate || !javaPart) {
84-
return nullptr;
85-
}
86-
87-
auto turboModuleLookup = turboModuleCache->find(name);
88-
if (turboModuleLookup != turboModuleCache->end()) {
89-
return turboModuleLookup->second;
90-
}
91-
92-
auto cxxModule =
93-
delegate->cthis()->getTurboModule(name, jsCallInvoker);
94-
if (cxxModule) {
95-
turboModuleCache->insert({name, cxxModule});
96-
return cxxModule;
97-
}
98-
99-
static auto getLegacyCxxModule =
100-
delegate->getClass()
101-
->getMethod<jni::alias_ref<CxxModuleWrapper::javaobject>(
102-
const std::string &)>("getLegacyCxxModule");
103-
auto legacyCxxModule = getLegacyCxxModule(delegate.get(), name);
104-
105-
if (legacyCxxModule) {
106-
auto turboModule = std::make_shared<react::TurboCxxModule>(
107-
legacyCxxModule->cthis()->getModule(), jsCallInvoker);
108-
turboModuleCache->insert({name, turboModule});
109-
return turboModule;
110-
}
111-
112-
static auto getJavaModule =
113-
javaPart->getClass()
114-
->getMethod<jni::alias_ref<JTurboModule>(
115-
const std::string &)>("getJavaModule");
116-
auto moduleInstance = getJavaModule(javaPart.get(), name);
117-
118-
if (moduleInstance) {
119-
auto turboModule = delegate->cthis()->getTurboModule(
120-
name, moduleInstance, jsCallInvoker, nativeCallInvoker);
121-
turboModuleCache->insert({name, turboModule});
122-
return turboModule;
123-
}
124-
125-
return nullptr;
126-
}));
68+
[turboModuleCache_ = std::weak_ptr<TurboModuleCache>(turboModuleCache_),
69+
jsCallInvoker_ = std::weak_ptr<CallInvoker>(jsCallInvoker_),
70+
nativeCallInvoker_ = std::weak_ptr<CallInvoker>(nativeCallInvoker_),
71+
delegate_ = jni::make_weak(delegate_),
72+
javaPart_ = jni::make_weak(javaPart_)](
73+
const std::string &name) -> std::shared_ptr<TurboModule> {
74+
auto turboModuleCache = turboModuleCache_.lock();
75+
auto jsCallInvoker = jsCallInvoker_.lock();
76+
auto nativeCallInvoker = nativeCallInvoker_.lock();
77+
auto delegate = delegate_.lockLocal();
78+
auto javaPart = javaPart_.lockLocal();
79+
80+
if (!turboModuleCache || !jsCallInvoker || !nativeCallInvoker ||
81+
!delegate || !javaPart) {
82+
return nullptr;
83+
}
84+
85+
auto turboModuleLookup = turboModuleCache->find(name);
86+
if (turboModuleLookup != turboModuleCache->end()) {
87+
return turboModuleLookup->second;
88+
}
89+
90+
auto cxxModule = delegate->cthis()->getTurboModule(name, jsCallInvoker);
91+
if (cxxModule) {
92+
turboModuleCache->insert({name, cxxModule});
93+
return cxxModule;
94+
}
95+
96+
static auto getLegacyCxxModule =
97+
delegate->getClass()
98+
->getMethod<jni::alias_ref<CxxModuleWrapper::javaobject>(
99+
const std::string &)>("getLegacyCxxModule");
100+
auto legacyCxxModule = getLegacyCxxModule(delegate.get(), name);
101+
102+
if (legacyCxxModule) {
103+
auto turboModule = std::make_shared<react::TurboCxxModule>(
104+
legacyCxxModule->cthis()->getModule(), jsCallInvoker);
105+
turboModuleCache->insert({name, turboModule});
106+
return turboModule;
107+
}
108+
109+
static auto getJavaModule =
110+
javaPart->getClass()
111+
->getMethod<jni::alias_ref<JTurboModule>(const std::string &)>(
112+
"getJavaModule");
113+
auto moduleInstance = getJavaModule(javaPart.get(), name);
114+
115+
if (moduleInstance) {
116+
auto turboModule = delegate->cthis()->getTurboModule(
117+
name, moduleInstance, jsCallInvoker, nativeCallInvoker);
118+
turboModuleCache->insert({name, turboModule});
119+
return turboModule;
120+
}
121+
122+
return nullptr;
123+
});
127124
}
128125

129126
} // namespace react

ReactCommon/turbomodule/core/TurboModuleBinding.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@ namespace react {
2121
* Public API to install the TurboModule system.
2222
*/
2323
TurboModuleBinding::TurboModuleBinding(
24-
const TurboModuleProviderFunctionType &moduleProvider)
25-
: moduleProvider_(moduleProvider) {}
24+
const TurboModuleProviderFunctionType &&moduleProvider)
25+
: moduleProvider_(std::move(moduleProvider)) {}
2626

2727
void TurboModuleBinding::install(
2828
jsi::Runtime &runtime,
29-
std::shared_ptr<TurboModuleBinding> binding) {
29+
const TurboModuleProviderFunctionType &&moduleProvider) {
3030
runtime.global().setProperty(
3131
runtime,
3232
"__turboModuleProxy",
3333
jsi::Function::createFromHostFunction(
3434
runtime,
3535
jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
3636
1,
37-
[binding](
37+
[binding =
38+
std::make_shared<TurboModuleBinding>(std::move(moduleProvider))](
3839
jsi::Runtime &rt,
3940
const jsi::Value &thisVal,
4041
const jsi::Value *args,
@@ -43,7 +44,7 @@ void TurboModuleBinding::install(
4344
}));
4445
}
4546

46-
void TurboModuleBinding::invalidate() const {
47+
TurboModuleBinding::~TurboModuleBinding() {
4748
LongLivedObjectCollection::get().clear();
4849
}
4950

ReactCommon/turbomodule/core/TurboModuleBinding.h

+3-8
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,10 @@ class TurboModuleBinding {
2828
*/
2929
static void install(
3030
jsi::Runtime &runtime,
31-
std::shared_ptr<TurboModuleBinding> binding);
31+
const TurboModuleProviderFunctionType &&moduleProvider);
3232

33-
TurboModuleBinding(const TurboModuleProviderFunctionType &moduleProvider);
34-
35-
/*
36-
* Invalidates the binding.
37-
* Can be called in any thread.
38-
*/
39-
void invalidate() const;
33+
TurboModuleBinding(const TurboModuleProviderFunctionType &&moduleProvider);
34+
virtual ~TurboModuleBinding();
4035

4136
/**
4237
* Get an TurboModule instance for the given module name.

ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.h

-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@
4444

4545
- (void)installJSBindingWithRuntime:(facebook::jsi::Runtime *)runtime;
4646

47-
- (std::shared_ptr<facebook::react::TurboModule>)getModule:(const std::string &)name;
48-
4947
- (void)invalidate;
5048

5149
@end

ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm

+29-42
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ static Class getFallbackClassFromName(const char *name)
3636
@implementation RCTTurboModuleManager {
3737
jsi::Runtime *_runtime;
3838
std::shared_ptr<facebook::react::CallInvoker> _jsInvoker;
39-
std::shared_ptr<react::TurboModuleBinding> _binding;
4039
__weak id<RCTTurboModuleManagerDelegate> _delegate;
4140
__weak RCTBridge *_bridge;
4241
/**
@@ -83,38 +82,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
8382
selector:@selector(bridgeDidInvalidateModules:)
8483
name:RCTBridgeDidInvalidateModulesNotification
8584
object:_bridge.parentBridge];
86-
87-
__weak __typeof(self) weakSelf = self;
88-
89-
auto moduleProvider = [weakSelf](const std::string &name) -> std::shared_ptr<react::TurboModule> {
90-
if (!weakSelf) {
91-
return nullptr;
92-
}
93-
94-
__strong __typeof(self) strongSelf = weakSelf;
95-
96-
auto moduleName = name.c_str();
97-
auto moduleWasNotInitialized = ![strongSelf moduleIsInitialized:moduleName];
98-
if (moduleWasNotInitialized) {
99-
[strongSelf->_bridge.performanceLogger markStartForTag:RCTPLTurboModuleSetup];
100-
}
101-
102-
/**
103-
* By default, all TurboModules are long-lived.
104-
* Additionally, if a TurboModule with the name `name` isn't found, then we
105-
* trigger an assertion failure.
106-
*/
107-
auto turboModule = [strongSelf provideTurboModule:moduleName];
108-
109-
if (moduleWasNotInitialized && [strongSelf moduleIsInitialized:moduleName]) {
110-
[strongSelf->_bridge.performanceLogger markStopForTag:RCTPLTurboModuleSetup];
111-
[strongSelf notifyAboutTurboModuleSetup:moduleName];
112-
}
113-
114-
return turboModule;
115-
};
116-
117-
_binding = std::make_shared<react::TurboModuleBinding>(moduleProvider);
11885
}
11986
return self;
12087
}
@@ -376,12 +343,36 @@ - (void)installJSBindingWithRuntime:(jsi::Runtime *)runtime
376343
return;
377344
}
378345

379-
react::TurboModuleBinding::install(*_runtime, _binding);
380-
}
346+
__weak __typeof(self) weakSelf = self;
381347

382-
- (std::shared_ptr<facebook::react::TurboModule>)getModule:(const std::string &)name
383-
{
384-
return _binding->getModule(name);
348+
react::TurboModuleBinding::install(
349+
*_runtime, [weakSelf](const std::string &name) -> std::shared_ptr<react::TurboModule> {
350+
if (!weakSelf) {
351+
return nullptr;
352+
}
353+
354+
__strong __typeof(self) strongSelf = weakSelf;
355+
356+
auto moduleName = name.c_str();
357+
auto moduleWasNotInitialized = ![strongSelf moduleIsInitialized:moduleName];
358+
if (moduleWasNotInitialized) {
359+
[strongSelf->_bridge.performanceLogger markStartForTag:RCTPLTurboModuleSetup];
360+
}
361+
362+
/**
363+
* By default, all TurboModules are long-lived.
364+
* Additionally, if a TurboModule with the name `name` isn't found, then we
365+
* trigger an assertion failure.
366+
*/
367+
auto turboModule = [strongSelf provideTurboModule:moduleName];
368+
369+
if (moduleWasNotInitialized && [strongSelf moduleIsInitialized:moduleName]) {
370+
[strongSelf->_bridge.performanceLogger markStopForTag:RCTPLTurboModuleSetup];
371+
[strongSelf notifyAboutTurboModuleSetup:moduleName];
372+
}
373+
374+
return turboModule;
375+
});
385376
}
386377

387378
#pragma mark RCTTurboModuleLookupDelegate
@@ -465,8 +456,6 @@ - (void)bridgeDidInvalidateModules:(NSNotification *)notification
465456
}
466457

467458
_turboModuleCache.clear();
468-
469-
_binding->invalidate();
470459
}
471460

472461
- (void)invalidate
@@ -491,8 +480,6 @@ - (void)invalidate
491480
}
492481

493482
_turboModuleCache.clear();
494-
495-
_binding->invalidate();
496483
}
497484

498485
@end

0 commit comments

Comments
 (0)