Fix RCTProfileHookModules instantiating all modules

Reviewed By: tadeuzagallo

Differential Revision: D3235048

fb-gh-sync-id: bdcd72fb241c5136e884c1705e027f178939970b
fbshipit-source-id: bdcd72fb241c5136e884c1705e027f178939970b
This commit is contained in:
Pieter De Baets 2016-05-04 06:54:12 -07:00 committed by Facebook Github Bot 3
parent aebf4db45a
commit a9a90aa2f0
6 changed files with 69 additions and 48 deletions

View File

@ -111,11 +111,6 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
// Synchronously initialize all native modules that cannot be loaded lazily
[self initModulesWithDispatchGroup:initModulesAndLoadSource];
if (RCTProfileIsProfiling()) {
// Depends on moduleDataByID being loaded
RCTProfileHookModules(self);
}
__block NSString *config;
dispatch_group_enter(initModulesAndLoadSource);
dispatch_async(bridgeQueue, ^{

View File

@ -98,6 +98,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
"bridge.", _moduleClass);
}
}
if (RCTProfileIsProfiling()) {
RCTProfileHookInstance(_instance);
}
// Bridge must be set before methodQueue is set up, as methodQueue
// initialization requires it (View Managers get their queue by calling
// self.bridge.uiManager.methodQueue)

View File

