iOS changes to switch to JSI

Summary:
change RCTCxxBridge to use JSIExecutorFactory+JSCRuntime
instead of JSCExecutorFactory.  Also remove JSC usage from RN in other
files.  This allows deleting files, too, which is done further down
the stack.

Reviewed By: RSNara

Differential Revision: D9369111

fbshipit-source-id: 67ef3146e3abe5244b6cf3249a0268598f91b277
This commit is contained in:
Marc Horowitz
2018-10-18 00:47:05 -07:00
committed by Facebook Github Bot
parent 6796e62bb3
commit c49d3653ef
19 changed files with 26 additions and 254 deletions

View File

@@ -5,9 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
#import <JavaScriptCore/JavaScriptCore.h>
#import <JavaScriptCore/JSBase.h>
#import <React/RCTBridge.h>
@class RCTModuleData;
@@ -15,8 +12,6 @@
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
RCT_EXTERN __attribute__((weak)) void RCTFBQuickPerformanceLoggerConfigureHooks(JSGlobalContextRef ctx);
#if RCT_DEBUG
RCT_EXTERN void RCTVerifyAllModulesExported(NSArray *extraModules);
#endif
@@ -141,15 +136,6 @@ RCT_EXTERN void RCTRegisterModule(Class);
@end
@interface RCTBridge (JavaScriptCore)
/**
* The raw JSGlobalContextRef used by the bridge.
*/
@property (nonatomic, readonly, assign) JSGlobalContextRef jsContextRef;
@end
@interface RCTBridge (Inspector)
@property (nonatomic, readonly, getter=isInspectable) BOOL inspectable;

View File

@@ -169,11 +169,6 @@ RCT_EXTERN void RCTEnableJSINativeModule(BOOL enabled);
*/
- (BOOL)moduleIsInitialized:(Class)moduleClass;
/**
* Retrieve an extra module that gets bound to the JS context, if any.
*/
- (id)jsBoundExtraModuleForClass:(Class)moduleClass;
/**
* All registered bridge module classes.
*/

View File

