mirror of
https://github.com/darlinghq/darling-libobjc2.git
synced 2024-11-23 12:19:44 +00:00
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:
parent
0957cbe425
commit
0d78186238
@ -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
|
||||
|
2
class.h
2
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
10
lock.h
10
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__
|
||||
|
95
sarray2.c
95
sarray2.c
@ -1,19 +1,27 @@
|
||||
#include <stdlib.h>
|
||||
#ifdef BUILD_TESTS
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#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<<base_shift) - 1)
|
||||
|
||||
static void init_pointers(SparseArray * sarray)
|
||||
{
|
||||
sarray->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(j<max)
|
||||
@ -48,7 +57,7 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index)
|
||||
}
|
||||
else while(j<max)
|
||||
{
|
||||
uint32_t zeromask = ~(sarray->mask >> 8);
|
||||
uint32_t zeromask = ~(sarray->mask >> base_shift);
|
||||
while(j<max)
|
||||
{
|
||||
//Look in child nodes
|
||||
@ -71,26 +80,80 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
|
@ -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_
|
||||
|
19
sendmsg.c
19
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
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user