[ReactNative] Fix crash when reload during profile (attempt #2)

Summary:
Fixes #1642

When reloading during profiling, the profile wouldn't unhook from the instance
being deallocated.
This commit is contained in:
Tadeu Zagallo 2015-07-22 10:54:45 -07:00
parent 8dd1256c25
commit 49b55804b1
4 changed files with 46 additions and 19 deletions

View File

@ -106,6 +106,13 @@ id<RCTJavaScriptExecutor> RCTGetLatestExecutor(void)
*/ */
[self registerModules]; [self registerModules];
/**
* If currently profiling, hook into the current instance
*/
if (RCTProfileIsProfiling()) {
RCTProfileHookModules(self);
}
/** /**
* Start the application script * Start the application script
*/ */
@ -361,6 +368,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
} }
moduleData.queue = nil; moduleData.queue = nil;
} }
dispatch_group_notify(group, dispatch_get_main_queue(), ^{ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{ [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
[_jsDisplayLink invalidate]; [_jsDisplayLink invalidate];
@ -368,11 +376,15 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
[_javaScriptExecutor invalidate]; [_javaScriptExecutor invalidate];
_javaScriptExecutor = nil; _javaScriptExecutor = nil;
}];
_modules = nil; if (RCTProfileIsProfiling()) {
_modulesByName = nil; RCTProfileUnhookModules(self);
_frameUpdateObservers = nil; }
_modules = nil;
_modulesByName = nil;
_frameUpdateObservers = nil;
}];
}); });
} }

View File

@ -103,6 +103,16 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *
RCTProfileEndEvent([NSString stringWithFormat:@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd)], category, arguments); \ RCTProfileEndEvent([NSString stringWithFormat:@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd)], category, arguments); \
} }
/**
* Hook into a bridge instance to log all bridge module's method calls
*/
RCT_EXTERN void RCTProfileHookModules(RCTBridge *);
/**
* Unhook from a given bridge instance's modules
*/
RCT_EXTERN void RCTProfileUnhookModules(RCTBridge *);
#else #else
#define RCTProfileBeginFlowEvent() #define RCTProfileBeginFlowEvent()
@ -125,4 +135,7 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *
#define RCTProfileBlock(block, ...) block #define RCTProfileBlock(block, ...) block
#define RCTProfileHookModules(...)
#define RCTProfileUnhookModules(...)
#endif #endif

View File

@ -124,6 +124,8 @@ static void RCTProfileForwardInvocation(NSObject *self, __unused SEL cmd, NSInvo
RCTProfileBeginEvent(); RCTProfileBeginEvent();
[invocation invoke]; [invocation invoke];
RCTProfileEndEvent(name, @"objc_call,modules,auto", nil); RCTProfileEndEvent(name, @"objc_call,modules,auto", nil);
} else if ([self respondsToSelector:invocation.selector]) {
[invocation invoke];
} else { } else {
// Use original selector to don't change error message // Use original selector to don't change error message
[self doesNotRecognizeSelector:invocation.selector]; [self doesNotRecognizeSelector:invocation.selector];
@ -144,14 +146,17 @@ static IMP RCTProfileMsgForward(NSObject *self, SEL selector)
return imp; return imp;
} }
static void RCTProfileHookModules(RCTBridge *); void RCTProfileHookModules(RCTBridge *bridge)
static void RCTProfileHookModules(RCTBridge *bridge)
{ {
for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) {
[moduleData dispatchBlock:^{ [moduleData dispatchBlock:^{
Class moduleClass = moduleData.cls; Class moduleClass = moduleData.cls;
Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0); Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
if (!proxyClass) {
return;
}
unsigned int methodCount; unsigned int methodCount;
Method *methods = class_copyMethodList(moduleClass, &methodCount); Method *methods = class_copyMethodList(moduleClass, &methodCount);
for (NSUInteger i = 0; i < methodCount; i++) { for (NSUInteger i = 0; i < methodCount; i++) {
@ -185,20 +190,17 @@ static void RCTProfileHookModules(RCTBridge *bridge)
} }
} }
void RCTProfileUnhookModules(RCTBridge *);
void RCTProfileUnhookModules(RCTBridge *bridge) void RCTProfileUnhookModules(RCTBridge *bridge)
{ {
for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { RCTProfileLock(
[moduleData dispatchBlock:^{ for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) {
RCTProfileLock( Class proxyClass = object_getClass(moduleData.instance);
Class proxyClass = object_getClass(moduleData.instance); if (moduleData.cls != proxyClass) {
if (moduleData.cls != proxyClass) { object_setClass(moduleData.instance, moduleData.cls);
object_setClass(moduleData.instance, moduleData.cls); objc_disposeClassPair(proxyClass);
objc_disposeClassPair(proxyClass); }
} };
); );
}];
};
} }

View File

@ -436,7 +436,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
*/ */
- (UIView *)reactSuperview - (UIView *)reactSuperview
{ {
RCTAssert(self.superview != nil, @"put reactNavSuperviewLink back"); RCTAssert(!_bridge.isValid || self.superview != nil, @"put reactNavSuperviewLink back");
return self.superview ? self.superview : self.reactNavSuperviewLink; return self.superview ? self.superview : self.reactNavSuperviewLink;
} }