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) {