From e482b6986f457c63155a70f4b27065a258a004e8 Mon Sep 17 00:00:00 2001 From: theraven Date: Fri, 21 May 2010 13:49:19 +0000 Subject: [PATCH] More fixes for the new dtable. Now passing all of the EtoileFoundation tests, which do lots of things involving categories, so make a good stress test. No longer installs headers by default. This is because GNUstep Make notices when the objc headers have changed (because GNUstep includes them) and so reinstalling libobjc2 was requiring a complete recompile of anything that you tried to build, even if you only changed one line. A better fix for this would be for install to use cmp or diff to check if the header has been modified before installing it, but I'm too lazy to do that right now. --- GNUmakefile | 2 ++ dtable.c | 56 ++++++++++++++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index ec54017..f05cfb5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -41,6 +41,7 @@ libobjc_C_FILES = \ libobjc_HEADER_FILES_DIR = objc libobjc_HEADER_FILES_INSTALL_DIR = objc +ifeq ($(install_headers), yes) libobjc_HEADER_FILES = \ Availability.h\ NXConstStr.h\ @@ -59,6 +60,7 @@ libobjc_HEADER_FILES = \ slot.h\ thr.h\ typedstream.h +endif libobjc_LIBRARIES_DEPEND_UPON += -lpthread diff --git a/dtable.c b/dtable.c index ebeccfe..1f41894 100644 --- a/dtable.c +++ b/dtable.c @@ -101,6 +101,7 @@ static void collectMethodsForMethodListToSparseArray( } static BOOL installMethodInDtable(Class class, + Class owner, SparseArray *dtable, struct objc_method *method, BOOL replaceExisting) @@ -108,32 +109,35 @@ static BOOL installMethodInDtable(Class class, assert(__objc_uninstalled_dtable != dtable); uint32_t sel_id = PTR_TO_IDX(method->selector->sel_id); struct objc_slot *slot = SparseArrayLookup(dtable, sel_id); - if (NULL != slot && slot->owner == class) + if (NULL != slot) { - if ((slot->method == method->imp) || !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++; - } - else - { - //fprintf(stderr, "Installing method %p %s in %s\n", method->imp, sel_get_name(method->selector), class->name); - slot = new_slot_for_method_in_class((void*)method, class); - SparseArrayInsert(dtable, sel_id, slot); - // Invalidate the superclass's slot, if it has one. - if (NULL != class->super_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 (NULL != (slot = - SparseArrayLookup(dtable_for_class(class->super_class), sel_id))) - { - slot->version++; - } + 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; } } + struct objc_slot *oldSlot = slot; + //fprintf(stderr, "Installing method %p %s in %s\n", method->imp, sel_get_name(method->selector), class->name); + slot = new_slot_for_method_in_class((void*)method, owner); + SparseArrayInsert(dtable, sel_id, slot); + // Invalidate the old slot, if there is one. + if (NULL != oldSlot) + { + //fprintf(stderr, "Overriding method %p %s from %s in %s with %x\n", slot->method, sel_get_name(method->selector), oldSlot->owner->name, class->name, method->imp); + oldSlot->version++; + } return YES; } static void installMethodsInClass(Class cls, + Class owner, SparseArray *methods, BOOL replaceExisting) { @@ -144,7 +148,7 @@ static void installMethodsInClass(Class cls, struct objc_method *m; while ((m = SparseArrayNext(methods, &idx))) { - if (!installMethodInDtable(cls, dtable, m, replaceExisting)) + if (!installMethodInDtable(cls, owner, dtable, m, replaceExisting)) { // Remove this method from the list, if it wasn't actually installed SparseArrayInsert(methods, idx, 0); @@ -152,23 +156,23 @@ static void installMethodsInClass(Class cls, } } -static void mergeMethodsFromSuperclass(Class cls, SparseArray *methods) +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)) { return; } + 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, newMethods, NO); + installMethodsInClass(subclass, super, newMethods, YES); // Recursively add the methods to the subclass's subclasses. - mergeMethodsFromSuperclass(subclass, newMethods); + mergeMethodsFromSuperclass(super, subclass, newMethods); SparseArrayDestroy(newMethods); } } @@ -184,9 +188,9 @@ void __objc_update_dispatch_table_for_class(Class cls) SparseArray *methods = SparseArrayNewWithDepth(dtable_depth); collectMethodsForMethodListToSparseArray((void*)cls->methods, methods); - installMethodsInClass(cls, methods, YES); + installMethodsInClass(cls, cls, methods, YES); // Methods now contains only the new methods for this class. - mergeMethodsFromSuperclass(cls, methods); + mergeMethodsFromSuperclass(cls, cls, methods); SparseArrayDestroy(methods); } @@ -232,7 +236,7 @@ static SparseArray *create_dtable_for_class(Class class) { for (unsigned i=0 ; icount ; i++) { - installMethodInDtable(class, dtable, &list->methods[i], NO); + installMethodInDtable(class, class, dtable, &list->methods[i], NO); } list = list->next; }