From 42a545fc7c8306ba61db0ca3196a4845b77b8bac Mon Sep 17 00:00:00 2001 From: theraven Date: Tue, 31 Aug 2010 20:40:08 +0000 Subject: [PATCH] In some irritating circumstances, the load order can cause a +load message to trigger other code, which sends messages with selectors that have not been mapped yet. The runtime was handling the message lookup correctly in this case, but only as a side-effect of the fallback code from when type-dependent dispatch is not possible. This resulted in a confusing warning message, telling you that you were calling a method with an incorrect signature, when the two signatures that it printed were the same. This case is now handled correctly, so the warning disappears (unless you really are calling a method with the wrong signature and have TDD enabled). --- class_table.c | 2 +- selector.h | 9 +++++++++ selector_table.c | 4 ++-- sendmsg2.c | 13 +++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) 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. "