Implement RCTJSCWrapper

Reviewed By: tadeuzagallo

Differential Revision: D3258713

fbshipit-source-id: 418eb9d350bf3541c976b631bd9799a1c578f5e5
This commit is contained in:
Alexey Lang 2016-05-31 12:50:48 -07:00 committed by Facebook Github Bot 8
parent 0f57702cd8
commit abe0b349bc
7 changed files with 306 additions and 77 deletions

View File

@ -24,6 +24,8 @@ typedef NS_ENUM(NSUInteger, RCTPLTag) {
RCTPLNativeModulePrepareConfig,
RCTPLNativeModuleInjectConfig,
RCTPLNativeModuleMainThreadUsesCount,
RCTPLJSCWrapperOpenLibrary,
RCTPLJSCWrapperLoadFunctions,
RCTPLJSCExecutorSetup,
RCTPLBridgeStartup,
RCTPLTTI,

View File

@ -97,6 +97,8 @@ NSArray *RCTPerformanceLoggerLabels(void)
@"NativeModulePrepareConfig",
@"NativeModuleInjectConfig",
@"NativeModuleMainThreadUsesCount",
@"JSCWrapperOpenLibrary",
@"JSCWrapperLoadFunctions",
@"JSCExecutorSetup",
@"BridgeStartup",
@"RootViewTTI",

View File

@ -25,17 +25,31 @@ RCT_EXTERN NSString *const RCTJSCThreadName;
*/
RCT_EXTERN NSString *const RCTJavaScriptContextCreatedNotification;
/**
* Uses a JavaScriptCore context as the execution engine.
*/
@interface RCTJSCExecutor : NSObject <RCTJavaScriptExecutor>
/**
* Sets a type of JSC library (system or custom) that's used
* to initialize RCTJSCWrapper.
* @default is NO.
*/
+ (void)setUseCustomJSCLibrary:(BOOL)useCustomLibrary;
/**
* Gets a type of JSC library (system or custom) that's used
* to initialize RCTJSCWrapper.
* @default is NO.
*/
+ (BOOL)useCustomJSCLibrary;
/**
* Create a NSError from a JSError object.
*
* If available, the error's userInfo property will contain the JS stacktrace under
* the RCTJSStackTraceKey key.
*/
RCT_EXTERN NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError);
/**
* Uses a JavaScriptCore context as the execution engine.
*/
@interface RCTJSCExecutor : NSObject <RCTJavaScriptExecutor>
- (NSError *)convertJSErrorToNSError:(JSValueRef)jsError context:(JSContextRef)context;
@end

View File

