More refactoring.

main
theraven 16 years ago
parent 2d84b96a72
commit 7b8b3839df

@ -17,6 +17,7 @@ Some individual files retain their original MIT license. These are:
blocks_runtime.m
class_table.c
hash_table.h
ivar.c
lock.h
mutation.m
pool.h
@ -27,6 +28,9 @@ objc/blocks_runtime.h
objc/runtime.h
NSBlocks.m
All of the private headers (those not in the objc/ directory) are also covered
by the MIT license, in as far as they are covered by copyright law.
These files may be used for any purpose, including binary-only redistribution,
according to the terms of the MIT license, as long as their copyright notices
remain intact. You may find the full text of the license for these files in

@ -26,6 +26,7 @@ libobjc_C_FILES = \
exception.c\
gc.c\
hash.c\
ivar.c\
init.c\
misc.c\
nil_method.c\

@ -24,7 +24,9 @@ struct objc_class
*/
long version;
/**
* A bitfield containing various flags.
* A bitfield containing various flags. See the objc_class_flags
* enumerated type for possible values. The top half of this value
* contains the class number.
*/
unsigned long info;
/**
@ -107,3 +109,56 @@ struct objc_class
*/
struct objc_property_list *properties;
};
/**
* An enumerated type describing all of the valid flags that may be used in the
* info field of a class.
*/
enum objc_class_flags
{
/** This class structure represents a class. */
objc_class_flag_class = (1<<0),
/** This class structure represents a metaclass. */
objc_class_flag_meta = (1<<1),
/**
* This class has been sent a +initalize message. This message is sent
* exactly once to every class that is sent a message by the runtime, just
* before the first other message is sent.
*/
objc_class_flag_initialized = (1<<2),
/**
* The class has been initialized by the runtime. Its super_class pointer
* should now point to a class, rather than a C string containing the class
* name, and its subclass and sibling class links will have been assigned,
* if applicable.
*/
objc_class_flag_resolved = (1<<3),
/**
* The class uses the new, Objective-C 2, runtime ABI. This ABI defines an
* ABI version field inside the class, and so will be used for all
* subsequent versions that retain some degree of compatibility.
*/
objc_class_flag_new_abi = (1<<4),
/**
* This class was created at run time and may be freed.
*/
objc_class_flag_user_created = (1<<5),
/**
* Instances of this class have a reference count and plane ID prepended to
* them. The default for this is set for classes, unset for metaclasses.
* It should be cleared by protocols, constant strings, and objects not
* allocated by NSAllocateObject().
*/
objc_class_flag_plane_aware = (1<<6)
};
static inline void objc_set_class_flag(struct objc_class *aClass,
enum objc_class_flags flag)
{
aClass->info |= (long)flag;
}
static inline BOOL objc_test_class_flag(struct objc_class *aClass,
enum objc_class_flags flag)
{
return aClass->info & (long)flag;
}

100
init.c

