diff --git a/GNUmakefile b/GNUmakefile index dc0959b..1e50073 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -44,7 +44,7 @@ libobjc_C_FILES = \ libobjcxx_CC_FILES = objcxx_eh.cc libobjcxx_LDFLAGS = -L./obj/$(GNUSTEP_TARGET_LDIR)/ -lstdc++ -lobjc -ifneq ($(enable_legacy), no) +ifeq ($(disable_legacy), yes) libobjc_C_FILES += legacy_malloc.c libobjc_CPPFLAGS += -DNO_LEGACY endif diff --git a/NSBlocks.m b/NSBlocks.m index 223d900..a469e46 100644 --- a/NSBlocks.m +++ b/NSBlocks.m @@ -21,16 +21,16 @@ static void createNSBlockSubclass(Class superclass, Class newClass, //metaClass->class_pointer = superclass->class_pointer; //metaClass->super_class = superclass->class_pointer; metaClass->info = objc_class_flag_meta; - metaClass->dtable = __objc_uninstalled_dtable; + metaClass->dtable = uninstalled_dtable; // Set up the new class newClass->isa = metaClass; newClass->super_class = (Class)superclass->name; newClass->name = name; newClass->info = objc_class_flag_class; - newClass->dtable = __objc_uninstalled_dtable; + newClass->dtable = uninstalled_dtable; - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); class_table_insert(newClass); } diff --git a/alias_table.c b/alias_table.c index cf2c148..ed39040 100644 --- a/alias_table.c +++ b/alias_table.c @@ -62,7 +62,7 @@ static alias_table_internal_table *alias_table; #include "pool.h" -PRIVATE void __objc_init_alias_table(void) +PRIVATE void init_alias_table(void) { alias_table = alias_table_internal_create(128); } diff --git a/class_table.c b/class_table.c index 6bc5697..9c261d2 100644 --- a/class_table.c +++ b/class_table.c @@ -132,7 +132,7 @@ PRIVATE Class class_table_next(void **e) (struct class_table_internal_table_enumerator**)e); } -PRIVATE void __objc_init_class_tables(void) +PRIVATE void init_class_tables(void) { class_table = class_table_internal_create(4096); objc_init_load_messages_table(); @@ -248,7 +248,7 @@ PRIVATE BOOL objc_resolve_class(Class cls) PRIVATE void objc_resolve_class_links(void) { - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); Class class = unresolved_class_list; BOOL resolvedClass; do @@ -347,8 +347,8 @@ static void reload_class(struct objc_class *class, struct objc_class *old) 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; + class->dtable = uninstalled_dtable; + class->isa->dtable = 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. @@ -401,8 +401,8 @@ PRIVATE void objc_load_class(struct objc_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; + class->dtable = uninstalled_dtable; + class->isa->dtable = 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. diff --git a/dtable.c b/dtable.c index 57f0125..899b3d9 100644 --- a/dtable.c +++ b/dtable.c @@ -10,7 +10,7 @@ #include "dtable.h" #include "visibility.h" -PRIVATE dtable_t __objc_uninstalled_dtable; +PRIVATE dtable_t uninstalled_dtable; /** Head of the list of temporary dtables. Protected by initialize_lock. */ PRIVATE InitializingDtable *temporary_dtables; @@ -56,14 +56,14 @@ struct objc_dtable mutex_t lock; }; -PRIVATE void __objc_init_dispatch_tables () +PRIVATE void init_dispatch_tables () { INIT_LOCK(initialize_lock); } Class class_getSuperclass(Class); -PRIVATE void __objc_update_dispatch_table_for_class(Class cls) +PRIVATE void update_dispatch_table_for_class(Class cls) { static BOOL warned = NO; if (!warned) @@ -79,7 +79,7 @@ static dtable_t create_dtable_for_class(Class class) // Don't create a dtable for a class that already has one if (classHasDtable(class)) { return dtable_for_class(class); } - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); // Make sure that another thread didn't create the dtable while we were // waiting on the lock. @@ -231,7 +231,7 @@ PRIVATE void objc_update_dtable_for_class(Class cls) // need to access it if ((NULL == dtable) || (NULL == dtable->slots)) { return; } - LOCK_UNTIL_RETURN(&dtable->lock); + LOCK_FOR_SCOPE(&dtable->lock); update_dtable(dtable); @@ -248,7 +248,7 @@ PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid) return slot; } - LOCK_UNTIL_RETURN(&dtable->lock); + LOCK_FOR_SCOPE(&dtable->lock); if (NULL == dtable->slots) { update_dtable(dtable); @@ -285,10 +285,10 @@ PRIVATE dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls) #else -PRIVATE void __objc_init_dispatch_tables () +PRIVATE void init_dispatch_tables () { INIT_LOCK(initialize_lock); - __objc_uninstalled_dtable = SparseArrayNewWithDepth(dtable_depth); + uninstalled_dtable = SparseArrayNewWithDepth(dtable_depth); } static BOOL installMethodInDtable(Class class, @@ -297,7 +297,7 @@ static BOOL installMethodInDtable(Class class, struct objc_method *method, BOOL replaceExisting) { - assert(__objc_uninstalled_dtable != dtable); + assert(uninstalled_dtable != dtable); uint32_t sel_id = method->selector->index; struct objc_slot *slot = SparseArrayLookup(dtable, sel_id); if (NULL != slot) @@ -357,7 +357,7 @@ static void installMethodsInClass(Class cls, BOOL replaceExisting) { SparseArray *dtable = dtable_for_class(cls); - assert(__objc_uninstalled_dtable != dtable); + assert(uninstalled_dtable != dtable); uint32_t idx = 0; struct objc_method *m; @@ -400,7 +400,7 @@ PRIVATE void objc_update_dtable_for_class(Class cls) if (!classHasDtable(cls)) { return; } //fprintf(stderr, "Updating dtable for %s\n", cls->name); - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); //fprintf(stderr, "Adding methods to %s\n", cls->name); SparseArray *methods = SparseArrayNewWithDepth(dtable_depth); @@ -410,7 +410,7 @@ PRIVATE void objc_update_dtable_for_class(Class cls) mergeMethodsFromSuperclass(cls, cls, methods); SparseArrayDestroy(methods); } -PRIVATE void __objc_update_dispatch_table_for_class(Class cls) +PRIVATE void update_dispatch_table_for_class(Class cls) { static BOOL warned = NO; if (!warned) @@ -427,7 +427,7 @@ static SparseArray *create_dtable_for_class(Class class) // Don't create a dtable for a class that already has one if (classHasDtable(class)) { return dtable_for_class(class); } - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); // Make sure that another thread didn't create the dtable while we were // waiting on the lock. @@ -444,7 +444,7 @@ static SparseArray *create_dtable_for_class(Class class) else { dtable_t super_dtable = dtable_for_class(super); - if (super_dtable == __objc_uninstalled_dtable) + if (super_dtable == uninstalled_dtable) { super_dtable = create_dtable_for_class(super); } @@ -478,19 +478,19 @@ PRIVATE void objc_resize_dtables(uint32_t newSize) // If dtables already have enough space to store all registered selectors, do nothing if (1< newSize) { return; } - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); dtable_depth <<= 1; - uint32_t oldMask = __objc_uninstalled_dtable->mask; + uint32_t oldMask = uninstalled_dtable->mask; - SparseArrayExpandingArray(__objc_uninstalled_dtable); + SparseArrayExpandingArray(uninstalled_dtable); // Resize all existing dtables void *e = NULL; struct objc_class *next; while ((next = class_table_next(&e))) { - if (next->dtable != (void*)__objc_uninstalled_dtable && + if (next->dtable != (void*)uninstalled_dtable && NULL != next->dtable && ((SparseArray*)next->dtable)->mask == oldMask) { @@ -532,7 +532,7 @@ PRIVATE void objc_send_initialize(id object) // NOTE: Ideally, we would actually lock on the class object using // objc_sync_enter(). This should be fixed once sync.m contains a (fast) // special case for classes. - LOCK_UNTIL_RETURN(&initialize_lock); + LOCK_FOR_SCOPE(&initialize_lock); // Make sure that the class is resolved. objc_resolve_class(class); diff --git a/dtable.h b/dtable.h index bf2e792..8b670f1 100644 --- a/dtable.h +++ b/dtable.h @@ -2,6 +2,7 @@ #include "class.h" #include "sarray2.h" #include "objc/slot.h" +#include "visibility.h" #include #ifdef __OBJC_LOW_MEMORY__ @@ -15,7 +16,7 @@ typedef SparseArray* dtable_t; /** * Pointer to the sparse array representing the pretend (uninstalled) dtable. */ -extern dtable_t __objc_uninstalled_dtable; +PRIVATE extern dtable_t uninstalled_dtable; /** * Structure for maintaining a linked list of temporary dtables. When sending * an +initialize message to a class, we create a temporary dtables and store @@ -41,7 +42,7 @@ extern mutex_t initialize_lock; */ static inline int classHasInstalledDtable(struct objc_class *cls) { - return (cls->dtable != __objc_uninstalled_dtable); + return (cls->dtable != uninstalled_dtable); } /** @@ -55,7 +56,7 @@ static inline dtable_t dtable_for_class(Class cls) { return cls->dtable; } - LOCK_UNTIL_RETURN(&initialize_lock); + LOCK_FOR_SCOPE(&initialize_lock); if (classHasInstalledDtable(cls)) { return cls->dtable; @@ -64,7 +65,7 @@ static inline dtable_t dtable_for_class(Class cls) * O(n) where n is the number of +initialize methods on the stack. In * practice, this is a very small number. Profiling with GNUstep showed that * this peaks at 8. */ - dtable_t dtable = __objc_uninstalled_dtable; + dtable_t dtable = uninstalled_dtable; InitializingDtable *buffer = temporary_dtables; while (NULL != buffer) { @@ -77,7 +78,7 @@ static inline dtable_t dtable_for_class(Class cls) } if (dtable == 0) { - dtable = __objc_uninstalled_dtable; + dtable = uninstalled_dtable; } return dtable; } @@ -88,7 +89,7 @@ static inline dtable_t dtable_for_class(Class cls) */ static inline int classHasDtable(struct objc_class *cls) { - return (dtable_for_class(cls) != __objc_uninstalled_dtable); + return (dtable_for_class(cls) != uninstalled_dtable); } /** diff --git a/hash_table.c b/hash_table.c index 0cd5f4f..47b4582 100644 --- a/hash_table.c +++ b/hash_table.c @@ -9,12 +9,11 @@ PRIVATE void objc_collect_garbage_data(void(*cleanup)(void*), void *garbage) { if (0 == garbage_queue) { - LOCK(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); if (0 == garbage_queue) { garbage_queue = dispatch_queue_create("ObjC deferred free queue", 0); } - UNLOCK(__objc_runtime_mutex); } dispatch_async_f(garbage_queue, garbage, cleanup); } diff --git a/loader.c b/loader.c index 149efbc..dd55581 100644 --- a/loader.c +++ b/loader.c @@ -3,19 +3,20 @@ #include "objc/runtime.h" #include "lock.h" #include "loader.h" +#include "visibility.h" /** * Runtime lock. This is exposed in */ -static mutex_t objc_runtime_mutex; -void *__objc_runtime_mutex = &objc_runtime_mutex; +PRIVATE mutex_t runtime_mutex; +LEGACY void *__objc_runtime_mutex = &runtime_mutex; -void __objc_sync_init(void); -void __objc_init_selector_tables(void); -void __objc_init_protocol_table(void); -void __objc_init_class_tables(void); -void __objc_init_dispatch_tables(void); -void __objc_init_alias_table(void); +void sync_init(void); +void init_selector_tables(void); +void init_protocol_table(void); +void init_class_tables(void); +void init_dispatch_tables(void); +void init_alias_table(void); void objc_send_load_message(Class class); /* Number of threads that are alive. */ @@ -42,23 +43,23 @@ void __objc_exec_class(struct objc_module_abi_8 *module) // pure-C main() function spawns two threads which then, concurrently, // call dlopen() or equivalent, and the platform's implementation of // this does not perform any synchronization. - INIT_LOCK(objc_runtime_mutex); + INIT_LOCK(runtime_mutex); // Create the lock used to protect the creation of hidden classes by // @synchronized() - __objc_sync_init(); + sync_init(); // Create the various tables that the runtime needs. - __objc_init_selector_tables(); - __objc_init_protocol_table(); - __objc_init_class_tables(); - __objc_init_dispatch_tables(); - __objc_init_alias_table(); + init_selector_tables(); + init_protocol_table(); + init_class_tables(); + init_dispatch_tables(); + init_alias_table(); first_run = NO; } // The runtime mutex is held for the entire duration of a load. It does // not need to be acquired or released in any of the called load functions. - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); struct objc_symbol_table_abi_8 *symbols = module->symbol_table; // Register all of the selectors used in this module. diff --git a/lock.h b/lock.h index 59ed3fa..3d9e70f 100644 --- a/lock.h +++ b/lock.h @@ -6,7 +6,6 @@ #ifndef __LIBOBJC_LOCK_H_INCLUDED__ #define __LIBOBJC_LOCK_H_INCLUDED__ - #ifdef WIN32 # include typedef HANDLE mutex_t; @@ -52,7 +51,7 @@ __attribute__((unused)) static void objc_release_lock(void *x) * Acquires the lock and automatically releases it at the end of the current * scope. */ -#define LOCK_UNTIL_RETURN(lock) \ +#define LOCK_FOR_SCOPE(lock) \ __attribute__((cleanup(objc_release_lock)))\ __attribute__((unused)) mutex_t *lock_pointer = lock;\ LOCK(lock) @@ -60,6 +59,10 @@ __attribute__((unused)) static void objc_release_lock(void *x) /** * The global runtime mutex. */ -extern void *__objc_runtime_mutex; +extern mutex_t runtime_mutex; + +#define LOCK_RUNTIME() LOCK(&runtime_mutex) +#define UNLOCK_RUNTIME() UNLOCK(&runtime_mutex) +#define LOCK_RUNTIME_FOR_SCOPE() LOCK_FOR_SCOPE(&runtime_mutex) #endif // __LIBOBJC_LOCK_H_INCLUDED__ diff --git a/protocol.c b/protocol.c index 316bba1..f8bfbd5 100644 --- a/protocol.c +++ b/protocol.c @@ -29,7 +29,7 @@ static int protocol_hash(const struct objc_protocol2 *protocol) static protocol_table *known_protocol_table; -void __objc_init_protocol_table(void) +void init_protocol_table(void) { known_protocol_table = protocol_create(128); } diff --git a/runtime.c b/runtime.c index b54237f..350f202 100644 --- a/runtime.c +++ b/runtime.c @@ -559,10 +559,11 @@ void objc_disposeClassPair(Class cls) Class meta = ((id)cls)->isa; // Remove from the runtime system so nothing tries updating the dtable // while we are freeing the class. - LOCK(__objc_runtime_mutex); - safe_remove_from_subclass_list(meta); - safe_remove_from_subclass_list(cls); - UNLOCK(__objc_runtime_mutex); + { + LOCK_RUNTIME_FOR_SCOPE(); + safe_remove_from_subclass_list(meta); + safe_remove_from_subclass_list(cls); + } // Free the method and ivar lists. freeMethodLists(cls); @@ -594,7 +595,7 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt metaClass->name = strdup(name); metaClass->info = objc_class_flag_meta | objc_class_flag_user_created | objc_class_flag_new_abi; - metaClass->dtable = __objc_uninstalled_dtable; + metaClass->dtable = uninstalled_dtable; metaClass->instance_size = sizeof(struct objc_class); // Set up the new class @@ -605,7 +606,7 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt newClass->name = strdup(name); newClass->info = objc_class_flag_class | objc_class_flag_user_created | objc_class_flag_new_abi; - newClass->dtable = __objc_uninstalled_dtable; + newClass->dtable = uninstalled_dtable; newClass->instance_size = superclass->instance_size; return newClass; @@ -658,6 +659,6 @@ const char *object_getClassName(id obj) void objc_registerClassPair(Class cls) { - LOCK_UNTIL_RETURN(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); class_table_insert(cls); } diff --git a/selector_table.c b/selector_table.c index dad5d27..9add1f1 100644 --- a/selector_table.c +++ b/selector_table.c @@ -220,7 +220,7 @@ void objc_resize_dtables(uint32_t); /** * Create data structures to store selectors. */ -PRIVATE void __objc_init_selector_tables() +PRIVATE void init_selector_tables() { selector_list = SparseArrayNew(); INIT_LOCK(selector_table_lock); @@ -329,7 +329,7 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs) //fprintf(stderr, "Not adding new copy\n"); return copy; } - LOCK_UNTIL_RETURN(&selector_table_lock); + LOCK_FOR_SCOPE(&selector_table_lock); copy = selector_lookup(aSel->name, aSel->types); if (NULL != copy && selector_identical(aSel, copy)) { @@ -516,7 +516,7 @@ PRIVATE void objc_register_selector_array(SEL selectors, unsigned long count) * All of the functions in this section are deprecated and should not be used * in new code. */ -#ifdef NO_LEGACY +#ifndef NO_LEGACY SEL sel_get_typed_uid (const char *name, const char *types) { if (NULL == name) { return NULL; } @@ -592,45 +592,3 @@ BOOL sel_eq(SEL s1, SEL s2) } #endif // NO_LEGACY - -/* - * Some simple sanity tests. - */ -#ifdef SEL_TEST -static void logSelector(SEL sel) -{ - fprintf(stderr, "%s = {%p, %s}\n", sel_getNameNonUnique(sel), sel->name, sel_getType_np(sel)); -} -void objc_resize_dtables(uint32_t ignored) {} - -int main(void) -{ - __objc_init_selector_tables(); - SEL a = sel_registerTypedName_np("foo:", "1234"); - logSelector(a); - a = sel_registerName("bar:"); - a = sel_registerName("foo:"); - logSelector(a); - logSelector(sel_get_any_typed_uid("foo:")); - a = sel_registerTypedName_np("foo:", "1234"); - logSelector(a); - logSelector(sel_get_any_typed_uid("foo:")); - a = sel_registerTypedName_np("foo:", "456"); - logSelector(a); - unsigned count = sel_copyTypes("foo:", NULL, 0); - const char *types[count]; - sel_copyTypes("foo:", types, count); - for (unsigned i=0 ; ivalue, ((struct sel_type_list *)SparseArrayLookup(selector_list, idx))->value); - } - fprintf(stderr, "Number of types: %d\n", count); - SEL sel; -} -#endif diff --git a/sendmsg2.c b/sendmsg2.c index 51f98cb..ce43c75 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -63,7 +63,7 @@ retry:; Class class = (*receiver)->isa; dtable_t dtable = dtable_for_class(class); /* Install the dtable if it hasn't already been initialized. */ - if (dtable == __objc_uninstalled_dtable) + if (dtable == uninstalled_dtable) { objc_send_initialize(*receiver); dtable = dtable_for_class(class); @@ -157,7 +157,7 @@ Slot_t objc_slot_lookup_super(struct objc_super *super, SEL selector) if (0 == result) { // Dtable should always be installed in the superclass - assert(dtable_for_class(class) != __objc_uninstalled_dtable); + assert(dtable_for_class(class) != uninstalled_dtable); result = &nil_slot; } return result; @@ -192,7 +192,7 @@ struct profile_info IMP method; }; -static void __objc_profile_init(void) +static void profile_init(void) { INIT_LOCK(profileLock); profileSymbols = fopen("objc_profile.symbols", "a"); @@ -207,12 +207,11 @@ void objc_profile_write_symbols(char **symbols) { if (NULL == profileData) { - LOCK(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); if (NULL == profileData) { - __objc_profile_init(); + profile_init(); } - UNLOCK(__objc_runtime_mutex); } LOCK(&profileLock); while(*symbols) @@ -239,12 +238,11 @@ void objc_msg_profile(id receiver, IMP method, // when we are not profiling. if (NULL == profileData) { - LOCK(__objc_runtime_mutex); + LOCK_RUNTIME_FOR_SCOPE(); if (NULL == profileData) { - __objc_profile_init(); + profile_init(); } - UNLOCK(__objc_runtime_mutex); } struct profile_info profile_data = { module, callsite, method }; fwrite(&profile_data, sizeof(profile_data), 1, profileData); @@ -260,7 +258,7 @@ Slot_t objc_get_slot(Class cls, SEL selector) { void *dtable = dtable_for_class(cls); /* Install the dtable if it hasn't already been initialized. */ - if (dtable == __objc_uninstalled_dtable) + if (dtable == uninstalled_dtable) { //objc_send_initialize((id)cls); dtable = dtable_for_class(cls); @@ -316,6 +314,7 @@ IMP class_getMethodImplementation_stret(Class cls, SEL name) // Legacy compatibility //////////////////////////////////////////////////////////////////////////////// +#ifndef NO_LEGACY /** * Legacy message lookup function. */ @@ -328,6 +327,17 @@ IMP get_imp(Class cls, SEL selector) { return class_getMethodImplementation(cls, selector); } + +/** + * Message send function that only ever worked on a small subset of compiler / + * architecture combinations. + */ +void *objc_msg_sendv(void) +{ + fprintf(stderr, "objc_msg_sendv() never worked correctly. Don't use it.\n"); + abort(); +} +#endif /** * Legacy message lookup function. Does not support fast proxies or safe IMP * caching. @@ -349,12 +359,3 @@ IMP objc_msg_lookup_super(struct objc_super *super, SEL selector) { return objc_slot_lookup_super(super, selector)->method; } -/** - * Message send function that only ever worked on a small subset of compiler / - * architecture combinations. - */ -void *objc_msg_sendv(void) -{ - fprintf(stderr, "objc_msg_sendv() never worked correctly. Don't use it.\n"); - abort(); -} diff --git a/sync.m b/sync.m index 634f0a3..57c9f2a 100644 --- a/sync.m +++ b/sync.m @@ -20,7 +20,7 @@ int snprintf(char *restrict s, size_t n, const char *restrict format, ...); static mutex_t at_sync_init_lock; -void __objc_sync_init(void) +PRIVATE void sync_init(void) { INIT_LOCK(at_sync_init_lock); } diff --git a/visibility.h b/visibility.h index 6521dec..33f653b 100644 --- a/visibility.h +++ b/visibility.h @@ -5,4 +5,9 @@ # define PUBLIC __attribute__ ((visibility("default"))) # define PRIVATE __attribute__ ((visibility("hidden"))) #endif +#ifdef NO_LEGACY +# define LEGACY PRIVATE +#else +# define LEGACY PUBLIC +#endif