Rewritten class loading.

main
theraven 16 years ago
parent a1329e22de
commit de71ebb6b1

@ -7,29 +7,28 @@ struct objc_class
* methods use when a message is sent to the class, rather than an
* instance.
*/
struct objc_class *isa;
struct objc_class *isa;
/**
* Pointer to the superclass. The compiler will set this to the name of
* the superclass, the runtime will initialize it to point to the real
* class.
*/
struct objc_class *super_class;
struct objc_class *super_class;
/**
* The name of this class. Set to the same value for both the class and
* its associated metaclass.
*/
const char* name;
const char *name;
/**
* The version of this class. This is not used by the language, but may be
* set explicitly at class load time.
*/
long version;
long version;
/**
* 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.
* enumerated type for possible values.
*/
unsigned long info;
unsigned long info;
/**
* The size of this class. For classes using the non-fragile ABI, the
* compiler will set this to a negative value The absolute value will be
@ -40,33 +39,33 @@ struct objc_class
* In both cases, this will be set to the size of an instance of the class
* after the class is registered with the runtime.
*/
long instance_size;
long instance_size;
/**
* Metadata describing the instance variables in this class.
*/
struct objc_ivar_list* ivars;
struct objc_ivar_list *ivars;
/**
* Metadata for for defining the mappings from selectors to IMPs. Linked
* list of method list structures, one per class and one per category.
*/
struct objc_method_list* methods;
struct objc_method_list *methods;
/**
* The dispatch table for this class. Intialized and maintained by the
* runtime.
*/
struct sarray * dtable;
void *dtable;
/**
* A pointer to the first subclass for this class. Filled in by the
* runtime.
*/
struct objc_class* subclass_list;
struct objc_class *subclass_list;
/**
* A pointer to the next sibling class to this. You may find all
* subclasses of a given class by following the subclass_list pointer and
* then subsequently following the sibling_class pointers in the
* subclasses.
*/
struct objc_class* sibling_class;
struct objc_class *sibling_class;
/**
* Metadata describing the protocols adopted by this class. Not used by
@ -76,7 +75,7 @@ struct objc_class
/**
* Pointer used by the Boehm GC.
*/
void* gc_object_type;
void *gc_object_type;
/**
* New ABI. The following fields are only available with classes compiled to
* support the new ABI. You may test whether any given class supports this
@ -86,7 +85,7 @@ struct objc_class
/**
* The version of the ABI used for this class. This is currently always zero.
*/
long abi_version;
long abi_version;
/**
* Array of pointers to variables where the runtime will store the ivar
@ -103,7 +102,7 @@ struct objc_class
* where they are used. The legacy-compatible ABI uses these with a double
* layer of indirection.
*/
int **ivar_offsets;
int **ivar_offsets;
/**
* List of declared properties on this class (NULL if none). This contains
* the accessor methods for each property.

@ -2,10 +2,63 @@
#include "objc/runtime.h"
#include "objc/hooks.h"
#include "class.h"
#include "method_list.h"
#include "selector.h"
#include "lock.h"
#include <stdlib.h>
#include <assert.h>
void __objc_register_selectors_from_class(Class class);
void *__objc_uninstalled_dtable;
void __objc_init_protocols(struct objc_protocol_list *protos);
void __objc_compute_ivar_offsets(Class class);
////////////////////////////////////////////////////////////////////////////////
// +load method hash table
////////////////////////////////////////////////////////////////////////////////
static int imp_compare(IMP i1, IMP i2)
{
return i1 == i2;
}
static int imp_hash(const IMP imp)
{
return ((int)imp) >> 4;
}
#define MAP_TABLE_NAME load_messages
#define MAP_TABLE_COMPARE_FUNCTION imp_compare
#define MAP_TABLE_HASH_KEY imp_hash
#define MAP_TABLE_HASH_VALUE imp_hash
#include "hash_table.h"
static load_messages_table *load_table;
SEL loadSel;
void objc_init_load_messages_table(void)
{
load_table = load_messages_create(4096);
loadSel = sel_registerName("load");
}
void objc_send_load_message(Class class)
{
for (struct objc_method_list *l=class->methods ; NULL!=l ; l=l->next)
{
for (int i=0 ; i<l->count ; i++)
{
Method m = &l->methods[i];
if (m->selector->name == loadSel->name)
{
if (load_messages_table_get(load_table, m->imp) == 0)
{
m->imp((id)class, loadSel);
load_messages_insert(load_table, m->imp);
}
}
}
}
}
// Get the functions for string hashing
#include "string_hash.h"
@ -38,6 +91,10 @@ static class_table_internal_table *class_table;
*/
static Class unresolved_class_list;
////////////////////////////////////////////////////////////////////////////////
// Class table manipulation
////////////////////////////////////////////////////////////////////////////////
void class_table_insert(Class class)
{
if (!objc_test_class_flag(class, objc_class_flag_resolved))
@ -65,13 +122,50 @@ Class class_table_next(void **e)
void __objc_init_class_tables(void)
{
class_table = class_table_internal_create(16);
class_table = class_table_internal_create(4096);
objc_init_load_messages_table();
}
void objc_resolve_class(Class cls)
////////////////////////////////////////////////////////////////////////////////
// Loader functions
////////////////////////////////////////////////////////////////////////////////
BOOL objc_resolve_class(Class cls)
{
// Skip this if the class is already resolved.
if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return; }
if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return YES; }
// We can only resolve the class if its superclass is resolved.
if (cls->super_class)
{
Class super = (Class)objc_getClass((char*)cls->super_class);
if (Nil == super) { return NO; }
if (!objc_test_class_flag(cls, objc_class_flag_resolved))
{
if (!objc_resolve_class(super))
{
return NO;
}
}
}
// Give up if we can't resolve the root class yet...
static Class root_class = Nil;
if (Nil == root_class)
{
root_class = (Class)objc_getClass(ROOT_OBJECT_CLASS_NAME);
if (Nil == root_class) { return NO; }
if (!objc_test_class_flag(root_class, objc_class_flag_resolved))
{
objc_resolve_class(root_class);
}
assert(root_class);
}
// Remove the class from the unresolved class list
if (Nil == cls->unresolved_class_prev)
{
@ -90,17 +184,6 @@ void objc_resolve_class(Class cls)
cls->unresolved_class_prev = Nil;
cls->unresolved_class_next = Nil;
static Class root_class = Nil;
if (Nil == root_class)
{
root_class = (Class)objc_getClass(ROOT_OBJECT_CLASS_NAME);
if (!objc_test_class_flag(root_class, objc_class_flag_resolved))
{
objc_resolve_class(root_class);
}
assert(root_class);
}
// Resolve the superclass pointer
// If this class has no superclass, use [NS]Object
@ -132,18 +215,30 @@ void objc_resolve_class(Class cls)
// Mark this class (and its metaclass) as resolved
objc_set_class_flag(cls, objc_class_flag_resolved);
objc_set_class_flag(cls->isa, objc_class_flag_resolved);
// Fix up the ivar offsets
__objc_compute_ivar_offsets(cls);
// Send the +load message, if required
objc_send_load_message(cls->isa);
if (_objc_load_callback)
{
_objc_load_callback(cls, 0);
}
return YES;
}
void __objc_resolve_class_links(void)
{
LOCK_UNTIL_RETURN(__objc_runtime_mutex);
Class class;
while ((class = unresolved_class_list))
Class class = unresolved_class_list;
while ((Nil != class))
{
Class next = class->unresolved_class_next;
objc_resolve_class(class);
class = next;
}
}
// FIXME: Remove this once all uses of it in the runtime have been removed
void __objc_add_class_to_hash(Class class)
{
Class old_class = class_table_get_safe(class->name);
@ -156,7 +251,49 @@ void __objc_add_class_to_hash(Class class)
class_table_insert (class);
}
/**
* Loads a class. This function assumes that the runtime mutex is locked.
*/
void objc_load_class(struct objc_class *class)
{
// The compiler initialises the super class pointer to the name of the
// superclass, not the superclass pointer.
// Note: With the new ABI, the class pointer is public. We could,
// therefore, directly reference the superclass from the compiler and make
// the linker resolve it. This should be done in the GCC-incompatible ABI.
const char *superclassName = (char*)class->super_class;
// Work around a bug in some versions of GCC that don't initialize the
// class structure correctly.
class->subclass_list = NULL;
// Insert the class into the class table
class_table_insert (class);
// Register all of the selectors used by this class and its metaclass
__objc_register_selectors_from_class(class);
__objc_register_selectors_from_class(class->isa);
// Set the uninstalled dtable. The compiler could do this as well.
class->dtable = __objc_uninstalled_dtable;
class->isa->dtable = __objc_uninstalled_dtable;
// If this is a root class, make the class into the metaclass's superclass.
// This means that all instance methods will be available to the class.
if (NULL == superclassName)
{
class->isa->super_class = class;
}
if (class->protocols)
{
__objc_init_protocols (class->protocols);
}
}
////////////////////////////////////////////////////////////////////////////////
// Public API
////////////////////////////////////////////////////////////////////////////////
int objc_getClassList(Class *buffer, int bufferLen)
{
@ -175,6 +312,16 @@ int objc_getClassList(Class *buffer, int bufferLen)
return count;
}
Class class_getSuperclass(Class cls)
{
if (!objc_test_class_flag(cls, objc_class_flag_resolved))
{
objc_resolve_class(cls);
}
return cls->super_class;
}
id objc_getClass(const char *name)
{
id class = (id)class_table_get_safe(name);

530
init.c

@ -38,9 +38,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define OBJC2_PROTOCOL_VERSION 3
void __objc_sync_init(void);
/* This list contains all modules currently loaded into the runtime. */
static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */
void __objc_resolve_class_links(void);
void objc_load_class(struct objc_class *class);
/* This list contains all proto_list's not yet assigned class links. */
static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */
@ -55,381 +54,20 @@ objc_mutex_t __objc_runtime_mutex = &objc_runtime_mutex;
/* Number of threads that are alive. */
int __objc_runtime_threads_alive = 1; /* !T:MUTEX */
void __objc_register_selector_array(SEL selectors, unsigned long count);
/* Check compiler vs runtime version. */
static void init_check_module_version (Module_t);
/* Assign isa links to protos. */
static void __objc_init_protocols (struct objc_protocol_list *protos);
void __objc_init_protocols (struct objc_protocol_list *protos);
/* Add protocol to class. */
static void __objc_class_add_protocols (Class, struct objc_protocol_list *);
/* This is a hook which is called by __objc_exec_class every time a
class or a category is loaded into the runtime. This may e.g. help
a dynamic loader determine the classes that have been loaded when
an object file is dynamically linked in. */
void (*_objc_load_callback) (Class class, Category *category); /* !T:SAFE */
/* Is all categories/classes resolved? */
BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
void __objc_register_selector_array(SEL selectors, unsigned long count);
/* Sends +load to all classes and categories in certain situations. */
static void objc_send_load (void);
/* Inserts all the classes defined in module in a tree of classes that
resembles the class hierarchy. This tree is traversed in preorder
and the classes in its nodes receive the +load message if these
methods were not executed before. The algorithm ensures that when
the +load method of a class is executed all the superclasses have
been already received the +load message. */
static void __objc_create_classes_tree (Module_t module);
static void __objc_call_callback (Module_t module);
/* A special version that works only before the classes are completely
installed in the runtime. */
static BOOL class_is_subclass_of_class (Class class, Class superclass);
extern void *__objc_uninstalled_dtable;
typedef struct objc_class_tree {
Class class;
struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */
} objc_class_tree;
/* This is a linked list of objc_class_tree trees. The head of these
trees are root classes (their super class is Nil). These different
trees represent different class hierarchies. */
static struct objc_list *__objc_class_tree_list = NULL;
/* Keeps the +load methods who have been already executed. This hash
should not be destroyed during the execution of the program. */
static cache_ptr __objc_load_methods = NULL;
/* This function is used when building the class tree used to send
ordinately the +load message to all classes needing it. The tree
is really needed so that superclasses will get the message before
subclasses.
This tree will contain classes which are being loaded (or have just
being loaded), and whose super_class pointers have not yet been
resolved. This implies that their super_class pointers point to a
string with the name of the superclass; when the first message is
sent to the class (/an object of that class) the class links will
be resolved, which will replace the super_class pointers with
pointers to the actual superclasses.
Unfortunately, the tree might also contain classes which had been
loaded previously, and whose class links have already been
resolved.
This function returns the superclass of a class in both cases, and
can be used to build the determine the class relationships while
building the tree.
*/
static Class class_superclass_of_class (Class class)
{
char *super_class_name;
/* If the class links have been resolved, use the resolved
* links. */
if (CLS_ISRESOLV (class))
return class->super_class;
/* Else, 'class' has not yet been resolved. This means that its
* super_class pointer is really the name of the super class (rather
* than a pointer to the actual superclass). */
super_class_name = (char *)class->super_class;
/* Return Nil for a root class. */
if (super_class_name == NULL)
return Nil;
/* Lookup the superclass of non-root classes. */
return objc_lookup_class (super_class_name);
}
/* Creates a tree of classes whose topmost class is directly inherited
from `upper' and the bottom class in this tree is
`bottom_class'. The classes in this tree are super classes of
`bottom_class'. `subclasses' member of each tree node point to the
next subclass tree node. */
static objc_class_tree *
create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper)
{
Class superclass = bottom_class->super_class ?
objc_lookup_class ((char *) bottom_class->super_class)
: Nil;
objc_class_tree *tree, *prev;
DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:");
DEBUG_PRINTF ("bottom_class = %s, upper = %s\n",
(bottom_class ? bottom_class->name : NULL),
(upper ? upper->name : NULL));
tree = prev = objc_calloc (1, sizeof (objc_class_tree));
prev->class = bottom_class;
while (superclass != upper)
{
tree = objc_calloc (1, sizeof (objc_class_tree));
tree->class = superclass;
tree->subclasses = list_cons (prev, tree->subclasses);
superclass = class_superclass_of_class (superclass);
prev = tree;
}
return tree;
}
/* Insert the `class' into the proper place in the `tree' class
hierarchy. This function returns a new tree if the class has been
successfully inserted into the tree or NULL if the class is not
part of the classes hierarchy described by `tree'. This function is
private to objc_tree_insert_class (), you should not call it
directly. */
static objc_class_tree *
__objc_tree_insert_class (objc_class_tree *tree, Class class)
{
DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n",
(int)tree, class->name);
if (tree == NULL)
return create_tree_of_subclasses_inherited_from (class, NULL);
else if (class == tree->class)
{
/* `class' has been already inserted */
DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name);
return tree;
}
else if (class_superclass_of_class (class) == tree->class)
{
/* If class is a direct subclass of tree->class then add class to the
list of subclasses. First check to see if it wasn't already
inserted. */
struct objc_list *list = tree->subclasses;
objc_class_tree *node;
while (list)
{
/* Class has been already inserted; do nothing just return
the tree. */
if (((objc_class_tree *) list->head)->class == class)
{
DEBUG_PRINTF ("2. class %s was previously inserted\n",
class->name);
return tree;
}
list = list->tail;
}
/* Create a new node class and insert it into the list of subclasses */
node = objc_calloc (1, sizeof (objc_class_tree));
node->class = class;
tree->subclasses = list_cons (node, tree->subclasses);
DEBUG_PRINTF ("3. class %s inserted\n", class->name);
return tree;
}
else
{
/* The class is not a direct subclass of tree->class. Search for
class's superclasses in the list of subclasses. */
struct objc_list *subclasses = tree->subclasses;
/* Precondition: the class must be a subclass of tree->class;
otherwise return NULL to indicate our caller that it must
take the next tree. */
if (! class_is_subclass_of_class (class, tree->class))
return NULL;
for (; subclasses != NULL; subclasses = subclasses->tail)
{
Class aClass = ((objc_class_tree *) (subclasses->head))->class;
if (class_is_subclass_of_class (class, aClass))
{
/* If we found one of class's superclasses we insert the
class into its subtree and return the original tree
since nothing has been changed. */
subclasses->head
= __objc_tree_insert_class (subclasses->head, class);
DEBUG_PRINTF ("4. class %s inserted\n", class->name);
return tree;
}
}
/* We haven't found a subclass of `class' in the `subclasses'
list. Create a new tree of classes whose topmost class is a
direct subclass of tree->class. */
{
objc_class_tree *new_tree
= create_tree_of_subclasses_inherited_from (class, tree->class);
tree->subclasses = list_cons (new_tree, tree->subclasses);
DEBUG_PRINTF ("5. class %s inserted\n", class->name);
return tree;
}
}
}
/* This function inserts `class' in the right tree hierarchy classes. */
static void
objc_tree_insert_class (Class class)
{
struct objc_list *list_node;
objc_class_tree *tree;
list_node = __objc_class_tree_list;
while (list_node)
{
tree = __objc_tree_insert_class (list_node->head, class);
if (tree)
{
list_node->head = tree;
break;
}
else
list_node = list_node->tail;
}
/* If the list was finished but the class hasn't been inserted,
insert it here. */
if (! list_node)
{
__objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
__objc_class_tree_list->head = __objc_tree_insert_class (NULL, class);
}
}
/* Traverse tree in preorder. Used to send +load. */
static void
objc_preorder_traverse (objc_class_tree *tree,
int level,
void (*function) (objc_class_tree *, int))
{
struct objc_list *node;
(*function) (tree, level);
for (node = tree->subclasses; node; node = node->tail)
objc_preorder_traverse (node->head, level + 1, function);
}
/* Traverse tree in postorder. Used to destroy a tree. */
static void
objc_postorder_traverse (objc_class_tree *tree,
int level,
void (*function) (objc_class_tree *, int))
{
struct objc_list *node;
for (node = tree->subclasses; node; node = node->tail)
objc_postorder_traverse (node->head, level + 1, function);
(*function) (tree, level);
}
/* Used to print a tree class hierarchy. */
#ifdef DEBUG
static void
__objc_tree_print (objc_class_tree *tree, int level)
{
int i;
for (i = 0; i < level; i++)
printf (" ");
printf ("%s\n", tree->class->name);
}
#endif
/* Walks on a linked list of methods in the reverse order and executes
all the methods corresponding to `op' selector. Walking in the
reverse order assures the +load of class is executed first and then
+load of categories because of the way in which categories are
added to the class methods. */
static void
__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op)
{
int i;
if (! method_list)
return;
/* First execute the `op' message in the following method lists */
__objc_send_message_in_list (method_list->method_next, class, op);
/* Search the method list. */
for (i = 0; i < method_list->method_count; i++)
{
Method_t mth = &method_list->method_list[i];
if (mth->method_name && sel_eq (mth->method_name, op)
&& ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp))
{
/* Add this method into the +load hash table */
objc_hash_add (&__objc_load_methods,
mth->method_imp,
mth->method_imp);
DEBUG_PRINTF ("sending +load in class: %s\n", class->name);
/* The method was found and wasn't previously executed. */
(*mth->method_imp) ((id)class, mth->method_name);
break;
}
}
}
static void
__objc_send_load (objc_class_tree *tree,
int level __attribute__ ((__unused__)))
{
static SEL load_sel = 0;
Class class = tree->class;
MethodList_t method_list = class->class_pointer->methods;
if (! load_sel)
load_sel = sel_register_name ("load");
__objc_send_message_in_list (method_list, class, load_sel);
}
static void
__objc_destroy_class_tree_node (objc_class_tree *tree,
int level __attribute__ ((__unused__)))
{
objc_free (tree);
}
/* This is used to check if the relationship between two classes
before the runtime completely installs the classes. */
static BOOL
class_is_subclass_of_class (Class class, Class superclass)
{
for (; class != Nil;)
{
if (class == superclass)
return YES;
class = class_superclass_of_class (class);
}
return NO;
}
/* This list contains all the classes in the runtime system for whom
their superclasses are not yet known to the runtime. */
static struct objc_list *unresolved_classes = 0;
/* Extern function used to reference the Object and NXConstantString
classes. */
@ -557,16 +195,11 @@ __objc_exec_class (Module_t module)
__objc_init_protocol_table ();
__objc_init_class_tables ();
__objc_init_dispatch_tables ();
__objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
__objc_load_methods = objc_hash_new (128,
(hash_func_type)objc_hash_ptr,
objc_compare_ptrs);
previous_constructors = 1;
}
/* Save the module pointer for later processing. (not currently used) */
LOCK(__objc_runtime_mutex);
__objc_module_list = list_cons (module, __objc_module_list);
/* Replace referenced selectors from names to SEL's. */
if (symtab->refs)
@ -578,40 +211,7 @@ __objc_exec_class (Module_t module)
DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
for (i = 0; i < symtab->cls_def_cnt; ++i)
{
Class class = (Class) symtab->defs[i];
const char *superclass = (char *) class->super_class;
/* Make sure we have what we think. */
assert (CLS_ISCLASS (class));
assert (CLS_ISMETA (class->class_pointer));
DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
/* Initialize the subclass list to be NULL.
In some cases it isn't and this crashes the program. */
class->subclass_list = NULL;
/* Store the class in the class table and assign class numbers. */
__objc_add_class_to_hash (class);
/* Register all of the selectors in the class and meta class. */
__objc_register_selectors_from_class (class);
__objc_register_selectors_from_class ((Class) class->class_pointer);
/* Install the fake dispatch tables */
class->dtable = __objc_uninstalled_dtable;
class->class_pointer->dtable = __objc_uninstalled_dtable;
/* Register the instance methods as class methods, this is
only done for root classes. */
__objc_register_instance_methods_to_class (class);
if (class->protocols)
__objc_init_protocols (class->protocols);
/* Check to see if the superclass is known in this point. If it's not
add the class to the unresolved_classes list. */
if (superclass && ! objc_lookup_class (superclass))
unresolved_classes = list_cons (class, unresolved_classes);
objc_load_class((Class) symtab->defs[i]);
}
/* Process category information from the module. */
@ -703,126 +303,13 @@ __objc_exec_class (Module_t module)
unclaimed_proto_list = 0;
}
objc_send_load ();
__objc_resolve_class_links();
UNLOCK(__objc_runtime_mutex);
}
static void
objc_send_load (void)
{
if (! __objc_module_list)
return;
/* Try to find out if all the classes loaded so far also have their
superclasses known to the runtime. We suppose that the objects
that are allocated in the +load method are in general of a class
declared in the same module. */
if (unresolved_classes)
{
Class class = unresolved_classes->head;
while (objc_lookup_class ((char *) class->super_class))
{
list_remove_head (&unresolved_classes);
if (unresolved_classes)
class = unresolved_classes->head;
else
break;
}
/* If we still have classes for whom we don't have yet their
super classes known to the runtime we don't send the +load
messages. */
if (unresolved_classes)
return;
}
/* Special check to allow creating and sending messages to constant
strings in +load methods. If these classes are not yet known,
even if all the other classes are known, delay sending of +load. */
if (! objc_lookup_class (CONSTANT_STRING_CLASS) ||
! objc_lookup_class (ROOT_OBJECT_CLASS_NAME))
return;
/* Iterate over all modules in the __objc_module_list and call on
them the __objc_create_classes_tree function. This function
creates a tree of classes that resembles the class hierarchy. */
list_mapcar (__objc_module_list,
(void (*) (void *)) __objc_create_classes_tree);
while (__objc_class_tree_list)
{
#ifdef DEBUG
objc_preorder_traverse (__objc_class_tree_list->head,
0, __objc_tree_print);
#endif
objc_preorder_traverse (__objc_class_tree_list->head,
0, __objc_send_load);
objc_postorder_traverse (__objc_class_tree_list->head,
0, __objc_destroy_class_tree_node);
list_remove_head (&__objc_class_tree_list);
}
list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_callback);
list_free (__objc_module_list);
__objc_module_list = NULL;
}
void __objc_compute_ivar_offsets(Class class);
static void
__objc_create_classes_tree (Module_t module)
{
/* The runtime mutex is locked in this point */
Symtab_t symtab = module->symtab;
int i;
/* Iterate thru classes defined in this module and insert them in
the classes tree hierarchy. */
for (i = 0; i < symtab->cls_def_cnt; i++)
{
Class class = (Class) symtab->defs[i];
objc_tree_insert_class (class);
__objc_compute_ivar_offsets (class);
}
}
static void
__objc_call_callback (Module_t module)
{
/* The runtime mutex is locked in this point. */
Symtab_t symtab = module->symtab;
int i;
/* Iterate thru classes defined in this module and call the callback
for each one. */
for (i = 0; i < symtab->cls_def_cnt; i++)
{
Class class = (Class) symtab->defs[i];
/* Call the _objc_load_callback for this class. */
if (_objc_load_callback)
_objc_load_callback (class, 0);
}
/* Call the _objc_load_callback for categories. Don't register the
instance methods as class methods for categories to root classes
since they were already added in the class. */
for (i = 0; i < symtab->cat_def_cnt; i++)
{
Category_t category = symtab->defs[i + symtab->cls_def_cnt];
Class class = objc_lookup_class (category->class_name);
if (_objc_load_callback)
_objc_load_callback (class, category);
}
}
/* Sanity check the version of gcc used to compile `module'. */
static void
@ -846,8 +333,7 @@ init_check_module_version (Module_t module)
}
struct objc_protocol *__objc_unique_protocol(struct objc_protocol*);
static void
__objc_init_protocols (struct objc_protocol_list *protos)
void __objc_init_protocols (struct objc_protocol_list *protos)
{
size_t i;
static Class proto_class = 0;

@ -7,7 +7,7 @@
#ifndef OBJC_HOOK
#define OBJC_HOOK extern
#endif
struct objc_category;
/**
* Class lookup hook. Set this to provide a mechanism for resolving classes
* that have not been registered with the runtime. This can be used for lazy
@ -18,3 +18,7 @@
* for lazy loading of categories.
*/
OBJC_HOOK Class (*_objc_lookup_class)(const char *name);
/**
* Class load callback.
*/
OBJC_HOOK void (*_objc_load_callback)(Class class, struct objc_category *category);

@ -418,11 +418,6 @@ const char * class_getName(Class cls)
return cls->name;
}
Class class_getSuperclass(Class cls)
{
return class_get_super_class(cls);
}
int class_getVersion(Class theClass)
{
return class_get_version(theClass);

Loading…
Cancel
Save