Add new ABI ivar metadata structures.

The new structure has extra fields for alignment and flags (e.g.
ownership).
Old structures are auto-upgraded at load time, so the rest of the code
can assume the presence of the new structure type.
main
David Chisnall 10 years ago
parent f55c158be8
commit 3dc096eb17

@ -121,7 +121,8 @@ struct objc_class
/**
* The version of the ABI used for this class. Zero indicates the ABI first
* implemented by clang 1.0. One indicates the presence of bitmaps
* indicating the offsets of strong, weak, and unretained ivars.
* indicating the offsets of strong, weak, and unretained ivars. Two
* indicates that the new ivar structure is used.
*/
long abi_version;
@ -265,6 +266,21 @@ static inline BOOL objc_test_class_flag(struct objc_class *aClass,
{
return (aClass->info & (unsigned long)flag) == (unsigned long)flag;
}
/**
* Checks the version of a class. Return values are:
* 0. Legacy GCC ABI compatible class.
* 1. First release of GNUstep ABI.
* 2. Second release of the GNUstep ABI, adds strong / weak ivar bitmaps.
* 3. Third release of the GNUstep ABI. Many cleanups.
*/
static inline int objc_get_class_version(struct objc_class *aClass)
{
if (!objc_test_class_flag(aClass, objc_class_flag_new_abi))
{
return 0;
}
return aClass->abi_version + 1;
}
/**
* Adds a class to the class table.

@ -10,9 +10,18 @@
ptrdiff_t objc_alignof_type(const char *);
ptrdiff_t objc_sizeof_type(const char *);
static struct objc_ivar_list *upgradeIvarList(Class cls, struct objc_ivar_list_legacy *l);
PRIVATE void objc_compute_ivar_offsets(Class class)
{
struct objc_ivar_list_legacy *legacy = NULL;
// If this is an old ABI class, then replace the ivar list with the new
// version
if (objc_get_class_version(class) < 3)
{
legacy = (struct objc_ivar_list_legacy *)class->ivars;
class->ivars = upgradeIvarList(class, legacy);
}
int i = 0;
/* If this class was compiled with support for late-bound ivars, the
* instance_size field will contain 0 - {the size of the instance variables
@ -56,30 +65,7 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
long ivar_size = (i+1 == class->ivars->count)
? (class_size - ivar->offset)
: ivar->offset - class->ivars->ivar_list[i+1].offset;
#if 0
// We only need to do the realignment for things that are
// bigger than a pointer, and we don't need to do it in GC mode
// where we don't add any extra padding.
if (!isGCEnabled && (ivar_size > sizeof(void*)))
{
long fudge = (ivar_start +ivar->offset + sizeof(void*)) % 16;
if (fudge != 0)
{
// If this is the first ivar in the class, then
// we can eat some of the padding that the compiler
// added...
if ((i == 0) && (ivar->offset > 0) && ((ivar_start + sizeof(void*) %16) == 0))
{
ivar->offset = 0;
}
else
{
ivar_start += fudge;
class->instance_size += fudge;
}
}
}
#endif
// FIXME: use alignment
ivar->offset += ivar_start;
/* If we're using the new ABI then we also set up the faster ivar
* offset variables.
@ -88,6 +74,9 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
{
*(class->ivar_offsets[i]) = ivar->offset;
}
// If we have a legacy ivar list, update the offset in it too -
// code from older compilers may access this directly!
legacy->ivar_list[i].offset = ivar->offset;
}
}
}
@ -144,42 +133,42 @@ 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)
ivar_ownership ownershipForIvar(Class cls, int idx)
{
struct objc_ivar_list *list = cls->ivars;
if ((ivar < list->ivar_list) || (ivar >= &list->ivar_list[list->count]))
if (objc_get_class_version(cls) < 2)
{
// Try the superclass
if (cls->super_class)
{
return ownershipForIvar(cls->super_class, ivar);
}
return ownership_invalid;
return ownership_unsafe;
}
if (!objc_test_class_flag(cls, objc_class_flag_new_abi))
if (objc_bitfield_test(cls->strong_pointers, idx))
{
return ownership_unsafe;
return ownership_strong;
}
if (cls->abi_version < 1)
if (objc_bitfield_test(cls->weak_pointers, idx))
{
return ownership_weak;
}
return ownership_unsafe;
}
if (objc_bitfield_test(cls->strong_pointers, (ivar - list->ivar_list)))
static struct objc_ivar_list *upgradeIvarList(Class cls, struct objc_ivar_list_legacy *l)
{
return ownership_strong;
if (l == NULL)
{
return NULL;
}
if (objc_bitfield_test(cls->weak_pointers, (ivar - list->ivar_list)))
struct objc_ivar_list *n = calloc(1, sizeof(struct objc_ivar_list) +
l->count*sizeof(struct objc_ivar));
n->count = l->count;
for (int i=0 ; i<l->count ; i++)
{
return ownership_weak;
n->ivar_list[i].name = l->ivar_list[i].name;
n->ivar_list[i].type = l->ivar_list[i].type;
n->ivar_list[i].offset = l->ivar_list[i].offset;
n->ivar_list[i].align = objc_alignof_type(n->ivar_list[i].type);
ivarSetOwnership(&n->ivar_list[i], ownershipForIvar(cls, i));
}
return ownership_unsafe;
return n;
}
////////////////////////////////////////////////////////////////////////////////
@ -188,9 +177,8 @@ ownership ownershipForIvar(Class cls, Ivar ivar)
void object_setIvar(id object, Ivar ivar, id value)
{
ownershipForIvar(object_getClass(object), ivar);
id *addr = (id*)((char*)object + ivar_getOffset(ivar));
switch (ownershipForIvar(object_getClass(object), ivar))
switch (ivarGetOwnership(ivar))
{
case ownership_strong:
objc_storeStrong(addr, value);
@ -226,9 +214,8 @@ Ivar object_setInstanceVariable(id obj, const char *name, void *value)
id object_getIvar(id object, Ivar ivar)
{
ownershipForIvar(object_getClass(object), ivar);
id *addr = (id*)((char*)object + ivar_getOffset(ivar));
switch (ownershipForIvar(object_getClass(object), ivar))
switch (ivarGetOwnership(ivar))
{
case ownership_strong:
return objc_retainAutoreleaseReturnValue(*addr);

@ -2,13 +2,80 @@
/**
* Metadata structure for an instance variable.
*
* Note: The modern Apple runtime apparently stores the alignment of the ivar
* here. We don't - we can compute it from the type, but it might be useful.
*
* It would also be good to add GC properties to this structure, and possibly
* an assignment policy (e.g. assign / retain / copy).
*/
struct objc_ivar
{
/**
* Name of this instance variable.
*/
const char *name;
/**
* Type encoding for this instance variable.
*/
const char *type;
/**
* The offset from the start of the object. When using the non-fragile
* ABI, this is initialized by the compiler to the offset from the start of
* the ivars declared by this class. It is then set by the runtime to the
* offset from the object pointer.
*/
int offset;
/**
* Alignment of this ivar.
*/
int align;
/**
* Flags for this instance variable.
*/
int flags;
};
/**
* Instance variable ownership.
*/
typedef enum {
/**
* Invalid. Indicates that this is not an instance variable with ownership
* semantics.
*/
ownership_invalid = 0,
/**
* Strong ownership. Assignments to this instance variable should retain
* the assigned value.
*/
ownership_strong = 1,
/**
* Weak ownership. This ivar is a zeroing weak reference to an object.
*/
ownership_weak = 2,
/**
* Object that has `__unsafe_unretained` semantics.
*/
ownership_unsafe = 3
} ivar_ownership;
/**
* Mask applied to the flags field to indicate ownership.
*/
static const int ivar_ownership_mask = 3;
static inline void ivarSetOwnership(Ivar ivar, ivar_ownership o)
{
ivar->flags = (ivar->flags & ~ivar_ownership_mask) | o;
}
/**
* Look up the ownership for a given instance variable.
*/
static inline ivar_ownership ivarGetOwnership(Ivar ivar)
{
return (ivar_ownership)(ivar->flags & ivar_ownership_mask);
}
/**
* Legacy ivar structure, inherited from the GCC ABI.
*/
struct objc_ivar_legacy
{
/**
* Name of this instance variable.
@ -27,6 +94,7 @@ struct objc_ivar
int offset;
};
/**
* A list of instance variables declared on this class. Unlike the method
* list, this is a single array and size. Categories are not allowed to add
@ -45,3 +113,20 @@ struct objc_ivar_list
*/
struct objc_ivar ivar_list[];
};
/**
* Legacy version of the ivar list
*/
struct objc_ivar_list_legacy
{
/**
* The number of instance variables in this list.
*/
int count;
/**
* An array of instance variable metadata structures. Note that this array
* has count elements.
*/
struct objc_ivar_legacy ivar_list[];
};

@ -142,6 +142,7 @@ BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment,
Ivar ivar = &cls->ivars->ivar_list[cls->ivars->count - 1];
ivar->name = strdup(name);
ivar->type = strdup(types);
ivar->align = alignment;
// Round up the offset of the ivar so it is correctly aligned.
long offset = cls->instance_size;
if (alignment != 0)
@ -725,6 +726,9 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt
objc_class_flag_new_abi;
newClass->dtable = uninstalled_dtable;
newClass->abi_version = 2;
metaClass->abi_version = 2;
if (Nil == superclass)
{
newClass->instance_size = sizeof(struct objc_class*);

Loading…
Cancel
Save