diff --git a/class_table.c b/class_table.c index cf06e10..372b7a0 100644 --- a/class_table.c +++ b/class_table.c @@ -131,7 +131,7 @@ void __objc_init_class_tables(void) // Loader functions //////////////////////////////////////////////////////////////////////////////// -BOOL objc_resolve_class(Class cls) +BOOL objc_resolve_class(Class cls) { // Skip this if the class is already resolved. if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return YES; } diff --git a/selector.h b/selector.h index 9125f56..c5d7446 100644 --- a/selector.h +++ b/selector.h @@ -33,5 +33,14 @@ static uint32_t get_untyped_idx(SEL aSel) return (uint32_t)(uintptr_t)untyped->name; } +/** + * Returns whether a selector is mapped. + */ +BOOL sel_is_mapped(SEL selector); +/** + * Registers the selector. This selector may be returned later, so it must not + * be freed. + */ +SEL objc_register_selector(SEL aSel); #endif // OBJC_SELECTOR_H_INCLUDED diff --git a/selector_table.c b/selector_table.c index 6b6b757..75e3de3 100644 --- a/selector_table.c +++ b/selector_table.c @@ -256,7 +256,7 @@ static inline void register_selector_locked(SEL aSel) /** * Registers a selector. This assumes that the argument is never deallocated. */ -static SEL objc_register_selector(SEL aSel) +SEL objc_register_selector(SEL aSel) { if (isSelRegistered(aSel)) { @@ -486,7 +486,7 @@ SEL sel_register_name(const char *name) return sel_registerName(name); } -SEL sel_register_typed_name (const char *name, const char *type) +SEL sel_register_typed_name(const char *name, const char *type) { return sel_registerTypedName_np(name, type); } diff --git a/sendmsg2.c b/sendmsg2.c index b95d0fe..563b7bb 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -35,6 +35,7 @@ Slot_t objc_msg_lookup_internal(id *receiver, SEL selector, id sender) { +retry:; Slot_t result = objc_dtable_lookup((*receiver)->isa->dtable, PTR_TO_IDX(selector->name)); if (0 == result) @@ -56,6 +57,13 @@ Slot_t objc_msg_lookup_internal(id *receiver, } if (0 == result) { + if (!sel_is_mapped(selector)) + { + objc_register_selector(selector); + // This should be a tail call, but GCC is stupid and won't let + // us tail call an always_inline function. + goto retry; + } if ((result = objc_dtable_lookup(dtable, get_untyped_idx(selector)))) { fprintf(stderr, "Calling %s with incorrect signature. " @@ -250,6 +258,11 @@ Slot_t objc_get_slot(Class cls, SEL selector) } if (NULL == result) { + if (!sel_is_mapped(selector)) + { + objc_register_selector(selector); + return objc_get_slot(cls, selector); + } if ((result = objc_dtable_lookup(dtable, get_untyped_idx(selector)))) { fprintf(stderr, "Calling %s with incorrect signature. "