Improve systrace markers

Reviewed By: mhorowitz

Differential Revision: D4860135

fbshipit-source-id: ce963010883e6b9cc8e34f7ff01b4018cd195eba
This commit is contained in:
Pieter De Baets 2017-05-12 17:57:12 -07:00 committed by Facebook Github Bot
parent 49e6d3965f
commit 6221053179
16 changed files with 111 additions and 90 deletions

View File

@ -54,7 +54,7 @@
RCTAssert(self.executorClass || self->_jsThread == [NSThread currentThread], \ RCTAssert(self.executorClass || self->_jsThread == [NSThread currentThread], \
@"This method must be called on JS thread") @"This method must be called on JS thread")
NSString *const RCTJSThreadName = @"com.facebook.React.JavaScript"; static NSString *const RCTJSThreadName = @"com.facebook.react.JavaScript";
using namespace facebook::react; using namespace facebook::react;
@ -76,7 +76,7 @@ static bool isRAMBundle(NSData *script) {
static void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger) { static void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger) {
__weak RCTPerformanceLogger *weakPerformanceLogger = performanceLogger; __weak RCTPerformanceLogger *weakPerformanceLogger = performanceLogger;
ReactMarker::logTaggedMarker = [weakPerformanceLogger](const ReactMarker::ReactMarkerId markerId, const char* tag) { ReactMarker::logTaggedMarker = [weakPerformanceLogger](const ReactMarker::ReactMarkerId markerId, const char *tag) {
switch (markerId) { switch (markerId) {
case ReactMarker::RUN_JS_BUNDLE_START: case ReactMarker::RUN_JS_BUNDLE_START:
[weakPerformanceLogger markStartForTag:RCTPLScriptExecution]; [weakPerformanceLogger markStartForTag:RCTPLScriptExecution];
@ -255,6 +255,8 @@ struct RCTInstanceCallback : public InstanceCallback {
- (void)start - (void)start
{ {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil);
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
postNotificationName:RCTJavaScriptWillStartLoadingNotification postNotificationName:RCTJavaScriptWillStartLoadingNotification
object:_parentBridge userInfo:@{@"bridge": self}]; object:_parentBridge userInfo:@{@"bridge": self}];
@ -349,6 +351,7 @@ struct RCTInstanceCallback : public InstanceCallback {
} }
}); });
} }
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
} }
- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress
@ -963,7 +966,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
[_performanceLogger markStopForTag:RCTPLBridgeStartup]; [_performanceLogger markStopForTag:RCTPLBridgeStartup];
RCT_PROFILE_BEGIN_EVENT(0, @"Processing pendingCalls", @{ @"count": @(_pendingCalls.count) }); RCT_PROFILE_BEGIN_EVENT(0, @"Processing pendingCalls", @{ @"count": [@(_pendingCalls.count) stringValue] });
// Phase B: _flushPendingCalls happens. Each block in _pendingCalls is // Phase B: _flushPendingCalls happens. Each block in _pendingCalls is
// executed, adding work to the queue, and _pendingCount is decremented. // executed, adding work to the queue, and _pendingCount is decremented.
// loading is set to NO. // loading is set to NO.
@ -1051,8 +1054,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
{ {
RCTAssert(onComplete != nil, @"onComplete block passed in should be non-nil"); RCTAssert(onComplete != nil, @"onComplete block passed in should be non-nil");
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);
@"-[RCTCxxBridge enqueueApplicationScript]", nil);
[self _tryAndHandleError:^{ [self _tryAndHandleError:^{
if (isRAMBundle(script)) { if (isRAMBundle(script)) {

View File

@ -20,7 +20,7 @@ class RCTNativeModule : public NativeModule {
std::string getName() override; std::string getName() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override; folly::dynamic getConstants() override;
void invoke(unsigned int methodId, folly::dynamic &&params) override; void invoke(unsigned int methodId, folly::dynamic &&params, int callId) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &&params) override; MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &&params) override;
private: private:

View File

@ -17,6 +17,10 @@
#import <React/RCTProfile.h> #import <React/RCTProfile.h>
#import <React/RCTUtils.h> #import <React/RCTUtils.h>
#ifdef WITH_FBSYSTRACE
#include <fbsystrace.h>
#endif
namespace facebook { namespace facebook {
namespace react { namespace react {
@ -50,20 +54,20 @@ folly::dynamic RCTNativeModule::getConstants() {
return ret; return ret;
} }
void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &&params) { void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &&params, int callId) {
// The BatchedBridge version of this buckets all the callbacks by thread, and // The BatchedBridge version of this buckets all the callbacks by thread, and
// queues one block on each. This is much simpler; we'll see how it goes and // queues one block on each. This is much simpler; we'll see how it goes and
// iterate. // iterate.
dispatch_block_t block = [this, methodId, params=std::move(params)] { dispatch_block_t block = [this, methodId, params=std::move(params), callId] {
if (!m_bridge.valid) { #ifdef WITH_FBSYSTRACE
return; if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
} }
#endif
invokeInner(methodId, std::move(params)); invokeInner(methodId, std::move(params));
}; };
dispatch_queue_t queue = m_moduleData.methodQueue; dispatch_queue_t queue = m_moduleData.methodQueue;
if (queue == RCTJSThread) { if (queue == RCTJSThread) {
block(); block();
} else if (queue) { } else if (queue) {
@ -76,6 +80,10 @@ MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactM
} }
MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly::dynamic &&params) { MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly::dynamic &&params) {
if (!m_bridge.valid) {
return folly::none;
}
id<RCTBridgeMethod> method = m_moduleData.methods[methodId]; id<RCTBridgeMethod> method = m_moduleData.methods[methodId];
if (RCT_DEBUG && !method) { if (RCT_DEBUG && !method) {
RCTLogError(@"Unknown methodID: %ud for module: %@", RCTLogError(@"Unknown methodID: %ud for module: %@",
@ -83,7 +91,6 @@ MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly
} }
NSArray *objcParams = convertFollyDynamicToId(params); NSArray *objcParams = convertFollyDynamicToId(params);
@try { @try {
id result = [method invokeWithBridge:m_bridge module:m_moduleData.instance arguments:objcParams]; id result = [method invokeWithBridge:m_bridge module:m_moduleData.instance arguments:objcParams];
return convertIdToFollyDynamic(result); return convertIdToFollyDynamic(result);
@ -99,7 +106,6 @@ MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly
exception, method.JSMethodName, m_moduleData.name, objcParams]; exception, method.JSMethodName, m_moduleData.name, objcParams];
RCTFatal(RCTErrorWithMessage(message)); RCTFatal(RCTErrorWithMessage(message));
} }
} }
} }

View File

@ -32,8 +32,8 @@
#import "RCTRootViewInternal.h" #import "RCTRootViewInternal.h"
#import "RCTScrollableProtocol.h" #import "RCTScrollableProtocol.h"
#import "RCTShadowView.h" #import "RCTShadowView.h"
#import "RCTUtils.h"
#import "RCTUIManagerObserverCoordinator.h" #import "RCTUIManagerObserverCoordinator.h"
#import "RCTUtils.h"
#import "RCTView.h" #import "RCTView.h"
#import "RCTViewManager.h" #import "RCTViewManager.h"
#import "UIView+React.h" #import "UIView+React.h"
@ -1192,7 +1192,7 @@ RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
RCTProfileEndFlowEvent(); RCTProfileEndFlowEvent();
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[UIManager flushUIBlocks]", (@{ RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[UIManager flushUIBlocks]", (@{
@"count": @(previousPendingUIBlocks.count), @"count": [@(previousPendingUIBlocks.count) stringValue],
})); }));
@try { @try {
for (RCTViewManagerUIBlock block in previousPendingUIBlocks) { for (RCTViewManagerUIBlock block in previousPendingUIBlocks) {
@ -1202,6 +1202,7 @@ RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
@catch (NSException *exception) { @catch (NSException *exception) {
RCTLogError(@"Exception thrown while executing UI block: %@", exception); RCTLogError(@"Exception thrown while executing UI block: %@", exception);
} }
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}); });
} }
} }

