diff --git a/GNUmakefile b/GNUmakefile index 19c77f8..bf325d8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -8,9 +8,7 @@ libobjc_VERSION = 4 libobjc_OBJC_FILES = \ NSBlocks.m\ - NXConstStr.m\ - Object.m\ - Protocol.m\ + Protocol2.m\ blocks_runtime.m\ mutation.m\ properties.m\ @@ -28,7 +26,6 @@ libobjc_C_FILES = \ hooks.c\ ivar.c\ loader.c\ - misc.c\ protocol.c\ runtime.c\ sarray2.c\ @@ -38,6 +35,7 @@ libobjc_C_FILES = \ ifneq ($(enable_legacy), no) libobjc_C_FILES += \ + legacy_malloc.c\ objects.c\ thr.c endif @@ -86,15 +84,3 @@ endif include $(GNUSTEP_MAKEFILES)/aggregate.make include $(GNUSTEP_MAKEFILES)/library.make - -ifeq ($(findstring no, $(debug)),) -before-all:: - @echo - @echo - @echo WARNING: You are building in debug mode. This will generate a LOT of console \ - output for every Objective-C program you run. If this is not what you \ - want, please compile with $(MAKE) debug=no - @echo - @echo -endif - diff --git a/NSBlocks.m b/NSBlocks.m index f343f70..223d900 100644 --- a/NSBlocks.m +++ b/NSBlocks.m @@ -1,5 +1,8 @@ -#import "objc/objc-api.h" +#import "objc/runtime.h" +#import "class.h" +#import "lock.h" #import "objc/blocks_runtime.h" +#import "dtable.h" #include struct objc_class _NSConcreteGlobalBlock; @@ -11,28 +14,24 @@ static struct objc_class _NSConcreteStackBlockMeta; static struct objc_class _NSBlock; static struct objc_class _NSBlockMeta; -void __objc_update_dispatch_table_for_class(Class); -void __objc_add_class_to_hash(Class); -extern struct sarray *__objc_uninstalled_dtable; -extern objc_mutex_t __objc_runtime_mutex; - static void createNSBlockSubclass(Class superclass, Class newClass, Class metaClass, char *name) { // Initialize the metaclass //metaClass->class_pointer = superclass->class_pointer; //metaClass->super_class = superclass->class_pointer; - metaClass->info = _CLS_META; + metaClass->info = objc_class_flag_meta; metaClass->dtable = __objc_uninstalled_dtable; // Set up the new class - newClass->class_pointer = metaClass; + newClass->isa = metaClass; newClass->super_class = (Class)superclass->name; newClass->name = name; - newClass->info = _CLS_CLASS; + newClass->info = objc_class_flag_class; newClass->dtable = __objc_uninstalled_dtable; - __objc_add_class_to_hash(newClass); + LOCK_UNTIL_RETURN(__objc_runtime_mutex); + class_table_insert(newClass); } diff --git a/NXConstStr.m b/NXConstStr.m deleted file mode 100644 index 55492e1..0000000 --- a/NXConstStr.m +++ /dev/null @@ -1,45 +0,0 @@ -/* Implementation of the NXConstantString class for Objective-C. - Copyright (C) 1995, 2009 Free Software Foundation, Inc. - Contributed by Pieter J. Schoenmakers - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3, or (at your option) any -later version. - -GCC is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -License for more details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#include "objc/NXConstStr.h" -#include "objc/objc-api.h" - -@implementation NXConstantString -+ (void)load -{ - __CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE; -} - --(const char *) cString -{ - return (c_string); -} /* -cString */ - --(unsigned int) length -{ - return (len); -} /* -length */ - -@end diff --git a/Object.m b/Object.m deleted file mode 100644 index f9543d9..0000000 --- a/Object.m +++ /dev/null @@ -1,360 +0,0 @@ -/* The implementation of class Object for Objective-C. - Copyright (C) 1993, 1994, 1995, 1997, 2002, 2009 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3, or (at your option) any -later version. - -GCC is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -License for more details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#include -#include -#include "objc/Object.h" -#include "objc/Protocol.h" -#include "objc/objc-api.h" - -#define MAX_CLASS_NAME_LEN 256 - -@implementation Object - -+ (void)load -{ - __CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE; -} -+ initialize -{ - // Object subclasses are not plane aware either. - __CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE; - return self; -} - -- init -{ - return self; -} - -+ new -{ - return [[self alloc] init]; -} - -+ alloc -{ - return class_create_instance(self); -} - -- free -{ - return object_dispose(self); -} - -- copy -{ - return [[self shallowCopy] deepen]; -} - -- shallowCopy -{ - return object_copy(self); -} - -- deepen -{ - return self; -} - -- deepCopy -{ - return [self copy]; -} - -- (Class)class -{ - return object_get_class(self); -} - -- (Class)superClass -{ - return object_get_super_class(self); -} - -- (MetaClass)metaClass -{ - return object_get_meta_class(self); -} - -- (const char *)name -{ - return object_get_class_name(self); -} - -- self -{ - return self; -} - -- (unsigned int)hash -{ - return (size_t)self; -} - -- (BOOL)isEqual:anObject -{ - return self==anObject; -} - -- (int)compare:(id)anotherObject; -{ - if ([self isEqual:anotherObject]) - return 0; - // Ordering objects by their address is pretty useless, - // so subclasses should override this is some useful way. - else if ((id)self > anotherObject) - return 1; - else - return -1; -} - -- (BOOL)isMetaClass -{ - return NO; -} - -- (BOOL)isClass -{ - return object_is_class(self); -} - -- (BOOL)isInstance -{ - return object_is_instance(self); -} - -- (BOOL)isKindOf:(Class)aClassObject -{ - Class class; - - for (class = self->isa; class!=Nil; class = class_get_super_class(class)) - if (class==aClassObject) - return YES; - return NO; -} - -- (BOOL)isMemberOf:(Class)aClassObject -{ - return self->isa==aClassObject; -} - -- (BOOL)isKindOfClassNamed:(const char *)aClassName -{ - Class class; - - if (aClassName!=NULL) - for (class = self->isa; class!=Nil; class = class_get_super_class(class)) - if (!strcmp(class_get_class_name(class), aClassName)) - return YES; - return NO; -} - -- (BOOL)isMemberOfClassNamed:(const char *)aClassName -{ - return ((aClassName!=NULL) - &&!strcmp(class_get_class_name(self->isa), aClassName)); -} - -BOOL class_respondsToSelector(Class, SEL); -+ (BOOL)instancesRespondTo:(SEL)aSel -{ - return class_respondsToSelector(self, aSel); -} - -- (BOOL)respondsTo:(SEL)aSel -{ - return class_respondsToSelector(isa, aSel); -} - -IMP class_getMethodImplementation(Class cls, SEL name); -+ (IMP)instanceMethodFor:(SEL)aSel -{ - return class_getMethodImplementation(self, aSel); -} - -// Indicates if the receiving class or instance conforms to the given protocol -// not usually overridden by subclasses -// -// Modified 9/5/94 to always search the class object's protocol list, rather -// than the meta class. - -+ (BOOL) conformsTo: (Protocol*)aProtocol -{ - size_t i; - struct objc_protocol_list* proto_list; - id parent; - - for (proto_list = ((Class)self)->protocols; - proto_list; proto_list = proto_list->next) - { - for (i=0; i < proto_list->count; i++) - { - if ([proto_list->list[i] conformsTo: aProtocol]) - return YES; - } - } - - if ((parent = [self superClass])) - return [parent conformsTo: aProtocol]; - else - return NO; -} - -- (BOOL) conformsTo: (Protocol*)aProtocol -{ - return [[self class] conformsTo:aProtocol]; -} - -- (IMP)methodFor:(SEL)aSel -{ - return class_getMethodImplementation(isa, aSel); -} - -struct objc_method *class_getInstanceMethod(Class aClass, SEL aSelector); -+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel -{ - return ((struct objc_method_description *) - class_getInstanceMethod(self, aSel)); -} - -struct objc_method *class_getClassMethod(Class aClass, SEL aSelector); -- (struct objc_method_description *)descriptionForMethod:(SEL)aSel -{ - return ((struct objc_method_description *) - (object_is_instance(self) - ?class_getInstanceMethod(self->isa, aSel) - :class_getClassMethod(self->isa, aSel))); -} - -- perform:(SEL)aSel -{ - IMP msg = objc_msg_lookup(self, aSel); - if (!msg) - return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; - return (*msg)(self, aSel); -} - -- perform:(SEL)aSel with:anObject -{ - IMP msg = objc_msg_lookup(self, aSel); - if (!msg) - return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; - return (*msg)(self, aSel, anObject); -} - -- perform:(SEL)aSel with:anObject1 with:anObject2 -{ - IMP msg = objc_msg_lookup(self, aSel); - if (!msg) - return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; - return (*msg)(self, aSel, anObject1, anObject2); -} - -- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame -{ - (void) argFrame; /* UNUSED */ - return (retval_t)[self doesNotRecognize: aSel]; -} - -- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame -{ - return objc_msg_sendv(self, aSel, argFrame); -} - -+ poseAs:(Class)aClassObject -{ - return class_pose_as(self, aClassObject); -} - -- (Class)transmuteClassTo:(Class)aClassObject -{ - if (object_is_instance(self)) - if (class_is_class(aClassObject)) - if (class_get_instance_size(aClassObject)==class_get_instance_size(isa)) - if ([self isKindOf:aClassObject]) - { - Class old_isa = isa; - isa = aClassObject; - return old_isa; - } - return nil; -} - -- subclassResponsibility:(SEL)aSel -{ - return [self error:"subclass should override %s", sel_get_name(aSel)]; -} - -- notImplemented:(SEL)aSel -{ - return [self error:"method %s not implemented", sel_get_name(aSel)]; -} - -- shouldNotImplement:(SEL)aSel -{ - return [self error:"%s should not implement %s", - object_get_class_name(self), sel_get_name(aSel)]; -} - -- doesNotRecognize:(SEL)aSel -{ - return [self error:"%s does not recognize %s", - object_get_class_name(self), sel_get_name(aSel)]; -} - -- error:(const char *)aString, ... -{ -#define FMT "error: %s (%s)\n%s\n" - char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self)) - +((aString!=NULL)?strlen((char*)aString):0)+8)]; - va_list ap; - - sprintf(fmt, FMT, object_get_class_name(self), - object_is_instance(self)?"instance":"class", - (aString!=NULL)?aString:""); - va_start(ap, aString); - objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap); - va_end(ap); - return nil; -#undef FMT -} - -+ (int)version -{ - return class_get_version(self); -} - -+ setVersion:(int)aVersion -{ - class_set_version(self, aVersion); - return self; -} - -@end - -long objc_get_stream_class_version (TypedStream* stream, Class class) -{ - return class_get_version(class); -} diff --git a/Protocol.m b/Protocol.m deleted file mode 100644 index 23606a9..0000000 --- a/Protocol.m +++ /dev/null @@ -1,198 +0,0 @@ -/* This file contains the implementation of class Protocol. - Copyright (C) 1993, 2004, 2009 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#include "objc/Protocol.h" -#include "objc/objc-api.h" - -/* Method description list */ -struct objc_method_description_list { - int count; - struct objc_method_description list[1]; -}; - -@interface Protocol2 : Protocol -{ - struct objc_method_description_list *optional_instance_methods, *optional_class_methods; - struct objc_property_list *properties, *optional_properties; -} -@end - -@implementation Protocol -+ (void)load -{ - __CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE; -} - -/* Obtaining attributes intrinsic to the protocol */ - -- (const char *)name -{ - return protocol_name; -} - -/* Testing protocol conformance */ - -- (BOOL) conformsTo: (Protocol *)aProtocolObject -{ - size_t i; - struct objc_protocol_list* proto_list; - - if (aProtocolObject == nil) - return NO; - - if (!strcmp(aProtocolObject->protocol_name, self->protocol_name)) - return YES; - - for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) - { - for (i=0; i < proto_list->count; i++) - { - if ([proto_list->list[i] conformsTo: aProtocolObject]) - return YES; - } - } - - return NO; -} - -/* Looking up information specific to a protocol */ - -- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel -{ - int i; - struct objc_protocol_list* proto_list; - const char* name = sel_get_name (aSel); - struct objc_method_description *result; - - if (instance_methods) - for (i = 0; i < instance_methods->count; i++) - { - if (!strcmp ((char*)instance_methods->list[i].name, name)) - return &(instance_methods->list[i]); - } - - for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) - { - size_t j; - for (j=0; j < proto_list->count; j++) - { - if ((result = [proto_list->list[j] - descriptionForInstanceMethod: aSel])) - return result; - } - } - - return NULL; -} - -- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; -{ - int i; - struct objc_protocol_list* proto_list; - const char* name = sel_get_name (aSel); - struct objc_method_description *result; - - if (class_methods) - for (i = 0; i < class_methods->count; i++) - { - if (!strcmp ((char*)class_methods->list[i].name, name)) - return &(class_methods->list[i]); - } - - for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) - { - size_t j; - for (j=0; j < proto_list->count; j++) - { - if ((result = [proto_list->list[j] - descriptionForClassMethod: aSel])) - return result; - } - } - - return NULL; -} - -- (unsigned) hash -{ - /* Compute a hash of the protocol_name; use the same hash algorithm - * that we use for class names; protocol names and class names are - * somewhat similar types of string spaces. - */ - int hash = 0, index; - - for (index = 0; protocol_name[index] != '\0'; index++) - { - hash = (hash << 4) ^ (hash >> 28) ^ protocol_name[index]; - } - - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - - return hash; -} - -/* - * Equality between formal protocols is only formal (nothing to do - * with actually checking the list of methods they have!). Two formal - * Protocols are equal if and only if they have the same name. - * - * Please note (for comparisons with other implementations) that - * checking the names is equivalent to checking that Protocol A - * conforms to Protocol B and Protocol B conforms to Protocol A, - * because this happens iff they have the same name. If they have - * different names, A conforms to B if and only if A includes B, but - * the situation where A includes B and B includes A is a circular - * dependency between Protocols which is forbidden by the compiler, so - * A conforms to B and B conforms to A with A and B having different - * names is an impossible case. - */ -- (BOOL) isEqual: (id)obj -{ - if (obj == self) - return YES; - - if ([obj isKindOf: [Protocol class]]) - { - if (strcmp (protocol_name, ((Protocol *)obj)->protocol_name) == 0) - return YES; - } - - return NO; -} -@end - -/** - * Objective-C 2 protocol objects are opaque. - */ -@implementation Protocol2 @end - -/** - * This class exists for the sole reason that the legacy GNU ABI did not - * provide a way of registering protocols with the runtime. With the new ABI, - * every protocol in a compilation unit that is not referenced should be added - * in a category on this class. This ensures that the runtime sees every - * protocol at least once and can perform uniquing. - */ -@interface __ObjC_Protocol_Holder_Ugly_Hack : Object @end -@implementation __ObjC_Protocol_Holder_Ugly_Hack @end diff --git a/category_loader.c b/category_loader.c index ea01f9f..c1d2299 100644 --- a/category_loader.c +++ b/category_loader.c @@ -24,6 +24,7 @@ static void load_category(struct objc_category *cat, struct objc_class *class) { register_methods(class, cat->instance_methods); register_methods(class->isa, cat->class_methods); + //fprintf(stderr, "Loading %s (%s)\n", cat->class_name, cat->name); if (cat->protocols) { @@ -36,11 +37,13 @@ static void load_category(struct objc_category *cat, struct objc_class *class) static BOOL try_load_category(struct objc_category *cat) { Class class = (Class)objc_getClass(cat->class_name); + //fprintf(stderr, "Trying to load %s (%s)\n", cat->class_name, cat->name); if (Nil != class) { load_category(cat, class); return YES; } + //fprintf(stderr, "waiting to load %s (%s)\n", cat->class_name, cat->name); return NO; } diff --git a/class.h b/class.h index 8dfe6a6..d9a0e93 100644 --- a/class.h +++ b/class.h @@ -159,9 +159,19 @@ static inline void objc_set_class_flag(struct objc_class *aClass, { aClass->info |= (long)flag; } +static inline void objc_clear_class_flag(struct objc_class *aClass, + enum objc_class_flags flag) +{ + aClass->info &= ~(long)flag; +} static inline BOOL objc_test_class_flag(struct objc_class *aClass, enum objc_class_flags flag) { return aClass->info & (long)flag; } + +/** + * Adds a class to the class table. + */ +void class_table_insert(Class class); #endif //__OBJC_CLASS_H_INCLUDED diff --git a/class_table.c b/class_table.c index dad69b9..d86f966 100644 --- a/class_table.c +++ b/class_table.c @@ -259,6 +259,7 @@ void __objc_resolve_class_links(void) objc_resolve_class_links(); } +/* // FIXME: Remove this once all uses of it in the runtime have been removed void __objc_add_class_to_hash(Class class) { @@ -271,6 +272,7 @@ void __objc_add_class_to_hash(Class class) // class number though, so we don't bother. class_table_insert (class); } +*/ /** * Loads a class. This function assumes that the runtime mutex is locked. diff --git a/dtable.c b/dtable.c index 821f3b5..9814ade 100644 --- a/dtable.c +++ b/dtable.c @@ -32,6 +32,7 @@ static void collectMethodsForMethodListToSparseArray( } for (unsigned i=0 ; icount ; i++) { + //fprintf(stderr, "Adding method %s (%d)\n", sel_getName(list->methods[i].selector), PTR_TO_IDX(list->methods[i].selector->name)); SparseArrayInsert(sarray, PTR_TO_IDX(list->methods[i].selector->name), (void*)&list->methods[i]); } @@ -48,6 +49,7 @@ static BOOL installMethodInDtable(Class class, struct objc_slot *slot = SparseArrayLookup(dtable, sel_id); if (NULL != slot) { + //fprintf(stderr, "Slot already exists...\n"); // If this method is the one already installed, pretend to install it again. if (slot->method == method->imp) { return NO; } @@ -59,7 +61,7 @@ static BOOL installMethodInDtable(Class class, // 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); + //fprintf(stderr, "Replacing method %p %s in %s with %p\n", slot->method, sel_getName(method->selector), class->name, method->imp); slot->method = method->imp; return YES; } @@ -71,19 +73,21 @@ static BOOL installMethodInDtable(Class class, 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; } + if (installedFor == owner) + { + //fprintf(stderr, "Not installing %s from %s in %s - already overridden from %s\n", sel_getName(method->selector), owner->name, class->name, slot->owner->name); + return NO; + } } } struct objc_slot *oldSlot = slot; - //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: ""); + //fprintf(stderr, "Installing method %p (%d) %s in %s (previous slot owned by %s)\n", method->imp, sel_id, sel_getName(method->selector), class->name, slot? oldSlot->owner->name: "(no one)"); 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); + //fprintf(stderr, "Overriding method %p %s from %s in %s with %x\n", slot->method, sel_getName(method->selector), oldSlot->owner->name, class->name, method->imp); oldSlot->version++; } return YES; @@ -140,6 +144,7 @@ void objc_update_dtable_for_class(Class cls) LOCK_UNTIL_RETURN(__objc_runtime_mutex); + //fprintf(stderr, "Adding methods to %s\n", cls->name); SparseArray *methods = SparseArrayNewWithDepth(dtable_depth); collectMethodsForMethodListToSparseArray((void*)cls->methods, methods); installMethodsInClass(cls, cls, methods, YES); diff --git a/dtable.h b/dtable.h index 229e273..5b97800 100644 --- a/dtable.h +++ b/dtable.h @@ -25,6 +25,9 @@ typedef struct _InitializingDtable extern InitializingDtable *temporary_dtables; mutex_t initialize_lock; +/** + * Returns whether a class has an installed dtable. + */ static inline int classHasInstalledDtable(struct objc_class *cls) { return ((void*)cls->dtable != __objc_uninstalled_dtable); @@ -69,7 +72,16 @@ static inline SparseArray *dtable_for_class(Class cls) return dtable; } +/** + * Returns whether a class has had a dtable created. The dtable may be + * installed, or stored in the look-aside buffer. + */ static inline int classHasDtable(struct objc_class *cls) { return (dtable_for_class(cls) != __objc_uninstalled_dtable); } +/** + * Updates the dtable for a class and its subclasses. Must be called after + * modifying a class's method list. + */ +void objc_update_dtable_for_class(Class); diff --git a/legacy_malloc.c b/legacy_malloc.c new file mode 100644 index 0000000..5792d4a --- /dev/null +++ b/legacy_malloc.c @@ -0,0 +1,36 @@ +#include + +void *valloc(size_t); + +// Stubs that just call the libc implementations when you call these. + +void *objc_malloc(size_t size) +{ + return malloc(size); +} + +void *objc_atomic_malloc(size_t size) +{ + return malloc(size); +} + +void *objc_valloc(size_t size) +{ + return valloc(size); +} + +void *objc_realloc(void *mem, size_t size) +{ + return realloc(mem, size); +} + +void * objc_calloc(size_t nelem, size_t size) +{ + return calloc(nelem, size); +} + +void objc_free(void *mem) +{ + free(mem); +} + diff --git a/protocol.c b/protocol.c index c330d8a..d707da1 100644 --- a/protocol.c +++ b/protocol.c @@ -1,6 +1,7 @@ #include "objc/runtime.h" #include "protocol.h" #include "properties.h" +#include "class.h" #include "lock.h" #include @@ -218,12 +219,54 @@ Protocol *objc_getProtocol(const char *name) return (Protocol*)protocol_for_name(name); } -BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other) +BOOL protocol_conformsToProtocol(Protocol *p1, Protocol *p2) { + // A protocol trivially conforms to itself + if (strcmp(p1->name, p2->name) == 0) { return YES; } + for (struct objc_protocol_list *list = p1->protocol_list ; + list != NULL ; list = list->next) + { + for (int i=0 ; icount ; i++) + { + fprintf(stderr, "recursively checking %s\n", list->list[i]->name); + if (strcmp(list->list[i]->name, p2->name) == 0) + { + return YES; + } + if (protocol_conformsToProtocol((Protocol*)list->list[i], p2)) + { + return YES; + } + } + } return NO; } +BOOL class_conformsToProtocol(Class cls, Protocol *protocol) +{ + fprintf(stderr, "Testing if %s conforms to %s\n", cls->name, protocol->name); + while (cls) + { + for (struct objc_protocol_list *protocols = cls->protocols; + protocols != NULL ; protocols = protocols->next) + { + for (int i=0 ; icount ; i++) + { + Protocol *p1 = (Protocol*)protocols->list[i]; + fprintf(stderr, "checking %s\n", p1->name); + if (protocol_conformsToProtocol(p1, protocol)) + { + return YES; + } + } + } + cls = cls->super_class; + } + return NO; +} + +//FIXME!!!! struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count) { diff --git a/protocol.h b/protocol.h index d5ffd46..d4b49ce 100644 --- a/protocol.h +++ b/protocol.h @@ -1,4 +1,5 @@ #include "selector.h" +#include struct objc_method_description_list { @@ -20,10 +21,12 @@ struct objc_method_description_list */ #ifdef __OBJC__ @interface Protocol +{ + @public #else struct objc_protocol -#endif { +#endif /** Class pointer. */ id isa; /** @@ -51,8 +54,9 @@ struct objc_protocol #endif #ifdef __OBJC__ -@interface Protocol2 +@interface Protocol2 : Protocol { + @public #else typedef struct objc_protocol2 { diff --git a/runtime.c b/runtime.c index 854d608..0f203be 100644 --- a/runtime.c +++ b/runtime.c @@ -1,4 +1,11 @@ #include "objc/runtime.h" +#include "selector.h" +#include "class.h" +#include "protocol.h" +#include "ivar.h" +#include "method_list.h" +#include "lock.h" +#include "dtable.h" /* Make glibc export strdup() */ @@ -6,72 +13,12 @@ #define __USE_BSD 1 #endif -#undef __objc_INCLUDE_GNU -#undef __thread_INCLUDE_GNU -#undef __objc_api_INCLUDE_GNU -#undef __encoding_INCLUDE_GNU - -#define objc_object objc_object_gnu -#define id object_ptr_gnu -#define IMP objc_imp_gnu -#define Method objc_method_gnu - -#define object_copy gnu_object_copy -#define object_dispose gnu_object_dispose -#define objc_super gnu_objc_super -#define objc_msg_lookup gnu_objc_msg_lookup -#define objc_msg_lookup_super gnu_objc_msg_lookup_super -#define BOOL GNU_BOOL -#define SEL GNU_SEL -#define Protocol GNU_Protocol -#define Class GNU_Class - -#undef YES -#undef NO -#undef Nil -#undef nil - -#include -#include -#undef GNU_BOOL -#include -#undef Class -#undef Protocol -#undef SEL -#undef objc_msg_lookup -#undef objc_msg_lookup_super -#undef objc_super -#undef Method -#undef IMP -#undef id -#undef objc_object - -// Reinstall definitions. -#undef YES -#undef NO -#undef Nil -#undef nil -#define YES ((BOOL)1) -#define NO ((BOOL)0) -#define nil ((id)_OBJC_NULL_PTR) -#define Nil ((Class)_OBJC_NULL_PTR) - #include +#include #include #include -/** - * Private runtime function for updating a dtable. - */ -void __objc_update_dispatch_table_for_class(Class); -/** - * Runtime library constant for uninitialized dispatch table. - */ -extern struct sarray *__objc_uninstalled_dtable; -/** - * Mutex used to protect the ObjC runtime library data structures. - */ -extern objc_mutex_t __objc_runtime_mutex; +Class objc_next_class(void*); /** * Looks up the instance method in a specific class, without recursing into @@ -80,12 +27,12 @@ extern objc_mutex_t __objc_runtime_mutex; static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector) { for (struct objc_method_list *methods = aClass->methods; - methods != NULL ; methods = methods->method_next) + methods != NULL ; methods = methods->next) { - for (int i=0 ; imethod_count ; i++) + for (int i=0 ; icount ; i++) { - Method_t method = &methods->method_list[i]; - if (method->method_name->sel_id == aSelector->sel_id) + Method method = &methods->methods[i]; + if (method->selector->name == aSelector->name) { return method; } @@ -103,87 +50,86 @@ static void objc_updateDtableForClassContainingMethod(Method m) { if (class_getInstanceMethodNonrecursive(nextClass, sel) == m) { - __objc_update_dispatch_table_for_class(nextClass); + objc_update_dtable_for_class(nextClass); return; } } } -BOOL -class_addIvar(Class cls, const char *name, - size_t size, uint8_t alignment, const char *types) +BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, + const char *types) { - struct objc_ivar_list *ivarlist; - unsigned off; - Ivar ivar; + // You can't add ivars to resolved classes (note: You ought to be able to + // add them to classes that currently have no instances) + if (objc_test_class_flag(cls, objc_class_flag_resolved)) + { + return NO; + } - if (CLS_ISRESOLV(cls) || CLS_ISMETA(cls)) - { - return NO; - } + if (class_getInstanceVariable(cls, name) != NULL) + { + return NO; + } - if (class_getInstanceVariable(cls, name) != NULL) - { - return NO; - } + struct objc_ivar_list *ivarlist = cls->ivars; - ivarlist = cls->ivars; + if (NULL == ivarlist) + { + cls->ivars = malloc(sizeof(struct objc_ivar_list)); + cls->ivars->count = 1; + } + else + { + ivarlist->count++; + // objc_ivar_list contains one ivar. Others follow it. + cls->ivars = realloc(ivarlist, sizeof(struct objc_ivar_list) + + (ivarlist->count - 1) * sizeof(struct objc_ivar)); + } + Ivar ivar = &cls->ivars->ivar_list[cls->ivars->count - 1]; + ivar->name = strdup(name); + ivar->type = strdup(types); + // Round up the offset of the ivar so it is correctly aligned. + long offset = cls->instance_size >> alignment; - if (NULL == ivarlist) - { - cls->ivars = objc_malloc(sizeof(struct objc_ivar_list)); - cls->ivars->ivar_count = 1; - } - else - { - ivarlist->ivar_count++; - // objc_ivar_list contains one ivar. Others follow it. - cls->ivars = objc_realloc(ivarlist, sizeof(struct objc_ivar_list) - + (ivarlist->ivar_count - - 1) * sizeof(struct objc_ivar)); - } + if (offset << alignment != cls->instance_size) + { + offset = (offset+ 1) << alignment; + } - ivar = &cls->ivars->ivar_list[cls->ivars->ivar_count - 1]; - ivar->ivar_name = strdup(name); - ivar->ivar_type = strdup(types); - // Round up the offset of the ivar so it is correctly aligned. - off = cls->instance_size >> alignment; - if (off << alignment != cls->instance_size) - off = (off + 1) << alignment; - ivar->ivar_offset = off; - // Increase the instance size to make space for this. - cls->instance_size = ivar->ivar_offset + size; - return YES; + ivar->offset = offset; + // Increase the instance size to make space for this. + cls->instance_size = ivar->offset + size; + return YES; } BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) { - const char *methodName = sel_get_name(name); + const char *methodName = sel_getName(name); struct objc_method_list *methods; - for (methods=cls->methods; methods!=NULL ; methods=methods->method_next) + for (methods=cls->methods; methods!=NULL ; methods=methods->next) { - for (int i=0 ; imethod_count ; i++) + for (int i=0 ; icount ; i++) { - Method_t method = &methods->method_list[i]; - if (strcmp(sel_get_name(method->method_name), methodName) == 0) + Method method = &methods->methods[i]; + if (strcmp(sel_getName(method->selector), methodName) == 0) { return NO; } } } - methods = objc_malloc(sizeof(struct objc_method_list)); - methods->method_next = cls->methods; + methods = malloc(sizeof(struct objc_method_list)); + methods->next = cls->methods; cls->methods = methods; - methods->method_count = 1; - methods->method_list[0].method_name = sel_register_typed_name(methodName, types); - methods->method_list[0].method_types = strdup(types); - methods->method_list[0].method_imp = (objc_imp_gnu)imp; + methods->count = 1; + methods->methods[0].selector = sel_registerTypedName_np(methodName, types); + methods->methods[0].types = strdup(types); + methods->methods[0].imp = imp; - if (CLS_ISRESOLV(cls)) + if (objc_test_class_flag(cls, objc_class_flag_resolved)) { - __objc_update_dispatch_table_for_class(cls); + objc_update_dtable_for_class(cls); } return YES; @@ -193,33 +139,15 @@ BOOL class_addProtocol(Class cls, Protocol *protocol) { if (class_conformsToProtocol(cls, protocol)) { return NO; } struct objc_protocol_list *protocols = cls->protocols; - protocols = objc_malloc(sizeof(struct objc_protocol_list)); + protocols = malloc(sizeof(struct objc_protocol_list)); if (protocols == NULL) { return NO; } protocols->next = cls->protocols; protocols->count = 1; - protocols->list[0] = protocol; + protocols->list[0] = (Protocol2*)protocol; cls->protocols = protocols; return YES; } - -BOOL class_conformsToProtocol(Class cls, Protocol *protocol) -{ - for (struct objc_protocol_list *protocols = cls->protocols; - protocols != NULL ; protocols = protocols->next) - { - for (int i=0 ; icount ; i++) - { - if (strcmp(protocols->list[i]->protocol_name, - protocol->protocol_name) == 0) - { - return YES; - } - } - } - return NO; -} - Ivar * class_copyIvarList(Class cls, unsigned int *outCount) { @@ -230,7 +158,7 @@ class_copyIvarList(Class cls, unsigned int *outCount) if (ivarlist != NULL) { - count = ivarlist->ivar_count; + count = ivarlist->count; } if (outCount != NULL) { @@ -244,7 +172,7 @@ class_copyIvarList(Class cls, unsigned int *outCount) list = malloc((count + 1) * sizeof(struct objc_ivar *)); list[count] = NULL; count = 0; - for (index = 0; index < ivarlist->ivar_count; index++) + for (index = 0; index < ivarlist->count; index++) { list[count++] = &ivarlist->ivar_list[index]; } @@ -259,9 +187,9 @@ class_copyMethodList(Class cls, unsigned int *outCount) Method *list; struct objc_method_list *methods; - for (methods = cls->methods; methods != NULL; methods = methods->method_next) + for (methods = cls->methods; methods != NULL; methods = methods->next) { - count += methods->method_count; + count += methods->count; } if (outCount != NULL) { @@ -275,13 +203,13 @@ class_copyMethodList(Class cls, unsigned int *outCount) list = malloc((count + 1) * sizeof(struct objc_method *)); list[count] = NULL; count = 0; - for (methods = cls->methods; methods != NULL; methods = methods->method_next) + for (methods = cls->methods; methods != NULL; methods = methods->next) { unsigned int index; - for (index = 0; index < methods->method_count; index++) + for (index = 0; index < methods->count; index++) { - list[count++] = &methods->method_list[index]; + list[count++] = &methods->methods[index]; } } @@ -322,7 +250,7 @@ class_copyProtocolList(Class cls, unsigned int *outCount) id class_createInstance(Class cls, size_t extraBytes) { - id obj = objc_malloc(cls->instance_size + extraBytes); + id obj = malloc(cls->instance_size + extraBytes); obj->isa = cls; return obj; } @@ -345,7 +273,7 @@ Method class_getInstanceMethod(Class aClass, SEL aSelector) Method class_getClassMethod(Class aClass, SEL aSelector) { - return class_getInstanceMethod(aClass->class_pointer, aSelector); + return class_getInstanceMethod(aClass->isa, aSelector); } Ivar class_getClassVariable(Class cls, const char* name) @@ -372,11 +300,11 @@ class_getInstanceVariable(Class cls, const char *name) { int i; - for (i = 0; i < ivarlist->ivar_count; i++) + for (i = 0; i < ivarlist->count; i++) { Ivar ivar = &ivarlist->ivar_list[i]; - if (strcmp(ivar->ivar_name, name) == 0) + if (strcmp(ivar->name, name) == 0) { return ivar; } @@ -415,7 +343,7 @@ const char * class_getName(Class cls) int class_getVersion(Class theClass) { - return class_get_version(theClass); + return theClass->version; } const char *class_getWeakIvarLayout(Class cls) @@ -426,7 +354,7 @@ const char *class_getWeakIvarLayout(Class cls) BOOL class_isMetaClass(Class cls) { - return CLS_ISMETA(cls); + return objc_test_class_flag(cls, objc_class_flag_meta); } IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) @@ -437,12 +365,12 @@ IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) class_addMethod(cls, name, imp, types); return NULL; } - IMP old = (IMP)method->method_imp; - method->method_imp = (objc_imp_gnu)imp; + IMP old = (IMP)method->imp; + method->imp = imp; - if (CLS_ISRESOLV(cls)) + if (objc_test_class_flag(cls, objc_class_flag_resolved)) { - __objc_update_dispatch_table_for_class(cls); + objc_update_dtable_for_class(cls); } return old; @@ -453,7 +381,7 @@ void class_setIvarLayout(Class cls, const char *layout) { struct objc_ivar_list *list = (struct objc_ivar_list*)layout; size_t listsize = sizeof(struct objc_ivar_list) + - sizeof(struct objc_ivar) * (list->ivar_count - 1); + sizeof(struct objc_ivar) * (list->count - 1); cls->ivars = malloc(listsize); memcpy(cls->ivars, list, listsize); } @@ -468,7 +396,7 @@ Class class_setSuperclass(Class cls, Class newSuper) void class_setVersion(Class theClass, int version) { - class_set_version(theClass, version); + theClass->version = version; } void class_setWeakIvarLayout(Class cls, const char *layout) @@ -478,44 +406,44 @@ void class_setWeakIvarLayout(Class cls, const char *layout) const char * ivar_getName(Ivar ivar) { - return ivar->ivar_name; + return ivar->name; } ptrdiff_t ivar_getOffset(Ivar ivar) { - return ivar->ivar_offset; + return ivar->offset; } const char * ivar_getTypeEncoding(Ivar ivar) { - return ivar->ivar_type; + return ivar->type; } void method_exchangeImplementations(Method m1, Method m2) { - IMP tmp = (IMP)m1->method_imp; - m1->method_imp = m2->method_imp; - m2->method_imp = (objc_imp_gnu)tmp; + IMP tmp = (IMP)m1->imp; + m1->imp = m2->imp; + m2->imp = tmp; objc_updateDtableForClassContainingMethod(m1); objc_updateDtableForClassContainingMethod(m2); } IMP method_getImplementation(Method method) { - return (IMP)method->method_imp; + return (IMP)method->imp; } SEL method_getName(Method method) { - return (SEL)method->method_name; + return (SEL)method->selector; } IMP method_setImplementation(Method method, IMP imp) { - IMP old = (IMP)method->method_imp; - method->method_imp = (objc_imp_gnu)old; + IMP old = (IMP)method->imp; + method->imp = old; objc_updateDtableForClassContainingMethod(method); return old; } @@ -535,12 +463,12 @@ static void freeMethodLists(Class aClass) struct objc_method_list *methods = aClass->methods; while(methods != NULL) { - for (int i=0 ; imethod_count ; i++) + for (int i=0 ; icount ; i++) { - free((void*)methods->method_list[i].method_types); + free((void*)methods->methods[i].types); } struct objc_method_list *current = methods; - methods = methods->method_next; + methods = methods->next; free(current); } } @@ -550,11 +478,11 @@ static void freeIvarLists(Class aClass) struct objc_ivar_list *ivarlist = aClass->ivars; if (NULL == ivarlist) { return; } - for (int i=0 ; iivar_count ; i++) + for (int i=0 ; icount ; i++) { Ivar ivar = &ivarlist->ivar_list[i]; - free((void*)ivar->ivar_type); - free((void*)ivar->ivar_name); + free((void*)ivar->type); + free((void*)ivar->name); } free(ivarlist); } @@ -589,10 +517,10 @@ void objc_disposeClassPair(Class cls) Class meta = ((id)cls)->isa; // Remove from the runtime system so nothing tries updating the dtable // while we are freeing the class. - objc_mutex_lock(__objc_runtime_mutex); + LOCK(__objc_runtime_mutex); safe_remove_from_subclass_list(meta); safe_remove_from_subclass_list(cls); - objc_mutex_unlock(__objc_runtime_mutex); + UNLOCK(__objc_runtime_mutex); // Free the method and ivar lists. freeMethodLists(cls); @@ -617,20 +545,22 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt Class metaClass = calloc(1, sizeof(struct objc_class)); // Initialize the metaclass - metaClass->class_pointer = superclass->class_pointer->class_pointer; - metaClass->super_class = superclass->class_pointer; + metaClass->isa = superclass->isa->isa; + metaClass->super_class = superclass->isa; metaClass->name = strdup(name); - metaClass->info = _CLS_META | _CLS_RUNTIME | _CLS_NEW_ABI; + metaClass->info = objc_class_flag_meta | objc_class_flag_user_created | + objc_class_flag_new_abi; metaClass->dtable = __objc_uninstalled_dtable; metaClass->instance_size = sizeof(struct objc_class); // Set up the new class - newClass->class_pointer = metaClass; + newClass->isa = metaClass; // Set the superclass pointer to the name. The runtime will fix this when // the class links are resolved. newClass->super_class = (Class)(superclass->name); newClass->name = strdup(name); - newClass->info = _CLS_CLASS | _CLS_RUNTIME | _CLS_NEW_ABI; + newClass->info = objc_class_flag_class | objc_class_flag_user_created | + objc_class_flag_new_abi; newClass->dtable = __objc_uninstalled_dtable; newClass->instance_size = superclass->instance_size; @@ -642,11 +572,12 @@ Class objc_allocateMetaClass(Class superclass, size_t extraBytes) Class metaClass = calloc(1, sizeof(struct objc_class) + extraBytes); // Initialize the metaclass - metaClass->class_pointer = superclass->class_pointer; - metaClass->super_class = superclass->class_pointer; + metaClass->isa = superclass->isa; + metaClass->super_class = superclass->isa; metaClass->name = "hidden class"; //strdup(superclass->name); - metaClass->info = _CLS_RESOLV | _CLS_INITIALIZED | _CLS_META | - _CLS_RUNTIME | _CLS_NEW_ABI; + metaClass->info = objc_class_flag_resolved | objc_class_flag_initialized | + objc_class_flag_meta | objc_class_flag_user_created | + objc_class_flag_new_abi; metaClass->dtable = __objc_uninstalled_dtable; metaClass->instance_size = sizeof(struct objc_class); @@ -689,16 +620,8 @@ const char *object_getClassName(id obj) return class_getName(object_getClass(obj)); } -void __objc_add_class_to_hash(Class cls); -void objc_resolve_class(Class cls); - void objc_registerClassPair(Class cls) { - Class metaClass = cls->class_pointer; - // Initialize the dispatch table for the class and metaclass. - __objc_update_dispatch_table_for_class(metaClass); - __objc_update_dispatch_table_for_class(cls); - __objc_add_class_to_hash(cls); - objc_resolve_class(cls); - + LOCK_UNTIL_RETURN(__objc_runtime_mutex); + class_table_insert(cls); } diff --git a/sarray2.c b/sarray2.c index bc511fe..4379b7a 100644 --- a/sarray2.c +++ b/sarray2.c @@ -11,7 +11,6 @@ static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData}; #define MAX_INDEX(sarray) (sarray->mask >> sarray->shift) #define DATA_SIZE(sarray) ((sarray->mask >> sarray->shift) + 1) -#define fprintf(...) // Tweak this value to trade speed for memory usage. Bigger values use more // memory, but give faster lookups. #define base_shift 8 @@ -74,7 +73,7 @@ static void *SparseArrayFind(SparseArray * sarray, uint32_t * index) uint32_t max = MAX_INDEX(sarray); if (sarray->shift == 0) { - while (jdata[j] != SARRAY_EMPTY) { @@ -97,13 +96,18 @@ static void *SparseArrayFind(SparseArray * sarray, uint32_t * index) { return ret; } + // The recursive call will set index to the correct value for + // the next index, but won't update j + } + else + { + //Add 2^n to index so j is still correct + (*index) += 1<shift; + //Zero off the next component of the index so we don't miss any. + *index &= zeromask; } //Go to the next child j++; - //Add 2^n to index so j is still correct - (*index) += 1<shift; - //Zero off the next component of the index so we don't miss any. - *index &= zeromask; } } return SARRAY_EMPTY; @@ -117,12 +121,10 @@ void *SparseArrayNext(SparseArray * sarray, uint32_t * idx) void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value) { - fprintf(stderr, "Inserting in : %p\n", sarray); if (sarray->shift > 0) { uint32_t i = MASK_INDEX(index); SparseArray *child = sarray->data[i]; - fprintf(stderr, "Child: %p\n", child); if(&EmptyArray == child) { // Insert missing nodes @@ -140,7 +142,6 @@ void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value) init_pointers(newsarray); sarray->data[i] = newsarray; child = newsarray; - fprintf(stderr, "Created child: %p\n", child); }// FIXME: Concurrency (don't CoW twice) else if (child->refCount > 1) { @@ -149,7 +150,6 @@ void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value) SparseArrayDestroy(child); child = sarray->data[i]; } - fprintf(stderr, "Recursing in insert\n"); SparseArrayInsert(child, index, value); } else