diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index 4ef041318..f389c98d1 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -15,6 +15,7 @@ #import #import +@class JSContext; @class JSValue; @class RCTBridge; @class RCTEventDispatcher; @@ -184,6 +185,11 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); */ @property (nonatomic, readonly, getter=isValid) BOOL valid; +/** + * The JSContext used by the bridge. + */ +@property (nonatomic, readonly, weak) JSContext *jsContext; + /** * Link to the Performance Logger that logs React Native perf events. */ diff --git a/React/Modules/JSCSamplingProfiler.m b/React/Modules/JSCSamplingProfiler.m index 70a90f629..b205539c1 100644 --- a/React/Modules/JSCSamplingProfiler.m +++ b/React/Modules/JSCSamplingProfiler.m @@ -36,13 +36,16 @@ RCT_EXPORT_METHOD(operationComplete:(__unused int)token result:(id)profileData e [request setHTTPBody:[profileData dataUsingEncoding:NSUTF8StringEncoding]]; // Send the request - NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:nil]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *sessionError) { + if (sessionError) { + RCTLogWarn(@"JS CPU Profile data failed to send. Is the packager server running locally?\nDetails: %@", error); + } else { + RCTLogInfo(@"JS CPU Profile data sent successfully."); + } + }]; - if (connection) { - RCTLogInfo(@"JSC CPU Profile data sent successfully."); - } else { - RCTLogWarn(@"JSC CPU Profile data failed to send."); - } + [sessionDataTask resume]; } - (void)operationCompletedWithResults:(NSString *)results diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.mm similarity index 95% rename from React/Modules/RCTDevMenu.m rename to React/Modules/RCTDevMenu.mm index cf2f9370d..3e2e1ed9e 100644 --- a/React/Modules/RCTDevMenu.m +++ b/React/Modules/RCTDevMenu.mm @@ -11,6 +11,11 @@ #import +#import + +#import + +#import "JSCSamplingProfiler.h" #import "RCTAssert.h" #import "RCTBridge+Private.h" #import "RCTDefines.h" @@ -531,6 +536,23 @@ RCT_EXPORT_MODULE() }]]; } + // Add toggles for JSC's sampling profiler, if the profiler is enabled + if (JSC_JSSamplingProfilerEnabled(self->_bridge.jsContext.JSGlobalContextRef)) { + JSContext *context = self->_bridge.jsContext; + // Allow to toggle the sampling profiler through RN's dev menu + [self->_bridge.devMenu addItem:[RCTDevMenuItem buttonItemWithTitle:@"Start / Stop JS Sampling Profiler" handler:^{ + JSGlobalContextRef globalContext = context.JSGlobalContextRef; + // JSPokeSamplingProfiler() toggles the profiling process + JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext); + + if (JSC_JSValueGetType(globalContext, jsResult) != kJSTypeNull) { + NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject]; + JSCSamplingProfiler *profilerModule = [self->_bridge moduleForClass:[JSCSamplingProfiler class]]; + [profilerModule operationCompletedWithResults:results]; + } + }]]; + } + [items addObjectsFromArray:_extraMenuItems]; return items; diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 2c2397ef4..e335b88d2 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -29,7 +29,7 @@ 137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; }; 137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; }; 13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; }; - 13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; }; + 13A0C28A1B74F71200B29F6F /* RCTDevMenu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.mm */; }; 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; }; 13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */; }; 13AB5E011DF777F2001A8C30 /* YGNodeList.c in Sources */ = {isa = PBXBuildFile; fileRef = 130A77051DF767AF001F9587 /* YGNodeList.c */; }; @@ -111,7 +111,7 @@ 2D3B5EB11D9B090100451313 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; }; 2D3B5EB21D9B090300451313 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; }; 2D3B5EB41D9B090A00451313 /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; }; - 2D3B5EB51D9B091100451313 /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; }; + 2D3B5EB51D9B091100451313 /* RCTDevMenu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.mm */; }; 2D3B5EB61D9B091400451313 /* RCTExceptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */; }; 2D3B5EB71D9B091800451313 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 13F17A841B8493E5007D4C75 /* RCTRedBox.m */; }; 2D3B5EB81D9B091B00451313 /* RCTSourceCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */; }; @@ -1163,7 +1163,7 @@ 13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevLoadingView.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevLoadingView.m; sourceTree = ""; }; 13A0C2871B74F71200B29F6F /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevMenu.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenu.m; sourceTree = ""; }; + 13A0C2881B74F71200B29F6F /* RCTDevMenu.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTDevMenu.mm; sourceTree = ""; }; 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = ""; }; 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = ""; }; 13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTParserUtils.h; sourceTree = ""; }; @@ -1433,7 +1433,7 @@ 13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */, 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */, 13A0C2871B74F71200B29F6F /* RCTDevMenu.h */, - 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */, + 13A0C2881B74F71200B29F6F /* RCTDevMenu.mm */, 13D9FEE91CDCCECF00158BD7 /* RCTEventEmitter.h */, 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */, 13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */, @@ -2416,7 +2416,7 @@ 2D3B5E9E1D9B08AD00451313 /* RCTJSStackFrame.m in Sources */, 2D3B5E941D9B087900451313 /* RCTBundleURLProvider.m in Sources */, 2D3B5EB81D9B091B00451313 /* RCTSourceCode.m in Sources */, - 2D3B5EB51D9B091100451313 /* RCTDevMenu.m in Sources */, + 2D3B5EB51D9B091100451313 /* RCTDevMenu.mm in Sources */, 2D3B5EBD1D9B092A00451313 /* RCTTiming.m in Sources */, 2D3B5EA81D9B08D300451313 /* RCTUtils.m in Sources */, 2D3B5EC81D9B095800451313 /* RCTActivityIndicatorViewManager.m in Sources */, @@ -2523,7 +2523,7 @@ 830A229E1A66C68A008503DA /* RCTRootView.m in Sources */, 13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */, 13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */, - 13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */, + 13A0C28A1B74F71200B29F6F /* RCTDevMenu.mm in Sources */, 13BCE8091C99CB9D00DD7AAD /* RCTRootShadowView.m in Sources */, 14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */, 006FC4141D9B20820057AAAD /* RCTMultipartDataTask.m in Sources */, diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index c8e4e70bd..35997bf89 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -276,9 +276,9 @@ void JSCExecutor::initOnJSVMThread() throw(JSException) { addNativeProfilingHooks(m_context); addNativeTracingLegacyHooks(m_context); PerfLogging::installNativeHooks(m_context); + #endif initSamplingProfilerOnMainJSCThread(m_context); - #endif #ifdef WITH_FB_MEMORY_PROFILING addNativeMemoryHooks(m_context); diff --git a/ReactCommon/cxxreact/JSCSamplingProfiler.cpp b/ReactCommon/cxxreact/JSCSamplingProfiler.cpp index f9944fb28..300036dd0 100644 --- a/ReactCommon/cxxreact/JSCSamplingProfiler.cpp +++ b/ReactCommon/cxxreact/JSCSamplingProfiler.cpp @@ -1,15 +1,16 @@ // Copyright 2004-present Facebook. All Rights Reserved. -#ifdef WITH_JSC_EXTRA_TRACING - #include "JSCSamplingProfiler.h" #include #include -#include #include #include +#ifndef __APPLE__ +#include +#endif + namespace facebook { namespace react { namespace { @@ -26,10 +27,11 @@ static JSValueRef pokeSamplingProfiler( void initSamplingProfilerOnMainJSCThread(JSGlobalContextRef ctx) { JSC_JSStartSamplingProfilingOnMainJSCThread(ctx); + + // Allow the profiler to be poked from JS as well + // (see SamplingProfiler.js for an example of how it could be used with the JSCSamplingProfiler module). installGlobalFunction(ctx, "pokeSamplingProfiler", pokeSamplingProfiler); } } } - -#endif // WITH_JSC_EXTRA_TRACING diff --git a/ReactCommon/cxxreact/JSCSamplingProfiler.h b/ReactCommon/cxxreact/JSCSamplingProfiler.h index 6331ec8b7..5705a3a5d 100644 --- a/ReactCommon/cxxreact/JSCSamplingProfiler.h +++ b/ReactCommon/cxxreact/JSCSamplingProfiler.h @@ -2,8 +2,6 @@ #pragma once -#ifdef WITH_JSC_EXTRA_TRACING - #include namespace facebook { @@ -12,5 +10,3 @@ namespace react { void initSamplingProfilerOnMainJSCThread(JSGlobalContextRef ctx); } } - -#endif // WITH_JSC_EXTRA_TRACING