Enable correct behaviour with respect to ARC for objc_{g,s}etIvar().

main
David Chisnall 10 years ago
parent 57858add6e
commit 2777fea77a

@ -25,6 +25,7 @@ set(TESTS
RuntimeTest.m RuntimeTest.m
WeakBlock_arc.m WeakBlock_arc.m
WeakReferences_arc.m WeakReferences_arc.m
ivar_arc.m
objc_msgSend.m objc_msgSend.m
msgInterpose.m msgInterpose.m
NilException.m NilException.m

@ -0,0 +1,52 @@
#include "Test.h"
#include "../objc/runtime.h"
@interface Foo : Test
{
@public
__weak id w;
__unsafe_unretained id u;
__strong id s;
}
@end
@implementation Foo @end
@interface Dealloc : Test
@end
int dealloc = 0;
@implementation Dealloc
- (void)dealloc
{
dealloc++;
}
@end
void setIvar(id obj, const char * name, id val)
{
object_setIvar(obj, class_getInstanceVariable(object_getClass(obj), name), val);
}
int main(void)
{
Foo *f = [Foo new];
Dealloc *d = [Dealloc new];
__unsafe_unretained Dealloc *dead;
setIvar(f, "w", d);
assert(f->w == d);
assert(dealloc == 0);
d = 0;
assert(dealloc == 1);
assert(f->w == nil);
dealloc = 0;
d = [Dealloc new];
dead = d;
setIvar(f, "s", d);
assert(dealloc == 0);
assert(f->s == d);
d = nil;
assert(dealloc == 0);
assert(f->s == dead);
setIvar(f, "s", nil);
assert(dealloc == 1);
assert(f->s == nil);
return 0;
}

@ -18,6 +18,24 @@ struct objc_bitfield
int32_t values[0]; int32_t values[0];
}; };
static inline BOOL objc_bitfield_test(uintptr_t bitfield, uint64_t field)
{
if (bitfield & 1)
{
uint64_t bit = 1<<(field+1);
return (bitfield & bit) == bit;
}
struct objc_bitfield *bf = (struct objc_bitfield*)bitfield;
uint64_t byte = field / 32;
if (byte >= bf->length)
{
return NO;
}
uint64_t bit = 1<<(field%32);
return (bf->values[byte] & bit) == bit;
}
struct objc_class struct objc_class
{ {
/** /**
@ -141,13 +159,13 @@ struct objc_class
* bits are set, from low to high, for each ivar in the object that is a * bits are set, from low to high, for each ivar in the object that is a
* strong pointer. * strong pointer.
*/ */
intptr_t strong_pointers; uintptr_t strong_pointers;
/** /**
* The location of all zeroing weak pointer ivars declared by this class. * The location of all zeroing weak pointer ivars declared by this class.
* The format of this field is the same as the format of the * The format of this field is the same as the format of the
* strong_pointers field. * strong_pointers field.
*/ */
intptr_t weak_pointers; uintptr_t weak_pointers;
}; };
/** /**

@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "objc/runtime.h" #include "objc/runtime.h"
#include "objc/objc-arc.h"
#include "class.h" #include "class.h"
#include "ivar.h" #include "ivar.h"
#include "visibility.h" #include "visibility.h"
@ -143,18 +144,69 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
} }
} }
typedef enum {
ownership_invalid,
ownership_strong,
ownership_weak,
ownership_unsafe
} ownership;
ownership ownershipForIvar(Class cls, Ivar ivar)
{
struct objc_ivar_list *list = cls->ivars;
if ((ivar < list->ivar_list) || (ivar >= &list->ivar_list[list->count]))
{
// Try the superclass
if (cls->super_class)
{
return ownershipForIvar(cls->super_class, ivar);
}
return ownership_invalid;
}
if (!objc_test_class_flag(cls, objc_class_flag_new_abi))
{
return ownership_unsafe;
}
if (cls->abi_version < 1)
{
return ownership_unsafe;
}
if (objc_bitfield_test(cls->strong_pointers, (ivar - list->ivar_list)))
{
return ownership_strong;
}
if (objc_bitfield_test(cls->weak_pointers, (ivar - list->ivar_list)))
{
return ownership_weak;
}
return ownership_unsafe;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Public API functions // Public API functions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void object_setIvar(id object, Ivar ivar, id value) void object_setIvar(id object, Ivar ivar, id value)
{ {
char *addr = (char*)object; ownershipForIvar(object_getClass(object), ivar);
addr += ivar_getOffset(ivar); id *addr = (id*)((char*)object + ivar_getOffset(ivar));
// FIXME: ARC ownership! We don't have enough information to do this switch (ownershipForIvar(object_getClass(object), ivar))
// correctly with the current ABI. We need to fix it with the next ABI {
// bump. case ownership_strong:
*(id*)addr = value; objc_storeStrong(addr, value);
break;
case ownership_weak:
objc_storeWeak(addr, value);
break;
case ownership_unsafe:
*addr = value;
break;
case ownership_invalid:
#ifndef NDEBUG
fprintf(stderr, "Ivar does not belong to this class!\n");
#endif
break;
}
} }
Ivar object_setInstanceVariable(id obj, const char *name, void *value) Ivar object_setInstanceVariable(id obj, const char *name, void *value)
@ -174,7 +226,23 @@ Ivar object_setInstanceVariable(id obj, const char *name, void *value)
id object_getIvar(id object, Ivar ivar) id object_getIvar(id object, Ivar ivar)
{ {
return *(id*)(((char*)object) + ivar_getOffset(ivar)); ownershipForIvar(object_getClass(object), ivar);
id *addr = (id*)((char*)object + ivar_getOffset(ivar));
switch (ownershipForIvar(object_getClass(object), ivar))
{
case ownership_strong:
return objc_retainAutoreleaseReturnValue(*addr);
case ownership_weak:
return objc_loadWeak(addr);
break;
case ownership_unsafe:
return *addr;
case ownership_invalid:
#ifndef NDEBUG
fprintf(stderr, "Ivar does not belong to this class!\n");
#endif
return nil;
}
} }
Ivar object_getInstanceVariable(id obj, const char *name, void **outValue) Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)

Loading…
Cancel
Save