@@ -44,8 +44,6 @@ NSArray<Class> *RCTGetModuleClasses(void)
return result;
}
void RCTFBQuickPerformanceLoggerConfigureHooks(__unused JSGlobalContextRef ctx) { }
/**
* Register the given class as a bridge module. All modules must be registered
* prior to the first bridge initialization.
@@ -272,11 +270,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return [self.batchedBridge moduleIsInitialized:moduleClass];
}
- (id)jsBoundExtraModuleForClass:(Class)moduleClass
{
return [self.batchedBridge jsBoundExtraModuleForClass:moduleClass];
}
- (void)reload
{
#if RCT_ENABLE_INSPECTOR
@@ -392,9 +385,4 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
[self.batchedBridge registerSegmentWithId:segmentId path:path];
}
- (JSGlobalContextRef)jsContextRef
{
return [self.batchedBridge jsContextRef];
}
@end

View File

@@ -7,8 +7,6 @@
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>

View File

@@ -10,7 +10,6 @@
#import <sys/stat.h>
#import <cxxreact/JSBundleType.h>
#import <jschelpers/JavaScriptCore.h>
#import "RCTBridge.h"
#import "RCTConvert.h"
@@ -20,6 +19,8 @@
NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomain";
static const int32_t JSNoBytecodeFileFormatVersion = -1;
@interface RCTSource()
{
@public

View File

@@ -29,15 +29,14 @@
#import <cxxreact/CxxNativeModule.h>
#import <cxxreact/Instance.h>
#import <cxxreact/JSBundleType.h>
#import <cxxreact/JSCExecutor.h>
#import <cxxreact/JSIndexedRAMBundle.h>
#import <cxxreact/ModuleRegistry.h>
#import <cxxreact/Platform.h>
#import <cxxreact/RAMBundleRegistry.h>
#import <jschelpers/Value.h>
#import <cxxreact/ReactMarker.h>
#import <jsi/JSCRuntime.h>
#import <jsireact/JSIExecutor.h>
#import "NSDataBigString.h"
#import "RCTJSCHelpers.h"
#import "RCTMessageThread.h"
#import "RCTObjcExecutor.h"
@@ -57,6 +56,7 @@ static NSString *const RCTJSThreadName = @"com.facebook.react.JavaScript";
typedef void (^RCTPendingCall)();
using namespace facebook::jsc;
using namespace facebook::react;
/**
@@ -178,18 +178,6 @@ struct RCTInstanceCallback : public InstanceCallback {
@synthesize performanceLogger = _performanceLogger;
@synthesize valid = _valid;
+ (void)initialize
{
if (self == [RCTCxxBridge class]) {
RCTPrepareJSCExecutor();
}
}
- (JSGlobalContextRef)jsContextRef
{
return (JSGlobalContextRef)(_reactInstance ? _reactInstance->getJavaScriptContext() : nullptr);
}
- (std::shared_ptr<MessageQueueThread>)jsMessageThread
{
return _jsMessageThread;
@@ -328,22 +316,13 @@ struct RCTInstanceCallback : public InstanceCallback {
executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self];
}
if (!executorFactory) {
BOOL useCustomJSC =
[self.delegate respondsToSelector:@selector(shouldBridgeUseCustomJSC:)] &&
[self.delegate shouldBridgeUseCustomJSC:self];
// We use the name of the device and the app for debugging & metrics
NSString *deviceName = [[UIDevice currentDevice] name];
NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
// The arg is a cache dir. It's not used with standard JSC.
executorFactory.reset(new JSCExecutorFactory(folly::dynamic::object
("OwnerIdentity", "ReactNative")
("AppIdentity", [(appName ?: @"unknown") UTF8String])
("DeviceIdentity", [(deviceName ?: @"unknown") UTF8String])
("UseCustomJSC", (bool)useCustomJSC)
#if RCT_PROFILE
("StartSamplingProfilerOnInit", (bool)self.devSettings.startSamplingProfilerOnLaunch)
#endif
));
executorFactory = std::make_shared<JSIExecutorFactory>(
makeJSCRuntime(),
[](const std::string &message, unsigned int logLevel) {
_RCTLogJavaScriptInternal(
static_cast<RCTLogLevel>(logLevel),
[NSString stringWithUTF8String:message.c_str()]);
}, nullptr);
}
} else {
id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass];
@@ -461,18 +440,6 @@ struct RCTInstanceCallback : public InstanceCallback {
return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
}
- (id)jsBoundExtraModuleForClass:(Class)moduleClass
{
if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate;
if ([cxxDelegate respondsToSelector:@selector(jsBoundExtraModuleForClass:)]) {
return [cxxDelegate jsBoundExtraModuleForClass:moduleClass];
}
}
return nil;
}
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistry
{
if (!self.valid) {
@@ -534,8 +501,6 @@ struct RCTInstanceCallback : public InstanceCallback {
std::make_unique<JSBigStdString>("true"));
}
#endif
[self installExtraJSBinding];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
@@ -634,16 +599,6 @@ struct RCTInstanceCallback : public InstanceCallback {
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
- (void)installExtraJSBinding
{
if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate;
if ([cxxDelegate respondsToSelector:@selector(installExtraJSBinding:)]) {
[cxxDelegate installExtraJSBinding:self.jsContextRef];
}
}
}
- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules
withDispatchGroup:(dispatch_group_t)dispatchGroup
lazilyDiscovered:(BOOL)lazilyDiscovered

View File

@@ -8,7 +8,6 @@
#include <memory>
#import <React/RCTBridgeDelegate.h>
#import <jschelpers/JavaScriptCore.h>
namespace facebook {
namespace react {
@@ -26,21 +25,9 @@ class JSExecutorFactory;
/**
* In the RCTCxxBridge, if this method is implemented, return a
* ExecutorFactory instance which can be used to create the executor.
* If not implemented, or returns an empty pointer, JSCExecutorFactory
* will be used.
* If not implemented, or returns an empty pointer, JSIExecutorFactory
* will be used with a JSCRuntime.
*/
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge;
@optional
/**
* Experimental: Perform installation of extra JS binding on the given JS context, as appropriate.
*/
- (void)installExtraJSBinding:(JSGlobalContextRef)jsContextRef;
/**
* Experimental: Get the instance of the extra module/class which gets bound via `installExtraJSBinding:`
*/
- (id)jsBoundExtraModuleForClass:(Class)moduleClass;
@end

