From 8a451d212c76fca22d6866940e6ea44c89966614 Mon Sep 17 00:00:00 2001 From: theraven Date: Fri, 21 May 2010 19:00:02 +0000 Subject: [PATCH] More dtable fixes - now the EtoileFoundation tests work when compiled with GCC too. Hopefully that's all of the irritating corner cases in category loading dealt with... --- dtable.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/dtable.c b/dtable.c index 1f41894..64f0d71 100644 --- a/dtable.c +++ b/dtable.c @@ -114,17 +114,34 @@ static BOOL installMethodInDtable(Class class, // If this method is the one already installed, pretend to install it again. if (slot->method == method->imp) { return NO; } - if (slot->owner == class) + // 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; } //fprintf(stderr, "Replacing method %p %s in %s with %x\n", slot->method, sel_get_name(method->selector), class->name, method->imp); slot->method = method->imp; - slot->version++; return YES; } + + Class installedFor = slot->owner; + // 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) { + //fprintf(stderr, "Not installing %s from %s in %s - already overridden from %s\n", sel_get_name(method->selector), owner->name, class->name, slot->owner->name); + return NO; } + } } struct objc_slot *oldSlot = slot; - //fprintf(stderr, "Installing method %p %s in %s\n", method->imp, sel_get_name(method->selector), class->name); + //fprintf(stderr, "Installing method %p (%d) %s in %s (previous slot owned by %s)\n", method->imp, sel_id, sel_get_name(method->selector), class->name, slot? oldSlot->owner->name: ""); slot = new_slot_for_method_in_class((void*)method, owner); SparseArrayInsert(dtable, sel_id, slot); // Invalidate the old slot, if there is one. @@ -183,6 +200,7 @@ void __objc_update_dispatch_table_for_class(Class cls) { // Only update real dtables if (!classHasDtable(cls)) { return; } + //fprintf(stderr, "Updating dtable for %s\n", cls->name); LOCK_UNTIL_RETURN(__objc_runtime_mutex);