Skip to content

Commit fea6af5

Browse files
philIipfacebook-github-bot
authored andcommitted
introduce native api to access RuntimeExecutor (facebook#42758)
Summary: Changelog: [iOS][Added] - introduce native api to access RuntimeExecutor The goal of this API is to provide a safe way to access the `jsi::runtime` in bridgeless mode. The decision to limit access to the runtime in bridgeless was a conscious one - the runtime pointer is not thread-safe and its lifecycle must be managed correctly by owners. However, interacting with the runtime is an advanced use case we would want to support. Our recommended ways to access the runtime in bridgeless mode is either 1) via the RuntimeExecutor, or 2) via a C++ TurboModule. This diff introduces the API that would allow for 1). The integration consists of these parts: - wrapper object for RuntimeExecutor access, `RCTRuntimeExecutor`. The NSObject wrapper is necessary so we can make it the property of a swift module - new protocol API,`RCTRuntimeExecutionModule`, for modules to access the RuntimeExecutor block - integration within the bridgeless infrastructure Reviewed By: javache Differential Revision: D53256188
1 parent e4342f5 commit fea6af5

File tree

6 files changed

+115
-2
lines changed

6 files changed

+115
-2
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@class RCTRuntimeExecutor;
9+
10+
/**
11+
* Have your module conform to this protocol to access the RuntimeExecutor.
12+
* Only available in the bridgeless runtime.
13+
*/
14+
@protocol RCTRuntimeExecutorModule <NSObject>
15+
16+
@property (nonatomic, nullable, readwrite) RCTRuntimeExecutor *runtimeExecutor;
17+
18+
@end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <ReactCommon/RuntimeExecutor.h>
9+
#import <jsi/jsi.h>
10+
11+
NS_ASSUME_NONNULL_BEGIN
12+
13+
typedef void (^RCTJSIRuntimeHandlingBlock)(facebook::jsi::Runtime &runtime);
14+
15+
@interface RCTRuntimeExecutor : NSObject
16+
17+
- (instancetype)init NS_UNAVAILABLE;
18+
19+
/**
20+
Initializes an object that wraps ways to access the RuntimeExecutor.
21+
22+
@param runtimeExecutor The instance of RuntimeExecutor.
23+
*/
24+
- (instancetype)initWithRuntimeExecutor:(facebook::react::RuntimeExecutor)runtimeExecutor NS_DESIGNATED_INITIALIZER;
25+
26+
- (void)execute:(RCTJSIRuntimeHandlingBlock)block;
27+
28+
@end
29+
30+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import "RCTRuntimeExecutor.h"
9+
10+
@implementation RCTRuntimeExecutor {
11+
facebook::react::RuntimeExecutor _runtimeExecutor;
12+
}
13+
14+
#pragma mark - Initializer
15+
16+
- (instancetype)initWithRuntimeExecutor:(facebook::react::RuntimeExecutor)runtimeExecutor
17+
{
18+
if (self = [super init]) {
19+
_runtimeExecutor = runtimeExecutor;
20+
}
21+
22+
return self;
23+
}
24+
25+
#pragma mark - Public API
26+
27+
- (void)execute:(RCTJSIRuntimeHandlingBlock)block
28+
{
29+
if (_runtimeExecutor) {
30+
_runtimeExecutor([=](facebook::jsi::Runtime &runtime) { block(runtime); });
31+
}
32+
}
33+
34+
@end

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
#import <React/RCTTurboModuleRegistry.h>
1616
#import <ReactCommon/RuntimeExecutor.h>
1717
#import <ReactCommon/TurboModuleBinding.h>
18+
1819
#import "RCTTurboModule.h"
1920

21+
@class RCTTurboModuleManager;
22+
2023
@protocol RCTTurboModuleManagerDelegate <NSObject>
2124

2225
/**
@@ -52,6 +55,12 @@
5255

5356
@end
5457

58+
@protocol RCTTurboModuleManagerRuntimeHandler <NSObject>
59+
60+
- (facebook::react::RuntimeExecutor)runtimeExecutorForTurboModuleManager:(RCTTurboModuleManager *)turboModuleManager;
61+
62+
@end
63+
5564
@interface RCTTurboModuleManager : NSObject <RCTTurboModuleRegistry>
5665

5766
- (instancetype)initWithBridge:(RCTBridge *)bridge
@@ -67,4 +76,6 @@
6776

6877
- (void)invalidate;
6978

79+
@property (nonatomic, weak, readwrite) id<RCTTurboModuleManagerRuntimeHandler> runtimeHandler;
80+
7081
@end

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import "RCTTurboModuleManager.h"
99
#import "RCTInteropTurboModule.h"
10+
#import "RCTRuntimeExecutor.h"
1011

1112
#import <atomic>
1213
#import <cassert>
@@ -24,8 +25,8 @@
2425
#import <React/RCTLog.h>
2526
#import <React/RCTModuleData.h>
2627
#import <React/RCTPerformanceLogger.h>
28+
#import <React/RCTRuntimeExecutorModule.h>
2729
#import <React/RCTUtils.h>
28-
#import <ReactCommon/RuntimeExecutor.h>
2930
#import <ReactCommon/TurboCxxModule.h>
3031
#import <ReactCommon/TurboModulePerfLogger.h>
3132
#import <ReactCommon/TurboModuleUtils.h>
@@ -676,6 +677,13 @@ - (BOOL)_shouldCreateObjCModule:(Class)moduleClass
676677
}
677678
}
678679

680+
// This is a more performant alternative for conformsToProtocol:@protocol(RCTRuntimeExecutorModule)
681+
if ([module respondsToSelector:@selector(setRuntimeExecutor:)]) {
682+
RCTRuntimeExecutor *runtimeExecutor = [[RCTRuntimeExecutor alloc]
683+
initWithRuntimeExecutor:[_runtimeHandler runtimeExecutorForTurboModuleManager:self]];
684+
[(id<RCTRuntimeExecutorModule>)module setRuntimeExecutor:runtimeExecutor];
685+
}
686+
679687
/**
680688
* Some modules need their own queues, but don't provide any, so we need to create it for them.
681689
* These modules typically have the following:

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags)
6363
sRuntimeDiagnosticFlags = [flags copy];
6464
}
6565

66-
@interface RCTInstance () <RCTTurboModuleManagerDelegate>
66+
@interface RCTInstance () <RCTTurboModuleManagerDelegate, RCTTurboModuleManagerRuntimeHandler>
6767
@end
6868

6969
@implementation RCTInstance {
@@ -208,6 +208,17 @@ - (Class)getModuleClassFromName:(const char *)name
208208
return nullptr;
209209
}
210210

211+
#pragma mark - RCTTurboModuleManagerRuntimeHandler
212+
213+
- (RuntimeExecutor)runtimeExecutorForTurboModuleManager:(RCTTurboModuleManager *)turboModuleManager
214+
{
215+
if (_valid) {
216+
return _reactInstance->getBufferedRuntimeExecutor();
217+
}
218+
219+
return nullptr;
220+
}
221+
211222
#pragma mark - Private
212223

213224
- (void)_start
@@ -259,6 +270,7 @@ - (void)_start
259270
bridgeModuleDecorator:_bridgeModuleDecorator
260271
delegate:self
261272
jsInvoker:std::make_shared<BridgelessJSCallInvoker>(bufferedRuntimeExecutor)];
273+
_turboModuleManager.runtimeHandler = self;
262274

263275
#if RCT_DEV
264276
/**

0 commit comments

Comments
 (0)