From 0d78186238e9e8c03084a099889626fb2b48d6b5 Mon Sep 17 00:00:00 2001 From: theraven Date: Fri, 14 May 2010 21:47:35 +0000 Subject: [PATCH] Some bug fixes and tidies. I now have an out-of-tree replacement for the dtable stuff, so sarray.{h,c} will be going away soon. The replacement offers similar (slightly worse currently) performance in microbenchmarks, but uses half as much memory (Gorm goes from 95MB to 48MB on my machine). This will be committed once it's been tweaked a little bit. --- GNUmakefile | 1 + class.h | 2 ++ dtable_legacy.c | 6 ++++ lock.h | 10 ++++++ sarray2.c | 95 ++++++++++++++++++++++++++++++++++++++++--------- sarray2.h | 6 ++++ sendmsg.c | 19 ++++------ sendmsg2.c | 2 +- 8 files changed, 112 insertions(+), 29 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 5089148..f6412a8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -74,6 +74,7 @@ libobjc_OBJCFLAGS += -g -std=c99 -march=native libobjc_LDFLAGS += -g -ltoydispatch libobjc_LIB_DIRS += -L toydispatch/obj +libobjc_CFLAGS += -O3 ifneq ($(findstring gcc, $(CC)),) libobjc_CFLAGS += -fgnu89-inline diff --git a/class.h b/class.h index f44ade3..ddadb39 100644 --- a/class.h +++ b/class.h @@ -1,4 +1,5 @@ +#ifndef __objc_runtime_INCLUDE_GNU struct objc_class { /** @@ -109,6 +110,7 @@ struct objc_class */ struct objc_property_list *properties; }; +#endif /** * An enumerated type describing all of the valid flags that may be used in the diff --git a/dtable_legacy.c b/dtable_legacy.c index d9a62a8..33b869b 100644 --- a/dtable_legacy.c +++ b/dtable_legacy.c @@ -343,3 +343,9 @@ __objc_update_dispatch_table_for_class (Class class) objc_mutex_unlock (__objc_runtime_mutex); } +void objc_resize_uninstalled_dtable(void) +{ + assert(__objc_uninstalled_dtable != NULL); + sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1); +} + diff --git a/lock.h b/lock.h index 12c3221..a964efa 100644 --- a/lock.h +++ b/lock.h @@ -40,4 +40,14 @@ static inline void init_recursive_mutex(pthread_mutex_t *x) # define DESTROY_LOCK(x) pthread_mutex_destroy(x) #endif +__attribute__((unused)) static void objc_release_lock(void *x) +{ + mutex_t *lock = *(mutex_t**)x; + UNLOCK(lock); +} +#define LOCK_UNTIL_RETURN(lock) \ + __attribute__((cleanup(objc_release_lock)))\ + __attribute__((unused)) mutex_t *lock_pointer = lock;\ + LOCK(lock) + #endif // __LIBOBJC_LOCK_H_INCLUDED__ diff --git a/sarray2.c b/sarray2.c index d9f19fc..36a2bd4 100644 --- a/sarray2.c +++ b/sarray2.c @@ -1,19 +1,27 @@ #include -#ifdef BUILD_TESTS +#include #include -#endif #include "sarray2.h" static void *EmptyArrayData[256]; -static SparseArray EmptyArray = { 0, 0xff, (void**)&EmptyArrayData}; +static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData}; + +#define MAX_INDEX(sarray) (sarray->mask >> sarray->shift) +#define DATA_SIZE(sarray) ((sarray->mask >> sarray->shift) + 1) + +#define fprintf(...) +// Tweak this value to trade speed for memory usage. Bigger values use more +// memory, but give faster lookups. +#define base_shift 8 +#define base_mask ((1<data = calloc(256, sizeof(void*)); + sarray->data = calloc(DATA_SIZE(sarray), sizeof(void*)); if(sarray->shift != 0) { - for(unsigned i=0 ; i<256 ; i++) + for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++) { sarray->data[i] = &EmptyArray; } @@ -23,8 +31,9 @@ static void init_pointers(SparseArray * sarray) SparseArray * SparseArrayNew() { SparseArray * sarray = calloc(1, sizeof(SparseArray)); - sarray->shift = 24; - sarray->mask = 0xff000000; + sarray->refCount = 1; + sarray->shift = 32-base_shift; + sarray->mask = base_mask << sarray->shift; init_pointers(sarray); return sarray; } @@ -33,7 +42,7 @@ SparseArray * SparseArrayNew() void * SparseArrayNext(SparseArray * sarray, uint32_t * index) { uint32_t j = MASK_INDEX((*index)); - uint32_t max = (sarray->mask >> sarray->shift) + 1; + uint32_t max = MAX_INDEX(sarray); if(sarray->shift == 0) { while(jmask >> 8); + uint32_t zeromask = ~(sarray->mask >> base_shift); while(jshift > 0) + fprintf(stderr, "Inserting in : %p\n", sarray); + if (sarray->shift > 0) { uint32_t i = MASK_INDEX(index); - if(sarray->data[i] == &EmptyArray) + SparseArray *child = sarray->data[i]; + fprintf(stderr, "Child: %p\n", child); + if(&EmptyArray == child) { + // Insert missing nodes SparseArray * newsarray = calloc(1, sizeof(SparseArray)); - newsarray->shift = sarray->shift - 8; - newsarray->mask = sarray->mask >> 8; + newsarray->refCount = 1; + if (base_shift >= sarray->shift) + { + newsarray->shift = 0; + } + else + { + newsarray->shift = sarray->shift - base_shift; + } + newsarray->mask = sarray->mask >> base_shift; init_pointers(newsarray); sarray->data[i] = newsarray; + child = newsarray; + fprintf(stderr, "Created child: %p\n", child); + } + else if (child->refCount > 1) + { + // Copy the copy-on-write part of the tree + sarray->data[i] = SparseArrayCopy(child); + SparseArrayDestroy(child); + child = sarray->data[i]; } - sarray = sarray->data[i]; + fprintf(stderr, "Recursing in insert\n"); + SparseArrayInsert(child, index, value); + } + else + { + sarray->data[index & sarray->mask] = value; } - sarray->data[index & sarray->mask] = value; +} + +SparseArray *SparseArrayCopy(SparseArray * sarray) +{ + SparseArray *copy = calloc(1, sizeof(SparseArray)); + copy->refCount = 1; + copy->shift = sarray->shift; + copy->mask = sarray->mask; + copy->data = malloc(sizeof(void*) * DATA_SIZE(sarray)); + memcpy(copy->data, sarray->data, sizeof(void*) * DATA_SIZE(sarray)); + // If the sarray has children, increase their refcounts and link them + if (sarray->shift > 0) + { + for (unsigned int i = 0 ; i<=MAX_INDEX(sarray); i++) + { + SparseArray *child = copy->data[i]; + __sync_fetch_and_add(&child->refCount, 1); + // Non-lazy copy. Uncomment if debugging + // copy->data[i] = SparseArrayCopy(copy->data[i]); + } + } + return copy; } void SparseArrayDestroy(SparseArray * sarray) { + // Don't really delete this sarray if its ref count is > 0 + if (sarray == &EmptyArray || + (__sync_sub_and_fetch(&sarray->refCount, 1) > 0)) + { + return; + } + if(sarray->shift > 0) { uint32_t max = (sarray->mask >> sarray->shift) + 1; diff --git a/sarray2.h b/sarray2.h index e4729a3..4b7e523 100644 --- a/sarray2.h +++ b/sarray2.h @@ -26,6 +26,7 @@ typedef struct { uint32_t mask; uint32_t shift; + uint32_t refCount; void ** data; } SparseArray; @@ -73,4 +74,9 @@ void SparseArrayDestroy(SparseArray * sarray); */ void * SparseArrayNext(SparseArray * sarray, uint32_t * index); +/** + * Creates a copy of the sparse array. + */ +SparseArray *SparseArrayCopy(SparseArray * sarray); + #endif //_SARRAY_H_INCLUDED_ diff --git a/sendmsg.c b/sendmsg.c index 317a5f7..eabea34 100644 --- a/sendmsg.c +++ b/sendmsg.c @@ -55,7 +55,7 @@ static void __objc_install_dispatch_table_for_class (Class); typedef struct _InitializingDtable { Class class; - struct sarray *dtable; + void *dtable; struct _InitializingDtable *next; } InitializingDtable; @@ -63,6 +63,7 @@ typedef struct _InitializingDtable InitializingDtable *temporary_dtables; #include "dtable_legacy.c" +//#include "dtable.c" /* Forward declare some functions */ static void __objc_init_install_dtable (id, SEL); @@ -96,7 +97,7 @@ __objc_get_forward_imp (id rcv, SEL sel) } -static inline IMP sarray_get_imp (struct sarray *dtable, size_t key) +static inline IMP sarray_get_imp (void *dtable, size_t key) { struct objc_slot *slot = sarray_get_safe (dtable, key); return (NULL != slot) ? slot->method : (IMP)0; @@ -120,7 +121,7 @@ get_imp (Class class, SEL sel) if (res == 0) { /* This will block if calling +initialize from another thread. */ - struct sarray *dtable = dtable_for_class(class); + void *dtable = dtable_for_class(class); /* Not a valid method */ if (dtable == __objc_uninstalled_dtable) { @@ -208,7 +209,7 @@ objc_msg_lookup (id receiver, SEL op) /** Get the dtable that we should be using for lookup. This will * block if we are in the middle of running +initialize in another * thread. */ - struct sarray *dtable = dtable_for_class(receiver->class_pointer); + void *dtable = dtable_for_class(receiver->class_pointer); /* Not a valid method */ if (dtable == __objc_uninstalled_dtable) { @@ -309,7 +310,7 @@ __objc_send_initialize (Class class) CLS_SETINITIALIZED (class->class_pointer); /* Create the dtable, but don't install it on the class quite yet. */ - struct sarray *dtable = create_dtable_for_class(class); + void *dtable = create_dtable_for_class(class); /* Taking a pointer to an on-stack object and storing it in a global is * usually a silly idea. It is safe here, because we invert this * transform before we return, and we use initialize_lock to make sure no @@ -494,13 +495,7 @@ inline struct sarray * objc_get_uninstalled_dtable () { - return __objc_uninstalled_dtable; -} - -void objc_resize_uninstalled_dtable(void) -{ - assert(__objc_uninstalled_dtable != NULL); - sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1); + return (void*)__objc_uninstalled_dtable; } // This is an ugly hack to make sure that the compiler can do inlining into diff --git a/sendmsg2.c b/sendmsg2.c index 80dcbf7..bebe9af 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -26,7 +26,7 @@ Slot_t objc_msg_lookup_internal(id *receiver, SEL selector, id sender) if (0 == result) { Class class = (*receiver)->class_pointer; - struct sarray *dtable = dtable_for_class(class); + void *dtable = dtable_for_class(class); /* Install the dtable if it hasn't already been initialized. */ if (dtable == __objc_uninstalled_dtable) {