diff --git a/GNUmakefile b/GNUmakefile index de4d386..e3063d8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -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)),) diff --git a/dtable.c b/dtable.c index b1eb56a..9c5fe4a 100644 --- a/dtable.c +++ b/dtable.c @@ -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 diff --git a/objc/slot.h b/objc/slot.h index 761c6df..0afd754 100644 --- a/objc/slot.h +++ b/objc/slot.h @@ -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__ diff --git a/selector.h b/selector.h index 5a7d08c..116d0b9 100644 --- a/selector.h +++ b/selector.h @@ -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); } /** diff --git a/selector_table.c b/selector_table.c index a0f24ac..40bdfcd 100644 --- a/selector_table.c +++ b/selector_table.c @@ -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 diff --git a/slot_pool.h b/slot_pool.h index 7bbd0ee..68502eb 100644 --- a/slot_pool.h +++ b/slot_pool.h @@ -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;