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.
This commit is contained in:
theraven 2010-05-14 21:47:35 +00:00
parent 0957cbe425
commit 0d78186238
8 changed files with 112 additions and 29 deletions

View File

@ -74,6 +74,7 @@ libobjc_OBJCFLAGS += -g -std=c99 -march=native
libobjc_LDFLAGS += -g -ltoydispatch libobjc_LDFLAGS += -g -ltoydispatch
libobjc_LIB_DIRS += -L toydispatch/obj libobjc_LIB_DIRS += -L toydispatch/obj
libobjc_CFLAGS += -O3
ifneq ($(findstring gcc, $(CC)),) ifneq ($(findstring gcc, $(CC)),)
libobjc_CFLAGS += -fgnu89-inline libobjc_CFLAGS += -fgnu89-inline

View File

@ -1,4 +1,5 @@
#ifndef __objc_runtime_INCLUDE_GNU
struct objc_class struct objc_class
{ {
/** /**
@ -109,6 +110,7 @@ struct objc_class
*/ */
struct objc_property_list *properties; struct objc_property_list *properties;
}; };
#endif
/** /**
* An enumerated type describing all of the valid flags that may be used in the * An enumerated type describing all of the valid flags that may be used in the

View File

@ -343,3 +343,9 @@ __objc_update_dispatch_table_for_class (Class class)
objc_mutex_unlock (__objc_runtime_mutex); 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);
}

10
lock.h
View File

@ -40,4 +40,14 @@ static inline void init_recursive_mutex(pthread_mutex_t *x)
# define DESTROY_LOCK(x) pthread_mutex_destroy(x) # define DESTROY_LOCK(x) pthread_mutex_destroy(x)
#endif #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__ #endif // __LIBOBJC_LOCK_H_INCLUDED__

View File

@ -1,19 +1,27 @@
#include <stdlib.h> #include <stdlib.h>
#ifdef BUILD_TESTS #include <string.h>
#include <stdio.h> #include <stdio.h>
#endif
#include "sarray2.h" #include "sarray2.h"
static void *EmptyArrayData[256]; 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<<base_shift) - 1)
static void init_pointers(SparseArray * sarray) static void init_pointers(SparseArray * sarray)
{ {
sarray->data = calloc(256, sizeof(void*)); sarray->data = calloc(DATA_SIZE(sarray), sizeof(void*));
if(sarray->shift != 0) if(sarray->shift != 0)
{ {
for(unsigned i=0 ; i<256 ; i++) for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
{ {
sarray->data[i] = &EmptyArray; sarray->data[i] = &EmptyArray;
} }
@ -23,8 +31,9 @@ static void init_pointers(SparseArray * sarray)
SparseArray * SparseArrayNew() SparseArray * SparseArrayNew()
{ {
SparseArray * sarray = calloc(1, sizeof(SparseArray)); SparseArray * sarray = calloc(1, sizeof(SparseArray));
sarray->shift = 24; sarray->refCount = 1;
sarray->mask = 0xff000000; sarray->shift = 32-base_shift;
sarray->mask = base_mask << sarray->shift;
init_pointers(sarray); init_pointers(sarray);
return sarray; return sarray;
} }
@ -33,7 +42,7 @@ SparseArray * SparseArrayNew()
void * SparseArrayNext(SparseArray * sarray, uint32_t * index) void * SparseArrayNext(SparseArray * sarray, uint32_t * index)
{ {
uint32_t j = MASK_INDEX((*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) if(sarray->shift == 0)
{ {
while(j<max) while(j<max)
@ -48,7 +57,7 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index)
} }
else while(j<max) else while(j<max)
{ {
uint32_t zeromask = ~(sarray->mask >> 8); uint32_t zeromask = ~(sarray->mask >> base_shift);
while(j<max) while(j<max)
{ {
//Look in child nodes //Look in child nodes
@ -71,26 +80,80 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index)
return SARRAY_EMPTY; return SARRAY_EMPTY;
} }
void SparseArrayInsert(SparseArray * sarray, uint32_t index, void * value) void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value)
{ {
while(sarray->shift > 0) fprintf(stderr, "Inserting in : %p\n", sarray);
if (sarray->shift > 0)
{ {
uint32_t i = MASK_INDEX(index); 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)); SparseArray * newsarray = calloc(1, sizeof(SparseArray));
newsarray->shift = sarray->shift - 8; newsarray->refCount = 1;
newsarray->mask = sarray->mask >> 8; if (base_shift >= sarray->shift)
{
newsarray->shift = 0;
}
else
{
newsarray->shift = sarray->shift - base_shift;
}
newsarray->mask = sarray->mask >> base_shift;
init_pointers(newsarray); init_pointers(newsarray);
sarray->data[i] = newsarray; sarray->data[i] = newsarray;
child = newsarray;
fprintf(stderr, "Created child: %p\n", child);
} }
sarray = sarray->data[i]; 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];
}
fprintf(stderr, "Recursing in insert\n");
SparseArrayInsert(child, index, value);
} }
sarray->data[index & sarray->mask] = value; else
{
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) 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) if(sarray->shift > 0)
{ {
uint32_t max = (sarray->mask >> sarray->shift) + 1; uint32_t max = (sarray->mask >> sarray->shift) + 1;

View File

@ -26,6 +26,7 @@ typedef struct
{ {
uint32_t mask; uint32_t mask;
uint32_t shift; uint32_t shift;
uint32_t refCount;
void ** data; void ** data;
} SparseArray; } SparseArray;
@ -73,4 +74,9 @@ void SparseArrayDestroy(SparseArray * sarray);
*/ */
void * SparseArrayNext(SparseArray * sarray, uint32_t * index); void * SparseArrayNext(SparseArray * sarray, uint32_t * index);
/**
* Creates a copy of the sparse array.
*/
SparseArray *SparseArrayCopy(SparseArray * sarray);
#endif //_SARRAY_H_INCLUDED_ #endif //_SARRAY_H_INCLUDED_

