diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index e7881c6836b..e2d93108abf 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,27 @@ +2010-10-11 Nicola Pero + + * class.c (objc_getClassList): New. + (objc_getRequiredClass): New. + (objc_getMetaClass): New. + (objc_lookupClass): New. + (objc_getClass): New. + (__objc_get_unknown_class_handler): New. + (objc_setGetUnknownClassHandler): New. + (objc_get_class): Use __objc_get_unknown_class_handler. + (objc_lookup_class): Call objc_getClass. + * objc/objc-api.h: Updated comment and copyright notice. + * objc/runtime.h: Updated comments. + (objc_getClass): New. + (objc_lookupClass): New. + (objc_getMetaClass): New. + (objc_getRequiredClass): New. + (objc_getClassList): New. + (objc_setGetUnknownClassHandler): New. + (objc_get_unknown_class_handler): New. + * objc-private/runtime.h: Use __objc_private_runtime_INCLUDE_GNU + instead of __objc_runtime_INCLUDE_GNU as include guard. + * objc-private/error.h (_objc_abort): Mark as noreturn. + 2010-10-11 Nicola Pero * Makefile.in (C_SOURCE_FILES): Added ivars.c. diff --git a/libobjc/class.c b/libobjc/class.c index cba9b843355..216d6ace0dc 100644 --- a/libobjc/class.c +++ b/libobjc/class.c @@ -408,9 +408,36 @@ class_table_print_histogram (void) /* This is a hook which is called by objc_get_class and objc_lookup_class if the runtime is not able to find the class. - This may e.g. try to load in the class using dynamic loading. */ + This may e.g. try to load in the class using dynamic loading. + + This hook was a public, global variable in the Traditional GNU + Objective-C Runtime API (objc/objc-api.h). The modern GNU + Objective-C Runtime API (objc/runtime.h) provides the + objc_setGetUnknownClassHandler() function instead. +*/ Class (*_objc_lookup_class) (const char *name) = 0; /* !T:SAFE */ +/* Temporarily while we still include objc/objc-api.h instead of objc/runtime.h. */ +#ifndef __objc_runtime_INCLUDE_GNU +typedef Class (*objc_get_unknown_class_handler)(const char *class_name); +#endif + +/* The handler currently in use. PS: if both + __obj_get_unknown_class_handler and _objc_lookup_class are defined, + __objc_get_unknown_class_handler is called first. */ +static objc_get_unknown_class_handler +__objc_get_unknown_class_handler = NULL; + +objc_get_unknown_class_handler +objc_setGetUnknownClassHandler (objc_get_unknown_class_handler + new_handler) +{ + objc_get_unknown_class_handler old_handler + = __objc_get_unknown_class_handler; + __objc_get_unknown_class_handler = new_handler; + return old_handler; +} + /* True when class links has been resolved. */ BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */ @@ -464,25 +491,106 @@ __objc_add_class_to_hash (Class class) objc_mutex_unlock (__objc_runtime_mutex); } +Class +objc_getClass (const char *name) +{ + Class class; + + if (name == NULL) + return Nil; + + class = class_table_get_safe (name); + + if (class) + return class; + + if (__objc_get_unknown_class_handler) + return (*__objc_get_unknown_class_handler) (name); + + if (_objc_lookup_class) + return (*_objc_lookup_class) (name); + + return Nil; +} + +Class +objc_lookupClass (const char *name) +{ + if (name == NULL) + return Nil; + else + return class_table_get_safe (name); +} + +Class +objc_getMetaClass (const char *name) +{ + Class class = objc_getClass (name); + + if (class) + return class->class_pointer; + else + return Nil; +} + +Class +objc_getRequiredClass (const char *name) +{ + Class class = objc_getClass (name); + + if (class) + return class; + else + _objc_abort ("objc_getRequiredClass ('%s') failed: class not found\n", name); +} + +int +objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn) +{ + /* Iterate over all entries in the table. */ + int hash, count = 0; + + objc_mutex_lock (__class_table_lock); + + for (hash = 0; hash < CLASS_TABLE_SIZE; hash++) + { + class_node_ptr node = class_table_array[hash]; + + while (node != NULL) + { + if (returnValue) + { + if (count < maxNumberOfClassesToReturn) + returnValue[count] = node->pointer; + else + { + objc_mutex_unlock (__class_table_lock); + return count; + } + } + count++; + node = node->next; + } + } + + objc_mutex_unlock (__class_table_lock); + return count; +} + +/* Traditional GNU Objective-C Runtime API. */ /* Get the class object for the class named NAME. If NAME does not identify a known class, the hook _objc_lookup_class is called. If this fails, nil is returned. */ Class objc_lookup_class (const char *name) { - Class class; - - class = class_table_get_safe (name); - - if (class) - return class; - - if (_objc_lookup_class) - return (*_objc_lookup_class) (name); - else - return 0; + return objc_getClass (name); } +/* Traditional GNU Objective-C Runtime API. Important: this method is + called automatically by the compiler while messaging (if using the + traditional ABI), so it is worth keeping it fast; don't make it + just a wrapper around objc_getClass(). */ /* Get the class object for the class named NAME. If NAME does not identify a known class, the hook _objc_lookup_class is called. If this fails, an error message is issued and the system aborts. */ @@ -496,13 +604,15 @@ objc_get_class (const char *name) if (class) return class; - if (_objc_lookup_class) + if (__objc_get_unknown_class_handler) + class = (*__objc_get_unknown_class_handler) (name); + + if ((!class) && _objc_lookup_class) class = (*_objc_lookup_class) (name); if (class) return class; - /* FIXME: Should we abort the program here ? */ _objc_abort ("objc runtime: cannot find class %s\n", name); return 0; diff --git a/libobjc/objc-private/error.h b/libobjc/objc-private/error.h index 2df9cb733ec..e8673f722ed 100644 --- a/libobjc/objc-private/error.h +++ b/libobjc/objc-private/error.h @@ -29,9 +29,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see This should only be used for errors that really are unrecorevable: failure to allocate memory, and failure to load an Objective-C module. All other usages of this function should be converted into - some milder type of error. + some milder type of error (unless aborting is explicitly required + by the documentation/API). */ void -_objc_abort (const char *fmt, ...); +_objc_abort (const char *fmt, ...) __attribute__ ((noreturn)); #endif /* __objc_private_error_INCLUDE_GNU */ diff --git a/libobjc/objc-private/runtime.h b/libobjc/objc-private/runtime.h index c924e4d4975..690427ed5a3 100644 --- a/libobjc/objc-private/runtime.h +++ b/libobjc/objc-private/runtime.h @@ -36,8 +36,8 @@ but can almost certainly be shrinked down. */ -#ifndef __objc_runtime_INCLUDE_GNU -#define __objc_runtime_INCLUDE_GNU +#ifndef __objc_private_runtime_INCLUDE_GNU +#define __objc_private_runtime_INCLUDE_GNU #include /* for varargs and va_list's */ @@ -98,4 +98,4 @@ extern void __objc_generate_gc_type_description (Class); } #endif /* __cplusplus */ -#endif /* not __objc_runtime_INCLUDE_GNU */ +#endif /* not __objc_private_runtime_INCLUDE_GNU */ diff --git a/libobjc/objc/objc-api.h b/libobjc/objc/objc-api.h index 07637337561..d31e13f6bf3 100644 --- a/libobjc/objc/objc-api.h +++ b/libobjc/objc/objc-api.h @@ -1,6 +1,6 @@ -/* GNU Objective-C Runtime API. +/* GNU Objective-C Runtime API - Traditional API Copyright (C) 1993, 1995, 1996, 1997, 2001, 2002, 2003, 2004, 2005, - 2007, 2009 Free Software Foundation, Inc. + 2007, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h index 95928c839f2..b15c522235d 100644 --- a/libobjc/objc/runtime.h +++ b/libobjc/objc/runtime.h @@ -1,4 +1,4 @@ -/* GNU Objective-C Runtime API. +/* GNU Objective-C Runtime API - Modern API Copyright (C) 2010 Free Software Foundation, Inc. Contributed by Nicola Pero @@ -146,14 +146,16 @@ struct objc_method_description #define _F_GCINVISIBLE 0x20 -/** Internals: defined inline. */ +/** Implementation: the following functions are defined inline. */ /* Return the class of 'object', or Nil if the object is nil. If 'object' is a class, the meta class is returned; if 'object' is a meta class, the root meta class is returned (note that this is different from the traditional GNU Objective-C Runtime API function object_get_class(), which for a meta class would return the meta - class itself). */ + class itself). This function is inline, so it is really fast and + should be used instead of accessing object->class_pointer + directly. */ static inline Class object_getClass (id object) { @@ -164,7 +166,7 @@ object_getClass (id object) } -/** Internals: the following functions are in selector.c. */ +/** Implementation: the following functions are in selector.c. */ /* Return the name of a given selector. */ objc_EXPORT const char *sel_getName (SEL selector); @@ -198,7 +200,7 @@ objc_EXPORT SEL set_registerTypedName (const char *name, const char *type); objc_EXPORT BOOL sel_isEqual (SEL first_selector, SEL second_selector); -/** Internals: the following functions are in objects.c. */ +/** Implementation: the following functions are in objects.c. */ /* Create an instance of class 'class_', adding extraBytes to the size of the returned object. This method allocates the appropriate @@ -228,7 +230,7 @@ objc_EXPORT const char * object_getClassName (id object); objc_EXPORT Class object_setClass (id object, Class class_); -/** Internals: the following functions are in ivars.c. */ +/** Implementation: the following functions are in ivars.c. */ /* Return an instance variable given the class and the instance variable name. This is an expensive function to call, so try to @@ -283,10 +285,81 @@ objc_EXPORT ptrdiff_t ivar_getOffset (Ivar variable); objc_EXPORT const char * ivar_getTypeEncoding (Ivar variable); +/** Implementation: the following functions are in class.c. */ + +/* Compatibility Note: The Apple/NeXT runtime does not have + objc_get_unknown_class_handler and + objc_setGetUnknownClassHandler(). They provide functionality that + the traditional GNU Objective-C Runtime API used to provide via the + _objc_lookup_class hook. */ + +/* An 'objc_get_unknown_class_handler' function is used by + objc_getClass() to get a class that is currently unknown to the + compiler. You could use it for example to have the class loaded by + dynamically loading a library. 'class_name' is the name of the + class. The function should return the Class object if it manages to + load the class, and Nil if not. */ +typedef Class (*objc_get_unknown_class_handler)(const char *class_name); + +/* Sets a new handler function for getting unknown classes (to be used + by objc_getClass () and related), and returns the previous one. + This function is not safe to call in a multi-threaded environment + because other threads may be trying to use the get unknown class + handler while you change it! */ +objc_get_unknown_class_handler +objc_setGetUnknownClassHandler (objc_get_unknown_class_handler new_handler); + + +/* Return the class with name 'name', if it is already registered with + the runtime. If it is not registered, and + objc_setGetUnknownClassHandler() has been called to set a handler + for unknown classes, the handler is called to give it a chance to + load the class in some other way. If the class is not known to the + runtime and the handler is not set or returns Nil, objc_getClass() + returns Nil. */ +objc_EXPORT Class objc_getClass (const char *name); + +/* Return the class with name 'name', if it is already registered with + the runtime. Return Nil if not. This function does not call the + objc_get_unknown_class_handler function if the class is not + found. */ +objc_EXPORT Class objc_lookupClass (const char *name); + +/* Return the meta class associated to the class with name 'name', if + it is already registered with the runtime. First, it finds the + class using objc_getClass(). Then, it returns the associated meta + class. If the class could not be found using objc_getClass(), + returns Nil. */ +objc_EXPORT Class objc_getMetaClass (const char *name); + +/* This is identical to objc_getClass(), but if the class is not found, + it aborts the process instead of returning Nil. */ +objc_EXPORT Class objc_getRequiredClass (const char *name); + +/* If 'returnValue' is NULL, 'objc_getClassList' returns the number of + classes currently registered with the runtime. If 'returnValue' is + not NULL, it should be a (Class *) pointer to an area of memory + which can contain up to 'maxNumberOfClassesToReturn' Class records. + 'objc_getClassList' will fill the area pointed to by 'returnValue' + with all the Classes registered with the runtime (or up to + maxNumberOfClassesToReturn if there are more than + maxNumberOfClassesToReturn). The function return value is the + number of classes actually returned in 'returnValue'. */ +objc_EXPORT int objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn); + +/* Compatibility Note: The Apple/NeXT runtime also has + + Class objc_getFutureClass (const char *name); + void objc_setFutureClass (Class class_, const char *name); + + the documentation is unclear on what they are supposed to do, and + the GNU Objective-C Runtime currently does not provide them. */ + + /* TODO: Add all the other functions in the API. */ -/** Internals: the following functions are in objc-foreach.c. */ +/** Implementation: the following functions are in objc-foreach.c. */ /* 'objc_enumerationMutation()' is called when a collection is mutated while being "fast enumerated". That is a hard error, and @@ -337,7 +410,7 @@ struct __objcFastEnumerationState */ -/** Internals: the following functions are implemented in encoding.c. */ +/** Implementation: the following functions are in encoding.c. */ /* Traditional GNU Objective-C Runtime functions that are currently used to implement method forwarding.