View File

@@ -12,7 +12,6 @@
#import <React/RCTCxxUtils.h>
#import <React/RCTUtils.h>
#include <jschelpers/JSCHelpers.h>
// A note about the implementation: This class is not used
// generically. It's a thin wrapper around a run loop which

View File

@@ -5,12 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/
#include <functional>
#include <memory>
#import <JavaScriptCore/JavaScriptCore.h>
#import <cxxreact/JSCExecutor.h>
#import <jschelpers/JavaScriptCore.h>
#import <Foundation/Foundation.h>
@class RCTBridge;
@class RCTModuleData;
@@ -19,19 +17,10 @@ namespace facebook {
namespace react {
class Instance;
class NativeModule;
std::vector<std::unique_ptr<NativeModule>> createNativeModules(NSArray<RCTModuleData *> *modules, RCTBridge *bridge, const std::shared_ptr<Instance> &instance);
JSContext *contextForGlobalContextRef(JSGlobalContextRef contextRef);
template<>
struct JSCValueEncoder<id> {
static Value toJSCValue(JSGlobalContextRef ctx, id obj) {
JSValue *value = [JSC_JSValue(ctx) valueWithObject:obj inContext:contextForGlobalContextRef(ctx)];
return {ctx, [value JSValueRef]};
}
};
NSError *tryAndReturnError(const std::function<void()>& func);
NSString *deriveSourceURL(NSURL *url);

View File

@@ -11,7 +11,7 @@
#import <React/RCTModuleData.h>
#import <React/RCTUtils.h>
#import <cxxreact/CxxNativeModule.h>
#import <jschelpers/Value.h>
#import <jsi/jsi.h>
#import "DispatchMessageQueueThread.h"
#import "RCTCxxModule.h"
@@ -20,6 +20,8 @@
namespace facebook {
namespace react {
using facebook::jsi::JSError;
std::vector<std::unique_ptr<NativeModule>> createNativeModules(NSArray<RCTModuleData *> *modules, RCTBridge *bridge, const std::shared_ptr<Instance> &instance)
{
std::vector<std::unique_ptr<NativeModule>> nativeModules;
@@ -37,39 +39,14 @@ std::vector<std::unique_ptr<NativeModule>> createNativeModules(NSArray<RCTModule
return nativeModules;
}
JSContext *contextForGlobalContextRef(JSGlobalContextRef contextRef)
{
static std::mutex s_mutex;
static NSMapTable *s_contextCache;
if (!contextRef) {
return nil;
}
// Adding our own lock here, since JSC internal ones are insufficient
std::lock_guard<std::mutex> lock(s_mutex);
if (!s_contextCache) {
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
s_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
}
JSContext *ctx = [s_contextCache objectForKey:(__bridge id)contextRef];
if (!ctx) {
ctx = [JSC_JSContext(contextRef) contextWithJSGlobalContextRef:contextRef];
[s_contextCache setObject:ctx forKey:(__bridge id)contextRef];
}
return ctx;
}
static NSError *errorWithException(const std::exception &e)
{
NSString *msg = @(e.what());
NSMutableDictionary *errorInfo = [NSMutableDictionary dictionary];
const JSException *jsException = dynamic_cast<const JSException*>(&e);
if (jsException) {
errorInfo[RCTJSRawStackTraceKey] = @(jsException->getStack().c_str());
const auto *jsError = dynamic_cast<const JSError*>(&e);
if (jsError) {
errorInfo[RCTJSRawStackTraceKey] = @(jsError->getStack().c_str());
msg = [@"Unhandled JS Exception: " stringByAppendingString:msg];
}

View File

@@ -269,12 +269,6 @@ RCT_EXPORT_MODULE()
}]];
}
if (devSettings.isJSCSamplingProfilerAvailable) {
[items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Start / Stop JS Sampling Profiler" handler:^{
[devSettings toggleJSCSamplingProfiler];
}]];
}
[items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{
return @"Toggle Inspector";
} handler:^{

View File

@@ -4,7 +4,6 @@
// LICENSE file in the root directory of this source tree.
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JSBase.h>
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>

View File

@@ -2,15 +2,12 @@
#if RCT_DEV
#import <jschelpers/JSCWrapper.h>
#import <UIKit/UIKit.h>
#import <React/RCTLog.h>
#import "RCTDefines.h"
#import "RCTInspectorPackagerConnection.h"
using namespace facebook::react;
static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";
static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)

View File

@@ -307,12 +307,3 @@ using namespace facebook::react;
}
@end
@implementation RCTBridge (RCTSurfacePresenter)
- (RCTSurfacePresenter *)surfacePresenter
{
return [self jsBoundExtraModuleForClass:[RCTSurfacePresenter class]];
}
@end

View File

@@ -3,7 +3,6 @@
#if RCT_DEV
#include <jschelpers/JavaScriptCore.h>
#include <jsinspector/InspectorInterfaces.h>
#import "RCTDefines.h"

View File

@@ -71,11 +71,6 @@
*/
- (void)toggleElementInspector;
/**
* Toggle JSC's sampling profiler.
*/
- (void)toggleJSCSamplingProfiler;
/**
* Enables starting of profiling sampler on launch
*/

View File

@@ -9,14 +9,9 @@
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import <jschelpers/JavaScriptCore.h>
#import "RCTBridge+Private.h"
#import "RCTBridgeModule.h"
#import "RCTEventDispatcher.h"
#import "RCTJSCSamplingProfiler.h"
#import "RCTLog.h"
#import "RCTProfile.h"
#import "RCTUtils.h"
@@ -29,7 +24,6 @@ static NSString *const kRCTDevSettingIsDebuggingRemotely = @"isDebuggingRemotely
static NSString *const kRCTDevSettingExecutorOverrideClass = @"executor-override";
static NSString *const kRCTDevSettingShakeToShowDevMenu = @"shakeToShow";
static NSString *const kRCTDevSettingIsPerfMonitorShown = @"RCTPerfMonitorKey";
static NSString *const kRCTDevSettingStartSamplingProfilerOnLaunch = @"startSamplingProfilerOnLaunch";
static NSString *const kRCTDevSettingsUserDefaultsKey = @"RCTDevMenu";
@@ -40,7 +34,6 @@ static NSString *const kRCTDevSettingsUserDefaultsKey = @"RCTDevMenu";
#if RCT_ENABLE_INSPECTOR
#import "RCTInspectorDevServerHelper.h"
#import <jschelpers/JSCWrapper.h>
#endif
#if RCT_DEV
@@ -112,7 +105,6 @@ static NSString *const kRCTDevSettingsUserDefaultsKey = @"RCTDevMenu";
BOOL _isJSLoaded;
#if ENABLE_PACKAGER_CONNECTION
RCTHandlerToken _reloadToken;
RCTHandlerToken _pokeSamplingProfilerToken;
#endif
}
@@ -177,14 +169,6 @@ RCT_EXPORT_MODULE()
}
queue:dispatch_get_main_queue()
forMethod:@"reload"];
_pokeSamplingProfilerToken =
[[RCTPackagerConnection sharedPackagerConnection]
addRequestHandler:^(NSDictionary<NSString *, id> *params, RCTPackagerClientResponder *responder) {
pokeSamplingProfiler(weakBridge, responder);
}
queue:dispatch_get_main_queue()
forMethod:@"pokeSamplingProfiler"];
#endif
#if RCT_ENABLE_INSPECTOR
@@ -201,32 +185,6 @@ RCT_EXPORT_MODULE()
#endif
}
#if ENABLE_PACKAGER_CONNECTION
static void pokeSamplingProfiler(RCTBridge *const bridge, RCTPackagerClientResponder *const responder)
{
if (!bridge) {
[responder respondWithError:@"The bridge is nil. Try again."];
return;
}
JSGlobalContextRef globalContext = bridge.jsContextRef;
if (!JSC_JSSamplingProfilerEnabled(globalContext)) {
[responder respondWithError:@"The JSSamplingProfiler is disabled. See 'iOS specific setup' section here https://fburl.com/u4lw7xeq for some help"];
return;
}
// JSPokeSamplingProfiler() toggles the profiling process
JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext);
if (JSC_JSValueGetType(globalContext, jsResult) == kJSTypeNull) {
[responder respondWithResult:@"started"];
} else {
JSContext *context = [JSC_JSContext(globalContext) contextWithJSGlobalContextRef:globalContext];
NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject];
[responder respondWithResult:results];
}
}
#endif
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
@@ -237,7 +195,6 @@ static void pokeSamplingProfiler(RCTBridge *const bridge, RCTPackagerClientRespo
[_liveReloadUpdateTask cancel];
#if ENABLE_PACKAGER_CONNECTION
[[RCTPackagerConnection sharedPackagerConnection] removeHandler:_reloadToken];
[[RCTPackagerConnection sharedPackagerConnection] removeHandler:_pokeSamplingProfilerToken];
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@@ -277,11 +234,6 @@ static void pokeSamplingProfiler(RCTBridge *const bridge, RCTPackagerClientRespo
return (_liveReloadURL != nil);
}
- (BOOL)isJSCSamplingProfilerAvailable
{
return JSC_JSSamplingProfilerEnabled(_bridge.jsContextRef);
}
RCT_EXPORT_METHOD(reload)
{
[_bridge reload];
@@ -394,20 +346,6 @@ RCT_EXPORT_METHOD(toggleElementInspector)
}
}
- (void)toggleJSCSamplingProfiler
{
JSGlobalContextRef globalContext = _bridge.jsContextRef;
// JSPokeSamplingProfiler() toggles the profiling process
JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext);
if (JSC_JSValueGetType(globalContext, jsResult) != kJSTypeNull) {
JSContext *context = [JSC_JSContext(globalContext) contextWithJSGlobalContextRef:globalContext];
NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject];
RCTJSCSamplingProfiler *profilerModule = [_bridge moduleForClass:[RCTJSCSamplingProfiler class]];
[profilerModule operationCompletedWithResults:results];
}
}
- (BOOL)isElementInspectorShown
{
return [[self settingForKey:kRCTDevSettingIsInspectorShown] boolValue];
@@ -423,16 +361,6 @@ RCT_EXPORT_METHOD(toggleElementInspector)
return [[self settingForKey:kRCTDevSettingIsPerfMonitorShown] boolValue];
}
- (void)setStartSamplingProfilerOnLaunch:(BOOL)startSamplingProfilerOnLaunch
{
[self _updateSettingWithValue:@(startSamplingProfilerOnLaunch) forKey:kRCTDevSettingStartSamplingProfilerOnLaunch];
}
- (BOOL)startSamplingProfilerOnLaunch
{
return [[self settingForKey:kRCTDevSettingStartSamplingProfilerOnLaunch] boolValue];
}
- (void)setExecutorClass:(Class)executorClass
{
_executorClass = executorClass;
@@ -554,7 +482,6 @@ RCT_EXPORT_METHOD(toggleElementInspector)
- (id)settingForKey:(NSString *)key { return nil; }
- (void)reload {}
- (void)toggleElementInspector {}
- (void)toggleJSCSamplingProfiler {}
@end

View File

@@ -1,5 +1,5 @@
load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "ANDROID_JSC_DEPS", "APPLE", "APPLE_JSC_DEPS", "get_android_inspector_flags", "get_apple_compiler_flags", "get_apple_inspector_flags", "get_debug_preprocessor_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "get_android_inspector_flags", "get_apple_compiler_flags", "get_apple_inspector_flags", "get_debug_preprocessor_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
CXX_LIBRARY_COMPILER_FLAGS = [
"-std=c++14",
@@ -121,14 +121,9 @@ rn_xplat_cxx_library(
"-fexceptions",
"-frtti",
],
fbandroid_deps = ANDROID_JSC_DEPS,
fbandroid_preprocessor_flags = get_android_inspector_flags(),
fbobjc_compiler_flags = get_apple_compiler_flags(),
fbobjc_deps = APPLE_JSC_DEPS,
fbobjc_force_static = True,
fbobjc_frameworks = [
"$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
],
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
force_static = True,
macosx_tests_override = [],

View File

@@ -1,4 +1,4 @@
load("//tools/build_defs/oss:rn_defs.bzl", "cxx_library", "react_native_xplat_dep", "react_native_xplat_target")
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "cxx_library", "react_native_xplat_dep", "react_native_xplat_target")
cxx_library(
name = "jsiexecutor",