blob: fab0093135aa033cb29dc28010f42cf262d72095 [file] [log] [blame]
//
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#import "Service/Sources/EDOBlockObject.h"
#import "Service/Sources/EDOHostService+Private.h"
#import "Service/Sources/EDOHostService.h"
#import "Service/Sources/EDOObject+Private.h"
#import "Service/Sources/EDOObject.h"
#import "Service/Sources/EDOParameter.h"
/** Expose the private class interface. */
@interface NSBlock : NSObject
+ (Class)class;
@end
/**
* Adding forwardInvocation: and methodSignatureForSelector: to NSBlock so when _objc_msgForward
* is attempting to recover from the failure, we can capture the invocation to reconstruct the
* call stack.
*/
@implementation NSBlock (EDOInvocation)
__attribute__((constructor)) static void SetupBlockInvocationForward() {
IMP forwardInvocationImp = imp_implementationWithBlock(^(id block, NSInvocation *invocation) {
EDOBlockObject *blockObject = [EDOBlockObject EDOBlockObjectFromBlock:block];
NSCAssert(blockObject, @"No block object to forward.");
[blockObject edo_forwardInvocation:invocation selector:nil returnByValue:NO];
});
BOOL forwardInvocationAdded =
class_addMethod([NSBlock class], @selector(forwardInvocation:), forwardInvocationImp, "v@:@");
if (!forwardInvocationAdded) {
// TODO(haowoo): Convert this and below into macros/methods.
NSLog(@"Failed to add forwardInvocation:.");
abort();
}
IMP methodSignatureImp = imp_implementationWithBlock(^(id block, SEL selector) {
return [NSMethodSignature signatureWithObjCTypes:[EDOBlockObject signatureFromBlock:block]];
});
BOOL methodSignatureAdded = class_addMethod(
[NSBlock class], @selector(methodSignatureForSelector:), methodSignatureImp, "v@::");
if (!methodSignatureAdded) {
NSLog(@"Failed to add methodSignatureForSelector:.");
abort();
}
}
- (EDOParameter *)edo_parameterForTarget:(EDOObject *)target
service:(EDOHostService *)service
hostPort:(EDOHostPort *)hostPort {
EDOBlockObject *blockObject = [EDOBlockObject EDOBlockObjectFromBlock:self];
return [EDOParameter parameterWithObject:blockObject
?: [service distantObjectForLocalObject:self
hostPort:hostPort]];
}
@end