Skip to content

Commit

Permalink
Finished rewriting the loader. It's now cleanly separated into logica…
Browse files Browse the repository at this point in the history
…lly-separate components, so there's a chance it might actually be maintainable...
  • Loading branch information
theraven committed Jun 2, 2010
1 parent 7c72069 commit bb8cafa
Show file tree
Hide file tree
Showing 19 changed files with 787 additions and 468 deletions.
6 changes: 4 additions & 2 deletions GNUmakefile
Expand Up @@ -20,20 +20,22 @@ libobjc_OBJC_FILES = \

libobjc_C_FILES = \
abi_version.c\
category_loader.c\
class_table.c\
encoding.c\
hash_table.c\
exception.c\
hooks.c\
ivar.c\
init.c\
loader.c\
misc.c\
nil_method.c\
protocol.c\
runtime.c\
sarray2.c\
selector_table.c\
sendmsg.c
sendmsg.c\
statics_loader.c

ifneq ($(enable_legacy), no)
libobjc_C_FILES += \
Expand Down
62 changes: 62 additions & 0 deletions buffer.h
@@ -0,0 +1,62 @@
/**
* buffer.h defines a simple dynamic array that is used to store temporary
* values for later processing. Define BUFFER_TYPE before including this file.
*/

#include <stdlib.h>

#define BUFFER_SIZE 128
static BUFFER_TYPE *buffered_object_buffer[BUFFER_SIZE];
static BUFFER_TYPE **buffered_object_overflow;
static int buffered_objects;
static int buffered_object_overflow_space;

static void set_buffered_object_at_index(BUFFER_TYPE *cat, unsigned int i)
{
if (i < BUFFER_SIZE)
{
buffered_object_buffer[i] = cat;
}
else
{
i -= BUFFER_SIZE;
if (NULL == buffered_object_overflow)
{
buffered_object_overflow =
calloc(BUFFER_SIZE, sizeof(BUFFER_TYPE*));
buffered_object_overflow_space = BUFFER_SIZE;
}
while (i > buffered_object_overflow_space)
{
buffered_object_overflow_space <<= 1;
buffered_object_overflow = realloc(buffered_object_overflow,
buffered_object_overflow_space * sizeof(BUFFER_TYPE*));
}
buffered_object_overflow[i] = cat;
}
}

static BUFFER_TYPE *buffered_object_at_index(unsigned int i)
{
if (i<BUFFER_SIZE)
{
return buffered_object_buffer[i];
}
return buffered_object_overflow[i-BUFFER_SIZE];
}

static void compact_buffer(void)
{
// Move up all of the non-NULL pointers
unsigned size = buffered_objects;
unsigned insert = 0;
for (unsigned i=0 ; i<size ; i++)
{
BUFFER_TYPE *c = buffered_object_at_index(i);
if (c != NULL)
{
set_buffered_object_at_index(c, insert++);
}
}
buffered_objects = insert;
}
35 changes: 35 additions & 0 deletions category.h
@@ -0,0 +1,35 @@

/**
* The structure used to represent a category.
*
* This provides a set of new definitions that are used to replace those
* contained within a class.
*
* Note: Objective-C 2 allows properties to be added to classes. The current
* ABI does not provide a field for adding properties in categories. This is
* likely to be added with ABI version 10. Until then, the methods created by
* a declared property will work, but introspection on the property will not.
*/
struct objc_category
{
/**
* The name of this category.
*/
const char *name;
/**
* The name of the class to which this category should be applied.
*/
const char *class_name;
/**
* The list of instance methods to add to the class.
*/
struct objc_method_list *instance_methods;
/**
* The list of class methods to add to the class.
*/
struct objc_method_list *class_methods;
/**
* The list of protocols adopted by this category.
*/
struct objc_protocol_list *protocols;
};
81 changes: 81 additions & 0 deletions category_loader.c
@@ -0,0 +1,81 @@
#include <stdio.h>
#include "objc/runtime.h"
#include "loader.h"

#define BUFFER_TYPE struct objc_category
#include "buffer.h"

static void register_methods(struct objc_class *cls, struct objc_method_list *l)
{
if (NULL == l) { return; }

// Replace the method names with selectors.
objc_register_selectors_from_list(l);
// Add the method list at the head of the list of lists.
l->next = cls->methods;
cls->methods = l;
// Update the dtable to catch the new methods.
// FIXME: We can make this more efficient by simply passing the new method
// list to the dtable and telling it only to update those methods.
objc_update_dtable_for_class(cls);
}