@ -706,104 +706,6 @@ __objc_exec_class (Module_t module)
UNLOCK(__objc_runtime_mutex);
}
static void
__objc_compute_ivar_offsets (Class class)
{
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
* declared for just this class}. The individual instance variable offset
* fields will then be the offsets from the start of the class, and so must
* have the size of the parent class prepended. */
if (class->instance_size <= 0)
{
Class super = class_superclass_of_class(class);
long ivar_start = 0;
if (Nil != super)
{
if (super->instance_size <= 0)
{
__objc_compute_ivar_offsets(super);
}
ivar_start = super->instance_size;
}
class->instance_size = ivar_start - class->instance_size;
/* For each instance variable, we add the offset if required (it will be zero
* if this class is compiled with a static ivar layout). We then set the
* value of a global variable to the offset value.
*
* Any class compiled with support for the non-fragile ABI, but not actually
* using it, will export the ivar offset field as a symbol.
*
* Note that using non-fragile ivars breaks @defs(). If you need equivalent
* functionality, provide an alternative @interface with all variables
* declared @public.
*/
if (class->ivars)
{
for (i = 0 ; i < class->ivars->ivar_count ; i++)
{
struct objc_ivar *ivar = &class->ivars->ivar_list[i];
ivar->ivar_offset += ivar_start;
/* If we're using the new ABI then we also set up the faster ivar
* offset variables.
*/
if (CLS_ISNEW_ABI(class))
{
*(class->ivar_offsets[i]) = ivar->ivar_offset;
}
}
}
}
else
{
if (NULL == class->ivars)
{
return;
}
Class super = class_superclass_of_class(class);
int start = class->ivars->ivar_list[0].ivar_offset;
/* Quick and dirty test. If the first ivar comes straight after the last
* class, then it's fine. */
if (Nil == super || start == super->instance_size)
{
return;
}
/* Find the last superclass with at least one ivar. */
while (NULL == super->ivars)
{
super = class_superclass_of_class(super);
}
struct objc_ivar *ivar =
&super->ivars->ivar_list[super->ivars->ivar_count-1];
if (start == (ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type)))
{
return;
}
/* The classes don't line up, but don't panic; check that the
* difference is not just padding for alignment */
int align = objc_alignof_type(class->ivars->ivar_list[0].ivar_type);
if (start > ivar->ivar_offset &&
start - ivar->ivar_offset < align)
{
return;
}
/* Panic if this class has an instance variable that overlaps the
* superclass. */
fprintf(stderr,
"Error: Instance variables in %s overlap superclass %s",
class->name, super->name);
fprintf(stderr,
"Offset of first instance variable, %s, is %d",
class->ivars->ivar_list[0].ivar_name, start);
fprintf(stderr,
"Last instance variable in superclass, %s, ends at offset %d",
ivar->ivar_name,
ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type));
fprintf(stderr, "This probably means that you are subclassing a class from a library, which has changed in a binary-incompatible way.\n");
abort();
}
}
static void
objc_send_load (void)
@ -866,6 +768,8 @@ objc_send_load (void)
__objc_module_list = NULL;
}
void __objc_compute_ivar_offsets(Class class);
static void
__objc_create_classes_tree (Module_t module)
{

105
ivar.c

@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <objc/runtime.h>
#include "class.h"
#include "ivar.h"
ptrdiff_t objc_alignof_type(const char *);
ptrdiff_t objc_sizeof_type(const char *);
void __objc_compute_ivar_offsets(Class class)
{
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
* declared for just this class}. The individual instance variable offset
* fields will then be the offsets from the start of the class, and so must
* have the size of the parent class prepended. */
if (class->instance_size <= 0)
{
Class super = class_getSuperclass(class);
long ivar_start = 0;
if (Nil != super)
{
if (super->instance_size <= 0)
{
__objc_compute_ivar_offsets(super);
}
ivar_start = super->instance_size;
}
class->instance_size = ivar_start - class->instance_size;
/* For each instance variable, we add the offset if required (it will be zero
* if this class is compiled with a static ivar layout). We then set the
* value of a global variable to the offset value.
*
* Any class compiled with support for the non-fragile ABI, but not actually
* using it, will export the ivar offset field as a symbol.
*
* Note that using non-fragile ivars breaks @defs(). If you need equivalent
* functionality, provide an alternative @interface with all variables
* declared @public.
*/
if (class->ivars)
{
for (i = 0 ; i < class->ivars->count ; i++)
{
struct objc_ivar *ivar = &class->ivars->ivar_list[i];
ivar->offset += ivar_start;
/* If we're using the new ABI then we also set up the faster ivar
* offset variables.
*/
if (objc_test_class_flag(class, objc_class_flag_new_abi))
{
*(class->ivar_offsets[i]) = ivar->offset;
}
}
}
}
else
{
if (NULL == class->ivars) { return; }
Class super = class_getSuperclass(class);
int start = class->ivars->ivar_list[0].offset;
/* Quick and dirty test. If the first ivar comes straight after the last
* class, then it's fine. */
if (Nil == super || start == super->instance_size) {return; }
/* Find the last superclass with at least one ivar. */
while (NULL == super->ivars)
{
super = class_getSuperclass(super);
}
struct objc_ivar *ivar =
&super->ivars->ivar_list[super->ivars->count-1];
if (start == (ivar->offset + objc_sizeof_type(ivar->type)))
{
return;
}
/* The classes don't line up, but don't panic; check that the
* difference is not just padding for alignment */
int align = objc_alignof_type(class->ivars->ivar_list[0].type);
if (start > ivar->offset && start - ivar->offset < align)
{
return;
}
/* Panic if this class has an instance variable that overlaps the
* superclass. */
fprintf(stderr,
"Error: Instance variables in %s overlap superclass %s. ",
class->name, super->name);
fprintf(stderr,
"Offset of first instance variable, %s, is %d. ",
class->ivars->ivar_list[0].name, start);
fprintf(stderr,
"Last instance variable in superclass, %s, ends at offset %d. ",
ivar->name, ivar->offset +
objc_sizeof_type(ivar->type));
fprintf(stderr, "This probably means that you are subclassing a"
"class from a library, which has changed in a binary-incompatible"
"way.\n");
abort();
}
}

@ -0,0 +1,47 @@
/**
* 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;
};
/**
* 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
* instance variables, because that would require existing objects to be
* reallocated, which is only possible with accurate GC (i.e. not in C).
*/
struct objc_ivar_list
{
/**
* The number of instance variables in this list.
*/
int count;
/**
* An array of instance variable metadata structures. Note that this array
* has count elements, not 1.
*/
struct objc_ivar ivar_list[1];
};
Loading…
Cancel
Save