diff --git a/Test/Category.m b/Test/Category.m new file mode 100644 index 0000000..44df27e --- /dev/null +++ b/Test/Category.m @@ -0,0 +1,26 @@ +#include "Test.h" +#include "../objc/runtime.h" + +#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" +@interface Foo : Test ++ (int)replaced; +@end +@implementation Foo ++ (int)replaced +{ + return 1; +} +@end + +@implementation Foo (bar) ++ (int)replaced +{ + return 2; +} +@end + +int main (void) +{ + assert([Foo replaced] == 2); + return 0; +} diff --git a/class.h b/class.h index 3d5e78e..4ab3022 100644 --- a/class.h +++ b/class.h @@ -97,6 +97,16 @@ struct objc_class * runtime. */ struct objc_class *subclass_list; + /** + * Pointer to the .cxx_construct method if one exists. This method needs + * to be called outside of the normal dispatch mechanism. + */ + IMP cxx_construct; + /** + * Pointer to the .cxx_destruct method if one exists. This method needs to + * be called outside of the normal dispatch mechanism. + */ + IMP cxx_destruct; /** * A pointer to the next sibling class to this. You may find all * subclasses of a given class by following the subclass_list pointer and diff --git a/dtable.c b/dtable.c index 36ba490..1717d8f 100644 --- a/dtable.c +++ b/dtable.c @@ -10,7 +10,6 @@ #include "class.h" #include "lock.h" #include "method_list.h" -#include "slot_pool.h" #include "dtable.h" #include "visibility.h" #include "asmconstants.h" @@ -21,8 +20,12 @@ _Static_assert(__builtin_offsetof(SparseArray, shift) == SHIFT_OFFSET, "Incorrect shift offset for assembly"); _Static_assert(__builtin_offsetof(SparseArray, data) == DATA_OFFSET, "Incorrect data offset for assembly"); +// Slots are now a public interface to part of the method structure, so make +// sure that it's safe to use method and slot structures interchangeably. _Static_assert(__builtin_offsetof(struct objc_slot, method) == SLOT_OFFSET, "Incorrect slot offset for assembly"); +_Static_assert(__builtin_offsetof(struct objc_method, imp) == SLOT_OFFSET, + "Incorrect slot offset for assembly"); PRIVATE dtable_t uninstalled_dtable; #if defined(WITH_TRACING) && defined (__x86_64) @@ -41,17 +44,34 @@ PRIVATE mutex_t initialize_lock; static uint32_t dtable_depth = 8; /** - * Returns YES if the class implements a method for the specified selector, NO - * otherwise. + * Starting at `cls`, finds the class that provides the implementation of the + * method identified by `sel`. */ -static BOOL ownsMethod(Class cls, SEL sel) +static Class ownerForMethod(Class cls, SEL sel) { struct objc_slot *slot = objc_get_slot2(cls, sel); - if ((NULL != slot) && (slot->owner == cls)) + if (slot == NULL) + { + return Nil; + } + if (cls->super_class == NULL) + { + return cls; + } + if (objc_get_slot2(cls->super_class, sel) == slot) { - return YES; + return ownerForMethod(cls->super_class, sel); } - return NO; + return cls; +} + +/** + * Returns YES if the class implements a method for the specified selector, NO + * otherwise. + */ +static BOOL ownsMethod(Class cls, SEL sel) +{ + return ownerForMethod(cls, sel) == cls; } @@ -75,22 +95,22 @@ static void checkARCAccessors(Class cls) autorelease = sel_registerName("autorelease"); isARC = sel_registerName("_ARCCompliantRetainRelease"); } - struct objc_slot *slot = objc_get_slot2(cls, retain); - if ((NULL != slot) && !ownsMethod(slot->owner, isARC)) + Class owner = ownerForMethod(cls, retain); + if ((NULL != owner) && !ownsMethod(owner, isARC)) { ARC_DEBUG_LOG("%s does not support ARC correctly (implements retain)\n", cls->name); objc_clear_class_flag(cls, objc_class_flag_fast_arc); return; } - slot = objc_get_slot2(cls, release); - if ((NULL != slot) && !ownsMethod(slot->owner, isARC)) + owner = ownerForMethod(cls, retain); + if ((NULL != owner) && !ownsMethod(owner, isARC)) { ARC_DEBUG_LOG("%s does not support ARC correctly (implements release)\n", cls->name); objc_clear_class_flag(cls, objc_class_flag_fast_arc); return; } - slot = objc_get_slot2(cls, autorelease); - if ((NULL != slot) && !ownsMethod(slot->owner, isARC)) + owner = ownerForMethod(cls, retain); + if ((NULL != owner) && !ownsMethod(owner, isARC)) { ARC_DEBUG_LOG("%s does not support ARC correctly (implements autorelease)\n", cls->name); objc_clear_class_flag(cls, objc_class_flag_fast_arc); @@ -99,6 +119,15 @@ static void checkARCAccessors(Class cls) objc_set_class_flag(cls, objc_class_flag_fast_arc); } +static BOOL selEqualUnTyped(SEL expected, SEL untyped) +{ + return (expected->index == untyped->index) +#ifdef TYPE_DEPENDENT_DISPATCH + || (get_untyped_idx(expected) == untyped->index) +#endif + ; +} + PRIVATE void checkARCAccessorsSlow(Class cls) { if (cls->dtable != uninstalled_dtable) @@ -113,31 +142,32 @@ PRIVATE void checkARCAccessorsSlow(Class cls) autorelease = sel_registerName("autorelease"); isARC = sel_registerName("_ARCCompliantRetainRelease"); } + BOOL superIsFast = YES; if (cls->super_class != Nil) { checkARCAccessorsSlow(cls->super_class); + superIsFast = objc_test_class_flag(cls->super_class, objc_class_flag_fast_arc); } - BOOL superIsFast = objc_test_class_flag(cls, objc_class_flag_fast_arc); BOOL selfImplementsRetainRelease = NO; for (struct objc_method_list *l=cls->methods ; l != NULL ; l= l->next) { for (int i=0 ; icount ; i++) { SEL s = l->methods[i].selector; - if (sel_isEqual(s, retain) || - sel_isEqual(s, release) || - sel_isEqual(s, autorelease)) + if (selEqualUnTyped(s, retain) || + selEqualUnTyped(s, release) || + selEqualUnTyped(s, autorelease)) { selfImplementsRetainRelease = YES; } - else if (sel_isEqual(s, isARC)) + else if (selEqualUnTyped(s, isARC)) { objc_set_class_flag(cls, objc_class_flag_fast_arc); return; } } } - if (superIsFast && ! selfImplementsRetainRelease) + if (superIsFast && !selfImplementsRetainRelease) { objc_set_class_flag(cls, objc_class_flag_fast_arc); } @@ -242,63 +272,87 @@ int objc_registerTracingHook(SEL aSel, objc_tracing_hook aHook) #endif } +/** + * Installs a new method in the dtable for `class`. If `replaceMethod` is + * `YES` then this will replace any dtable entry where the original is + * `method_to_replace`. This is used when a superclass method is replaced, to + * replace all subclass dtable entries that are inherited, but not ones that + * are overridden. + */ static BOOL installMethodInDtable(Class class, - Class owner, SparseArray *dtable, struct objc_method *method, + struct objc_method *method_to_replace, BOOL replaceExisting) { ASSERT(uninstalled_dtable != dtable); uint32_t sel_id = method->selector->index; - struct objc_slot *slot = SparseArrayLookup(dtable, sel_id); - if (NULL != slot) + struct objc_method *oldMethod = SparseArrayLookup(dtable, sel_id); + // If we're being asked to replace an existing method, don't if it's the + // wrong one. + if ((replaceExisting) && (method_to_replace != oldMethod)) { - // If this method is the one already installed, pretend to install it again. - if (slot->method == method->imp) { return NO; } - - // If the existing slot is for this class, we can just replace the - // implementation. We don't need to bump the version; this operation - // updates cached slots, it doesn't invalidate them. - if (slot->owner == owner) - { - // Don't replace methods if we're not meant to (if they're from - // later in a method list, for example) - if (!replaceExisting) { return NO; } - slot->method = method->imp; - return YES; - } - - // Check whether the owner of this method is a subclass of the one that - // owns this method. If it is, then we don't want to install this - // method irrespective of other cases, because it has been overridden. - for (Class installedFor = slot->owner ; - Nil != installedFor ; - installedFor = installedFor->super_class) - { - if (installedFor == owner) - { - return NO; - } - } + return NO; } - struct objc_slot *oldSlot = slot; - slot = new_slot_for_method_in_class((void*)method, owner); - SparseArrayInsert(dtable, sel_id, slot); + // If we're not being asked to replace existing methods and there is an + // existing one, don't replace it. + if (!replaceExisting && (oldMethod != NULL)) + { + return NO; + } + // If this method is the one already installed, pretend to install it again. + if (NULL != oldMethod && (oldMethod->imp == method->imp)) + { + return NO; + } + SparseArrayInsert(dtable, sel_id, method); // In TDD mode, we also register the first typed method that we // encounter as the untyped version. #ifdef TYPE_DEPENDENT_DISPATCH - SparseArrayInsert(dtable, get_untyped_idx(method->selector), slot); + uint32_t untyped_idx = get_untyped_idx(method->selector); + SparseArrayInsert(dtable, untyped_idx, method); #endif + + static SEL cxx_construct, cxx_destruct; + if (NULL == cxx_construct) + { + cxx_construct = sel_registerName(".cxx_construct"); + cxx_destruct = sel_registerName(".cxx_destruct"); + } + if (selEqualUnTyped(method->selector, cxx_construct)) + { + class->cxx_construct = method->imp; + } + else if (selEqualUnTyped(method->selector, cxx_destruct)) + { + class->cxx_destruct = method->imp; + } + + for (struct objc_class *subclass=class->subclass_list ; + Nil != subclass ; subclass = subclass->sibling_class) + { + // Don't bother updating dtables for subclasses that haven't been + // initialized yet + if (!classHasDtable(subclass)) { continue; } + + // Recursively install this method in all subclasses + installMethodInDtable(subclass, + dtable_for_class(subclass), + method, + oldMethod, + YES); + } + // Invalidate the old slot, if there is one. - if (NULL != oldSlot) + if (NULL != oldMethod) { - oldSlot->version++; + objc_method_cache_version++; } return YES; } static void installMethodsInClass(Class cls, - Class owner, + SparseArray *methods_to_replace, SparseArray *methods, BOOL replaceExisting) { @@ -309,7 +363,10 @@ static void installMethodsInClass(Class cls, struct objc_method *m; while ((m = SparseArrayNext(methods, &idx))) { - if (!installMethodInDtable(cls, owner, dtable, m, replaceExisting)) + struct objc_method *method_to_replace = methods_to_replace + ? SparseArrayLookup(methods_to_replace, m->selector->index) + : NULL; + if (!installMethodInDtable(cls, dtable, m, method_to_replace, replaceExisting)) { // Remove this method from the list, if it wasn't actually installed SparseArrayInsert(methods, idx, 0); @@ -317,27 +374,6 @@ static void installMethodsInClass(Class cls, } } -static void mergeMethodsFromSuperclass(Class super, Class cls, SparseArray *methods) -{ - for (struct objc_class *subclass=cls->subclass_list ; - Nil != subclass ; subclass = subclass->sibling_class) - { - // Don't bother updating dtables for subclasses that haven't been - // initialized yet - if (!classHasDtable(subclass)) { continue; } - - // Create a new (copy-on-write) array to pass down to children - SparseArray *newMethods = SparseArrayCopy(methods); - // Install all of these methods except ones that are overridden in the - // subclass. All of the methods that we are updating were added in a - // superclass, so we don't replace versions registered to the subclass. - installMethodsInClass(subclass, super, newMethods, YES); - // Recursively add the methods to the subclass's subclasses. - mergeMethodsFromSuperclass(super, subclass, newMethods); - SparseArrayDestroy(newMethods); - } -} - Class class_getSuperclass(Class); PRIVATE void objc_update_dtable_for_class(Class cls) @@ -349,9 +385,9 @@ PRIVATE void objc_update_dtable_for_class(Class cls) SparseArray *methods = SparseArrayNewWithDepth(dtable_depth); collectMethodsForMethodListToSparseArray((void*)cls->methods, methods, YES); - installMethodsInClass(cls, cls, methods, YES); - // Methods now contains only the new methods for this class. - mergeMethodsFromSuperclass(cls, cls, methods); + SparseArray *super_dtable = cls->super_class ? dtable_for_class(cls->super_class) + : NULL; + installMethodsInClass(cls, super_dtable, methods, YES); SparseArrayDestroy(methods); checkARCAccessors(cls); } @@ -365,10 +401,11 @@ PRIVATE void add_method_list_to_class(Class cls, LOCK_RUNTIME_FOR_SCOPE(); SparseArray *methods = SparseArrayNewWithDepth(dtable_depth); + SparseArray *super_dtable = cls->super_class ? dtable_for_class(cls->super_class) + : NULL; collectMethodsForMethodListToSparseArray(list, methods, NO); - installMethodsInClass(cls, cls, methods, YES); + installMethodsInClass(cls, super_dtable, methods, YES); // Methods now contains only the new methods for this class. - mergeMethodsFromSuperclass(cls, cls, methods); SparseArrayDestroy(methods); checkARCAccessors(cls); } @@ -386,7 +423,7 @@ static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable) Class super = class_getSuperclass(class); dtable_t dtable; - + dtable_t super_dtable = NULL; if (Nil == super) { @@ -394,7 +431,7 @@ static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable) } else { - dtable_t super_dtable = dtable_for_class(super); + super_dtable = dtable_for_class(super); if (super_dtable == uninstalled_dtable) { if (super->isa == class) @@ -412,15 +449,18 @@ static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable) // When constructing the initial dtable for a class, we iterate along the // method list in forward-traversal order. The first method that we // encounter is always the one that we want to keep, so we instruct - // installMethodInDtable() not to replace methods that are already - // associated with this class. + // installMethodInDtable() to replace only methods that are inherited from + // the superclass. struct objc_method_list *list = (void*)class->methods; while (NULL != list) { for (unsigned i=0 ; icount ; i++) { - installMethodInDtable(class, class, dtable, &list->methods[i], NO); + struct objc_method *super_method = super_dtable + ? SparseArrayLookup(super_dtable, list->methods[i].selector->index) + : NULL; + installMethodInDtable(class, dtable, &list->methods[i], super_method, YES); } list = list->next; } @@ -623,7 +663,7 @@ PRIVATE void objc_send_initialize(id object) initializeSel = sel_registerName("initialize"); } - struct objc_slot *initializeSlot = skipMeta ? 0 : + struct objc_method *initializeSlot = skipMeta ? 0 : objc_dtable_lookup(dtable, initializeSel->index); // If there's no initialize method, then don't bother installing and @@ -662,6 +702,6 @@ PRIVATE void objc_send_initialize(id object) // Store the buffer in the temporary dtables list. Note that it is safe to // insert it into a global list, even though it's a temporary variable, // because we will clean it up after this function. - initializeSlot->method((id)class, initializeSel); + initializeSlot->imp((id)class, initializeSel); } diff --git a/legacy.c b/legacy.c index 6d8c22a..5cbe3b3 100644 --- a/legacy.c +++ b/legacy.c @@ -79,7 +79,12 @@ static struct objc_method_list *upgradeMethodList(struct objc_method_list_legacy l->next = upgradeMethodList(old->next); } l->size = sizeof(struct objc_method); - memcpy(&l->methods, &old->methods, old->count * sizeof(struct objc_method)); + for (int i=0 ; icount ; i++) + { + l->methods[i].imp = old->methods[i].imp; + l->methods[i].selector = old->methods[i].selector; + l->methods[i].types = old->methods[i].types; + } return l; } diff --git a/method_list.h b/method_list.h index 91c3991..3e64eec 100644 --- a/method_list.h +++ b/method_list.h @@ -2,6 +2,25 @@ * Metadata structure describing a method. */ struct objc_method +{ + /** + * A pointer to the function implementing this method. + */ + IMP imp; + /** + * Selector used to send messages to this method. The type encoding of + * this method should match the types field. + */ + SEL selector; + /** + * The type encoding for this selector. Used only for introspection, and + * only required because of the stupid selector handling in the old GNU + * runtime. In future, this field may be reused for something else. + */ + const char *types; +}; + +struct objc_method_legacy { /** * Selector used to send messages to this method. The type encoding of @@ -63,5 +82,5 @@ struct objc_method_list_legacy /** * An array of methods. Note that the actual size of this is count. */ - struct objc_method methods[]; + struct objc_method_legacy methods[]; }; diff --git a/objc/slot.h b/objc/slot.h index 47d078b..605910d 100644 --- a/objc/slot.h +++ b/objc/slot.h @@ -27,19 +27,11 @@ */ struct objc_slot { - /** The method pointer for this method. */ IMP method; - /** The current version. This changes if the method changes or if a - * subclass overrides this method, potentially invalidating this cache. */ - int version; - /** - * The method for this slot. - */ - Method method_metadata; - /** The class to which this slot is attached (used internally). */ - Class owner; } OBJC_NONPORTABLE; +_Atomic(uint64_t) objc_method_cache_version; + struct objc_slot_v1 { /** The class to which this slot is attached (used internally). */ diff --git a/runtime.c b/runtime.c index 0138906..3d2ac67 100644 --- a/runtime.c +++ b/runtime.c @@ -36,13 +36,11 @@ PRIVATE void call_cxx_destruct(id obj) while (cls) { - struct objc_slot *slot = objc_get_slot2(cls, cxx_destruct); - cls = Nil; - if (NULL != slot) + if (cls->cxx_destruct) { - cls = slot->owner->super_class; - slot->method(obj, cxx_destruct); + cls->cxx_destruct(obj, cxx_destruct); } + cls = cls->super_class; } } @@ -53,15 +51,14 @@ static void call_cxx_construct_for_class(Class cls, id obj) { cxx_construct = sel_registerName(".cxx_construct"); } - struct objc_slot *slot = objc_get_slot2(cls, cxx_construct); - if (NULL != slot) + + if (cls->super_class) { - cls = slot->owner->super_class; - if (Nil != cls) - { - call_cxx_construct_for_class(cls, obj); - } - slot->method(obj, cxx_construct); + call_cxx_construct_for_class(cls->super_class, obj); + } + if (cls->cxx_construct) + { + cls->cxx_construct(obj, cxx_construct); } } @@ -91,27 +88,6 @@ static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector) return NULL; } -static void objc_updateDtableForClassContainingMethod(Method m) -{ - Class nextClass = Nil; - void *state = NULL; - SEL sel = method_getName(m); - while (Nil != (nextClass = objc_next_class(&state))) - { - if (class_getInstanceMethodNonrecursive(nextClass, sel) == m) - { - objc_update_dtable_for_class(nextClass); - return; - } - Class meta = object_getClass((id)nextClass); - if (class_getInstanceMethodNonrecursive(meta, sel) == m) - { - objc_update_dtable_for_class(meta); - return; - } - } -} - BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types) { @@ -395,9 +371,8 @@ Method class_getInstanceMethod(Class aClass, SEL aSelector) return NULL; } } - - // Then do the slow lookup to find the method. - return slot->method_metadata; + // Slots are the same as methods. + return (struct objc_method*)slot; } Method m = class_getInstanceMethodNonrecursive(aClass, aSelector); if (NULL != m) @@ -494,12 +469,6 @@ IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) } IMP old = (IMP)method->imp; method->imp = imp; - - if (objc_test_class_flag(cls, objc_class_flag_resolved)) - { - objc_update_dtable_for_class(cls); - } - return old; } @@ -561,8 +530,6 @@ void method_exchangeImplementations(Method m1, Method m2) IMP tmp = (IMP)m1->imp; m1->imp = m2->imp; m2->imp = tmp; - objc_updateDtableForClassContainingMethod(m1); - objc_updateDtableForClassContainingMethod(m2); } IMP method_getImplementation(Method method) @@ -583,7 +550,6 @@ IMP method_setImplementation(Method method, IMP imp) if (NULL == method) { return (IMP)NULL; } IMP old = (IMP)method->imp; method->imp = imp; - objc_updateDtableForClassContainingMethod(method); return old; } diff --git a/sendmsg2.c b/sendmsg2.c index 060f64d..c867fee 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -19,10 +19,10 @@ static struct objc_slot_v1 nil_slot_D_v1 = { Nil, Nil, 0, 1, (IMP)nil_method_D } static struct objc_slot_v1 nil_slot_d_v1 = { Nil, Nil, 0, 1, (IMP)nil_method_d }; static struct objc_slot_v1 nil_slot_f_v1 = { Nil, Nil, 0, 1, (IMP)nil_method_f }; -static struct objc_slot nil_slot = { (IMP)nil_method, 1, NULL, Nil }; -static struct objc_slot nil_slot_D = { (IMP)nil_method_D, 1, NULL, Nil }; -static struct objc_slot nil_slot_d = { (IMP)nil_method_d, 1, NULL, Nil }; -static struct objc_slot nil_slot_f = { (IMP)nil_method_f, 1, NULL, Nil }; +static struct objc_method nil_slot = { (IMP)nil_method, NULL, NULL }; +static struct objc_method nil_slot_D = { (IMP)nil_method_D, NULL, NULL }; +static struct objc_method nil_slot_d = { (IMP)nil_method_d, NULL, NULL }; +static struct objc_method nil_slot_f = { (IMP)nil_method_f, NULL, NULL }; struct objc_slot* objc_slot_lookup(id *receiver, SEL selector); @@ -39,7 +39,7 @@ static IMP forward2(id self, SEL _cmd) } IMP (*__objc_msg_forward2)(id, SEL) = forward2; -__thread struct objc_slot uncacheable_slot = { (IMP)nil_method, 0, NULL, Nil }; +__thread struct objc_method uncacheable_slot = { (IMP)nil_method, NULL, NULL }; __thread struct objc_slot_v1 uncacheable_slot_v1 = { Nil, Nil, 0, 0, (IMP)nil_method }; #ifndef NO_SELECTOR_MISMATCH_WARNINGS @@ -47,11 +47,12 @@ static struct objc_slot* objc_selector_type_mismatch(Class cls, SEL selector, struct objc_slot *result) { fprintf(stderr, "Calling [%s %c%s] with incorrect signature. " - "Method has %s, selector has %s\n", + "Method has %s (%s), selector has %s\n", cls->name, class_isMetaClass(cls) ? '+' : '-', sel_getName(selector), - result->method_metadata->types, + sel_getType_np(((struct objc_method*)result)->selector), + ((struct objc_method*)result)->types, sel_getType_np(selector)); return result; } @@ -75,8 +76,7 @@ static struct objc_slot *call_mismatch_hook(Class cls, SEL sel, struct objc_slot (_objc_selector_type_mismatch2 == objc_selector_type_mismatch))) { struct objc_slot_v1 fwdslot; - fwdslot.owner = slot->owner; - fwdslot.types = slot->method_metadata->types; + fwdslot.types = ((struct objc_method*)slot)->types; fwdslot.selector = sel; fwdslot.method = slot->method; struct objc_slot_v1 *slot_v1 = _objc_selector_type_mismatch(cls, sel, &uncacheable_slot_v1); @@ -84,9 +84,8 @@ static struct objc_slot *call_mismatch_hook(Class cls, SEL sel, struct objc_slot { return slot; } - uncacheable_slot.owner = slot_v1->owner; - uncacheable_slot.method = slot_v1->method; - return &uncacheable_slot; + uncacheable_slot.imp = slot_v1->method; + return (struct objc_slot*)&uncacheable_slot; } return _objc_selector_type_mismatch2(cls, sel, slot); } @@ -139,8 +138,8 @@ retry:; } if (0 == result) { - uncacheable_slot.method = __objc_msg_forward2(*receiver, selector); - result = &uncacheable_slot; + uncacheable_slot.imp = __objc_msg_forward2(*receiver, selector); + result = (struct objc_slot*)&uncacheable_slot; } } } @@ -191,8 +190,8 @@ struct objc_slot_v1 *objc_msg_lookup_sender(id *receiver, SEL selector, id sende } struct objc_slot *slot = objc_msg_lookup_internal(receiver, selector); - uncacheable_slot_v1.owner = slot->owner; - uncacheable_slot_v1.types = slot->method_metadata->types; + uncacheable_slot_v1.owner = Nil; + uncacheable_slot_v1.types = sel_getType_np(((struct objc_method*)slot)->selector); uncacheable_slot_v1.selector = selector; uncacheable_slot_v1.method = slot->method; return &uncacheable_slot_v1; @@ -217,12 +216,12 @@ struct objc_slot* objc_slot_lookup(id *receiver, SEL selector) } switch (selector->types[0]) { - case 'D': return &nil_slot_D; - case 'd': return &nil_slot_d; - case 'f': return &nil_slot_f; + case 'D': return (struct objc_slot*)&nil_slot_D; + case 'd': return (struct objc_slot*)&nil_slot_d; + case 'f': return (struct objc_slot*)&nil_slot_f; } } - return &nil_slot; + return (struct objc_slot*)&nil_slot; } return objc_msg_lookup_internal(receiver, selector); @@ -254,11 +253,11 @@ struct objc_slot *objc_slot_lookup_super2(struct objc_super *super, SEL selector objc_send_initialize((id)class); return objc_slot_lookup_super2(super, selector); } - return &nil_slot; + return (struct objc_slot*)&nil_slot; } return result; } - return &nil_slot; + return (struct objc_slot*)&nil_slot; } struct objc_slot_v1 *objc_slot_lookup_super(struct objc_super *super, SEL selector) @@ -289,8 +288,8 @@ struct objc_slot_v1 *objc_slot_lookup_super(struct objc_super *super, SEL select } return &nil_slot_v1; } - uncacheable_slot_v1.owner = result->owner; - uncacheable_slot_v1.types = result->method_metadata->types; + uncacheable_slot_v1.owner = Nil; + uncacheable_slot_v1.types = sel_getType_np(((struct objc_method*)result)->selector); uncacheable_slot_v1.selector = selector; uncacheable_slot_v1.method = result->method; return &uncacheable_slot_v1; @@ -422,9 +421,9 @@ struct objc_slot_v1 *objc_get_slot(Class cls, SEL selector) { return NULL; } - uncacheable_slot_v1.owner = result->owner; + uncacheable_slot_v1.owner = Nil; // Don't leak extended type encodings! - uncacheable_slot_v1.types = sel_getType_np(result->method_metadata->selector); + uncacheable_slot_v1.types = sel_getType_np(((struct objc_method*)result)->selector); uncacheable_slot_v1.selector = selector; uncacheable_slot_v1.method = result->method; return &uncacheable_slot_v1; diff --git a/slot_pool.h b/slot_pool.h index a1e918c..cd52d24 100644 --- a/slot_pool.h +++ b/slot_pool.h @@ -9,9 +9,7 @@ static inline struct objc_slot *new_slot_for_method_in_class(Method method, Class class) { struct objc_slot *slot = slot_pool_alloc(); - slot->owner = class; slot->method_metadata = method; slot->method = method->imp; - slot->version = 1; return slot; }