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
# debugger actually works...
#libobjc_CFLAGS += -fno-inline
libobjc_CFLAGS += -fno-inline
libobjc_OBJCFLAGS += $(libobjc_CFLAGS) $(libobjc_CFLAGS)
ifneq ($(findstring gcc, $(CC)),)

@ -46,17 +46,15 @@ struct objc_dtable
uint32_t version;
struct objc_slot *slot;
} cache[8];
Class cls;
struct slots_list
{
uint32_t idx;
struct objc_slot *slot;
} *slots;
mutex_t lock;
struct objc_slot **slots;
int slot_count;
int slot_size;
mutex_t lock;
Class cls;
};
static void update_dtable(dtable_t dtable);
PRIVATE void init_dispatch_tables ()
{
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.
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->cls = class;
INIT_LOCK(dtable->lock);
// Initialise it
update_dtable(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;
}
static struct slots_list *find_slot(uint32_t uid,
struct slots_list *slots, int slot_count)
static struct objc_slot *find_slot(uint32_t uid,
struct objc_slot **slots, int slot_count)
{
if (slot_count == 0) { return NULL; }
int idx = slot_count >> 1;
struct slots_list *slot = &slots[idx];
struct objc_slot *slot = slots[idx];
if (slot_count == 1)
{
if (slot->idx == uid)
if (slot->selector->index == uid)
{
return slot;
}
return NULL;
}
if (slot->idx > uid)
if (slot->selector->index > uid)
{
return find_slot(uid, slots, idx);
}
if (slot->idx < uid)
if (slot->selector->index < uid)
{
return find_slot(uid, slots+idx, slot_count - idx);
}
if (slot->idx == uid)
if (slot->selector->index == uid)
{
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)
{
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)
@ -159,35 +161,36 @@ static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx)
{
dtable->slot_size += 16;
dtable->slots = realloc(dtable->slots, dtable->slot_size *
sizeof(struct slots_list));
sizeof(struct objc_slot));
assert(NULL != dtable->slots && "Out of memory!");
}
dtable->slots[dtable->slot_count].slot = slot;
dtable->slots[dtable->slot_count++].idx = idx;
dtable->slots[dtable->slot_count++] = slot;
}
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)
{
struct slots_list *s = find_slot(idx, dtable->slots, old_slot_count);
if (NULL != s)
{
s->slot->method = m->imp;
s->slot->version++;
}
else
uint32_t idx = sel->index;
struct objc_slot *s = find_slot(idx, dtable->slots, old_slot_count);
if (NULL != s)
{
s->method = m->imp;
s->version++;
}
else
{
struct objc_slot *slot = new_slot_for_method_in_class(m, cls);
slot->selector = sel;
insert_slot(dtable, slot, idx);
if (Nil != cls->super_class)
{
struct objc_slot *slot = new_slot_for_method_in_class(m, cls);
insert_slot(dtable, slot, idx);
if (Nil != cls->super_class)
slot = objc_dtable_lookup(dtable_for_class(cls->super_class), idx);
if (NULL != slot)
{
slot = objc_dtable_lookup(dtable_for_class(cls->super_class), idx);
if (NULL != slot)
{
slot->version++;
}
slot->version++;
}
}
}
}
static void update_dtable(dtable_t dtable)
{
@ -200,7 +203,7 @@ static void update_dtable(dtable_t dtable)
if (NULL == dtable->slots)
{
dtable->slots = calloc(sizeof(struct slots_list), 16);
dtable->slots = calloc(sizeof(struct objc_slot), 16);
dtable->slot_size = 16;
}
@ -209,12 +212,12 @@ static void update_dtable(dtable_t dtable)
uint32_t idx = 0;
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
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
}
mergesort(dtable->slots, dtable->slot_count, sizeof(struct slots_list),
mergesort(dtable->slots, dtable->slot_count, sizeof(struct objc_slot*),
slot_cmp);
SparseArrayDestroy(methods);
}
@ -253,10 +256,9 @@ PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid)
{
update_dtable(dtable);
}
struct slots_list *s = find_slot(uid, dtable->slots, dtable->slot_count);
if (NULL != s)
slot = find_slot(uid, dtable->slots, dtable->slot_count);
if (NULL != slot)
{
slot = s->slot;
int i = HASH_UID(uid);
volatile struct cache_line *cache = &dtable->cache[i];
// Simplified multiword atomic exchange. First we write a value that

@ -32,11 +32,13 @@ struct objc_slot
* cache hits. Profiling is probably required here. */
Class cachedFor;
/** 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
* subclass overrides this method, potentially invalidating this cache. */
int version;
/** The method pointer for this method. */
IMP method;
/** Selector for this method. */
SEL selector;
} OBJC_NONPORTABLE;
#endif // __OBJC_SLOT_H_INCLUDED__

@ -48,7 +48,13 @@ __attribute__((unused))
static uint32_t get_untyped_idx(SEL aSel)
{
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.
*/
static SparseArray *selector_list = NULL;
PRIVATE SparseArray *selector_list = NULL;
// Get the functions for string hashing
#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
// encoding, so we're wasting a lot of memory like this.
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 *)selector_pool_alloc();
typeList->value = aSel->types;
@ -360,6 +360,29 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
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.
*/
@ -371,7 +394,7 @@ const char *sel_getName(SEL sel)
if (isSelRegistered(sel))
{
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;
}
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();
slot->owner = class;
slot->types = method->selector->types;
slot->selector = method->selector;
slot->method = method->imp;
slot->version = 1;

Loading…
Cancel
Save