Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -747,5 +747,55 @@ { M68K_ARG(id, object, a0) return _objc_rootAutorelease(object); } + +struct objc_hashtable *__saveds +glue_objc_hashtable_new PPC_PARAMS(objc_hashtable_hash_func hash, + objc_hashtable_equal_func equal, uint32_t size) +{ + M68K_ARG(objc_hashtable_hash_func, hash, a0) + M68K_ARG(objc_hashtable_equal_func, equal, a1) + M68K_ARG(uint32_t, size, d0) + + return objc_hashtable_new(hash, equal, size); +} + +void __saveds +glue_objc_hashtable_set PPC_PARAMS(struct objc_hashtable *table, + const void *key, const void *object) +{ + M68K_ARG(struct objc_hashtable *, table, a0) + M68K_ARG(const void *, key, a1) + M68K_ARG(const void *, object, a2) + + objc_hashtable_set(table, key, object); +} + +void *__saveds +glue_objc_hashtable_get PPC_PARAMS(struct objc_hashtable *table, + const void *key) +{ + M68K_ARG(struct objc_hashtable *, table, a0) + M68K_ARG(const void *, key, a1) + + return objc_hashtable_get(table, key); +} + +void __saveds +glue_objc_hashtable_delete PPC_PARAMS(struct objc_hashtable *table, + const void *key) +{ + M68K_ARG(struct objc_hashtable *, table, a0) + M68K_ARG(const void *, key, a1) + + objc_hashtable_delete(table, key); +} + +void __saveds +glue_objc_hashtable_free PPC_PARAMS(struct objc_hashtable *table) +{ + M68K_ARG(struct objc_hashtable *, table, a0) + + objc_hashtable_free(table); +} Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -140,10 +140,15 @@ extern char *glue_property_copyAttributeValue(void); extern void *glue_objc_destructInstance(void); extern void *glue_objc_autoreleasePoolPush(void); extern void glue_objc_autoreleasePoolPop(void); extern id glue__objc_rootAutorelease(void); +extern struct objc_hashtable *glue_objc_hashtable_new(void); +extern void glue_objc_hashtable_set(void); +extern void *glue_objc_hashtable_get(void); +extern void glue_objc_hashtable_delete(void); +extern void glue_objc_hashtable_free(void); #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; @@ -661,10 +666,15 @@ (CONST_APTR)glue_property_copyAttributeValue, (CONST_APTR)glue_objc_destructInstance, (CONST_APTR)glue_objc_autoreleasePoolPush, (CONST_APTR)glue_objc_autoreleasePoolPop, (CONST_APTR)glue__objc_rootAutorelease, + (CONST_APTR)glue_objc_hashtable_new, + (CONST_APTR)glue_objc_hashtable_set, + (CONST_APTR)glue_objc_hashtable_get, + (CONST_APTR)glue_objc_hashtable_delete, + (CONST_APTR)glue_objc_hashtable_free, (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -1,14 +1,12 @@ ==base _ObjFWRTBase ==basetype struct Library * ==libname objfwrt68k.library ==bias 30 ==public -* Functions that are only for the linklib. +* The following function is only for the linklib. bool glue_objc_init(unsigned int version, struct objc_libc *libc, FILE *stdout, FILE *stderr)(d0,a0,a1,a2) -* These have a built-in declaration in the compiler that does not use the -* registers and thus always need glue. void glue___objc_exec_class(struct objc_module *_Nonnull module)(a0) IMP _Nonnull glue_objc_msg_lookup(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) @@ -83,6 +81,12 @@ char *_Nullable glue_property_copyAttributeValue(objc_property_t _Nonnull property, const char *_Nonnull name)(a0,a1) void *_Nullable glue_objc_destructInstance(id _Nullable object)(a0) void *_Null_unspecified glue_objc_autoreleasePoolPush(void)() void glue_objc_autoreleasePoolPop(void *_Null_unspecified pool)(a0) id _Nullable glue__objc_rootAutorelease(id _Nullable object)(a0) +* The following functions are private! Don't use! +struct objc_hashtable *_Nonnull glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size)(a0,a1,d0) +void glue_objc_hashtable_set(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object)(a0,a1,a2) +void *_Nullable glue_objc_hashtable_get(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) +void glue_objc_hashtable_delete(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) +void glue_objc_hashtable_free(struct objc_hashtable *_Nonnull table)(a0) ==end Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -673,5 +673,37 @@ id _objc_rootAutorelease(id object) { return glue__objc_rootAutorelease(object); } + +struct objc_hashtable * +objc_hashtable_new(objc_hashtable_hash_func hash, + objc_hashtable_equal_func equal, uint32_t size) +{ + return glue_objc_hashtable_new(hash, equal, size); +} + +void +objc_hashtable_set(struct objc_hashtable *table, const void *key, + const void *object) +{ + glue_objc_hashtable_set(table, key, object); +} + +void * +objc_hashtable_get(struct objc_hashtable *table, const void *key) +{ + return glue_objc_hashtable_get(table, key); +} + +void +objc_hashtable_delete(struct objc_hashtable *table, const void *key) +{ + glue_objc_hashtable_delete(table, key); +} + +void +objc_hashtable_free(struct objc_hashtable *table) +{ + glue_objc_hashtable_free(table); +} Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -1,8 +1,7 @@ -/* Functions that are only for the linklib. */ +/* The following function is only for the linklib. */ bool glue_objc_init(unsigned int, struct objc_libc *, FILE *, FILE *); -/* All other functions. */ void glue___objc_exec_class(struct objc_module *); IMP glue_objc_msg_lookup(id, SEL); IMP glue_objc_msg_lookup_stret(id, SEL); IMP glue_objc_msg_lookup_super(struct objc_super *, SEL); IMP glue_objc_msg_lookup_super_stret(struct objc_super *, SEL); @@ -77,5 +76,11 @@ char *glue_property_copyAttributeValue(objc_property_t, const char *); void *glue_objc_destructInstance(id); void *glue_objc_autoreleasePoolPush(void); void glue_objc_autoreleasePoolPop(void *); id glue__objc_rootAutorelease(id); +/* The following functions are private! Don't use! */ +struct objc_hashtable *glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size); +void glue_objc_hashtable_set(struct objc_hashtable *table, const void *key, const void *object); +void *glue_objc_hashtable_get(struct objc_hashtable *table, const void *key); +void glue_objc_hashtable_delete(struct objc_hashtable *table, const void *key); +void glue_objc_hashtable_free(struct objc_hashtable *table); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -1,9 +1,9 @@ ##base _ObjFWRTBase ##bias 30 ##public -* Functions that are only for the linklib. +* The following function is only for the linklib. glue_objc_init(version,libc,stdout,stderr)(sysv,r12base) glue___objc_exec_class(module)(sysv,r12base) glue_objc_msg_lookup(object,selector)(sysv,r12base) glue_objc_msg_lookup_stret(object,selector)(sysv,r12base) glue_objc_msg_lookup_super(super,selector)(sysv,r12base) @@ -79,6 +79,12 @@ glue_property_copyAttributeValue(property,name)(sysv,r12base) glue_objc_destructInstance(object)(sysv,r12base) glue_objc_autoreleasePoolPush()(sysv,r12base) glue_objc_autoreleasePoolPop(pool)(sysv,r12base) glue__objc_rootAutorelease(object)(sysv,r12base) +* The following functions are private! Don't use! +glue_objc_hashtable_new(hash,equal,size)(sysv,r12base) +glue_objc_hashtable_set(table,key,object)(sysv,r12base) +glue_objc_hashtable_get(table,key)(sysv,r12base) +glue_objc_hashtable_delete(table,key)(sysv,r12base) +glue_objc_hashtable_free(table)(sysv,r12base) ##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -27,10 +27,14 @@ # ifndef _Nullable # define _Nullable # endif #endif +typedef uint32_t (*_Nonnull objc_hashtable_hash_func)(const void *_Nonnull key); +typedef bool (*_Nonnull objc_hashtable_equal_func)(const void *_Nonnull key1, + const void *_Nonnull key2); + struct objc_class { Class _Nonnull isa; Class _Nullable superclass; const char *_Nonnull name; unsigned long version; @@ -187,13 +191,12 @@ const void *_Nonnull key, *_Nonnull object; uint32_t hash; }; struct objc_hashtable { - uint32_t (*_Nonnull hash)(const void *_Nonnull key); - bool (*_Nonnull equal)(const void *_Nonnull key1, - const void *_Nonnull key2); + objc_hashtable_hash_func hash; + objc_hashtable_equal_func equal; uint32_t count, size; struct objc_hashtable_bucket *_Nonnull *_Nullable data; }; struct objc_sparsearray { @@ -276,12 +279,11 @@ extern void objc_unregister_class(Class _Nonnull); extern void objc_unregister_all_classes(void); extern uint32_t objc_hash_string(const void *_Nonnull); extern bool objc_equal_string(const void *_Nonnull, const void *_Nonnull); extern struct objc_hashtable *_Nonnull objc_hashtable_new( - uint32_t (*_Nonnull)(const void *_Nonnull), - bool (*_Nonnull)(const void *_Nonnull, const void *_Nonnull), uint32_t); + objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); extern struct objc_hashtable_bucket objc_deleted_bucket; extern void objc_hashtable_set(struct objc_hashtable *_Nonnull, const void *_Nonnull, const void *_Nonnull); extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull, const void *_Nonnull); Index: src/tlskey.h ================================================================== --- src/tlskey.h +++ src/tlskey.h @@ -31,15 +31,13 @@ typedef pthread_key_t of_tlskey_t; #elif defined(OF_WINDOWS) # include typedef DWORD of_tlskey_t; #elif defined(OF_AMIGAOS) -# import "OFList.h" -@class OFMapTable; -typedef struct { - OFMapTable *mapTable; - of_list_object_t *listObject; +typedef struct of_tlskey { + struct objc_hashtable *table; + struct of_tlskey *next, *previous; } *of_tlskey_t; #endif #ifdef __cplusplus extern "C" { Index: src/tlskey.m ================================================================== --- src/tlskey.m +++ src/tlskey.m @@ -21,16 +21,30 @@ #ifdef OF_AMIGAOS # include # include -# import "OFMapTable.h" -# import "OFList.h" +/* + * As we use this file in both the runtime and ObjFW, and since AmigaOS always + * has the runtime, use the hashtable from the runtime. + */ +# import "runtime/private.h" -static const of_map_table_functions_t functions = { NULL }; -static OFList *allKeys = nil; +static of_tlskey_t firstKey = NULL, lastKey = NULL; static struct SignalSemaphore semaphore; + +static uint32_t +hashFunc(const void *ptr) +{ + return (uint32_t)(uintptr_t)ptr; +} + +static bool +equalFunc(const void *ptr1, const void *ptr2) +{ + return (ptr1 == ptr2); +} OF_CONSTRUCTOR() { InitSemaphore(&semaphore); } @@ -42,18 +56,32 @@ #if defined(OF_HAVE_PTHREADS) return (pthread_key_create(key, NULL) == 0); #elif defined(OF_WINDOWS) return ((*key = TlsAlloc()) != TLS_OUT_OF_INDEXES); #elif defined(OF_AMIGAOS) - if ((*key = calloc(1, sizeof(**key))) == NULL) + if ((*key = malloc(sizeof(**key))) == NULL) return false; - /* - * We create the map table lazily, as some TLS are created in - * constructors, at which time OFMapTable is not available yet. - */ + (*key)->table = NULL; + + ObtainSemaphore(&semaphore); + @try { + (*key)->next = NULL; + (*key)->previous = lastKey; + + if (lastKey != NULL) + lastKey->next = *key; + + lastKey = *key; + + if (firstKey == NULL) + firstKey = *key; + } @finally { + ReleaseSemaphore(&semaphore); + } + /* We create the hash table lazily. */ return true; #endif } bool @@ -64,12 +92,21 @@ #elif defined(OF_WINDOWS) return TlsFree(key); #elif defined(OF_AMIGAOS) ObtainSemaphore(&semaphore); @try { - [allKeys removeListObject: key->listObject]; - [key->mapTable release]; + if (key->previous != NULL) + key->previous->next = key->next; + if (key->next != NULL) + key->next->previous = key->previous; + + if (firstKey == key) + firstKey = key->next; + if (lastKey == key) + lastKey = key->previous; + + objc_hashtable_free(key->table); free(key); } @finally { ReleaseSemaphore(&semaphore); } @@ -76,33 +113,21 @@ return true; #endif } #ifdef OF_AMIGAOS -static void -unsafeCreateMapTable(of_tlskey_t key) -{ - key->mapTable = [[OFMapTable alloc] initWithKeyFunctions: functions - objectFunctions: functions]; - - if (allKeys == nil) - allKeys = [[OFList alloc] init]; - - key->listObject = [allKeys appendObject: key->mapTable]; -} - void * of_tlskey_get(of_tlskey_t key) { void *ret; ObtainSemaphore(&semaphore); @try { - if (key->mapTable == NULL) - unsafeCreateMapTable(key); + if (key->table == NULL) + return NULL; - ret = [key->mapTable objectForKey: FindTask(NULL)]; + ret = objc_hashtable_get(key->table, FindTask(NULL)); } @finally { ReleaseSemaphore(&semaphore); } return ret; @@ -113,18 +138,17 @@ { ObtainSemaphore(&semaphore); @try { struct Task *task = FindTask(NULL); - if (key->mapTable == NULL) - unsafeCreateMapTable(key); + if (key->table == NULL) + key->table = objc_hashtable_new(hashFunc, equalFunc, 2); if (ptr == NULL) - [key->mapTable removeObjectForKey: task]; + objc_hashtable_delete(key->table, task); else - [key->mapTable setObject: ptr - forKey: task]; + objc_hashtable_set(key->table, task, ptr); } @catch (id e) { return false; } @finally { ReleaseSemaphore(&semaphore); } @@ -137,13 +161,14 @@ { ObtainSemaphore(&semaphore); @try { struct Task *task = FindTask(NULL); - for (of_list_object_t *iter = allKeys.firstListObject; - iter != NULL; iter = iter->next) - [iter->object removeObjectForKey: task]; + for (of_tlskey_t iter = firstKey; iter != NULL; + iter = iter->next) + if (iter->table != NULL) + objc_hashtable_delete(iter->table, task); } @finally { ReleaseSemaphore(&semaphore); } } #endif