static void load_category(struct objc_category *cat, struct objc_class *class)
{
register_methods(class, cat->instance_methods);
register_methods(class->isa, cat->class_methods);

if (cat->protocols)
{
objc_init_protocols(cat->protocols);
cat->protocols->next = class->protocols;
class->protocols = cat->protocols;
}
}

static BOOL try_load_category(struct objc_category *cat)
{
Class class = (Class)objc_getClass(cat->class_name);
if (Nil != class)
{
load_category(cat, class);
return YES;
}
return NO;
}

/**
* Attaches a category to its class, if the class is already loaded. Buffers
* it for future resolution if not.
*/
void objc_try_load_category(struct objc_category *cat)
{
if (!try_load_category(cat))
{
set_buffered_object_at_index(cat, buffered_objects++);
}
}

void objc_load_buffered_categories(void)
{
BOOL shouldReshuffle = NO;

for (unsigned i=0 ; i<buffered_objects ; i++)
{
struct objc_category *c = buffered_object_at_index(i);
if (NULL != c)
{
if (try_load_category(c))
{
set_buffered_object_at_index(NULL, i);
shouldReshuffle = YES;
}
}
}

if (shouldReshuffle)
{
compact_buffer();
}
}

4 changes: 3 additions & 1 deletion class.h
@@ -1,4 +1,5 @@

#ifndef __OBJC_CLASS_H_INCLUDED
#define __OBJC_CLASS_H_INCLUDED
#ifndef __objc_runtime_INCLUDE_GNU
struct objc_class
{
Expand Down Expand Up @@ -163,3 +164,4 @@ static inline BOOL objc_test_class_flag(struct objc_class *aClass,
{
return aClass->info & (long)flag;
}
#endif //__OBJC_CLASS_H_INCLUDED
27 changes: 19 additions & 8 deletions class_table.c
Expand Up @@ -8,10 +8,10 @@
#include <stdlib.h>
#include <assert.h>

void __objc_register_selectors_from_class(Class class);
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);
void objc_init_protocols(struct objc_protocol_list *protos);
void objc_compute_ivar_offsets(Class class);

////////////////////////////////////////////////////////////////////////////////
// +load method hash table
Expand Down Expand Up @@ -216,7 +216,7 @@ BOOL objc_resolve_class(Class cls)
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);
objc_compute_ivar_offsets(cls);
// Send the +load message, if required
objc_send_load_message(cls->isa);
if (_objc_load_callback)
Expand All @@ -226,7 +226,7 @@ BOOL objc_resolve_class(Class cls)
return YES;
}

void __objc_resolve_class_links(void)
void objc_resolve_class_links(void)
{
LOCK_UNTIL_RETURN(__objc_runtime_mutex);
Class class = unresolved_class_list;
Expand All @@ -247,6 +247,17 @@ void __objc_resolve_class_links(void)
}
} while (resolvedClass);
}
void __objc_resolve_class_links(void)
{
static BOOL warned = NO;
if (!warned)
{
fprintf(stderr,
"Warning: Calling deprecated private ObjC runtime function %s\n", __func__);
warned = YES;
}
objc_resolve_class_links();
}

// FIXME: Remove this once all uses of it in the runtime have been removed
void __objc_add_class_to_hash(Class class)
Expand Down Expand Up @@ -281,8 +292,8 @@ void objc_load_class(struct objc_class *class)
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);
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;
Expand All @@ -297,7 +308,7 @@ void objc_load_class(struct objc_class *class)

if (class->protocols)
{
__objc_init_protocols (class->protocols);
objc_init_protocols(class->protocols);
}
}

Expand Down
13 changes: 12 additions & 1 deletion dtable.c
Expand Up @@ -195,7 +195,7 @@ static void mergeMethodsFromSuperclass(Class super, Class cls, SparseArray *meth

Class class_getSuperclass(Class);

void __objc_update_dispatch_table_for_class(Class cls)
void objc_update_dtable_for_class(Class cls)
{
// Only update real dtables
if (!classHasDtable(cls)) { return; }
Expand All @@ -210,6 +210,17 @@ void __objc_update_dispatch_table_for_class(Class cls)
mergeMethodsFromSuperclass(cls, cls, methods);
SparseArrayDestroy(methods);
}
void __objc_update_dispatch_table_for_class(Class cls)
{
static BOOL warned = NO;
if (!warned)
{
fprintf(stderr,
"Warning: Calling deprecated private ObjC runtime function %s\n", __func__);
warned = YES;
}
objc_update_dtable_for_class(cls);
}

static SparseArray *create_dtable_for_class(Class class)
{
Expand Down

0 comments on commit bb8cafa

Please sign in to comment.