[ReactNative] Remove RCT_IMPORT_METHOD macro and generate lookup table dynamically
Summary: @public This removes the last piece of data that was still stored on the DATA section, `RCT_IMPORT_METHOD`. JS calls now dynamically populate a lookup table simultaneously on JS and Native, instead of creating a mapping at load time. Test Plan: Everything still runs, tests are green.
This commit is contained in:
parent
86dc92d5ab
commit
d3065fc2e7
|
@ -305,10 +305,12 @@ var MessageQueueMixin = {
|
|||
return guardReturn(this._callFunction, [moduleID, methodID, params], null, this);
|
||||
},
|
||||
|
||||
_callFunction: function(moduleID, methodID, params) {
|
||||
var moduleName = this._localModuleIDToModuleName[moduleID];
|
||||
_callFunction: function(moduleName, methodName, params) {
|
||||
if (isFinite(moduleName)) {
|
||||
moduleName = this._localModuleIDToModuleName[moduleName];
|
||||
methodName = this._localModuleNameToMethodIDToName[moduleName][methodName];
|
||||
}
|
||||
|
||||
var methodName = this._localModuleNameToMethodIDToName[moduleName][methodID];
|
||||
if (DEBUG_SPY_MODE) {
|
||||
console.log(
|
||||
'N->JS: ' + moduleName + '.' + methodName +
|
||||
|
|
|
@ -75,22 +75,15 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
|||
/**
|
||||
* This method is used to call functions in the JavaScript application context.
|
||||
* It is primarily intended for use by modules that require two-way communication
|
||||
* with the JavaScript code. Method should be registered using the
|
||||
* RCT_IMPORT_METHOD macro below. Attempting to call a method that has not been
|
||||
* registered will result in an error. Safe to call from any thread.
|
||||
* with the JavaScript code. Safe to call from any thread.
|
||||
*/
|
||||
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
|
||||
|
||||
/**
|
||||
* This macro is used to register a JS method to be called via the enqueueJSCall
|
||||
* bridge method. You should place this macro inside any file that uses the
|
||||
* imported method. If a method has already been registered by another class, it
|
||||
* is not necessary to register it again, but it is good practice. Registering
|
||||
* the same method more than once will not result in an error.
|
||||
* DEPRECATED: Do not use.
|
||||
*/
|
||||
#define RCT_IMPORT_METHOD(module, method) \
|
||||
__attribute__((used, section("__DATA,RCTImport"))) \
|
||||
static const char *__rct_import_##module##_##method##__ = #module"."#method;
|
||||
_Pragma("message(\"This macro is no longer required\")")
|
||||
|
||||
/**
|
||||
* URL of the script that was loaded into the bridge.
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import <mach-o/dyld.h>
|
||||
#import <mach-o/getsect.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTContextExecutor.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
|
@ -54,16 +50,6 @@ typedef NS_ENUM(NSUInteger, RCTJavaScriptFunctionKind) {
|
|||
RCTJavaScriptFunctionKindAsync,
|
||||
};
|
||||
|
||||
#ifdef __LP64__
|
||||
typedef struct mach_header_64 *RCTHeaderValue;
|
||||
typedef struct section_64 RCTHeaderSection;
|
||||
#define RCTGetSectByNameFromHeader getsectbynamefromheader_64
|
||||
#else
|
||||
typedef struct mach_header *RCTHeaderValue;
|
||||
typedef struct section RCTHeaderSection;
|
||||
#define RCTGetSectByNameFromHeader getsectbynamefromheader
|
||||
#endif
|
||||
|
||||
#define RCTAssertJSThread() \
|
||||
RCTAssert(![NSStringFromClass([_javaScriptExecutor class]) isEqualToString:@"RCTContextExecutor"] || \
|
||||
[[[NSThread currentThread] name] isEqualToString:@"com.facebook.React.JavaScript"], \
|
||||
|
@ -114,40 +100,6 @@ NSString *RCTBridgeModuleNameForClass(Class cls)
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function scans all classes available at runtime and returns an array
|
||||
* of all JSMethods registered.
|
||||
*/
|
||||
static NSArray *RCTJSMethods(void)
|
||||
{
|
||||
static NSArray *JSMethods;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSMutableSet *uniqueMethods = [NSMutableSet set];
|
||||
|
||||
Dl_info info;
|
||||
dladdr(&RCTJSMethods, &info);
|
||||
|
||||
const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
|
||||
unsigned long size = 0;
|
||||
const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTImport", &size);
|
||||
if (sectionData) {
|
||||
for (const uint8_t *addr = sectionData;
|
||||
addr < sectionData + size;
|
||||
addr += sizeof(const char **)) {
|
||||
|
||||
// Get data entry
|
||||
NSString *entry = @(*(const char **)addr);
|
||||
[uniqueMethods addObject:entry];
|
||||
}
|
||||
}
|
||||
|
||||
JSMethods = [uniqueMethods allObjects];
|
||||
});
|
||||
|
||||
return JSMethods;
|
||||
}
|
||||
|
||||
// TODO: Can we just replace RCTMakeError with this function instead?
|
||||
static NSDictionary *RCTJSErrorFromNSError(NSError *error)
|
||||
{
|
||||
|
@ -596,80 +548,6 @@ static NSDictionary *RCTRemoteModulesConfig(NSDictionary *modulesByName)
|
|||
return moduleConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* As above, but for local modules/methods, which represent JS classes
|
||||
* and methods that will be called by the native code via the bridge.
|
||||
* Structure is essentially the same as for remote modules:
|
||||
*
|
||||
* "ModuleName1": {
|
||||
* "moduleID": 0,
|
||||
* "methods": {
|
||||
* "methodName1": {
|
||||
* "methodID": 0,
|
||||
* "type": "local"
|
||||
* },
|
||||
* "methodName2": {
|
||||
* "methodID": 1,
|
||||
* "type": "local"
|
||||
* },
|
||||
* etc...
|
||||
* }
|
||||
* },
|
||||
* etc...
|
||||
*/
|
||||
static NSMutableDictionary *RCTLocalModuleIDs;
|
||||
static NSMutableDictionary *RCTLocalMethodIDs;
|
||||
static NSMutableArray *RCTLocalModuleNames;
|
||||
static NSMutableArray *RCTLocalMethodNames;
|
||||
static NSDictionary *RCTLocalModulesConfig()
|
||||
{
|
||||
static NSMutableDictionary *localModules;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
||||
RCTLocalModuleIDs = [[NSMutableDictionary alloc] init];
|
||||
RCTLocalMethodIDs = [[NSMutableDictionary alloc] init];
|
||||
RCTLocalModuleNames = [[NSMutableArray alloc] init];
|
||||
RCTLocalMethodNames = [[NSMutableArray alloc] init];
|
||||
|
||||
localModules = [[NSMutableDictionary alloc] init];
|
||||
for (NSString *moduleDotMethod in RCTJSMethods()) {
|
||||
|
||||
NSArray *parts = [moduleDotMethod componentsSeparatedByString:@"."];
|
||||
RCTAssert(parts.count == 2, @"'%@' is not a valid JS method definition - expected 'Module.method' format.", moduleDotMethod);
|
||||
|
||||
// Add module if it doesn't already exist
|
||||
NSString *moduleName = parts[0];
|
||||
NSDictionary *module = localModules[moduleName];
|
||||
if (!module) {
|
||||
module = @{
|
||||
@"moduleID": @(localModules.count),
|
||||
@"methods": [[NSMutableDictionary alloc] init]
|
||||
};
|
||||
localModules[moduleName] = module;
|
||||
[RCTLocalModuleNames addObject:moduleName];
|
||||
}
|
||||
|
||||
// Add method if it doesn't already exist
|
||||
NSString *methodName = parts[1];
|
||||
NSMutableDictionary *methods = module[@"methods"];
|
||||
if (!methods[methodName]) {
|
||||
methods[methodName] = @{
|
||||
@"methodID": @(methods.count),
|
||||
@"type": @"local"
|
||||
};
|
||||
[RCTLocalMethodNames addObject:methodName];
|
||||
}
|
||||
|
||||
// Add module and method lookup
|
||||
RCTLocalModuleIDs[moduleDotMethod] = module[@"moduleID"];
|
||||
RCTLocalMethodIDs[moduleDotMethod] = methods[methodName][@"methodID"];
|
||||
}
|
||||
});
|
||||
|
||||
return localModules;
|
||||
}
|
||||
|
||||
@interface RCTFrameUpdate (Private)
|
||||
|
||||
- (instancetype)initWithDisplayLink:(CADisplayLink *)displayLink;
|
||||
|
@ -734,12 +612,6 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
RCTAssertMainThread();
|
||||
|
||||
if ((self = [super init])) {
|
||||
|
||||
/**
|
||||
* Pre register modules
|
||||
*/
|
||||
RCTLocalModulesConfig();
|
||||
|
||||
_bundleURL = bundleURL;
|
||||
_moduleProvider = block;
|
||||
_launchOptions = [launchOptions copy];
|
||||
|
@ -1052,7 +924,6 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
|
|||
// Inject module data into JS context
|
||||
NSString *configJSON = RCTJSONStringify(@{
|
||||
@"remoteModuleConfig": RCTRemoteModulesConfig(_modulesByName),
|
||||
@"localModulesConfig": RCTLocalModulesConfig()
|
||||
}, NULL);
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
[_javaScriptExecutor injectJSONText:configJSON
|
||||
|
@ -1211,13 +1082,6 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
|
|||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* - TODO (#5906496): When we build a `MessageQueue.m`, handling all the requests could
|
||||
* cause both a queue of "responses". We would flush them here. However, we
|
||||
* currently just expect each objc block to handle its own response sending
|
||||
* using a `RCTResponseSenderBlock`.
|
||||
*/
|
||||
|
||||
#pragma mark - RCTBridge methods
|
||||
|
||||
/**
|
||||
|
@ -1225,16 +1089,11 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
|
|||
*/
|
||||
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
|
||||
{
|
||||
NSNumber *moduleID = RCTLocalModuleIDs[moduleDotMethod];
|
||||
RCTAssert(moduleID != nil, @"Module '%@' not registered.",
|
||||
[[moduleDotMethod componentsSeparatedByString:@"."] firstObject]);
|
||||
|
||||
NSNumber *methodID = RCTLocalMethodIDs[moduleDotMethod];
|
||||
RCTAssert(methodID != nil, @"Method '%@' not registered.", moduleDotMethod);
|
||||
NSArray *ids = [moduleDotMethod componentsSeparatedByString:@"."];
|
||||
|
||||
[self _invokeAndProcessModule:@"BatchedBridge"
|
||||
method:@"callFunctionReturnFlushedQueue"
|
||||
arguments:@[moduleID ?: @0, methodID ?: @0, args ?: @[]]
|
||||
arguments:@[ids[0], ids[1], args ?: @[]]
|
||||
context:RCTGetExecutorID(_javaScriptExecutor)];
|
||||
}
|
||||
|
||||
|
@ -1245,18 +1104,10 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
|
|||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
NSString *moduleDotMethod = @"JSTimersExecution.callTimers";
|
||||
NSNumber *moduleID = RCTLocalModuleIDs[moduleDotMethod];
|
||||
RCTAssert(moduleID != nil, @"Module '%@' not registered.",
|
||||
[[moduleDotMethod componentsSeparatedByString:@"."] firstObject]);
|
||||
|
||||
NSNumber *methodID = RCTLocalMethodIDs[moduleDotMethod];
|
||||
RCTAssert(methodID != nil, @"Method '%@' not registered.", moduleDotMethod);
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
[self _actuallyInvokeAndProcessModule:@"BatchedBridge"
|
||||
method:@"callFunctionReturnFlushedQueue"
|
||||
arguments:@[moduleID, methodID, @[@[timer]]]
|
||||
arguments:@[@"JSTimersExecution", @"callTimers", @[@[timer]]]
|
||||
context:RCTGetExecutorID(_javaScriptExecutor)];
|
||||
};
|
||||
|
||||
|
|
|
@ -89,10 +89,6 @@ RCT_EXPORT_MODULE()
|
|||
return self;
|
||||
}
|
||||
|
||||
RCT_IMPORT_METHOD(RCTNativeAppEventEmitter, emit);
|
||||
RCT_IMPORT_METHOD(RCTDeviceEventEmitter, emit);
|
||||
RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent);
|
||||
|
||||
- (void)sendAppEventWithName:(NSString *)name body:(id)body
|
||||
{
|
||||
[_bridge enqueueJSCall:@"RCTNativeAppEventEmitter.emit"
|
||||
|
|
|
@ -119,9 +119,6 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
|||
return YES;
|
||||
}
|
||||
|
||||
RCT_IMPORT_METHOD(AppRegistry, runApplication)
|
||||
RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
|
||||
- (void)setLoadingView:(UIView *)loadingView
|
||||
{
|
||||
_loadingView = loadingView;
|
||||
|
|
|
@ -149,8 +149,6 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
|||
reactTouch[@"timestamp"] = @(nativeTouch.timestamp * 1000); // in ms, for JS
|
||||
}
|
||||
|
||||
RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
|
||||
|
||||
/**
|
||||
* Constructs information about touch events to send across the serialized
|
||||
* boundary. This data should be compliant with W3C `Touch` objects. This data
|
||||
|
|
|
@ -365,7 +365,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
JSValueRef moduleJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)requireJSRef, NULL, 1, (const JSValueRef *)&moduleNameJSRef, &errorJSRef);
|
||||
JSStringRelease(moduleNameJSStringRef);
|
||||
|
||||
if (moduleJSRef != NULL && errorJSRef == NULL) {
|
||||
if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
|
||||
|
||||
// get method
|
||||
JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
|
||||
|
|
|
@ -74,8 +74,6 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
RCT_IMPORT_METHOD(JSTimersExecution, callTimers)
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
|
Loading…
Reference in New Issue