mirror of
https://github.com/status-im/react-native.git
synced 2025-01-14 03:26:07 +00:00
Use JSC C API for better invocation speed
Summary: This converts the existing JSEvaluateScript call for `require('<ModuleName>').<MethodName>.apply(null, <args>);` to native JSC C API methods which shaves off about 10-15% of invocation time on average, I used pretty primitive profiling methods to track the minimum, maximum and average invocation time so would appreciate any extra eyes on the performance. If the argument count is zero the method is invoked directly with no arguments, if the argument count is 1 it's invoked directly with just that argument. If there is more than 1 argument then apply is used and the arguments are passed as the second parameter. Ensured all existing tests pass and instruments leaks shows nothing is leaking. Closes https://github.com/facebook/react-native/pull/1037 Github Author: Robert Payne <robertpayne@me.com> Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
parent
82a082a794
commit
c91e2eb567
@ -291,21 +291,78 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
||||
return;
|
||||
}
|
||||
NSError *error;
|
||||
NSString *argsString = RCTJSONStringify(arguments, &error);
|
||||
NSString *argsString = (arguments.count == 1) ? RCTJSONStringify(arguments[0], &error) : RCTJSONStringify(arguments, &error);
|
||||
if (!argsString) {
|
||||
RCTLogError(@"Cannot convert argument to string: %@", error);
|
||||
onComplete(nil, error);
|
||||
return;
|
||||
}
|
||||
NSString *execString = [NSString stringWithFormat:@"require('%@').%@.apply(null, %@);", name, method, argsString];
|
||||
|
||||
JSValueRef jsError = NULL;
|
||||
JSStringRef execJSString = JSStringCreateWithCFString((__bridge CFStringRef)execString);
|
||||
JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, NULL, 0, &jsError);
|
||||
JSStringRelease(execJSString);
|
||||
JSValueRef errorJSRef = NULL;
|
||||
JSValueRef resultJSRef = NULL;
|
||||
JSGlobalContextRef contextJSRef = JSContextGetGlobalContext(strongSelf->_context.ctx);
|
||||
JSObjectRef globalObjectJSRef = JSContextGetGlobalObject(strongSelf->_context.ctx);
|
||||
|
||||
if (!result) {
|
||||
onComplete(nil, RCTNSErrorFromJSError(strongSelf->_context.ctx, jsError));
|
||||
// get require
|
||||
JSStringRef requireNameJSStringRef = JSStringCreateWithUTF8CString("require");
|
||||
JSValueRef requireJSRef = JSObjectGetProperty(contextJSRef, globalObjectJSRef, requireNameJSStringRef, &errorJSRef);
|
||||
JSStringRelease(requireNameJSStringRef);
|
||||
|
||||
if (requireJSRef != NULL && errorJSRef == NULL) {
|
||||
|
||||
// get module
|
||||
JSStringRef moduleNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)name);
|
||||
JSValueRef moduleNameJSRef = JSValueMakeString(contextJSRef, moduleNameJSStringRef);
|
||||
JSValueRef moduleJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)requireJSRef, NULL, 1, (const JSValueRef *)&moduleNameJSRef, &errorJSRef);
|
||||
JSStringRelease(moduleNameJSStringRef);
|
||||
|
||||
if (moduleJSRef != NULL && errorJSRef == NULL) {
|
||||
|
||||
// get method
|
||||
JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
|
||||
JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
|
||||
JSStringRelease(methodNameJSStringRef);
|
||||
|
||||
if (methodJSRef != NULL && errorJSRef == NULL) {
|
||||
|
||||
// direct method invoke with no arguments
|
||||
if (arguments.count == 0) {
|
||||
resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 0, NULL, &errorJSRef);
|
||||
}
|
||||
// direct method invoke with 1 argument
|
||||
else if(arguments.count == 1) {
|
||||
JSStringRef argsJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)argsString);
|
||||
JSValueRef argsJSRef = JSValueMakeFromJSONString(contextJSRef, argsJSStringRef);
|
||||
resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 1, &argsJSRef, &errorJSRef);
|
||||
JSStringRelease(argsJSStringRef);
|
||||
} else {
|
||||
// apply invoke with array of arguments
|
||||
|
||||
// get apply
|
||||
JSStringRef applyNameJSStringRef = JSStringCreateWithUTF8CString("apply");
|
||||
JSValueRef applyJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)methodJSRef, applyNameJSStringRef, &errorJSRef);
|
||||
JSStringRelease(applyNameJSStringRef);
|
||||
|
||||
if (applyJSRef != NULL && errorJSRef == NULL) {
|
||||
// invoke apply
|
||||
JSStringRef argsJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)argsString);
|
||||
JSValueRef argsJSRef = JSValueMakeFromJSONString(contextJSRef, argsJSStringRef);
|
||||
|
||||
JSValueRef args[2];
|
||||
args[0] = JSValueMakeNull(contextJSRef);
|
||||
args[1] = argsJSRef;
|
||||
|
||||
resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)applyJSRef, (JSObjectRef)methodJSRef, 2, args, &errorJSRef);
|
||||
JSStringRelease(argsJSStringRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!resultJSRef) {
|
||||
onComplete(nil, RCTNSErrorFromJSError(contextJSRef, errorJSRef));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -315,8 +372,8 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
||||
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(strongSelf->_context.ctx, result)) {
|
||||
JSStringRef jsJSONString = JSValueCreateJSONString(strongSelf->_context.ctx, result, 0, nil);
|
||||
if (!JSValueIsNull(contextJSRef, resultJSRef)) {
|
||||
JSStringRef jsJSONString = JSValueCreateJSONString(contextJSRef, resultJSRef, 0, nil);
|
||||
if (jsJSONString) {
|
||||
NSString *objcJSONString = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsJSONString);
|
||||
JSStringRelease(jsJSONString);
|
||||
|
Loading…
x
Reference in New Issue
Block a user