Skip to content
Browse files

Return to the old way of having imp_implementationWithBlock usage be …

…optional.
  • Loading branch information...
1 parent 5e3d376 commit 22d67fb455c6e5c737098e19eb3ba399f4b4206e @zwaldowski zwaldowski committed Apr 13, 2012
Showing with 177 additions and 218 deletions.
  1. +1 −6 A2BlockClosure.h
  2. +51 −197 A2BlockClosure.m
  3. +123 −13 A2BlockDelegate.m
  4. +2 −2 A2DynamicDelegate.m
View
7 A2BlockClosure.h
@@ -10,6 +10,7 @@
NSMutableArray *_allocations;
id _block;
void *_methodCIF;
+ void *_blockCIF;
void *_closure;
void *_functionPointer;
}
@@ -19,10 +20,4 @@
@property (nonatomic, readonly) id block;
@property (nonatomic, readonly) void *functionPointer;
-@end
-
-@interface A2ArgumentsOnlyBlockClosure : A2BlockClosure {
- void *_blockCIF;
-}
-
@end
View
248 A2BlockClosure.m
@@ -9,7 +9,6 @@
#endif
#import <objc/runtime.h>
#import <ffi.h>
-#import <pthread.h>
#pragma mark - Block Internals
@@ -68,18 +67,6 @@
do { if (!(condition)) { [NSException raise: NSInternalInconsistencyException format: [NSString stringWithFormat: @"%s: %@", __PRETTY_FUNCTION__, desc], ## __VA_ARGS__]; } } while(0)
#endif
-#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7
-extern IMP imp_implementationWithBlock(id block) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
-#else
-extern IMP imp_implementationWithBlock(void *block) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
-#endif
-extern void *imp_getBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
-extern BOOL imp_removeBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
-
-IMP a2_imp_implementationWithBlock (id block, const char *types);
-id a2_imp_getBlock(IMP anImp);
-void a2_imp_removeBlock(IMP anImp);
-
#pragma mark - Core Graphics FFI types
const ffi_type *_ffi_type_elements_nsrange[] = { &ffi_type_ulong, &ffi_type_ulong, NULL };
@@ -156,28 +143,13 @@ BOOL a2_blockIsCompatible(id block, NSMethodSignature *signature) {
#pragma mark - FFI closure functions
-@interface A2BlockClosure ()
-
-+ (void (*)(ffi_cif*, void*, void**, void*))invocationFunction;
-
-@property (nonatomic, readonly) ffi_cif *callInterface;
-
-@end
-
-static void a2_executeBlockImplementation(ffi_cif *cif, void *ret, void **args, void *userdata) {
- A2BlockClosure *self = userdata;
- BlockRef block = (void *)self.block;
- args[1] = self.block;
- ffi_call(self.callInterface, block->invoke, ret, args);
-}
-
static void a2_executeArgumentsOnlyBlock(ffi_cif *cif, void *ret, void **args, void *userdata) {
A2BlockClosure *self = userdata;
- BlockRef block = (void *)self.block;
+ BlockRef block = (void *)(self->_block);
void **innerArgs = args + 1;
- innerArgs[0] = self.block;
- ffi_call(self.callInterface, block->invoke, ret, innerArgs);
+ innerArgs[0] = block;
+ ffi_call(self->_blockCIF, block->invoke, ret, innerArgs);
}
static inline size_t a2_getStructSize(const char *encodingType) {
@@ -207,32 +179,29 @@ - (void *)a2_allocate: (size_t)howmuch
}
- (ffi_type *) a2_typeForSignature:(const char *)argumentType {
-
- ffi_type *type = NULL;
-
switch (*argumentType) {
case _C_ID:
case _C_CLASS:
case _C_SEL:
case _C_ATOM:
case _C_CHARPTR:
case _C_PTR:
- type = &ffi_type_pointer; break;
+ return &ffi_type_pointer; break;
case _C_BOOL:
case _C_UCHR:
- type = &ffi_type_uchar; break;
- case _C_CHR: type = &ffi_type_schar; break;
- case _C_SHT: type = &ffi_type_sshort; break;
- case _C_USHT: type = &ffi_type_ushort; break;
- case _C_INT: type = &ffi_type_sint; break;
- case _C_UINT: type = &ffi_type_uint; break;
- case _C_LNG: type = &ffi_type_slong; break;
- case _C_ULNG: type = &ffi_type_ulong; break;
- case _C_LNG_LNG: type = &ffi_type_sint64; break;
- case _C_ULNG_LNG: type = &ffi_type_uint64; break;
- case _C_FLT: type = &ffi_type_float; break;
- case _C_DBL: type = &ffi_type_double; break;
- case _C_VOID: type = &ffi_type_void; break;
+ return &ffi_type_uchar; break;
+ case _C_CHR: return &ffi_type_schar; break;
+ case _C_SHT: return &ffi_type_sshort; break;
+ case _C_USHT: return &ffi_type_ushort; break;
+ case _C_INT: return &ffi_type_sint; break;
+ case _C_UINT: return &ffi_type_uint; break;
+ case _C_LNG: return &ffi_type_slong; break;
+ case _C_ULNG: return &ffi_type_ulong; break;
+ case _C_LNG_LNG: return &ffi_type_sint64; break;
+ case _C_ULNG_LNG: return &ffi_type_uint64; break;
+ case _C_FLT: return &ffi_type_float; break;
+ case _C_DBL: return &ffi_type_double; break;
+ case _C_VOID: return &ffi_type_void; break;
case _C_BFLD:
case _C_ARY_B:
{
@@ -242,46 +211,47 @@ - (ffi_type *) a2_typeForSignature:(const char *)argumentType {
if (size > 0) {
if (size == 1)
- type = &ffi_type_uchar;
+ return &ffi_type_uchar;
else if (size == 2)
- type = &ffi_type_ushort;
+ return &ffi_type_ushort;
else if (size <= 4)
- type = &ffi_type_uint;
+ return &ffi_type_uint;
else {
- type = [self a2_allocate: sizeof(ffi_type)];
+ ffi_type *type = [self a2_allocate: sizeof(ffi_type)];
type->size = size;
type->alignment = align;
type->type = FFI_TYPE_STRUCT;
type->elements = [self a2_allocate: (size + 1) * sizeof(ffi_type *)];
for (NSUInteger i = 0; i < size; i++)
type->elements[i] = &ffi_type_uchar;
type->elements[size] = NULL;
+ return type;
}
break;
}
}
case _C_STRUCT_B:
{
if (!strcmp(argumentType, @encode(NSRange))) {
- type = &ffi_type_nsrange; break;
+ return &ffi_type_nsrange; break;
} else if (!strcmp(argumentType, @encode(CGSize))) {
- type = &ffi_type_cgsize; break;
+ return &ffi_type_cgsize; break;
} else if (!strcmp(argumentType, @encode(CGPoint))) {
- type = &ffi_type_cgpoint; break;
+ return &ffi_type_cgpoint; break;
} else if (!strcmp(argumentType, @encode(CGRect))) {
- type = &ffi_type_cgrect; break;
+ return &ffi_type_cgrect; break;
}
#if !TARGET_OS_MAC
- else if (!strcmp(argumentType, @encode(NSSize))) {
- type = &ffi_type_cgsize; break;
+ if (!strcmp(argumentType, @encode(NSSize))) {
+ return &ffi_type_cgsize; break;
} else if (!strcmp(argumentType, @encode(NSPoint))) {
- type = &ffi_type_cgpoint; break;
+ return &ffi_type_cgpoint; break;
} else if (!strcmp(argumentType, @encode(NSRect))) {
- type = &ffi_type_cgrect; break;
+ return &ffi_type_cgrect; break;
}
#endif
- type = [self a2_allocate: sizeof(ffi_type)];
+ ffi_type *type = [self a2_allocate: sizeof(ffi_type)];
type->size = 0;
type->alignment = 0;
type->type = FFI_TYPE_STRUCT;
@@ -294,38 +264,31 @@ - (ffi_type *) a2_typeForSignature:(const char *)argumentType {
argumentType = NSGetSizeAndAlignment(argumentType, NULL, NULL);
index++;
}
- type->elements[index] = NULL;
+
+ return type;
break;
}
default:
{
- type = &ffi_type_void;
NSCAssert(0, @"Unknown type in sig");
+ return &ffi_type_void;
break;
}
}
- return type;
-}
-
-- (ffi_cif *)callInterface {
- return _methodCIF;
-}
-
-+ (void (*)(ffi_cif*, void*, void**, void*))invocationFunction {
- return a2_executeBlockImplementation;
}
- (id)initWithBlock: (id) block methodSignature: (NSMethodSignature *) signature
{
+ NSAlwaysAssert(a2_blockIsCompatible(block, signature), @"Attempt to implement a method with incompatible block");
if ((self = [super init]))
{
_allocations = [NSMutableArray new];
_block = [block copy];
_closure = ffi_closure_alloc(sizeof(ffi_closure), &_functionPointer);
- NSUInteger methodArgCount = signature.numberOfArguments;
- ffi_cif methodCif;
+ NSUInteger methodArgCount = signature.numberOfArguments, blockArgCount = signature.numberOfArguments - 1;
+ ffi_cif methodCif, blockCif;
ffi_type **methodArgs = [self a2_allocate: methodArgCount * sizeof(ffi_type *)];
ffi_type *returnType = [self a2_typeForSignature: signature.methodReturnType];
@@ -336,14 +299,21 @@ - (id)initWithBlock: (id) block methodSignature: (NSMethodSignature *) signature
methodArgs[i] = [self a2_typeForSignature: [signature getArgumentTypeAtIndex: i]];
}
- ffi_status status = ffi_prep_cif(&methodCif, FFI_DEFAULT_ABI, methodArgCount, returnType, methodArgs);
+ ffi_type **blockArgs = methodArgs + 1;
- NSAlwaysAssert(status == FFI_OK, @"Unable to create function interface for block. %@ %@", [self class], self.block);
+ ffi_status methodStatus = ffi_prep_cif(&methodCif, FFI_DEFAULT_ABI, methodArgCount, returnType, methodArgs);
+ ffi_status blockStatus = ffi_prep_cif(&blockCif, FFI_DEFAULT_ABI, blockArgCount, returnType, blockArgs);
+
+ NSAlwaysAssert(methodStatus == FFI_OK, @"Unable to create function interface for method. %@ %@", [self class], self.block);
+ NSAlwaysAssert(blockStatus == FFI_OK, @"Unable to create function interface for block. %@ %@", [self class], self.block);
_methodCIF = malloc(sizeof(ffi_cif));
*(ffi_cif *)_methodCIF = methodCif;
- status = ffi_prep_closure_loc(_closure, _methodCIF, [[self class] invocationFunction], self, _functionPointer);
+ _blockCIF = malloc(sizeof(ffi_cif));
+ *(ffi_cif *)_blockCIF = blockCif;
+
+ ffi_status status = ffi_prep_closure_loc(_closure, _methodCIF, a2_executeArgumentsOnlyBlock, self, _functionPointer);
NSAlwaysAssert(status == FFI_OK, @"Unable to create function closure for block. %@ %@", [self class], self.block);
}
@@ -356,127 +326,11 @@ - (void)dealloc
ffi_closure_free(_closure);
if (_methodCIF)
free(_methodCIF);
- if (_allocations)
- [_allocations release];
+ if (_blockCIF)
+ free(_blockCIF);
+ [_allocations release];
[_block release];
[super dealloc];
}
-@end
-
-@implementation A2ArgumentsOnlyBlockClosure
-
-- (ffi_cif *)callInterface {
- return _blockCIF;
-}
-
-+ (void (*)(ffi_cif*, void*, void**, void*))invocationFunction {
- return a2_executeArgumentsOnlyBlock;
-}
-
-- (id)initWithBlock: (id) block methodSignature: (NSMethodSignature *) signature
-{
- NSAlwaysAssert(a2_blockIsCompatible(block, signature), @"Attempt to implement a method with incompatible block");
- if ((self = [super initWithBlock: block methodSignature: signature]))
- {
- ffi_cif blockCif;
- NSUInteger blockArgCount = signature.numberOfArguments - 1;
- ffi_type *returnType = (((ffi_cif *)_methodCIF)->rtype);
- ffi_type **blockArgs = (((ffi_cif *)_methodCIF)->arg_types) + 1;
-
- ffi_status status = ffi_prep_cif(&blockCif, FFI_DEFAULT_ABI, blockArgCount, returnType, blockArgs);
- NSAlwaysAssert(status == FFI_OK, @"Unable to create function interface for block. %@ %@", [self class], self.block);
-
- _blockCIF = malloc(sizeof(ffi_cif));
- *(ffi_cif *)_blockCIF = blockCif;
- }
- return self;
-}
-
-- (void)dealloc
-{
- free(_blockCIF);
- [super dealloc];
-}
-
-@end
-
-#pragma mark - imp_implementationWithBlock wrapper
-
-static pthread_mutex_t _blockImplementationLock = PTHREAD_MUTEX_INITIALIZER;
-static NSMutableDictionary *_blockImplementations = nil;
-
-IMP a2_imp_implementationWithBlock (id block, const char *types) {
- // Prefer Apple's implementation
- if (&imp_implementationWithBlock != NULL) {
- block = [[block copy] autorelease];
-#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7
- return imp_implementationWithBlock( block );
-#else
- return imp_implementationWithBlock( (void *) block );
-#endif
- }
-
- if (!block || !types)
- return NULL;
-
- IMP implementation = NULL;
-
- pthread_mutex_lock(&_blockImplementationLock);
-
- if (!_blockImplementations)
- _blockImplementations = [NSMutableDictionary new];
-
- NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes: types];
- A2BlockClosure *closure = [[A2BlockClosure alloc] initWithBlock: block methodSignature: signature];
- implementation = closure.functionPointer;
- [_blockImplementations setObject: closure forKey: [NSValue valueWithPointer: implementation]];
- [closure release];
-
- pthread_mutex_unlock(&_blockImplementationLock);
-
- return implementation;
-}
-
-id a2_imp_getBlock(IMP anImp) {
- // Prefer Apple's implementation
- if (&imp_getBlock != NULL) {
- return (id)imp_getBlock(anImp);
- }
-
- if (!anImp)
- return nil;
-
- id block = nil;
-
- pthread_mutex_lock(&_blockImplementationLock);
-
- if (_blockImplementations) {
- A2BlockClosure *closure = [_blockImplementations objectForKey: [NSValue valueWithPointer: anImp]];
- block = closure.block;
- }
-
- pthread_mutex_unlock(&_blockImplementationLock);
-
- return block;
-}
-
-void a2_imp_removeBlock(IMP anImp) {
- // Prefer Apple's implementation
- if (&imp_removeBlock != NULL) {
- imp_removeBlock(anImp);
- }
-
- if (!anImp)
- return;
-
- pthread_mutex_lock(&_blockImplementationLock);
-
- if (_blockImplementations) {
- [_blockImplementations removeObjectForKey: [NSValue valueWithPointer: anImp]];
- }
-
- pthread_mutex_unlock(&_blockImplementationLock);
-
-
-}
+@end
View
136 A2BlockDelegate.m
@@ -22,13 +22,21 @@
void *A2BlockDelegateProtocolsKey;
void *A2BlockDelegateMapKey;
+// Block Property Accessors
+static id a2_blockPropertyGetter(NSObject *self, SEL _cmd);
+static void a2_blockPropertySetter(NSObject *self, SEL _cmd, id block);
+
// Function Declarations
-extern char *a2_property_copyAttributeValue(objc_property_t property, const char *attributeName);
+static char *a2_property_copyAttributeValue(objc_property_t property, const char *attributeName);
extern char *property_copyAttributeValue(objc_property_t property, const char *attributeName) WEAK_IMPORT_ATTRIBUTE;
-extern SEL a2_getterForProperty(Class cls, NSString *propertyName);
-extern SEL a2_setterForProperty(Class cls, NSString *propertyName);
+static SEL a2_getterForProperty(Class cls, NSString *propertyName);
+static SEL a2_setterForProperty(Class cls, NSString *propertyName);
-extern IMP a2_imp_implementationWithBlock (id block, const char *types);
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7
+extern IMP imp_implementationWithBlock(id block) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
+#else
+extern IMP imp_implementationWithBlock(void *block) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
+#endif
#pragma mark -
@@ -43,6 +51,8 @@ + (NSMutableDictionary *) a2_selectorCacheForProtocol: (Protocol *) protocol;
+ (NSMutableSet *) a2_protocols;
++ (BOOL) a2_getProtocol: (Protocol **) _protocol representedSelector: (SEL *) _representedSelector forPropertyAccessor: (SEL) selector;
+
@end
@interface NSObject (A2DelegateProtocols)
@@ -102,6 +112,76 @@ + (NSMutableSet *) a2_protocols
return protocols;
}
++ (BOOL) a2_getProtocol: (Protocol **) _protocol representedSelector: (SEL *) _representedSelector forPropertyAccessor: (SEL) selector
+{
+ __block BOOL found = NO;
+
+ [[self a2_protocols] enumerateObjectsUsingBlock: ^(Protocol *protocol, BOOL *stop) {
+ NSString *representedName = [[self a2_selectorCacheForProtocol: protocol] objectForKey: NSStringFromSelector(selector)];
+
+ if (representedName)
+ {
+ *_representedSelector = NSSelectorFromString(representedName);
+ *_protocol = protocol;
+ found = *stop = YES;
+ }
+ }];
+
+ if (found) return YES;
+
+ NSString *propertyName = NSStringFromSelector(selector);
+ if ([propertyName hasPrefix: @"set"])
+ {
+ unichar firstChar = [propertyName characterAtIndex: 3];
+ NSString *coda = [propertyName substringWithRange: NSMakeRange(4, propertyName.length - 5)]; // -5 to remove trailing ':'
+ propertyName = [NSString stringWithFormat: @"%c%@", tolower(firstChar), coda];
+ }
+
+ if (!class_getProperty(self, propertyName.UTF8String))
+ {
+ // It's not a simple -xBlock/setXBlock: pair
+
+ // If selector ends in ':', it's a setter.
+ const BOOL isSetter = [NSStringFromSelector(selector) hasSuffix: @":"];
+ const char *key = (isSetter ? "S" : "G");
+
+ unsigned int i, count;
+ objc_property_t *properties = class_copyPropertyList(self, &count);
+
+ for (i = 0; i < count; ++i)
+ {
+ objc_property_t property = properties[i];
+
+ char *accessorName = a2_property_copyAttributeValue(property, key);
+ SEL accessor = sel_getUid(accessorName);
+ if (sel_isEqual(selector, accessor))
+ {
+ propertyName = [NSString stringWithUTF8String: property_getName(property)];
+ break; // from for-loop
+ }
+
+ free(accessorName);
+ }
+
+ free(properties);
+ }
+
+ if (!propertyName) return NO;
+
+ [[self a2_protocols] enumerateObjectsUsingBlock: ^(Protocol *protocol, BOOL *stop) {
+ NSString *selectorName = [[self a2_propertyMapForProtocol: protocol] objectForKey: propertyName];
+ if (!selectorName) return;
+
+ [[self a2_selectorCacheForProtocol: protocol] setObject: selectorName forKey: NSStringFromSelector(selector)];
+
+ *_representedSelector = NSSelectorFromString(selectorName);
+ *_protocol = protocol;
+ found = *stop = YES;
+ }];
+
+ return found;
+}
+
#pragma mark Data Source
+ (void) linkCategoryBlockProperty: (NSString *) propertyName withDataSourceMethod: (SEL) selector
@@ -154,20 +234,30 @@ + (void) linkProtocol: (Protocol *) protocol methods: (NSDictionary *) dictionar
SEL representedSelector = NSSelectorFromString(selectorName);
SEL getter = a2_getterForProperty(self, propertyName);
+ IMP getterImplementation = NULL;
+ if (&imp_implementationWithBlock != NULL) {
+ getterImplementation = imp_implementationWithBlock( (void *) [[^id (NSObject *obj) {
+ return [[obj dynamicDelegateForProtocol: protocol] blockImplementationForMethod: representedSelector];
+ } copy] autorelease]);
+ } else {
+ getterImplementation = (IMP) a2_blockPropertyGetter;
+ }
const char *getterTypes = "@@:";
- IMP getterImplementation = a2_imp_implementationWithBlock(^id (NSObject *obj) {
- return [[obj dynamicDelegateForProtocol: protocol] blockImplementationForMethod: representedSelector];
- }, getterTypes);
BOOL success = class_addMethod(self, getter, getterImplementation, getterTypes);
NSAlwaysAssert(success, @"Could not implement getter for \"%@\" property.", propertyName);
SEL setter = a2_setterForProperty(self, propertyName);
+ IMP setterImplementation = NULL;
+ if (&imp_implementationWithBlock != NULL) {
+ setterImplementation = imp_implementationWithBlock( (void *) [[^(NSObject *obj, id block) {
+ if ([obj respondsToSelector:@selector(a2_checkRegisteredProtocol:)])
+ [obj performSelector:@selector(a2_checkRegisteredProtocol:) withObject:protocol];
+ [[obj dynamicDelegateForProtocol: protocol] implementMethod: representedSelector withBlock: block];
+ } copy] autorelease]);
+ } else {
+ setterImplementation = (IMP) a2_blockPropertySetter;
+ }
const char *setterTypes = "v@:@";
- IMP setterImplementation = a2_imp_implementationWithBlock(^(NSObject *obj, id block) {
- if ([obj respondsToSelector:@selector(a2_checkRegisteredProtocol:)])
- [obj performSelector:@selector(a2_checkRegisteredProtocol:) withObject:protocol];
- [[obj dynamicDelegateForProtocol: protocol] implementMethod: representedSelector withBlock: block];
- }, setterTypes);
success = class_addMethod(self, setter, setterImplementation, setterTypes);
NSAlwaysAssert(success, @"Could not implement setter for \"%@\" property.", propertyName);
}];
@@ -179,7 +269,7 @@ + (void) linkProtocol: (Protocol *) protocol methods: (NSDictionary *) dictionar
#pragma mark - Functions
-SEL a2_getterForProperty(Class cls, NSString *propertyName)
+static SEL a2_getterForProperty(Class cls, NSString *propertyName)
{
SEL getter = NULL;
objc_property_t property = class_getProperty(cls, propertyName.UTF8String);
@@ -334,3 +424,23 @@ static inline void a2_iteratePropertyAttributes(const char *attrs, BOOL (^fn)(co
});
return result;
}
+
+static id a2_blockPropertyGetter(NSObject *self, SEL _cmd)
+{
+ Protocol *protocol;
+ SEL representedSelector;
+ if (![self.class a2_getProtocol: &protocol representedSelector: &representedSelector forPropertyAccessor: _cmd])
+ return nil;
+
+ return [[self dynamicDelegateForProtocol: protocol] blockImplementationForMethod: representedSelector];
+}
+static void a2_blockPropertySetter(NSObject *self, SEL _cmd, id block)
+{
+ Protocol *protocol;
+ SEL representedSelector;
+ if (![self.class a2_getProtocol: &protocol representedSelector: &representedSelector forPropertyAccessor: _cmd])
+ return;
+
+ [[self dynamicDelegateForProtocol: protocol] implementMethod: representedSelector withBlock: block];
+
+}
View
4 A2DynamicDelegate.m
@@ -219,9 +219,9 @@ + (void) implementMethod: (SEL) selector classMethod: (BOOL) isClassMethod withB
else
{
Class cls = isClassMethod ? object_getClass(self) : self;
- A2BlockClosure *closure = [[A2ArgumentsOnlyBlockClosure alloc] initWithBlock: block methodSignature: protoSig];
- class_replaceMethod(cls, selector, closure.functionPointer, methodDescription.types);
+ A2BlockClosure *closure = [[A2BlockClosure alloc] initWithBlock: block methodSignature: protoSig];
[self.implementationMap setObject: closure forKey: key];
+ class_replaceMethod(cls, selector, closure.functionPointer, methodDescription.types);
[closure release];
}
}

0 comments on commit 22d67fb

Please sign in to comment.
Something went wrong with that request. Please try again.