diff --git a/GNUmakefile b/GNUmakefile index c6d669e..514ac8c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -22,6 +22,7 @@ libobjc_OBJC_FILES = \ libobjc_C_FILES = \ abi_version.c\ + alias_table.c\ caps.c\ category_loader.c\ class_table.c\ diff --git a/Makefile b/Makefile index 46692e6..42dbe10 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ OBJECTS = \ NSBlocks.o\ Protocol2.o\ abi_version.o\ + alias_table.o\ blocks_runtime.o\ caps.o\ category_loader.o\ diff --git a/Makefile.clang b/Makefile.clang index 0b2c081..2ed2f8f 100644 --- a/Makefile.clang +++ b/Makefile.clang @@ -18,6 +18,7 @@ OBJECTS = \ NSBlocks.bc\ Protocol2.bc\ abi_version.bc\ + alias_table.bc\ blocks_runtime.bc\ caps.bc\ category_loader.bc\ diff --git a/alias.h b/alias.h new file mode 100644 index 0000000..edf5ef3 --- /dev/null +++ b/alias.h @@ -0,0 +1,27 @@ +/** Declaration of a helper function for getting class references from aliases. + Copyright (c) 2011 Free Software Foundation, Inc. + + Written by: Niels Grewe + Created: March 2011 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +#include "objc/runtime.h" + +Class alias_getClass(const char *alias_name); diff --git a/alias_table.c b/alias_table.c new file mode 100644 index 0000000..fda7fb2 --- /dev/null +++ b/alias_table.c @@ -0,0 +1,125 @@ +/** A hash table for mapping compatibility aliases to classes. + Copyright (c) 2011 Free Software Foundation, Inc. + + Written by: Niels Grewe + Created: March 2011 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "objc/runtime.h" +#include "class.h" +#include "lock.h" +#include "string_hash.h" + +#include + +struct objc_alias +{ + const char* name; + Class class; +}; + +typedef struct objc_alias *Alias; + +static int alias_compare(const char *name, const Alias alias) +{ + return string_compare(name, alias->name); +} + +static int alias_hash(const Alias alias) +{ + return string_hash(alias->name); +} +#define MAP_TABLE_NAME alias_table_internal +#define MAP_TABLE_COMPARE_FUNCTION alias_compare +#define MAP_TABLE_HASH_KEY string_hash +#define MAP_TABLE_HASH_VALUE alias_hash + +#include "hash_table.h" + +static alias_table_internal_table *alias_table; + +#define POOL_NAME alias +#define POOL_TYPE struct objc_alias +#include "pool.h" + + +__attribute__((constructor)) static void alias_table_create_implicitly() +{ + alias_table = alias_table_internal_create(128); +} + + +static Alias alias_table_get_safe(const char *alias_name) +{ + return alias_table_internal_table_get(alias_table, alias_name); +} + + +Class alias_getClass(const char *alias_name) +{ + if (NULL == alias_name) + { + return NULL; + } + + Alias alias = alias_table_get_safe(alias_name); + + if (NULL == alias) + { + return NULL; + } + + return alias->class; +} + +void alias_table_insert(Alias alias) +{ + alias_table_internal_insert(alias_table, alias); +} + +BOOL class_registerAlias_np(Class class, const char *alias) +{ + if ((NULL == alias) || (NULL == class)) + { + return 0; + } + + /* + * If there already exists a matching alias, determine whether we the existing + * alias is the correct one. Please note that objc_getClass() goes through the + * alias lookup and will create the alias table if necessary. + */ + Class existingClass = (Class)objc_getClass(alias); + if (NULL != existingClass) + { + /* + * Return YES if the alias has already been registered for this very + * class, and NO if the alias is already used for another class. + */ + return (class == existingClass); + } + + Alias newAlias = alias_pool_alloc(); + newAlias->name = strdup(alias); + newAlias->class = class; + alias_table_insert(newAlias); + return 1; +} diff --git a/caps.c b/caps.c index dda3b7b..d1f3c56 100644 --- a/caps.c +++ b/caps.c @@ -13,6 +13,7 @@ static const int32_t caps = (1<super_class == old->super_class) && + BOOL equalLayouts = (class->super_class == old->super_class) && (class->instance_size == old->instance_size); // If either of the classes has an empty ivar list, then the other one must too. if ((NULL == class->ivars) || (NULL == old->ivars)) @@ -312,7 +313,7 @@ static void reload_class(struct objc_class *class, struct objc_class *old) } // If the layouts are equal, then we can simply tack the class's method - // list on to the front of the old class and update the dtable. + // list on to the front of the old class and update the dtable. if (equalLayouts) { class->methods->next = old->methods; @@ -326,7 +327,7 @@ static void reload_class(struct objc_class *class, struct objc_class *old) // Ideally, we'd want to capture the subclass list here. Unfortunately, // this is not possible because the subclass will contain methods that - // refer to ivars in the superclass. + // refer to ivars in the superclass. // // We can't use the non-fragile ABI's offset facility easily, because we'd // have to have two (or more) offsets for the same ivar. This gets messy @@ -371,8 +372,8 @@ void objc_load_class(struct objc_class *class) { if (objc_developer_mode_developer != mode) { - fprintf(stderr, - "Loading two versions of %s. The class that will be used is undefined\n", + fprintf(stderr, + "Loading two versions of %s. The class that will be used is undefined\n", class->name); } reload_class(class, existingClass); @@ -452,6 +453,11 @@ id objc_getClass(const char *name) if (nil != class) { return class; } + // Second chance lookup via @compatibilty_alias: + class = (id)alias_getClass(name); + if (nil != class) { return class; } + + // Third chance lookup via the hook: if (0 != _objc_lookup_class) { class = (id)_objc_lookup_class(name); diff --git a/objc/capabilities.h b/objc/capabilities.h index 8521671..3cae127 100644 --- a/objc/capabilities.h +++ b/objc/capabilities.h @@ -2,7 +2,7 @@ * capabilities.h - This file defines the list of capabilities. Runtime * capabilities can be checked. You may use #ifdef to test at compile time * whether the runtime on the current platform understands the capability. - * This does not mean that the runtime implements the capability, however. + * This does not mean that the runtime implements the capability, however. * * A copy of this file exists for compatibility in GNUstep's Objective-C * framework. When using this framework in conjunction with the GNU @@ -10,7 +10,7 @@ * even if the corresponding macros are available at compile time. * Additionally, several are compile-time options in the GNUstep runtime, so * although they are present in the header and understood by the runtime, they - * may not be supported by the installed runtime. + * may not be supported by the installed runtime. */ #include "Availability.h" @@ -22,7 +22,7 @@ extern "C" { #endif /** - * The runtime supports zero-cost exceptions. + * The runtime supports zero-cost exceptions. */ #define OBJC_CAP_EXCEPTIONS 0 /** @@ -42,12 +42,12 @@ extern "C" { */ #define OBJC_CAP_OPTIONAL_PROTOCOLS 4 /** - * The runtime supports non-fragile instance variables. + * The runtime supports non-fragile instance variables. */ #define OBJC_CAP_NONFRAGILE_IVARS 5 /** * The runtime supports making method lookup dependent on the types, as well as - * the name, of the selector. + * the name, of the selector. */ #define OBJC_CAP_TYPE_DEPENDENT_DISPATCH 6 /** @@ -73,6 +73,14 @@ extern "C" { */ #define OBJC_UNIFIED_EXCEPTION_MODEL 9 +/** + * The runtime provides a hook that allows the compiler to register class + * aliases declared with the @compatibility_alias keyword. This allows the + * runtime to resolve the alias, e.g. if objc_getClass() is called with an + * alias as the argument. + */ +#define OBJC_CAP_REGISTERED_COMPATIBILITY_ALIASES 10 + /** * Macro used to require the existence of a specific capability. This creates * a function that is called by the loader and tests that the runtime supports diff --git a/objc/runtime.h b/objc/runtime.h index d36faed..37ff87d 100644 --- a/objc/runtime.h +++ b/objc/runtime.h @@ -17,7 +17,7 @@ extern "C" { #include "Availability.h" // Undo GNUstep substitutions -#ifdef class_setVersion +#ifdef class_setVersion # undef class_setVersion #endif #ifdef class_getClassMethod @@ -57,7 +57,7 @@ typedef struct objc_selector *SEL; typedef struct objc_class *Class; /** - * Type for Objective-C objects. + * Type for Objective-C objects. */ typedef struct objc_object { @@ -96,7 +96,7 @@ typedef id (*IMP)(id, SEL, ...); typedef struct objc_method *Method; /** - * Objective-C boolean type. + * Objective-C boolean type. */ # ifdef STRICT_APPLE_COMPATIBILITY typedef signed char BOOL; @@ -148,7 +148,7 @@ struct objc_method_description #ifndef YES # define YES ((BOOL)1) #endif -#ifndef NO +#ifndef NO # define NO ((BOOL)0) #endif @@ -182,7 +182,7 @@ BOOL class_addIvar(Class cls, const char *types); /** - * Adds a method to the class. + * Adds a method to the class. */ BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); @@ -314,6 +314,13 @@ const char *class_getWeakIvarLayout(Class cls); */ BOOL class_isMetaClass(Class cls); +/** + * Registers an alias for the class. Returns YES if the alias could be + * registered successfully. + */ +OBJC_NONPORTABLE +BOOL class_registerAlias_np(Class cls, const char *alias); + /** * Replaces the named method with a new implementation. Note: the GNUstep * Objective-C runtime uses typed selectors, however the types of the selector