@ -12,13 +12,8 @@
#import <cinttypes>
#import <memory>
#import <pthread.h>
#import <string>
#ifdef WITH_FB_JSC_TUNING
#include <string>
#include <fbjsc/jsc_config_ios.h>
#endif
#import <JavaScriptCore/JavaScriptCore.h>
#import <UIKit/UIDevice.h>
#import "RCTAssert.h"
@ -33,6 +28,7 @@
#import "RCTJSCProfiler.h"
#import "RCTRedBox.h"
#import "RCTSourceCode.h"
#import "RCTJSCWrapper.h"
NSString *const RCTJSCThreadName = @"com.facebook.react.JavaScript";
@ -137,6 +133,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)init)
JSStringRef _bundleURL;
RandomAccessBundleData _randomAccessBundle;
RCTJSCWrapper *_jscWrapper;
}
@synthesize valid = _valid;
@ -144,36 +142,36 @@ RCT_NOT_IMPLEMENTED(-(instancetype)init)
RCT_EXPORT_MODULE()
static NSString *RCTJSValueToNSString(JSContextRef context, JSValueRef value, JSValueRef *exception)
static NSString *RCTJSValueToNSString(RCTJSCWrapper *jscWrapper, JSContextRef context, JSValueRef value, JSValueRef *exception)
{
JSStringRef JSString = JSValueToStringCopy(context, value, exception);
JSStringRef JSString = jscWrapper->JSValueToStringCopy(context, value, exception);
if (!JSString) {
return nil;
}
CFStringRef string = JSStringCopyCFString(kCFAllocatorDefault, JSString);
JSStringRelease(JSString);
CFStringRef string = jscWrapper->JSStringCopyCFString(kCFAllocatorDefault, JSString);
jscWrapper->JSStringRelease(JSString);
return (__bridge_transfer NSString *)string;
}
static NSString *RCTJSValueToJSONString(JSContextRef context, JSValueRef value, JSValueRef *exception, unsigned indent)
static NSString *RCTJSValueToJSONString(RCTJSCWrapper *jscWrapper, JSContextRef context, JSValueRef value, JSValueRef *exception, unsigned indent)
{
JSStringRef JSString = JSValueCreateJSONString(context, value, indent, exception);
CFStringRef string = JSStringCopyCFString(kCFAllocatorDefault, JSString);
JSStringRelease(JSString);
JSStringRef jsString = jscWrapper->JSValueCreateJSONString(context, value, indent, exception);
CFStringRef string = jscWrapper->JSStringCopyCFString(kCFAllocatorDefault, jsString);
jscWrapper->JSStringRelease(jsString);
return (__bridge_transfer NSString *)string;
}
NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
static NSError *RCTNSErrorFromJSError(RCTJSCWrapper *jscWrapper, JSContextRef context, JSValueRef jsError)
{
NSMutableDictionary *errorInfo = [NSMutableDictionary new];
NSString *description = jsError ? RCTJSValueToNSString(context, jsError, NULL) : @"Unknown JS error";
NSString *description = jsError ? RCTJSValueToNSString(jscWrapper, context, jsError, NULL) : @"Unknown JS error";
errorInfo[NSLocalizedDescriptionKey] = [@"Unhandled JS Exception: " stringByAppendingString:description];
NSString *details = jsError ? RCTJSValueToJSONString(context, jsError, NULL, 0) : nil;
NSString *details = jsError ? RCTJSValueToJSONString(jscWrapper, context, jsError, NULL, 0) : nil;
if (details) {
errorInfo[NSLocalizedFailureReasonErrorKey] = details;
@ -219,6 +217,11 @@ NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
return [NSError errorWithDomain:RCTErrorDomain code:1 userInfo:errorInfo];
}
- (NSError *)convertJSErrorToNSError:(JSValueRef)jsError context:(JSContextRef)context
{
return RCTNSErrorFromJSError(_jscWrapper, context, jsError);
}
#if RCT_DEV
static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
@ -259,6 +262,18 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
}
}
static BOOL useCustomJSCLibrary = NO;
+ (void)setUseCustomJSCLibrary:(BOOL)useCustomLibrary
{
useCustomJSCLibrary = useCustomLibrary;
}
+ (BOOL)useCustomJSCLibrary
{
return useCustomJSCLibrary;
}
- (instancetype)init
{
if (self = [super init]) {
@ -290,7 +305,7 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
}
if (!_context) {
JSContext *context = [JSContext new];
JSContext *context = [_jscWrapper->JSContext new];
_context = [[RCTJavaScriptContext alloc] initWithJSContext:context onThread:_javaScriptThread];
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptContextCreatedNotification
@ -312,21 +327,33 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
{
__weak RCTJSCExecutor *weakSelf = self;
#ifdef WITH_FB_JSC_TUNING
[self executeBlockOnJavaScriptQueue:^{
RCTJSCExecutor *strongSelf = weakSelf;
if (!strongSelf.valid) {
return;
}
strongSelf->_jscWrapper = RCTJSCWrapperCreate(useCustomJSCLibrary);
}];
[self executeBlockOnJavaScriptQueue:^{
RCTJSCExecutor *strongSelf = weakSelf;
if (!strongSelf.valid) {
return;
}
if (strongSelf->_jscWrapper->configureJSContextForIOS == NULL) {
return;
}
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
RCTAssert(cachesPath != nil, @"cachesPath should not be nil");
if (cachesPath) {
std::string path = std::string([cachesPath UTF8String]);
configureJSContextForIOS(strongSelf.context.ctx, path);
strongSelf->_jscWrapper->configureJSContextForIOS(strongSelf.context.ctx, path);
}
}];
#endif
[self addSynchronousHookWithName:@"noop" usingBlock:^{}];
@ -454,11 +481,12 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
return;
}
JSStringRef execJSString = JSStringCreateWithUTF8CString(sourceCode.UTF8String);
JSStringRef jsURL = JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String);
JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL);
JSStringRelease(jsURL);
JSStringRelease(execJSString);
RCTJSCWrapper *jscWrapper = strongSelf->_jscWrapper;
JSStringRef execJSString = jscWrapper->JSStringCreateWithUTF8CString(sourceCode.UTF8String);
JSStringRef jsURL = jscWrapper->JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String);
jscWrapper->JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL);
jscWrapper->JSStringRelease(jsURL);
jscWrapper->JSStringRelease(execJSString);
}];
#endif
}
@ -496,6 +524,12 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
_randomAccessBundle.bundle.reset();
_randomAccessBundle.table.reset();
if (_jscWrapper) {
RCTJSCWrapperRelease(_jscWrapper);
_jscWrapper = NULL;
}
if (_cookieMap) {
CFRelease(_cookieMap);
}
@ -539,41 +573,42 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
JSValueRef errorJSRef = NULL;
JSValueRef resultJSRef = NULL;
JSGlobalContextRef contextJSRef = JSContextGetGlobalContext(strongSelf->_context.ctx);
RCTJSCWrapper *jscWrapper = strongSelf->_jscWrapper;
JSGlobalContextRef contextJSRef = jscWrapper->JSContextGetGlobalContext(strongSelf->_context.ctx);
JSContext *context = strongSelf->_context.context;
JSObjectRef globalObjectJSRef = JSContextGetGlobalObject(strongSelf->_context.ctx);
JSObjectRef globalObjectJSRef = jscWrapper->JSContextGetGlobalObject(strongSelf->_context.ctx);
// get the BatchedBridge object
JSStringRef moduleNameJSStringRef = JSStringCreateWithUTF8CString("__fbBatchedBridge");
JSValueRef moduleJSRef = JSObjectGetProperty(contextJSRef, globalObjectJSRef, moduleNameJSStringRef, &errorJSRef);
JSStringRelease(moduleNameJSStringRef);
JSStringRef moduleNameJSStringRef = jscWrapper->JSStringCreateWithUTF8CString("__fbBatchedBridge");
JSValueRef moduleJSRef = jscWrapper->JSObjectGetProperty(contextJSRef, globalObjectJSRef, moduleNameJSStringRef, &errorJSRef);
jscWrapper->JSStringRelease(moduleNameJSStringRef);
if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
if (moduleJSRef != NULL && errorJSRef == NULL && !jscWrapper->JSValueIsUndefined(contextJSRef, moduleJSRef)) {
// get method
JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
JSStringRelease(methodNameJSStringRef);
JSStringRef methodNameJSStringRef = jscWrapper->JSStringCreateWithCFString((__bridge CFStringRef)method);
JSValueRef methodJSRef = jscWrapper->JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
jscWrapper->JSStringRelease(methodNameJSStringRef);
if (methodJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, methodJSRef)) {
if (methodJSRef != NULL && errorJSRef == NULL && !jscWrapper->JSValueIsUndefined(contextJSRef, methodJSRef)) {
JSValueRef jsArgs[arguments.count];
for (NSUInteger i = 0; i < arguments.count; i++) {
jsArgs[i] = [JSValue valueWithObject:arguments[i] inContext:context].JSValueRef;
jsArgs[i] = [jscWrapper->JSValue valueWithObject:arguments[i] inContext:context].JSValueRef;
}
resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, arguments.count, jsArgs, &errorJSRef);
resultJSRef = jscWrapper->JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, arguments.count, jsArgs, &errorJSRef);
} else {
if (!errorJSRef && JSValueIsUndefined(contextJSRef, methodJSRef)) {
if (!errorJSRef && jscWrapper->JSValueIsUndefined(contextJSRef, methodJSRef)) {
error = RCTErrorWithMessage([NSString stringWithFormat:@"Unable to execute JS call: method %@ is undefined", method]);
}
}
} else {
if (!errorJSRef && JSValueIsUndefined(contextJSRef, moduleJSRef)) {
if (!errorJSRef && jscWrapper->JSValueIsUndefined(contextJSRef, moduleJSRef)) {
error = RCTErrorWithMessage(@"Unable to execute JS call: __fbBatchedBridge is undefined");
}
}
if (errorJSRef || error) {
if (!error) {
error = RCTNSErrorFromJSError(contextJSRef, errorJSRef);
error = RCTNSErrorFromJSError(jscWrapper, contextJSRef, errorJSRef);
}
onComplete(nil, error);
return;
@ -585,8 +620,8 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
id objcValue;
// We often return `null` from JS when there is nothing for native side. JSONKit takes an extra hundred microseconds
// to handle this simple case, so we are adding a shortcut to make executeJSCall method even faster
if (!JSValueIsNull(contextJSRef, resultJSRef)) {
objcValue = [[JSValue valueWithJSValueRef:resultJSRef inContext:context] toObject];
if (!jscWrapper->JSValueIsNull(contextJSRef, resultJSRef)) {
objcValue = [[jscWrapper->JSValue valueWithJSValueRef:resultJSRef inContext:context] toObject];
}
onComplete(objcValue, nil);
@ -624,8 +659,6 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
script = nullTerminatedScript;
}
_bundleURL = JSStringCreateWithUTF8CString(sourceURL.absoluteString.UTF8String);
__weak RCTJSCExecutor *weakSelf = self;
[self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
@ -637,15 +670,17 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
RCTPerformanceLoggerStart(RCTPLScriptExecution);
JSValueRef jsError = NULL;
JSStringRef execJSString = JSStringCreateWithUTF8CString((const char *)script.bytes);
JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, _bundleURL, 0, &jsError);
JSStringRelease(execJSString);
RCTJSCWrapper *jscWrapper = strongSelf->_jscWrapper;
JSStringRef execJSString = jscWrapper->JSStringCreateWithUTF8CString((const char *)script.bytes);
JSStringRef bundleURL = jscWrapper->JSStringCreateWithUTF8CString(sourceURL.absoluteString.UTF8String);
JSValueRef result = jscWrapper->JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, bundleURL, 0, &jsError);
jscWrapper->JSStringRelease(execJSString);
RCTPerformanceLoggerEnd(RCTPLScriptExecution);
if (onComplete) {
NSError *error;
if (!result) {
error = RCTNSErrorFromJSError(strongSelf->_context.ctx, jsError);
error = RCTNSErrorFromJSError(jscWrapper, strongSelf->_context.ctx, jsError);
}
onComplete(error);
}
@ -684,9 +719,11 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
if (!strongSelf || !strongSelf.isValid) {
return;
}
JSStringRef execJSString = JSStringCreateWithCFString((__bridge CFStringRef)script);
JSValueRef valueToInject = JSValueMakeFromJSONString(strongSelf->_context.ctx, execJSString);
JSStringRelease(execJSString);
RCTJSCWrapper *jscWrapper = strongSelf->_jscWrapper;
JSStringRef execJSString = jscWrapper->JSStringCreateWithCFString((__bridge CFStringRef)script);
JSValueRef valueToInject = jscWrapper->JSValueMakeFromJSONString(strongSelf->_context.ctx, execJSString);
jscWrapper->JSStringRelease(execJSString);
if (!valueToInject) {
NSString *errorDesc = [NSString stringWithFormat:@"Can't make JSON value from script '%@'", script];
@ -699,17 +736,17 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
return;
}
JSObjectRef globalObject = JSContextGetGlobalObject(strongSelf->_context.ctx);
JSStringRef JSName = JSStringCreateWithCFString((__bridge CFStringRef)objectName);
JSObjectSetProperty(strongSelf->_context.ctx, globalObject, JSName, valueToInject, kJSPropertyAttributeNone, NULL);
JSStringRelease(JSName);
JSObjectRef globalObject = jscWrapper->JSContextGetGlobalObject(strongSelf->_context.ctx);
JSStringRef JSName = jscWrapper->JSStringCreateWithCFString((__bridge CFStringRef)objectName);
jscWrapper->JSObjectSetProperty(strongSelf->_context.ctx, globalObject, JSName, valueToInject, kJSPropertyAttributeNone, NULL);
jscWrapper->JSStringRelease(JSName);
if (onComplete) {
onComplete(nil);
}
}), 0, @"js_call,json_call", (@{@"objectName": objectName}))];
}
static bool readRandomAccessModule(const RandomAccessBundleData& bundleData, size_t offset, size_t size, char *data)
static bool readRandomAccessModule(const RandomAccessBundleData &bundleData, size_t offset, size_t size, char *data)
{
return fseek(bundleData.bundle.get(), offset + bundleData.baseOffset, SEEK_SET) == 0 &&
fread(data, 1, size, bundleData.bundle.get()) == size;
@ -726,17 +763,18 @@ static void executeRandomAccessModule(RCTJSCExecutor *executor, uint32_t moduleI
char url[14]; // 10 = maximum decimal digits in a 32bit unsigned int + ".js" + null byte
sprintf(url, "%" PRIu32 ".js", moduleID);
JSStringRef code = JSStringCreateWithUTF8CString(data.get());
RCTJSCWrapper *jscWrapper = executor->_jscWrapper;
JSStringRef code = jscWrapper->JSStringCreateWithUTF8CString(data.get());
JSValueRef jsError = NULL;
JSStringRef sourceURL = JSStringCreateWithUTF8CString(url);
JSValueRef result = JSEvaluateScript(executor->_context.ctx, code, NULL, sourceURL, 0, &jsError);
JSStringRef sourceURL = jscWrapper->JSStringCreateWithUTF8CString(url);
JSValueRef result = jscWrapper->JSEvaluateScript(executor->_context.ctx, code, NULL, sourceURL, 0, &jsError);
JSStringRelease(code);
JSStringRelease(sourceURL);
jscWrapper->JSStringRelease(code);
jscWrapper->JSStringRelease(sourceURL);
if (!result) {
dispatch_async(dispatch_get_main_queue(), ^{
RCTFatal(RCTNSErrorFromJSError(executor->_context.ctx, jsError));
RCTFatal(RCTNSErrorFromJSError(jscWrapper, executor->_context.ctx, jsError));
[executor invalidate];
});
}
@ -780,7 +818,7 @@ static void executeRandomAccessModule(RCTJSCExecutor *executor, uint32_t moduleI
}];
}
static RandomAccessBundleStartupCode readRAMBundle(file_ptr bundle, RandomAccessBundleData& randomAccessBundle)
static RandomAccessBundleStartupCode readRAMBundle(file_ptr bundle, RandomAccessBundleData &randomAccessBundle)
{
// read in magic header, number of entries, and length of the startup section
uint32_t header[3];
@ -846,13 +884,10 @@ static RandomAccessBundleStartupCode readRAMBundle(file_ptr bundle, RandomAccess
RCT_EXPORT_METHOD(setContextName:(nonnull NSString *)name)
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
if (JSGlobalContextSetName != NULL) {
#pragma clang diagnostic pop
JSStringRef JSName = JSStringCreateWithCFString((__bridge CFStringRef)name);
JSGlobalContextSetName(_context.ctx, JSName);
JSStringRelease(JSName);
if (_jscWrapper->JSGlobalContextSetName != NULL) {
JSStringRef JSName = _jscWrapper->JSStringCreateWithCFString((__bridge CFStringRef)name);
_jscWrapper->JSGlobalContextSetName(_context.ctx, JSName);
_jscWrapper->JSStringRelease(JSName);
}
}

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <JavaScriptCore/JavaScriptCore.h>
#import "RCTDefines.h"
#import <string>
typedef JSStringRef (*JSValueToStringCopyFuncType)(JSContextRef, JSValueRef, JSValueRef *);
typedef JSStringRef (*JSStringCreateWithCFStringFuncType)(CFStringRef);
typedef CFStringRef (*JSStringCopyCFStringFuncType)(CFAllocatorRef, JSStringRef);
typedef JSStringRef (*JSStringCreateWithUTF8CStringFuncType)(const char *);
typedef void (*JSStringReleaseFuncType)(JSStringRef);
typedef void (*JSGlobalContextSetNameFuncType)(JSGlobalContextRef, JSStringRef);
typedef JSGlobalContextRef (*JSContextGetGlobalContextFuncType)(JSContextRef);
typedef void (*JSObjectSetPropertyFuncType)(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSPropertyAttributes, JSValueRef *);
typedef JSObjectRef (*JSContextGetGlobalObjectFuncType)(JSContextRef);
typedef JSValueRef (*JSObjectGetPropertyFuncType)(JSContextRef, JSObjectRef, JSStringRef, JSValueRef *);
typedef JSValueRef (*JSValueMakeFromJSONStringFuncType)(JSContextRef, JSStringRef);
typedef JSValueRef (*JSObjectCallAsFunctionFuncType)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef *, JSValueRef *);
typedef JSValueRef (*JSValueMakeNullFuncType)(JSContextRef);
typedef JSStringRef (*JSValueCreateJSONStringFuncType)(JSContextRef, JSValueRef, unsigned, JSValueRef *);
typedef bool (*JSValueIsUndefinedFuncType)(JSContextRef, JSValueRef);
typedef bool (*JSValueIsNullFuncType)(JSContextRef, JSValueRef);
typedef JSValueRef (*JSEvaluateScriptFuncType)(JSContextRef, JSStringRef, JSObjectRef, JSStringRef, int, JSValueRef *);
typedef void (*configureJSContextForIOSFuncType)(JSContextRef ctx, const std::string &cacheDir);
typedef struct RCTJSCWrapper {
JSValueToStringCopyFuncType JSValueToStringCopy;
JSStringCreateWithCFStringFuncType JSStringCreateWithCFString;
JSStringCopyCFStringFuncType JSStringCopyCFString;
JSStringCreateWithUTF8CStringFuncType JSStringCreateWithUTF8CString;
JSStringReleaseFuncType JSStringRelease;
JSGlobalContextSetNameFuncType JSGlobalContextSetName;
JSContextGetGlobalContextFuncType JSContextGetGlobalContext;
JSObjectSetPropertyFuncType JSObjectSetProperty;
JSContextGetGlobalObjectFuncType JSContextGetGlobalObject;
JSObjectGetPropertyFuncType JSObjectGetProperty;
JSValueMakeFromJSONStringFuncType JSValueMakeFromJSONString;
JSObjectCallAsFunctionFuncType JSObjectCallAsFunction;
JSValueMakeNullFuncType JSValueMakeNull;
JSValueCreateJSONStringFuncType JSValueCreateJSONString;
JSValueIsUndefinedFuncType JSValueIsUndefined;
JSValueIsNullFuncType JSValueIsNull;
JSEvaluateScriptFuncType JSEvaluateScript;
Class JSContext;
Class JSValue;
configureJSContextForIOSFuncType configureJSContextForIOS;
} RCTJSCWrapper;
RCT_EXTERN RCTJSCWrapper *RCTJSCWrapperCreate(BOOL useCustomJSC);
RCT_EXTERN void RCTJSCWrapperRelease(RCTJSCWrapper *wrapper);

View File

@ -0,0 +1,112 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTJSCWrapper.h"
#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import "RCTLog.h"
#import "RCTPerformanceLogger.h"
#include <dlfcn.h>
static void *RCTCustomLibraryHandler(void)
{
static dispatch_once_t token;
static void *handler;
dispatch_once(&token, ^{
const char *path = [[[NSBundle mainBundle] pathForResource:@"JavaScriptCore"
ofType:nil
inDirectory:@"JavaScriptCore.framework"] UTF8String];
if (path) {
RCTPerformanceLoggerStart(RCTPLJSCWrapperOpenLibrary);
handler = dlopen(path, RTLD_LAZY);
RCTPerformanceLoggerEnd(RCTPLJSCWrapperOpenLibrary);
if (!handler) {
RCTLogWarn(@"Can't load custome JSC library: %s", dlerror());
}
}
});
return handler;
}
static void RCTSetUpSystemLibraryPointers(RCTJSCWrapper *wrapper)
{
wrapper->JSValueToStringCopy = JSValueToStringCopy;
wrapper->JSStringCreateWithCFString = JSStringCreateWithCFString;
wrapper->JSStringCopyCFString = JSStringCopyCFString;
wrapper->JSStringCreateWithUTF8CString = JSStringCreateWithUTF8CString;
wrapper->JSStringRelease = JSStringRelease;
wrapper->JSGlobalContextSetName = JSGlobalContextSetName;
wrapper->JSContextGetGlobalContext = JSContextGetGlobalContext;
wrapper->JSObjectSetProperty = JSObjectSetProperty;
wrapper->JSContextGetGlobalObject = JSContextGetGlobalObject;
wrapper->JSObjectGetProperty = JSObjectGetProperty;
wrapper->JSValueMakeFromJSONString = JSValueMakeFromJSONString;
wrapper->JSObjectCallAsFunction = JSObjectCallAsFunction;
wrapper->JSValueMakeNull = JSValueMakeNull;
wrapper->JSValueCreateJSONString = JSValueCreateJSONString;
wrapper->JSValueIsUndefined = JSValueIsUndefined;
wrapper->JSValueIsNull = JSValueIsNull;
wrapper->JSEvaluateScript = JSEvaluateScript;
wrapper->JSContext = [JSContext class];
wrapper->JSValue = [JSValue class];
wrapper->configureJSContextForIOS = NULL;
}
static void RCTSetUpCustomLibraryPointers(RCTJSCWrapper *wrapper)
{
void *libraryHandle = RCTCustomLibraryHandler();
if (!libraryHandle) {
RCTSetUpSystemLibraryPointers(wrapper);
return;
}
RCTPerformanceLoggerStart(RCTPLJSCWrapperLoadFunctions);
wrapper->JSValueToStringCopy = (JSValueToStringCopyFuncType)dlsym(libraryHandle, "JSValueToStringCopy");
wrapper->JSStringCreateWithCFString = (JSStringCreateWithCFStringFuncType)dlsym(libraryHandle, "JSStringCreateWithCFString");
wrapper->JSStringCopyCFString = (JSStringCopyCFStringFuncType)dlsym(libraryHandle, "JSStringCopyCFString");
wrapper->JSStringCreateWithUTF8CString = (JSStringCreateWithUTF8CStringFuncType)dlsym(libraryHandle, "JSStringCreateWithUTF8CString");
wrapper->JSStringRelease = (JSStringReleaseFuncType)dlsym(libraryHandle, "JSStringRelease");
wrapper->JSGlobalContextSetName = (JSGlobalContextSetNameFuncType)dlsym(libraryHandle, "JSGlobalContextSetName");
wrapper->JSContextGetGlobalContext = (JSContextGetGlobalContextFuncType)dlsym(libraryHandle, "JSContextGetGlobalContext");
wrapper->JSObjectSetProperty = (JSObjectSetPropertyFuncType)dlsym(libraryHandle, "JSObjectSetProperty");
wrapper->JSContextGetGlobalObject = (JSContextGetGlobalObjectFuncType)dlsym(libraryHandle, "JSContextGetGlobalObject");
wrapper->JSObjectGetProperty = (JSObjectGetPropertyFuncType)dlsym(libraryHandle, "JSObjectGetProperty");
wrapper->JSValueMakeFromJSONString = (JSValueMakeFromJSONStringFuncType)dlsym(libraryHandle, "JSValueMakeFromJSONString");
wrapper->JSObjectCallAsFunction = (JSObjectCallAsFunctionFuncType)dlsym(libraryHandle, "JSObjectCallAsFunction");
wrapper->JSValueMakeNull = (JSValueMakeNullFuncType)dlsym(libraryHandle, "JSValueMakeNull");
wrapper->JSValueCreateJSONString = (JSValueCreateJSONStringFuncType)dlsym(libraryHandle, "JSValueCreateJSONString");
wrapper->JSValueIsUndefined = (JSValueIsUndefinedFuncType)dlsym(libraryHandle, "JSValueIsUndefined");
wrapper->JSValueIsNull = (JSValueIsNullFuncType)dlsym(libraryHandle, "JSValueIsNull");
wrapper->JSEvaluateScript = (JSEvaluateScriptFuncType)dlsym(libraryHandle, "JSEvaluateScript");
wrapper->JSContext = (__bridge Class)dlsym(libraryHandle, "OBJC_CLASS_$_JSContext");
wrapper->JSValue = (__bridge Class)dlsym(libraryHandle, "OBJC_CLASS_$_JSValue");
wrapper->configureJSContextForIOS = (configureJSContextForIOSFuncType)dlsym(libraryHandle, "configureJSContextForIOS");
RCTPerformanceLoggerEnd(RCTPLJSCWrapperLoadFunctions);
}
RCTJSCWrapper *RCTJSCWrapperCreate(BOOL useCustomJSC)
{
RCTJSCWrapper *wrapper = (RCTJSCWrapper *)malloc(sizeof(RCTJSCWrapper));
if (useCustomJSC && [UIDevice currentDevice].systemVersion.floatValue >= 8) {
RCTSetUpCustomLibraryPointers(wrapper);
} else {
RCTSetUpSystemLibraryPointers(wrapper);
}
return wrapper;
}
void RCTJSCWrapperRelease(RCTJSCWrapper *wrapper)
{
if (wrapper) {
free(wrapper);
}
}

View File

@ -94,6 +94,7 @@
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
85C199EE1CD2407900DAD810 /* RCTJSCWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */; };
E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; };
/* End PBXBuildFile section */
@ -302,6 +303,8 @@
83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTConvert.h; sourceTree = "<group>"; };
83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
85C199EC1CD2407900DAD810 /* RCTJSCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCWrapper.h; sourceTree = "<group>"; };
85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSCWrapper.mm; sourceTree = "<group>"; };
ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderStyle.h; sourceTree = "<group>"; };
E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTextDecorationLineType.h; sourceTree = "<group>"; };
E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAccessibilityManager.h; sourceTree = "<group>"; };
@ -324,6 +327,8 @@
children = (
134FCB391A6E7F0800051CC8 /* RCTJSCExecutor.h */,
134FCB3A1A6E7F0800051CC8 /* RCTJSCExecutor.mm */,
85C199EC1CD2407900DAD810 /* RCTJSCWrapper.h */,
85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */,
);
path = Executors;
sourceTree = "<group>";
@ -723,6 +728,7 @@
13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */,
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,
13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */,
85C199EE1CD2407900DAD810 /* RCTJSCWrapper.mm in Sources */,
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */,
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */,
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,