Tidy up low memory profile to use slots directly.

main
theraven 15 years ago
parent 535ba87a8e
commit 12385fcb1e

@ -102,7 +102,7 @@ libobjc_CFLAGS += -Wno-unused-function
# Uncomment this when debugging - it makes everything slow, but means that the # Uncomment this when debugging - it makes everything slow, but means that the
# debugger actually works... # debugger actually works...
#libobjc_CFLAGS += -fno-inline libobjc_CFLAGS += -fno-inline
libobjc_OBJCFLAGS += $(libobjc_CFLAGS) $(libobjc_CFLAGS) libobjc_OBJCFLAGS += $(libobjc_CFLAGS) $(libobjc_CFLAGS)
ifneq ($(findstring gcc, $(CC)),) ifneq ($(findstring gcc, $(CC)),)

@ -46,17 +46,15 @@ struct objc_dtable
uint32_t version; uint32_t version;
struct objc_slot *slot; struct objc_slot *slot;
} cache[8]; } cache[8];
Class cls; mutex_t lock;
struct slots_list struct objc_slot **slots;
{
uint32_t idx;
struct objc_slot *slot;
} *slots;
int slot_count; int slot_count;
int slot_size; int slot_size;
mutex_t lock; Class cls;
}; };
static void update_dtable(dtable_t dtable);
PRIVATE void init_dispatch_tables () PRIVATE void init_dispatch_tables ()
{ {
INIT_LOCK(initialize_lock); INIT_LOCK(initialize_lock);
@ -76,11 +74,14 @@ static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
// waiting on the lock. // waiting on the lock.
if (classHasDtable(class)) { return dtable_for_class(class); } if (classHasDtable(class)) { return dtable_for_class(class); }
/* Allocate dtable if necessary */ // Allocate the dtable
dtable_t dtable = calloc(1, sizeof(struct objc_dtable)); dtable_t dtable = calloc(1, sizeof(struct objc_dtable));
dtable->cls = class; dtable->cls = class;
INIT_LOCK(dtable->lock); INIT_LOCK(dtable->lock);
// Initialise it
update_dtable(dtable);
return dtable; return dtable;
} }
@ -119,29 +120,29 @@ static struct objc_slot* check_cache(dtable_t dtable, uint32_t uid)
return (idx == uid) && (slot->version == version) ? slot : NULL; return (idx == uid) && (slot->version == version) ? slot : NULL;
} }
static struct slots_list *find_slot(uint32_t uid, static struct objc_slot *find_slot(uint32_t uid,
struct slots_list *slots, int slot_count) struct objc_slot **slots, int slot_count)
{ {
if (slot_count == 0) { return NULL; } if (slot_count == 0) { return NULL; }
int idx = slot_count >> 1; int idx = slot_count >> 1;
struct slots_list *slot = &slots[idx]; struct objc_slot *slot = slots[idx];
if (slot_count == 1) if (slot_count == 1)
{ {
if (slot->idx == uid) if (slot->selector->index == uid)
{ {
return slot; return slot;
} }
return NULL; return NULL;
} }
if (slot->idx > uid) if (slot->selector->index > uid)
{ {
return find_slot(uid, slots, idx); return find_slot(uid, slots, idx);
} }
if (slot->idx < uid) if (slot->selector->index < uid)
{ {
return find_slot(uid, slots+idx, slot_count - idx); return find_slot(uid, slots+idx, slot_count - idx);
} }
if (slot->idx == uid) if (slot->selector->index == uid)
{ {
return slot; return slot;
} }
@ -150,7 +151,8 @@ static struct slots_list *find_slot(uint32_t uid,
static int slot_cmp(const void *l, const void *r) static int slot_cmp(const void *l, const void *r)
{ {
return (((struct slots_list*)l)->idx - ((struct slots_list*)r)->idx); return (*(struct objc_slot**)l)->selector->index
- (*(struct objc_slot**)r)->selector->index;
} }
static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx) static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx)
@ -159,25 +161,26 @@ static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx)
{ {
dtable->slot_size += 16; dtable->slot_size += 16;
dtable->slots = realloc(dtable->slots, dtable->slot_size * dtable->slots = realloc(dtable->slots, dtable->slot_size *
sizeof(struct slots_list)); sizeof(struct objc_slot));
assert(NULL != dtable->slots && "Out of memory!"); assert(NULL != dtable->slots && "Out of memory!");
} }
dtable->slots[dtable->slot_count].slot = slot; dtable->slots[dtable->slot_count++] = slot;
dtable->slots[dtable->slot_count++].idx = idx;
} }
static void add_slot_to_dtable(uint32_t idx, dtable_t dtable, uint32_t static void add_slot_to_dtable(SEL sel, dtable_t dtable, uint32_t
old_slot_count, struct objc_method *m, Class cls) old_slot_count, struct objc_method *m, Class cls)
{ {
struct slots_list *s = find_slot(idx, dtable->slots, old_slot_count); uint32_t idx = sel->index;
struct objc_slot *s = find_slot(idx, dtable->slots, old_slot_count);
if (NULL != s) if (NULL != s)
{ {
s->slot->method = m->imp; s->method = m->imp;
s->slot->version++; s->version++;
} }
else else
{ {
struct objc_slot *slot = new_slot_for_method_in_class(m, cls); struct objc_slot *slot = new_slot_for_method_in_class(m, cls);
slot->selector = sel;
insert_slot(dtable, slot, idx); insert_slot(dtable, slot, idx);
if (Nil != cls->super_class) if (Nil != cls->super_class)
{ {
@ -200,7 +203,7 @@ static void update_dtable(dtable_t dtable)
if (NULL == dtable->slots) if (NULL == dtable->slots)
{ {
dtable->slots = calloc(sizeof(struct slots_list), 16); dtable->slots = calloc(sizeof(struct objc_slot), 16);
dtable->slot_size = 16; dtable->slot_size = 16;
} }
@ -209,12 +212,12 @@ static void update_dtable(dtable_t dtable)
uint32_t idx = 0; uint32_t idx = 0;
while ((m = SparseArrayNext(methods, &idx))) while ((m = SparseArrayNext(methods, &idx)))
{ {
add_slot_to_dtable(m->selector->index, dtable, old_slot_count, m, cls); add_slot_to_dtable(m->selector, dtable, old_slot_count, m, cls);
#ifdef TYPE_DEPENDENT_DISPATCH #ifdef TYPE_DEPENDENT_DISPATCH
add_slot_to_dtable(get_untyped_idx(m->selector), dtable, old_slot_count, m, cls); add_slot_to_dtable(sel_getUntyped(m->selector), dtable, old_slot_count, m, cls);
#endif #endif
} }
mergesort(dtable->slots, dtable->slot_count, sizeof(struct slots_list), mergesort(dtable->slots, dtable->slot_count, sizeof(struct objc_slot*),
slot_cmp); slot_cmp);
SparseArrayDestroy(methods); SparseArrayDestroy(methods);
} }
@ -253,10 +256,9 @@ PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid)
{ {
update_dtable(dtable); update_dtable(dtable);
} }
struct slots_list *s = find_slot(uid, dtable->slots, dtable->slot_count); slot = find_slot(uid, dtable->slots, dtable->slot_count);
if (NULL != s) if (NULL != slot)
{ {
slot = s->slot;
int i = HASH_UID(uid); int i = HASH_UID(uid);
volatile struct cache_line *cache = &dtable->cache[i]; volatile struct cache_line *cache = &dtable->cache[i];
// Simplified multiword atomic exchange. First we write a value that // Simplified multiword atomic exchange. First we write a value that

@ -32,11 +32,13 @@ struct objc_slot
* cache hits. Profiling is probably required here. */ * cache hits. Profiling is probably required here. */
Class cachedFor; Class cachedFor;
/** The (typed) selector for the method identified by this slot. */ /** The (typed) selector for the method identified by this slot. */
SEL selector; const char *types;
/** The current version. This changes if the method changes or if a /** The current version. This changes if the method changes or if a
* subclass overrides this method, potentially invalidating this cache. */ * subclass overrides this method, potentially invalidating this cache. */
int version; int version;
/** The method pointer for this method. */ /** The method pointer for this method. */
IMP method; IMP method;
/** Selector for this method. */
SEL selector;
} OBJC_NONPORTABLE; } OBJC_NONPORTABLE;
#endif // __OBJC_SLOT_H_INCLUDED__ #endif // __OBJC_SLOT_H_INCLUDED__

@ -48,7 +48,13 @@ __attribute__((unused))
static uint32_t get_untyped_idx(SEL aSel) static uint32_t get_untyped_idx(SEL aSel)
{ {
SEL untyped = sel_registerTypedName_np(sel_getName(aSel), 0); SEL untyped = sel_registerTypedName_np(sel_getName(aSel), 0);
return (uint32_t)(uintptr_t)untyped->name; return untyped->index;
}
__attribute__((unused))
static SEL sel_getUntyped(SEL aSel)
{
return sel_registerTypedName_np(sel_getName(aSel), 0);
} }
/** /**

@ -41,7 +41,7 @@ static uint32_t selector_count = 1;
/** /**
* Mapping from selector numbers to selector names. * Mapping from selector numbers to selector names.
*/ */
static SparseArray *selector_list = NULL; PRIVATE SparseArray *selector_list = NULL;
// Get the functions for string hashing // Get the functions for string hashing
#include "string_hash.h" #include "string_hash.h"
@ -301,7 +301,7 @@ static inline void register_selector_locked(SEL aSel)
// This is quite horrible. Most selectors will only have one type // This is quite horrible. Most selectors will only have one type
// encoding, so we're wasting a lot of memory like this. // encoding, so we're wasting a lot of memory like this.
struct sel_type_list *typeListHead = struct sel_type_list *typeListHead =
SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)untyped->name); SparseArrayLookup(selector_list, untyped->index);
struct sel_type_list *typeList = struct sel_type_list *typeList =
(struct sel_type_list *)selector_pool_alloc(); (struct sel_type_list *)selector_pool_alloc();
typeList->value = aSel->types; typeList->value = aSel->types;
@ -360,6 +360,29 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
return copy; return copy;
} }
PRIVATE uint32_t sel_nextTypeIndex(uint32_t untypedIdx, uint32_t idx)
{
struct sel_type_list *list =
SparseArrayLookup(selector_list, untypedIdx);
if (NULL == list) { return 0; }
const char *selName = list->value;
list = list->next;
BOOL found = untypedIdx == idx;
while (NULL != list)
{
SEL sel = selector_lookup(selName, list->value);
if (sel->index == untypedIdx) { return 0; }
if (found)
{
return sel->index;
}
found = (sel->index == idx);
}
return 0;
}
/** /**
* Public API functions. * Public API functions.
*/ */
@ -371,7 +394,7 @@ const char *sel_getName(SEL sel)
if (isSelRegistered(sel)) if (isSelRegistered(sel))
{ {
struct sel_type_list * list = struct sel_type_list * list =
SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)sel->name); SparseArrayLookup(selector_list, sel->index);
name = (list == NULL) ? NULL : list->value; name = (list == NULL) ? NULL : list->value;
} }
else else

@ -10,6 +10,7 @@ static inline struct objc_slot *new_slot_for_method_in_class(Method method,
{ {
struct objc_slot *slot = slot_pool_alloc(); struct objc_slot *slot = slot_pool_alloc();
slot->owner = class; slot->owner = class;
slot->types = method->selector->types;
slot->selector = method->selector; slot->selector = method->selector;
slot->method = method->imp; slot->method = method->imp;
slot->version = 1; slot->version = 1;

Loading…
Cancel
Save