View File

@ -68,7 +68,7 @@ RCT_EXTERN void _RCTProfileBeginEvent(NSThread *calleeThread,
NSTimeInterval time, NSTimeInterval time,
uint64_t tag, uint64_t tag,
NSString *name, NSString *name,
NSDictionary *args); NSDictionary<NSString *, NSString *> *args);
#define RCT_PROFILE_BEGIN_EVENT(tag, name, args) \ #define RCT_PROFILE_BEGIN_EVENT(tag, name, args) \
do { \ do { \
if (RCTProfileIsProfiling()) { \ if (RCTProfileIsProfiling()) { \
@ -104,7 +104,7 @@ RCT_EXTERN void _RCTProfileEndEvent(NSThread *calleeThread,
*/ */
RCT_EXTERN NSUInteger RCTProfileBeginAsyncEvent(uint64_t tag, RCT_EXTERN NSUInteger RCTProfileBeginAsyncEvent(uint64_t tag,
NSString *name, NSString *name,
NSDictionary *args); NSDictionary<NSString *, NSString *> *args);
/** /**
* The ID returned by BeginEvent should then be passed into EndEvent, with the * The ID returned by BeginEvent should then be passed into EndEvent, with the

View File

@ -71,7 +71,7 @@ if (!RCTProfileIsProfiling()) { \
static RCTProfileCallbacks *callbacks; static RCTProfileCallbacks *callbacks;
static char *systrace_buffer; static char *systrace_buffer;
static systrace_arg_t *RCTProfileSystraceArgsFromNSDictionary(NSDictionary *args) static systrace_arg_t *systraceArgsFromDictionary(NSDictionary<NSString *, NSString *> *args)
{ {
if (args.count == 0) { if (args.count == 0) {
return NULL; return NULL;
@ -79,14 +79,11 @@ static systrace_arg_t *RCTProfileSystraceArgsFromNSDictionary(NSDictionary *args
systrace_arg_t *systrace_args = malloc(sizeof(systrace_arg_t) * args.count); systrace_arg_t *systrace_args = malloc(sizeof(systrace_arg_t) * args.count);
__block size_t i = 0; __block size_t i = 0;
[args enumerateKeysAndObjectsUsingBlock:^(id key, id value, __unused BOOL *stop) { [args enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, __unused BOOL *stop) {
const char *keyc = [key description].UTF8String; systrace_args[i].key = [key UTF8String];
systrace_args[i].key = keyc; systrace_args[i].key_len = [key length];
systrace_args[i].key_len = (int)strlen(keyc); systrace_args[i].value = [value UTF8String];
systrace_args[i].value_len = [value length];
const char *valuec = RCTJSONStringify(value, NULL).UTF8String;
systrace_args[i].value = valuec;
systrace_args[i].value_len = (int)strlen(valuec);
i++; i++;
}]; }];
return systrace_args; return systrace_args;
@ -123,7 +120,7 @@ static NSDictionary *RCTProfileGetMemoryUsage(void)
TASK_BASIC_INFO, TASK_BASIC_INFO,
(task_info_t)&info, (task_info_t)&info,
&size); &size);
if( kerr == KERN_SUCCESS ) { if ( kerr == KERN_SUCCESS ) {
return @{ return @{
@"suspend_count": @(info.suspend_count), @"suspend_count": @(info.suspend_count),
@"virtual_size": RCTProfileMemory(info.virtual_size), @"virtual_size": RCTProfileMemory(info.virtual_size),
@ -545,12 +542,12 @@ void _RCTProfileBeginEvent(
NSTimeInterval time, NSTimeInterval time,
uint64_t tag, uint64_t tag,
NSString *name, NSString *name,
NSDictionary *args NSDictionary<NSString *, NSString *> *args
) { ) {
CHECK(); CHECK();
if (callbacks != NULL) { if (callbacks != NULL) {
callbacks->begin_section(tag, name.UTF8String, args.count, RCTProfileSystraceArgsFromNSDictionary(args)); callbacks->begin_section(tag, name.UTF8String, args.count, systraceArgsFromDictionary(args));
return; return;
} }
@ -603,7 +600,7 @@ void _RCTProfileEndEvent(
NSUInteger RCTProfileBeginAsyncEvent( NSUInteger RCTProfileBeginAsyncEvent(
uint64_t tag, uint64_t tag,
NSString *name, NSString *name,
NSDictionary *args NSDictionary<NSString *, NSString *> *args
) { ) {
CHECK(0); CHECK(0);
@ -613,7 +610,8 @@ NSUInteger RCTProfileBeginAsyncEvent(
NSUInteger currentEventID = ++eventID; NSUInteger currentEventID = ++eventID;
if (callbacks != NULL) { if (callbacks != NULL) {
callbacks->begin_async_section(tag, name.UTF8String, (int)(currentEventID % INT_MAX), args.count, RCTProfileSystraceArgsFromNSDictionary(args)); callbacks->begin_async_section(tag, name.UTF8String, (int)(currentEventID % INT_MAX),
args.count, systraceArgsFromDictionary(args));
} else { } else {
dispatch_async(RCTProfileGetQueue(), ^{ dispatch_async(RCTProfileGetQueue(), ^{
RCTProfileOngoingEvents[@(currentEventID)] = @[ RCTProfileOngoingEvents[@(currentEventID)] = @[

View File

@ -10,6 +10,10 @@
#include <cxxreact/JsArgumentHelpers.h> #include <cxxreact/JsArgumentHelpers.h>
#include <cxxreact/NativeModule.h> #include <cxxreact/NativeModule.h>
#ifdef WITH_FBSYSTRACE
#include <fbsystrace.h>
#endif
#include "CatalystInstanceImpl.h" #include "CatalystInstanceImpl.h"
#include "ReadableNativeArray.h" #include "ReadableNativeArray.h"
@ -80,9 +84,14 @@ folly::dynamic JavaNativeModule::getConstants() {
} }
} }
void JavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) { void JavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) {
messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params)] { messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params), callId] {
static auto invokeMethod = wrapper_->getClass()->getMethod<void(jint, ReadableNativeArray::javaobject)>("invoke"); static auto invokeMethod = wrapper_->getClass()->getMethod<void(jint, ReadableNativeArray::javaobject)>("invoke");
#ifdef WITH_FBSYSTRACE
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#endif
invokeMethod( invokeMethod(
wrapper_, wrapper_,
static_cast<jint>(reactMethodId), static_cast<jint>(reactMethodId),
@ -148,13 +157,18 @@ folly::dynamic NewJavaNativeModule::getConstants() {
} }
} }
void NewJavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) { void NewJavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) {
if (reactMethodId >= methods_.size()) { if (reactMethodId >= methods_.size()) {
throw std::invalid_argument( throw std::invalid_argument(
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]")); folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]"));
} }
CHECK(!methods_[reactMethodId].isSyncHook()) << "Trying to invoke a synchronous hook asynchronously"; CHECK(!methods_[reactMethodId].isSyncHook()) << "Trying to invoke a synchronous hook asynchronously";
messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params)] () mutable { messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params), callId] () mutable {
#ifdef WITH_FBSYSTRACE
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#endif
invokeInner(reactMethodId, std::move(params)); invokeInner(reactMethodId, std::move(params));
}); });
} }

View File

@ -59,7 +59,7 @@ class JavaNativeModule : public NativeModule {
std::string getName() override; std::string getName() override;
folly::dynamic getConstants() override; folly::dynamic getConstants() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override; void invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override; MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
private: private:
@ -80,7 +80,7 @@ class NewJavaNativeModule : public NativeModule {
std::string getName() override; std::string getName() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override; folly::dynamic getConstants() override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override; void invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override; MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
private: private:

View File

@ -7,7 +7,8 @@
#include <folly/json.h> #include <folly/json.h>
#include <cxxreact/JsArgumentHelpers.h> #include "JsArgumentHelpers.h"
#include "SystraceSection.h"
using facebook::xplat::module::CxxModule; using facebook::xplat::module::CxxModule;
@ -75,7 +76,7 @@ folly::dynamic CxxNativeModule::getConstants() {
return constants; return constants;
} }
void CxxNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) { void CxxNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) {
if (reactMethodId >= methods_.size()) { if (reactMethodId >= methods_.size()) {
throw std::invalid_argument(folly::to<std::string>("methodId ", reactMethodId, throw std::invalid_argument(folly::to<std::string>("methodId ", reactMethodId,
" out of range [0..", methods_.size(), "]")); " out of range [0..", methods_.size(), "]"));
@ -128,7 +129,13 @@ void CxxNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params
// stack. I'm told that will be possible in the future. TODO // stack. I'm told that will be possible in the future. TODO
// mhorowitz #7128529: convert C++ exceptions to Java // mhorowitz #7128529: convert C++ exceptions to Java
messageQueueThread_->runOnQueue([method, params=std::move(params), first, second] () { messageQueueThread_->runOnQueue([method, params=std::move(params), first, second, callId] () {
#ifdef WITH_FBSYSTRACE
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#endif
SystraceSection s(method.name.c_str());
try { try {
method.func(std::move(params), first, second); method.func(std::move(params), first, second);
} catch (const facebook::xplat::JsArgumentException& ex) { } catch (const facebook::xplat::JsArgumentException& ex) {

View File

@ -27,7 +27,7 @@ public:
std::string getName() override; std::string getName() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override; folly::dynamic getConstants() override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override; void invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) override;
MethodCallResult callSerializableNativeHook(unsigned int hookId, folly::dynamic&& args) override; MethodCallResult callSerializableNativeHook(unsigned int hookId, folly::dynamic&& args) override;
private: private:

View File

@ -182,7 +182,7 @@ static bool canUseInspector(JSContextRef context) {
#endif #endif
void JSCExecutor::initOnJSVMThread() throw(JSException) { void JSCExecutor::initOnJSVMThread() throw(JSException) {
SystraceSection s("JSCExecutor.initOnJSVMThread"); SystraceSection s("JSCExecutor::initOnJSVMThread");
#if defined(__APPLE__) #if defined(__APPLE__)
const bool useCustomJSC = m_jscConfig.getDefault("UseCustomJSC", false).getBool(); const bool useCustomJSC = m_jscConfig.getDefault("UseCustomJSC", false).getBool();
@ -353,20 +353,15 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
} else } else
#endif #endif
{ {
#ifdef WITH_FBSYSTRACE String jsScript;
fbsystrace_begin_section( {
TRACE_TAG_REACT_CXX_BRIDGE, SystraceSection s_("JSCExecutor::loadApplicationScript-createExpectingAscii");
"JSCExecutor::loadApplicationScript-createExpectingAscii"); ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START);
#endif jsScript = jsStringFromBigString(m_context, *script);
ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP);
ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START); }
String jsScript = jsStringFromBigString(m_context, *script);
ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP);
#ifdef WITH_FBSYSTRACE
fbsystrace_end_section(TRACE_TAG_REACT_CXX_BRIDGE);
#endif
SystraceSection s_("JSCExecutor::loadApplicationScript-evaluateScript");
evaluateScript(m_context, jsScript, jsSourceURL); evaluateScript(m_context, jsScript, jsSourceURL);
} }
@ -457,9 +452,9 @@ void JSCExecutor::flush() {
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
SystraceSection s("JSCExecutor::callFunction"); SystraceSection s("JSCExecutor::callFunction");
// This weird pattern is because Value is not default constructible. // This weird pattern is because Value is not default constructible.
// The lambda is inlined, so there's no overhead. // The lambda is inlined, so there's no overhead.
auto result = [&] { auto result = [&] {
try { try {
if (!m_callFunctionReturnResultAndFlushedQueueJS) { if (!m_callFunctionReturnResultAndFlushedQueueJS) {
@ -524,8 +519,7 @@ Value JSCExecutor::callFunctionSyncWithValue(
void JSCExecutor::setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue) { void JSCExecutor::setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue) {
try { try {
SystraceSection s("JSCExecutor.setGlobalVariable", SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName);
"propName", propName);
auto valueToInject = Value::fromJSON(m_context, jsStringFromBigString(m_context, *jsonValue)); auto valueToInject = Value::fromJSON(m_context, jsStringFromBigString(m_context, *jsonValue));
Object::getGlobalObject(m_context).setProperty(propName.c_str(), valueToInject); Object::getGlobalObject(m_context).setProperty(propName.c_str(), valueToInject);

View File

@ -118,14 +118,7 @@ void ModuleRegistry::callNativeMethod(unsigned int moduleId, unsigned int method
throw std::runtime_error( throw std::runtime_error(
folly::to<std::string>("moduleId ", moduleId, " out of range [0..", modules_.size(), ")")); folly::to<std::string>("moduleId ", moduleId, " out of range [0..", modules_.size(), ")"));
} }
modules_[moduleId]->invoke(methodId, std::move(params), callId);
#ifdef WITH_FBSYSTRACE
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#endif
modules_[moduleId]->invoke(methodId, std::move(params));
} }
MethodCallResult ModuleRegistry::callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params) { MethodCallResult ModuleRegistry::callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params) {

View File

@ -5,8 +5,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <folly/dynamic.h>
#include <cxxreact/Executor.h> #include <cxxreact/Executor.h>
#include <folly/dynamic.h>
namespace facebook { namespace facebook {
namespace react { namespace react {
@ -29,7 +29,7 @@ class NativeModule {
virtual folly::dynamic getConstants() = 0; virtual folly::dynamic getConstants() = 0;
// TODO mhorowitz: do we need initialize()/onCatalystInstanceDestroy() in C++ // TODO mhorowitz: do we need initialize()/onCatalystInstanceDestroy() in C++
// or only Java? // or only Java?
virtual void invoke(unsigned int reactMethodId, folly::dynamic&& params) = 0; virtual void invoke(unsigned int reactMethodId, folly::dynamic&& params, int callId) = 0;
virtual MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& args) = 0; virtual MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& args) = 0;
}; };

View File

@ -124,27 +124,21 @@ void NativeToJsBridge::callFunction(
int systraceCookie = -1; int systraceCookie = -1;
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
systraceCookie = m_systraceCookie++; systraceCookie = m_systraceCookie++;
std::string tracingName = fbsystrace_is_tracing(TRACE_TAG_REACT_CXX_BRIDGE) ?
folly::to<std::string>("JSCall__", module, '_', method) : std::string();
SystraceSection s(tracingName.c_str());
FbSystraceAsyncFlow::begin( FbSystraceAsyncFlow::begin(
TRACE_TAG_REACT_CXX_BRIDGE, TRACE_TAG_REACT_CXX_BRIDGE,
tracingName.c_str(), "JSCall",
systraceCookie); systraceCookie);
#else
std::string tracingName;
#endif #endif
runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie] runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie]
(JSExecutor* executor) { (JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end( FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE, TRACE_TAG_REACT_CXX_BRIDGE,
tracingName.c_str(), "JSCall",
systraceCookie); systraceCookie);
SystraceSection s(tracingName.c_str()); SystraceSection s("NativeToJsBridge::callFunction", "module", module, "method", method);
#endif #endif
// This is safe because we are running on the executor's thread: it won't // This is safe because we are running on the executor's thread: it won't
// destruct until after it's been unregistered (which we check above) and // destruct until after it's been unregistered (which we check above) and
// that will happen on this thread // that will happen on this thread
@ -169,9 +163,8 @@ void NativeToJsBridge::invokeCallback(double callbackId, folly::dynamic&& argume
TRACE_TAG_REACT_CXX_BRIDGE, TRACE_TAG_REACT_CXX_BRIDGE,
"<callback>", "<callback>",
systraceCookie); systraceCookie);
SystraceSection s("NativeToJsBridge.invokeCallback"); SystraceSection s("NativeToJsBridge::invokeCallback");
#endif #endif
executor->invokeCallback(callbackId, arguments); executor->invokeCallback(callbackId, arguments);
}); });
} }

View File

@ -123,9 +123,6 @@ void removeGlobal(JSGlobalContextRef ctx, const char* name) {
} }
JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source) { JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source) {
#ifdef WITH_FBSYSTRACE
fbsystrace::FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "evaluateScript");
#endif
JSValueRef exn, result; JSValueRef exn, result;
result = JSC_JSEvaluateScript(context, script, NULL, source, 0, &exn); result = JSC_JSEvaluateScript(context, script, NULL, source, 0, &exn);
if (result == nullptr) { if (result == nullptr) {

View File

@ -41,9 +41,10 @@ private:
class String : public noncopyable { class String : public noncopyable {
public: public:
explicit String(JSContextRef context, const char* utf8) : explicit String(): m_context(nullptr), m_string(nullptr) {} // dummy empty constructor
m_context(context), m_string(JSC_JSStringCreateWithUTF8CString(context, utf8))
{} explicit String(JSContextRef context, const char* utf8)
: m_context(context), m_string(JSC_JSStringCreateWithUTF8CString(context, utf8)) {}
String(String&& other) : String(String&& other) :
m_context(other.m_context), m_string(other.m_string) m_context(other.m_context), m_string(other.m_string)
@ -65,18 +66,30 @@ public:
} }
} }
String& operator=(String&& other) {
if (m_string) {
JSC_JSStringRelease(m_context, m_string);
}
m_context = other.m_context;
m_string = other.m_string;
other.m_string = nullptr;
return *this;
}
operator JSStringRef() const { operator JSStringRef() const {
return m_string; return m_string;
} }
// Length in characters // Length in characters
size_t length() const { size_t length() const {
return JSC_JSStringGetLength(m_context, m_string); return m_string ? JSC_JSStringGetLength(m_context, m_string) : 0;
} }
// Length in bytes of a null-terminated utf8 encoded value // Length in bytes of a null-terminated utf8 encoded value
size_t utf8Size() const { size_t utf8Size() const {
return JSC_JSStringGetMaximumUTF8CStringSize(m_context, m_string); return m_string ? JSC_JSStringGetMaximumUTF8CStringSize(m_context, m_string) : 0;
} }
/* /*
@ -94,6 +107,9 @@ public:
* https://mathiasbynens.be/notes/javascript-unicode * https://mathiasbynens.be/notes/javascript-unicode
*/ */
std::string str() const { std::string str() const {
if (!m_string) {
return "";
}
const JSChar* utf16 = JSC_JSStringGetCharactersPtr(m_context, m_string); const JSChar* utf16 = JSC_JSStringGetCharactersPtr(m_context, m_string);
size_t stringLength = JSC_JSStringGetLength(m_context, m_string); size_t stringLength = JSC_JSStringGetLength(m_context, m_string);
return unicode::utf16toUTF8(utf16, stringLength); return unicode::utf16toUTF8(utf16, stringLength);
@ -101,7 +117,7 @@ public:
// Assumes that utf8 is null terminated // Assumes that utf8 is null terminated
bool equals(const char* utf8) { bool equals(const char* utf8) {
return JSC_JSStringIsEqualToUTF8CString(m_context, m_string, utf8); return m_string ? JSC_JSStringIsEqualToUTF8CString(m_context, m_string, utf8) : false;
} }
// This assumes ascii is nul-terminated. // This assumes ascii is nul-terminated.