diff --git a/GNUmakefile b/GNUmakefile index f1c7d88..bdc7361 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -24,20 +24,25 @@ libobjc_C_FILES = \ encoding.c\ hash_table.c\ exception.c\ - gc.c\ hash.c\ + hooks.c\ ivar.c\ init.c\ misc.c\ nil_method.c\ - objects.c\ protocol.c\ runtime.c\ sarray2.c\ selector.c\ selector_table.c\ - sendmsg.c\ + sendmsg.c + +ifneq ($(enable_legacy), no) +libobjc_C_FILES += \ + gc.c\ + objects.c\ thr.c +endif libobjc_HEADER_FILES_DIR = objc libobjc_HEADER_FILES_INSTALL_DIR = objc diff --git a/class.c b/class.c index 00cfecb..76ca09a 100644 --- a/class.c +++ b/class.c @@ -118,11 +118,6 @@ Class class_table_next (void **e); ** Objective-C runtime functions **/ -/* This is a hook which is called by objc_get_class and - objc_lookup_class if the runtime is not able to find the class. - This may e.g. try to load in the class using dynamic loading. */ -Class (*_objc_lookup_class) (const char *name) = 0; /* !T:SAFE */ - Class class_table_get_safe(const char*); /* This function adds a class to the class hash table, and assigns the @@ -154,79 +149,3 @@ __objc_add_class_to_hash (Class class) UNLOCK(__objc_runtime_mutex); } - -/* Get the class object for the class named NAME. If NAME does not - identify a known class, the hook _objc_lookup_class is called. If - this fails, nil is returned. */ -Class -objc_lookup_class (const char *name) -{ - Class class; - - class = class_table_get_safe (name); - - if (class) - return class; - - if (_objc_lookup_class) - return (*_objc_lookup_class) (name); - else - return 0; -} - -/* Get the class object for the class named NAME. If NAME does not - identify a known class, the hook _objc_lookup_class is called. If - this fails, an error message is issued and the system aborts. */ -Class -objc_get_class (const char *name) -{ - Class class; - - class = class_table_get_safe (name); - - if (class) - return class; - - if (_objc_lookup_class) - class = (*_objc_lookup_class) (name); - - if (class) - return class; - - objc_error (nil, OBJC_ERR_BAD_CLASS, - "objc runtime: cannot find class %s\n", name); - return 0; -} - -MetaClass -objc_get_meta_class (const char *name) -{ - return objc_get_class (name)->class_pointer; -} - -/* This function provides a way to enumerate all the classes in the - executable. Pass *ENUM_STATE == NULL to start the enumeration. The - function will return 0 when there are no more classes. - For example: - id class; - void *es = NULL; - while ((class = objc_next_class (&es))) - ... do something with class; -*/ -Class -objc_next_class (void **enum_state) -{ - Class class; - - class = class_table_next ( enum_state); - - return class; -} - -Class -class_pose_as (Class impostor, Class super_class) -{ - fprintf(stderr, "Class posing is no longer supported.\n"); - fprintf(stderr, "Please use class_replaceMethod() instead.\n"); - abort(); -} diff --git a/class_table.c b/class_table.c index 3845de4..ccab6ae 100644 --- a/class_table.c +++ b/class_table.c @@ -1,5 +1,7 @@ #include "magic_objects.h" -#include "objc/objc-api.h" +#include "objc/runtime.h" +#include "objc/hooks.h" +#include "class.h" #include "lock.h" #include #include @@ -38,7 +40,7 @@ static Class unresolved_class_list; void class_table_insert(Class class) { - if (!CLS_ISRESOLV(class)) + if (!objc_test_class_flag(class, objc_class_flag_resolved)) { if (Nil != unresolved_class_list) { @@ -69,7 +71,7 @@ void __objc_init_class_tables(void) void objc_resolve_class(Class cls) { // Skip this if the class is already resolved. - if (CLS_ISRESOLV(cls)) { return; } + if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return; } // Remove the class from the unresolved class list if (Nil == cls->unresolved_class_prev) { @@ -91,8 +93,8 @@ void objc_resolve_class(Class cls) static Class root_class = Nil; if (Nil == root_class) { - root_class = objc_get_class(ROOT_OBJECT_CLASS_NAME); - if (!CLS_ISRESOLV(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); } @@ -107,15 +109,15 @@ void objc_resolve_class(Class cls) if (NULL != cls->super_class) { // Resolve the superclass if it isn't already resolved - super = objc_get_class((char*)cls->super_class); - if (!CLS_ISRESOLV(super)) + super = (Class)objc_getClass((char*)cls->super_class); + if (!objc_test_class_flag(super, objc_class_flag_resolved)) { objc_resolve_class(super); } - superMeta = super->class_pointer; + superMeta = super->isa; // Set the superclass pointer for the class and the superclass cls->super_class = super; - cls->class_pointer->super_class = super->class_pointer; + cls->isa->super_class = super->isa; } // Don't make the root class a subclass of itself if (cls != super) @@ -124,25 +126,26 @@ void objc_resolve_class(Class cls) cls->sibling_class = super->subclass_list; super->subclass_list = cls; // Set up the metaclass links - cls->class_pointer->sibling_class = superMeta->subclass_list; - superMeta->subclass_list = cls->class_pointer; + cls->isa->sibling_class = superMeta->subclass_list; + superMeta->subclass_list = cls->isa; } // Mark this class (and its metaclass) as resolved - CLS_SETRESOLV(cls); - CLS_SETRESOLV(cls->class_pointer); + objc_set_class_flag(cls, objc_class_flag_resolved); + objc_set_class_flag(cls->isa, objc_class_flag_resolved); } void __objc_resolve_class_links(void) { - LOCK(__objc_runtime_mutex); + LOCK_UNTIL_RETURN(__objc_runtime_mutex); Class class; while ((class = unresolved_class_list)) { objc_resolve_class(class); } - UNLOCK(__objc_runtime_mutex); } +// Public API + int objc_getClassList(Class *buffer, int bufferLen) { if (buffer == NULL) @@ -160,3 +163,57 @@ int objc_getClassList(Class *buffer, int bufferLen) return count; } +id objc_getClass(const char *name) +{ + id class = (id)class_table_get_safe(name); + + if (nil != class) { return class; } + + if (0 != _objc_lookup_class) + { + class = (id)_objc_lookup_class(name); + } + + return class; +} + +id objc_lookUpClass(const char *name) +{ + return (id)class_table_get_safe(name); +} + + +id objc_getMetaClass(const char *name) +{ + Class cls = (Class)objc_getClass(name); + return cls == Nil ? nil : (id)cls->isa; +} + +// Legacy interface compatibility + +id objc_get_class(const char *name) +{ + return objc_getClass(name); +} + +id objc_lookup_class(const char *name) +{ + return objc_getClass(name); +} + +id objc_get_meta_class(const char *name) +{ + return objc_getMetaClass(name); +} + +Class objc_next_class(void **enum_state) +{ + return class_table_next ( enum_state); +} + +Class class_pose_as(Class impostor, Class super_class) +{ + fprintf(stderr, "Class posing is no longer supported.\n"); + fprintf(stderr, "Please use class_replaceMethod() instead.\n"); + abort(); +} diff --git a/hash_table.h b/hash_table.h index 7ee4fb1..040aae8 100644 --- a/hash_table.h +++ b/hash_table.h @@ -20,6 +20,7 @@ #include "lock.h" #include #include +#include #ifndef MAP_TABLE_NAME # error You must define MAP_TABLE_NAME. diff --git a/hooks.c b/hooks.c new file mode 100644 index 0000000..c43691b --- /dev/null +++ b/hooks.c @@ -0,0 +1,3 @@ +#include +#define OBJC_HOOK +#include diff --git a/lock.h b/lock.h index a964efa..ad11892 100644 --- a/lock.h +++ b/lock.h @@ -45,9 +45,18 @@ __attribute__((unused)) static void objc_release_lock(void *x) mutex_t *lock = *(mutex_t**)x; UNLOCK(lock); } +/** + * Acquires the lock and automatically releases it at the end of the current + * scope. + */ #define LOCK_UNTIL_RETURN(lock) \ __attribute__((cleanup(objc_release_lock)))\ __attribute__((unused)) mutex_t *lock_pointer = lock;\ LOCK(lock) +/** + * The global runtime mutex. + */ +extern void *__objc_runtime_mutex; + #endif // __LIBOBJC_LOCK_H_INCLUDED__ diff --git a/objc/hooks.h b/objc/hooks.h new file mode 100644 index 0000000..b3d9ce5 --- /dev/null +++ b/objc/hooks.h @@ -0,0 +1,20 @@ +/** + * This file includes all of the hooks that can be used to alter the behaviour + * of the runtime. + */ + + +#ifndef OBJC_HOOK +#define OBJC_HOOK extern +#endif + +/** + * 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 + * library loading, for example. The hook takes a class name as an argument + * and returns the class. A JIT compiler could use this to allow classes to be + * compiled the first time that they are looked up. If the class is already + * registered with the runtime, this will not be called, so it can not be used + * for lazy loading of categories. + */ +OBJC_HOOK Class (*_objc_lookup_class)(const char *name); diff --git a/runtime.c b/runtime.c index 6eaea21..08e94a6 100644 --- a/runtime.c +++ b/runtime.c @@ -636,17 +636,6 @@ IMP method_setImplementation(Method method, IMP imp) return old; } -id objc_getClass(const char *name) -{ - return (id)objc_get_class(name); -} - -id objc_getMetaClass(const char *name) -{ - Class cls = (Class)objc_getClass(name); - return cls == Nil ? nil : (id)cls->class_pointer; -} - id objc_getRequiredClass(const char *name) { id cls = objc_getClass(name); @@ -657,12 +646,6 @@ id objc_getRequiredClass(const char *name) return cls; } -id objc_lookUpClass(const char *name) -{ - // TODO: Check these are the right way around. - return (id)objc_lookup_class(name); -} - static void freeMethodLists(Class aClass) { struct objc_method_list *methods = aClass->methods;