Ensure that objects that support ARC will use ARC, even if they are

created without sending a message to the class.

Also ensure that protocols are always valid objects so that ARC doesn't
become confused.
main
David Chisnall 10 years ago
parent 5c21e73f26
commit d44bf5655b

@ -20,6 +20,8 @@
- (id)self { return self; }
@end
@implementation Protocol2 @end
@interface __IncompleteProtocol : Protocol2 @end
@implementation __IncompleteProtocol @end
/**
* This class exists for the sole reason that the legacy GNU ABI did not

@ -91,6 +91,50 @@ static void checkARCAccessors(Class cls)
objc_set_class_flag(cls, objc_class_flag_fast_arc);
}
PRIVATE void checkARCAccessorsSlow(Class cls)
{
if (cls->dtable != uninstalled_dtable)
{
return;
}
static SEL retain, release, autorelease, isARC;
if (NULL == retain)
{
retain = sel_registerName("retain");
release = sel_registerName("release");
autorelease = sel_registerName("autorelease");
isARC = sel_registerName("_ARCCompliantRetainRelease");
}
if (cls->super_class != Nil)
{
checkARCAccessorsSlow(cls->super_class);
}
BOOL superIsFast = objc_test_class_flag(cls, objc_class_flag_fast_arc);
BOOL selfImplementsRetainRelease = NO;
for (struct objc_method_list *l=cls->methods ; l != NULL ; l= l->next)
{
for (int i=0 ; i<l->count ; i++)
{
SEL s = l->methods[i].selector;
if (sel_isEqual(s, retain) ||
sel_isEqual(s, release) ||
sel_isEqual(s, autorelease))
{
selfImplementsRetainRelease = YES;
}
else if (sel_isEqual(s, isARC))
{
objc_set_class_flag(cls, objc_class_flag_fast_arc);
return;
}
}
}
if (superIsFast && ! selfImplementsRetainRelease)
{
objc_set_class_flag(cls, objc_class_flag_fast_arc);
}
}
static void collectMethodsForMethodListToSparseArray(
struct objc_method_list *list,
SparseArray *sarray,

@ -126,3 +126,9 @@ void add_method_list_to_class(Class cls,
* Destroys a dtable.
*/
void free_dtable(dtable_t dtable);
/**
* Checks whether the class supports ARC. This can be used before the dtable
* is installed.
*/
void checkARCAccessorsSlow(Class cls);

@ -45,6 +45,17 @@ struct objc_protocol2 *protocol_for_name(const char *name)
static id ObjC2ProtocolClass = 0;
static id incompleteProtocolClass(void)
{
static id IncompleteProtocolClass = 0;
if (IncompleteProtocolClass == nil)
{
IncompleteProtocolClass = objc_getClass("__IncompleteProtocol");
}
return IncompleteProtocolClass;
}
static int isEmptyProtocol(struct objc_protocol2 *aProto)
{
int isEmpty =
@ -497,7 +508,7 @@ Protocol*__unsafe_unretained* objc_copyProtocolList(unsigned int *outCount)
Protocol *objc_allocateProtocol(const char *name)
{
if (objc_getProtocol(name) != NULL) { return NULL; }
Protocol *p = calloc(1, sizeof(Protocol2));
Protocol *p = (Protocol*)class_createInstance((Class)incompleteProtocolClass(), 0);
p->name = strdup(name);
return p;
}
@ -506,7 +517,7 @@ void objc_registerProtocol(Protocol *proto)
if (NULL == proto) { return; }
LOCK_RUNTIME_FOR_SCOPE();
if (objc_getProtocol(proto->name) != NULL) { return; }
if (nil != proto->isa) { return; }
if (incompleteProtocolClass() != proto->isa) { return; }
proto->isa = ObjC2ProtocolClass;
protocol_table_insert((struct objc_protocol2*)proto);
}
@ -517,7 +528,7 @@ void protocol_addMethodDescription(Protocol *aProtocol,
BOOL isInstanceMethod)
{
if ((NULL == aProtocol) || (NULL == name) || (NULL == types)) { return; }
if (nil != aProtocol->isa) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; }
Protocol2 *proto = (Protocol2*)aProtocol;
struct objc_method_description_list **listPtr;
if (isInstanceMethod)
@ -561,6 +572,7 @@ void protocol_addMethodDescription(Protocol *aProtocol,
void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
{
if ((NULL == aProtocol) || (NULL == addition)) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; }
Protocol2 *proto = (Protocol2*)aProtocol;
if (NULL == proto->protocol_list)
{
@ -584,7 +596,7 @@ void protocol_addProperty(Protocol *aProtocol,
BOOL isInstanceProperty)
{
if ((NULL == aProtocol) || (NULL == name)) { return; }
if (nil != aProtocol->isa) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; }
if (!isInstanceProperty) { return; }
Protocol2 *proto = (Protocol2*)aProtocol;
struct objc_property_list **listPtr;

@ -348,6 +348,7 @@ id class_createInstance(Class cls, size_t extraBytes)
if (Nil == cls) { return nil; }
id obj = gc->allocate_class(cls, extraBytes);
obj->isa = cls;
checkARCAccessorsSlow(cls);
call_cxx_construct(obj);
return obj;
}

Loading…
Cancel
Save