Skip to content

Commit

Permalink
fix(ios): use auto release pool for cpp thread
Browse files Browse the repository at this point in the history
  • Loading branch information
ozonelmy authored and zealotchen0 committed Aug 7, 2023
1 parent 285e3ba commit 2afda7f
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 98 deletions.
65 changes: 37 additions & 28 deletions ios/sdk/base/HippyBatchedBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,12 @@ - (void)stopLoadingWithError:(NSError *)error {
}

_loading = NO;
__weak HippyBatchedBridge *weakSelf = self;
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
[self->_javaScriptExecutor invalidate];
HippyBatchedBridge *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf->_javaScriptExecutor invalidate];
}
}];

[[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScriptDidFailToLoadNotification object:_parentBridge
Expand Down Expand Up @@ -714,22 +718,18 @@ - (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue {
if (queue == HippyJSThread) {
// HippyProfileBeginFlowEvent();
HippyAssert(_javaScriptExecutor != nil, @"Need JS executor to schedule JS work");

__weak HippyBatchedBridge *weakSelf = self;
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
// HippyProfileEndFlowEvent();

// HIPPY_PROFILE_BEGIN_EVENT(0, @"-[HippyBatchedBridge dispatchBlock", @{ @"loading": @(self.loading) });

@autoreleasepool {
if (self.loading) {
HippyAssert(self->_pendingCalls != nil, @"Can't add pending call, bridge is no longer loading");
[self->_pendingCalls addObject:block];
} else {
block();
}
HippyBatchedBridge *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
if (strongSelf.loading) {
HippyAssert(strongSelf->_pendingCalls != nil, @"Can't add pending call, bridge is no longer loading");
[strongSelf->_pendingCalls addObject:block];
} else {
block();
}

// HIPPY_PROFILE_END_EVENT(HippyProfileTagAlways, @"");
}];
} else if (queue) {
dispatch_async(queue, block);
Expand Down Expand Up @@ -785,19 +785,24 @@ - (void)invalidate {

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[self->_displayLink invalidate];
__weak HippyBatchedBridge *weakSelf = self;
[self->_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
std::lock_guard<std::mutex> lock(self->_moduleDataMutex);
self->_displayLink = nil;
[self->_javaScriptExecutor invalidate];
self->_javaScriptExecutor = nil;

self->_moduleDataByName = nil;
self->_moduleDataByID = nil;
self->_moduleClassesByID = nil;
self->_pendingCalls = nil;

if (self->_flowIDMap != NULL) {
CFRelease(self->_flowIDMap);
HippyBatchedBridge *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
std::lock_guard<std::mutex> lock(strongSelf->_moduleDataMutex);
strongSelf->_displayLink = nil;
[strongSelf->_javaScriptExecutor invalidate];
strongSelf->_javaScriptExecutor = nil;

strongSelf->_moduleDataByName = nil;
strongSelf->_moduleDataByID = nil;
strongSelf->_moduleClassesByID = nil;
strongSelf->_pendingCalls = nil;

if (strongSelf->_flowIDMap != NULL) {
CFRelease(strongSelf->_flowIDMap);
}
}];
});
Expand Down Expand Up @@ -885,8 +890,12 @@ - (JSValue *)callFunctionOnModule:(NSString *)module
*/
- (void)_immediatelyCallTimer:(NSNumber *)timer {
HippyAssertJSThread();
__weak HippyBatchedBridge *weakSelf = self;
[_javaScriptExecutor executeAsyncBlockOnJavaScriptQueue:^{
[self _actuallyInvokeAndProcessModule:@"JSTimersExecution" method:@"callTimers" arguments:@[@[timer]]];
HippyBatchedBridge *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf _actuallyInvokeAndProcessModule:@"JSTimersExecution" method:@"callTimers" arguments:@[@[timer]]];
}
}];
}

Expand Down
153 changes: 83 additions & 70 deletions ios/sdk/base/executors/HippyJSCExecutor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,15 @@ - (NSString *)executorkey {
}

HIPPY_EXPORT_METHOD(setContextName:(NSString *)contextName) {
__weak HippyJSCExecutor *weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
[[self JSContext] setName:contextName];
HippyJSCExecutor *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[[strongSelf JSContext] setName:contextName];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.bridge setUpDevClientWithName:contextName];
[strongSelf.bridge setUpDevClientWithName:contextName];
});
}];
}
Expand Down Expand Up @@ -592,72 +597,70 @@ - (void)_executeJSCall:(NSString *)method
HippyAssert(onComplete != nil, @"onComplete block should not be nil");
__weak HippyJSCExecutor *weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
@autoreleasepool {
HippyJSCExecutor *strongSelf = weakSelf;
if (!strongSelf || !strongSelf.isValid || nullptr == strongSelf.pScope) {
HippyJSCExecutor *strongSelf = weakSelf;
if (!strongSelf || !strongSelf.isValid || nullptr == strongSelf.pScope) {
return;
}
@try {
HippyBridge *bridge = [strongSelf bridge];
NSString *moduleName = [bridge moduleName];
NSError *executeError = nil;
id objcValue = nil;
std::shared_ptr<hippy::napi::Ctx> jscContext = self.pScope->GetContext();
std::shared_ptr<hippy::napi::CtxValue> batchedbridge_value = jscContext->GetProperty(jscContext->GetGlobalObject(), "__fbBatchedBridge");
std::shared_ptr<hippy::napi::JSCCtxValue> jsc_resultValue = nullptr;
std::u16string exception;
JSContext *jsContext = [strongSelf JSContext];
JSGlobalContextRef globalContextRef = [strongSelf JSGlobalContextRef];
if (!jsContext || !globalContextRef) {
onComplete([NSNull null], nil);
return;
}
@try {
HippyBridge *bridge = [strongSelf bridge];
NSString *moduleName = [bridge moduleName];
NSError *executeError = nil;
id objcValue = nil;
std::shared_ptr<hippy::napi::Ctx> jscContext = self.pScope->GetContext();
std::shared_ptr<hippy::napi::CtxValue> batchedbridge_value = jscContext->GetProperty(jscContext->GetGlobalObject(), "__fbBatchedBridge");
std::shared_ptr<hippy::napi::JSCCtxValue> jsc_resultValue = nullptr;
std::u16string exception;
JSContext *jsContext = [strongSelf JSContext];
JSGlobalContextRef globalContextRef = [strongSelf JSGlobalContextRef];
if (!jsContext || !globalContextRef) {
onComplete([NSNull null], nil);
return;
}
if (batchedbridge_value) {
std::shared_ptr<hippy::napi::CtxValue> method_value = jscContext->GetProperty(batchedbridge_value, [method UTF8String]);
if (method_value) {
if (jscContext->IsFunction(method_value)) {
std::shared_ptr<hippy::napi::CtxValue> function_params[arguments.count];
for (NSUInteger i = 0; i < arguments.count; i++) {
JSValueRef value = [JSValue valueWithObject:arguments[i] inContext:jsContext].JSValueRef;
function_params[i] = std::make_shared<hippy::napi::JSCCtxValue>(globalContextRef, value);
}
hippy::napi::JSCTryCatch tryCatch(true, jscContext);
std::shared_ptr<hippy::napi::CtxValue> resultValue
= jscContext->CallFunction(method_value, arguments.count, function_params);
if (tryCatch.HasCaught()) {
exception = StringViewUtils::Convert(tryCatch.GetExceptionMsg(), unicode_string_view::Encoding::Utf16).utf16_value();
}
jsc_resultValue = std::static_pointer_cast<hippy::napi::JSCCtxValue>(resultValue);
} else {
executeError
= HippyErrorWithMessageAndModuleName([NSString stringWithFormat:@"%@ is not a function", method], moduleName);
if (batchedbridge_value) {
std::shared_ptr<hippy::napi::CtxValue> method_value = jscContext->GetProperty(batchedbridge_value, [method UTF8String]);
if (method_value) {
if (jscContext->IsFunction(method_value)) {
std::shared_ptr<hippy::napi::CtxValue> function_params[arguments.count];
for (NSUInteger i = 0; i < arguments.count; i++) {
JSValueRef value = [JSValue valueWithObject:arguments[i] inContext:jsContext].JSValueRef;
function_params[i] = std::make_shared<hippy::napi::JSCCtxValue>(globalContextRef, value);
}
hippy::napi::JSCTryCatch tryCatch(true, jscContext);
std::shared_ptr<hippy::napi::CtxValue> resultValue
= jscContext->CallFunction(method_value, arguments.count, function_params);
if (tryCatch.HasCaught()) {
exception = StringViewUtils::Convert(tryCatch.GetExceptionMsg(), unicode_string_view::Encoding::Utf16).utf16_value();
}
jsc_resultValue = std::static_pointer_cast<hippy::napi::JSCCtxValue>(resultValue);
} else {
executeError = HippyErrorWithMessageAndModuleName(
[NSString stringWithFormat:@"property/function %@ not found in __fbBatchedBridge", method], moduleName);
executeError
= HippyErrorWithMessageAndModuleName([NSString stringWithFormat:@"%@ is not a function", method], moduleName);
}
} else {
executeError = HippyErrorWithMessageAndModuleName(@"__fbBatchedBridge not found", moduleName);
executeError = HippyErrorWithMessageAndModuleName(
[NSString stringWithFormat:@"property/function %@ not found in __fbBatchedBridge", method], moduleName);
}
if (!exception.empty() || executeError) {
if (!exception.empty()) {
NSString *string = [NSString stringWithCharacters: reinterpret_cast<const unichar*>(exception.c_str()) length:exception.length()];
executeError = HippyErrorWithMessageAndModuleName(string, moduleName);
}
} else if (jsc_resultValue) {
JSValueRef resutlRef = jsc_resultValue->value_;
JSValue *objc_value = [JSValue valueWithJSValueRef:resutlRef inContext:[strongSelf JSContext]];
objcValue = unwrapResult ? [objc_value toObject] : objc_value;
} else {
executeError = HippyErrorWithMessageAndModuleName(@"__fbBatchedBridge not found", moduleName);
}
if (!exception.empty() || executeError) {
if (!exception.empty()) {
NSString *string = [NSString stringWithCharacters: reinterpret_cast<const unichar*>(exception.c_str()) length:exception.length()];
executeError = HippyErrorWithMessageAndModuleName(string, moduleName);
}
onComplete(objcValue, executeError);
} @catch (NSException *exception) {
NSString *moduleName = strongSelf.bridge.moduleName?:@"unknown";
NSMutableDictionary *userInfo = [exception.userInfo mutableCopy]?:[NSMutableDictionary dictionary];
[userInfo setObject:moduleName forKey:HippyFatalModuleName];
[userInfo setObject:arguments?:[NSArray array] forKey:@"arguments"];
NSException *reportException = [NSException exceptionWithName:exception.name reason:exception.reason userInfo:userInfo];
MttHippyException(reportException);
} else if (jsc_resultValue) {
JSValueRef resutlRef = jsc_resultValue->value_;
JSValue *objc_value = [JSValue valueWithJSValueRef:resutlRef inContext:[strongSelf JSContext]];
objcValue = unwrapResult ? [objc_value toObject] : objc_value;
}
onComplete(objcValue, executeError);
} @catch (NSException *exception) {
NSString *moduleName = strongSelf.bridge.moduleName?:@"unknown";
NSMutableDictionary *userInfo = [exception.userInfo mutableCopy]?:[NSMutableDictionary dictionary];
[userInfo setObject:moduleName forKey:HippyFatalModuleName];
[userInfo setObject:arguments?:[NSArray array] forKey:@"arguments"];
NSException *reportException = [NSException exceptionWithName:exception.name reason:exception.reason userInfo:userInfo];
MttHippyException(reportException);
}
}];
}
Expand All @@ -669,14 +672,13 @@ - (void)executeApplicationScript:(NSData *)script
HippyAssertParam(script);
HippyAssertParam(sourceURL);

// HippyProfileBeginFlowEvent();
__weak HippyJSCExecutor *weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
// HippyProfileEndFlowEvent();
if (!self.isValid) {
HippyJSCExecutor *strongSelf = weakSelf;
if (!strongSelf || !strongSelf.isValid) {
return;
}

NSError *error = executeApplicationScript(script, sourceURL, isCommonBundle, self->_performanceLogger, [self JSGlobalContextRef]);
NSError *error = executeApplicationScript(script, sourceURL, isCommonBundle, strongSelf->_performanceLogger, [strongSelf JSGlobalContextRef]);
if (onComplete) {
onComplete(error);
}
Expand Down Expand Up @@ -756,12 +758,19 @@ static void handleJsExcepiton(std::shared_ptr<Scope> scope) {
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block {
auto engine = [[HippyJSEnginesMapper defaultInstance] JSEngineForKey:self.executorkey];
if (engine) {
dispatch_block_t autoReleaseBlock = ^(void){
if (block) {
@autoreleasepool {
block();
}
}
};
if (engine->GetJSRunner()->IsJsThread() == false) {
std::shared_ptr<JavaScriptTask> task = std::make_shared<JavaScriptTask>();
task->callback = block;
task->callback = autoReleaseBlock;
engine->GetJSRunner()->PostTask(task);
} else {
block();
autoReleaseBlock();
}
}
}
Expand All @@ -770,7 +779,14 @@ - (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block {
auto engine = [[HippyJSEnginesMapper defaultInstance] JSEngineForKey:self.executorkey];
if (engine) {
std::shared_ptr<JavaScriptTask> task = std::make_shared<JavaScriptTask>();
task->callback = block;
dispatch_block_t autoReleaseBlock = ^(void){
if (block) {
@autoreleasepool {
block();
}
}
};
task->callback = autoReleaseBlock;
engine->GetJSRunner()->PostTask(task);
}
}
Expand All @@ -790,10 +806,7 @@ - (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)object
}

__weak HippyJSCExecutor *weakSelf = self;
// HippyProfileBeginFlowEvent();
[self executeBlockOnJavaScriptQueue:^{
// HippyProfileEndFlowEvent();

HippyJSCExecutor *strongSelf = weakSelf;
if (!strongSelf || !strongSelf.isValid) {
return;
Expand Down

0 comments on commit 2afda7f

Please sign in to comment.