@ -15,6 +15,11 @@
#import "RCTViewManager.h"
#import "RCTRootView.h"
/**
* Default name for the UIManager queue
*/
RCT_EXTERN char *const RCTUIManagerQueueName;
/**
* Posted right before re-render happens. This is a chance for views to invalidate their state so
* next render cycle will pick up updated views and layout appropriately.

View File

@ -46,6 +46,7 @@ static void RCTTraverseViewNodes(id<RCTComponent> view, void (^block)(id<RCTComp
}
}
char *const RCTUIManagerQueueName = "com.facebook.react.ShadowQueue";
NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification = @"RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification";
NSString *const RCTUIManagerDidRegisterRootViewNotification = @"RCTUIManagerDidRegisterRootViewNotification";
NSString *const RCTUIManagerDidRemoveRootViewNotification = @"RCTUIManagerDidRemoveRootViewNotification";
@ -321,13 +322,11 @@ RCT_EXPORT_MODULE()
- (dispatch_queue_t)methodQueue
{
if (!_shadowQueue) {
const char *queueName = "com.facebook.react.ShadowQueue";
if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
_shadowQueue = dispatch_queue_create(queueName, attr);
_shadowQueue = dispatch_queue_create(RCTUIManagerQueueName, attr);
} else {
_shadowQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
_shadowQueue = dispatch_queue_create(RCTUIManagerQueueName, DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(_shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
}
}
@ -1090,7 +1089,7 @@ RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
RCTProfileBeginFlowEvent();
dispatch_async(dispatch_get_main_queue(), ^{
RCTProfileEndFlowEvent();
RCT_PROFILE_BEGIN_EVENT(0, @"UIManager flushUIBlocks", nil);
RCT_PROFILE_BEGIN_EVENT(0, @"-[UIManager flushUIBlocks]", nil);
@try {
for (dispatch_block_t block in previousPendingUIBlocks) {
block();

View File

@ -10,6 +10,7 @@
#import <Foundation/Foundation.h>
#import "RCTDefines.h"
#import "RCTAssert.h"
/**
* RCTProfile
@ -151,6 +152,11 @@ RCT_EXTERN void RCTProfileHookModules(RCTBridge *);
*/
RCT_EXTERN void RCTProfileUnhookModules(RCTBridge *);
/**
* Hook into all of a module's methods
*/
RCT_EXTERN void RCTProfileHookInstance(id instance);
/**
* Send systrace or cpu profiling information to the packager
* to present to the user
@ -217,6 +223,7 @@ RCT_EXTERN void RCTProfileHideControls(void);
#define RCTProfileBlock(block, ...) block
#define RCTProfileHookModules(...)
#define RCTProfileHookInstance(...)
#define RCTProfileUnhookModules(...)
#define RCTProfileSendResult(...)

View File

@ -214,7 +214,31 @@ void RCTProfileTrampolineEnd(void)
RCT_PROFILE_END_EVENT(0, @"objc_call,modules,auto", nil);
}
static void RCTProfileHookInstance(id instance)
static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *);
static UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag)
{
UIView *view = originalCreateView(self, _cmd, tag);
RCTProfileHookInstance(view);
return view;
}
static void RCTProfileHookUIManager(RCTUIManager *uiManager)
{
dispatch_async(dispatch_get_main_queue(), ^{
for (id view in [uiManager valueForKey:@"viewRegistry"]) {
RCTProfileHookInstance([uiManager viewForReactTag:view]);
}
Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:));
if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
method_setImplementation(createView, (IMP)RCTProfileCreateView);
}
});
}
void RCTProfileHookInstance(id instance)
{
Class moduleClass = object_getClass(instance);
@ -279,18 +303,10 @@ static void RCTProfileHookInstance(id instance)
objc_registerClassPair(proxyClass);
object_setClass(instance, proxyClass);
}
static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *);
RCT_EXTERN UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag);
UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag)
{
UIView *view = originalCreateView(self, _cmd, tag);
RCTProfileHookInstance(view);
return view;
if (moduleClass == [RCTUIManager class]) {
RCTProfileHookUIManager((RCTUIManager *)instance);
}
}
void RCTProfileHookModules(RCTBridge *bridge)
@ -305,23 +321,13 @@ void RCTProfileHookModules(RCTBridge *bridge)
#pragma clang diagnostic pop
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
[bridge dispatchBlock:^{
RCTProfileHookInstance(moduleData.instance);
} queue:moduleData.methodQueue];
// Only hook modules with an instance, to prevent initializing everything
if ([moduleData hasInstance]) {
[bridge dispatchBlock:^{
RCTProfileHookInstance(moduleData.instance);
} queue:moduleData.methodQueue];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
RCTProfileHookInstance([bridge.uiManager viewForReactTag:view]);
}
Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:));
if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
method_setImplementation(createView, (IMP)RCTProfileCreateView);
}
});
}
static void RCTProfileUnhookInstance(id instance)
@ -337,17 +343,22 @@ void RCTProfileUnhookModules(RCTBridge *bridge)
dispatch_group_enter(RCTProfileGetUnhookGroup());
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
RCTProfileUnhookInstance(moduleData.instance);
NSDictionary *moduleDataByID = [bridge valueForKey:@"moduleDataByID"];
for (RCTModuleData *moduleData in moduleDataByID) {
if ([moduleData hasInstance]) {
RCTProfileUnhookInstance(moduleData.instance);
}
}
dispatch_async(dispatch_get_main_queue(), ^{
for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
RCTProfileUnhookInstance(view);
}
if ([bridge moduleIsInitialized:[RCTUIManager class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
RCTProfileUnhookInstance(view);
}
dispatch_group_leave(RCTProfileGetUnhookGroup());
});
dispatch_group_leave(RCTProfileGetUnhookGroup());
});
}
}
#pragma mark - Private ObjC class only used for the vSYNC CADisplayLink target
@ -457,8 +468,7 @@ void RCTProfileInit(RCTBridge *bridge)
// Set up thread ordering
dispatch_async(RCTProfileGetQueue(), ^{
NSString *shadowQueue = @(dispatch_queue_get_label([[bridge uiManager] methodQueue]));
NSArray *orderedThreads = @[@"JS async", RCTJSCThreadName, shadowQueue, @"main"];
NSArray *orderedThreads = @[@"JS async", @"RCTPerformanceLogger", RCTJSCThreadName, @(RCTUIManagerQueueName), @"main"];
[orderedThreads enumerateObjectsUsingBlock:^(NSString *thread, NSUInteger idx, __unused BOOL *stop) {
RCTProfileAddEvent(RCTProfileTraceEvents,
@"ph": @"M", // metadata event