View File

@ -55,7 +55,7 @@ static void __objc_install_dispatch_table_for_class (Class);
typedef struct _InitializingDtable typedef struct _InitializingDtable
{ {
Class class; Class class;
struct sarray *dtable; void *dtable;
struct _InitializingDtable *next; struct _InitializingDtable *next;
} InitializingDtable; } InitializingDtable;
@ -63,6 +63,7 @@ typedef struct _InitializingDtable
InitializingDtable *temporary_dtables; InitializingDtable *temporary_dtables;
#include "dtable_legacy.c" #include "dtable_legacy.c"
//#include "dtable.c"
/* Forward declare some functions */ /* Forward declare some functions */
static void __objc_init_install_dtable (id, SEL); 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); struct objc_slot *slot = sarray_get_safe (dtable, key);
return (NULL != slot) ? slot->method : (IMP)0; return (NULL != slot) ? slot->method : (IMP)0;
@ -120,7 +121,7 @@ get_imp (Class class, SEL sel)
if (res == 0) if (res == 0)
{ {
/* This will block if calling +initialize from another thread. */ /* 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 */ /* Not a valid method */
if (dtable == __objc_uninstalled_dtable) 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 /** Get the dtable that we should be using for lookup. This will
* block if we are in the middle of running +initialize in another * block if we are in the middle of running +initialize in another
* thread. */ * thread. */
struct sarray *dtable = dtable_for_class(receiver->class_pointer); void *dtable = dtable_for_class(receiver->class_pointer);
/* Not a valid method */ /* Not a valid method */
if (dtable == __objc_uninstalled_dtable) if (dtable == __objc_uninstalled_dtable)
{ {
@ -309,7 +310,7 @@ __objc_send_initialize (Class class)
CLS_SETINITIALIZED (class->class_pointer); CLS_SETINITIALIZED (class->class_pointer);
/* Create the dtable, but don't install it on the class quite yet. */ /* 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 /* 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 * 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 * transform before we return, and we use initialize_lock to make sure no
@ -494,13 +495,7 @@ inline
struct sarray * struct sarray *
objc_get_uninstalled_dtable () objc_get_uninstalled_dtable ()
{ {
return __objc_uninstalled_dtable; return (void*)__objc_uninstalled_dtable;
}
void objc_resize_uninstalled_dtable(void)
{
assert(__objc_uninstalled_dtable != NULL);
sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
} }
// This is an ugly hack to make sure that the compiler can do inlining into // This is an ugly hack to make sure that the compiler can do inlining into

View File

@ -26,7 +26,7 @@ Slot_t objc_msg_lookup_internal(id *receiver, SEL selector, id sender)
if (0 == result) if (0 == result)
{ {
Class class = (*receiver)->class_pointer; 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. */ /* Install the dtable if it hasn't already been initialized. */
if (dtable == __objc_uninstalled_dtable) if (dtable == __objc_uninstalled_dtable)
{ {