remove obsolete code and update other stuff fro new runtime api

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29840 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2010-03-05 05:24:43 +00:00
parent e08da453bc
commit ef908fbb5b
3 changed files with 117 additions and 830 deletions

View file

@ -1,3 +1,14 @@
2010-03-05 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Additions/GNUstepBase/GSObjCRuntime.h:
* Source/Additions/GSObjCRuntime.m:
Old 'experimental/work-in-progress' functions mostly removed ...
GSAllocMethodList() GSAppendMethodToList() GSRemoveMethodFromList()
GSMethodListForSelector() GSMethodFromList() GSAddMethodList()
GSRemoveMethodList()
Other functions rewritten in terms of the new runtime API and marked
as deprecated if they add nothing.
2010-03-04 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSKeyValueObserving.m: use class_addMethod() to add setters

View file

@ -125,31 +125,6 @@ extern "C" {
#define _C_GCINVISIBLE '!'
#endif
#if defined(NeXT_RUNTIME)
#elif defined(__GNUSTEP_RUNTIME__)
#define class_nextMethodList(aClass,anIterator) (({\
if (*(anIterator) == 0) \
*((struct objc_method_list**)(anIterator)) = (aClass)->methods; \
else \
*(anIterator) = (*((struct objc_method_list**)(anIterator)))->method_next; \
}), *(anIterator))
#else /* Old GNU runtime */
#define class_nextMethodList(aClass,anIterator) (({\
if (*(anIterator) == 0) \
*((struct objc_method_list**)(anIterator)) = (aClass)->methods; \
else \
*(anIterator) = (*((struct objc_method_list**)(anIterator)))->method_next; \
}), *(anIterator))
#endif
/*
* Functions for accessing instance variables directly -
* We can copy an ivar into arbitrary data,
@ -167,10 +142,10 @@ GS_EXPORT void
GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data);
GS_EXPORT NSArray *
GSObjCMethodNames(id obj);
GSObjCMethodNames(id obj, BOOL recurse);
GS_EXPORT NSArray *
GSObjCVariableNames(id obj);
GSObjCVariableNames(id obj, BOOL recurse);
GS_EXPORT void
GSObjCAddClassBehavior(Class receiver, Class behavior);
@ -181,6 +156,18 @@ GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars);
GS_EXPORT void
GSObjCAddClasses(NSArray *classes);
/**
* Given a NULL terminated list of methods, add them to the class.<br />
* If the method already exists in a superclass, the new version overrides
* that one, but if the method already exists in the class itsself, the
* new one is quietly ignored (replace==NO) or replaced with the new
* version (if replace==YES).<br />
* To add class methods, cls should be the metaclass of the class to
* which the methods are being added.
*/
GS_EXPORT void
GSObjCAddMethods(Class cls, Method *list, BOOL replace);
/*
* Functions for key-value encoding ... they access values in an object
* either by selector or directly, but do so using NSNumber for the
@ -203,19 +190,7 @@ GSObjCSetVal(NSObject *self, const char *key, id val, SEL sel,
*/
/**
* Fills a nil terminated array of Class objects referenced by buffer
* with max number of classes registered with the objc runtime.
* The provided buffer must be large enough to hold max + 1 Class objects.
* If buffer is nil, the function returns the number of Class
* objects that would be inserted if the buffer is large enough.
* Otherwise returns the number of Class objects that did not fit
* into the provided buffer. This function keeps a cache of the class
* list for future invocations when used with the GNU runtime. If
* clearCache is YES, this cache will be invalidated and rebuild. The
* flag has no effect for the NeXT runtime.
* This function is provided as consistent API to both runtimes.
* In the case of the GNU runtime it is likely more efficient to use
* objc_next_class() to iterate over the classes.
* Deprecated ... use objc_getClassList()
*/
GS_EXPORT unsigned int
GSClassList(Class *buffer, unsigned int max, BOOL clearCache);
@ -325,9 +300,8 @@ GSRegisterProtocol(Protocol *proto);
* are incompatible between the GNU and NeXT/Apple runtimes.
* We introduce GSMethod, GSMethodList and GSIVar to allow portability.
*/
typedef struct objc_method *GSMethod;
typedef struct objc_method_list *GSMethodList;
typedef struct objc_ivar *GSIVar;
typedef Method GSMethod;
typedef Ivar GSIVar;
/**
* Returns the pointer to the method structure
@ -349,208 +323,29 @@ GSGetMethod(Class cls, SEL sel,
BOOL searchSuperClasses);
/**
* Flushes the cached method dispatch table for the class.
* Call this function after any manipulations in the method structures.<br/>
* It should be safe to use this function in +load implementations.<br/>
* This function should currently (June 2003) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.
* Deprecated .. does nothing.
*/
GS_EXPORT void
GSFlushMethodCacheForClass (Class cls);
/**
* Returns the pointer to the instance variable structure
* for the instance variable name in the specified class.
* This function searches the specified class and its superclasses.<br/>
* It should be safe to use this function in +load implementations.<br/>
* This function should currently (June 2003) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.
* Deprecated .. use class_getInstanceVariable()
*/
GS_EXPORT GSIVar
GSCGetInstanceVariableDefinition(Class cls, const char *name);
/**
* Returns the pointer to the instance variable structure
* for the instance variable name in the specified class.
* This function searches the specified class and its superclasses.<br/>
* It is not necessarily safe to use this function
* in +load implementations.<br/>
* This function should currently (June 2003) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.
* Deprecated .. use class_getInstanceVariable()
*/
GS_EXPORT GSIVar
GSObjCGetInstanceVariableDefinition(Class cls, NSString *name);
/**
* <p>Returns a pointer to objc_malloc'ed memory large enough
* to hold a struct objc_method_list with 'count' number of
* struct objc_method entries. The memory returned is
* initialized with 0, including the method count and
* next method list fields. </p>
* <p> This function is intended for use in conjunction with
* GSAppendMethodToList() to fill the memory and GSAddMethodList()
* to activate the method list. </p>
* <p>After method list manipulation you should call
* GSFlushMethodCacheForClass() for the changes to take effect.</p>
* <p><em>WARNING:</em> Manipulating the runtime structures
* can be hazardous!</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
GSMethodList
GSAllocMethodList (unsigned int count);
/**
* <p>Inserts the method described by sel, types and imp
* into the slot of the list's method_count incremented by 1.
* This function does not and cannot check whether
* the list provided has the necessary capacity.</p>
* <p>The GNU runtime makes a difference between method lists
* that are "free standing" and those that "attached" to classes.
* For "free standing" method lists (e.g. created with GSAllocMethodList()
* that have not been added to a class or those which have been removed
* via GSRemoveMethodList()) isFree must be passed YES.
* When manipulating "attached" method lists, specify NO.</p>
* <p>This function is intended for use in conjunction with
* GSAllocMethodList() to allocate the list and GSAddMethodList()
* to activate the method list. </p>
* <p>After method list manipulation you should call
* GSFlushMethodCacheForClass() for the changes to take effect.</p>
* <p><em>WARNING:</em> Manipulating the runtime structures
* can be hazardous!</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
void
GSAppendMethodToList (GSMethodList list,
SEL sel,
const char *types,
IMP imp,
BOOL isFree);
/**
* <p>Removes the method identified by sel
* from the method list moving the following methods up in the list,
* leaving the last entry blank. After this call, all references
* of previous GSMethodFromList() calls with this list should be
* considered invalid. If the values they referenced are needed, they
* must be copied to external buffers before this function is called.</p>
* <p>Returns YES if the a matching method was found a removed,
* NO otherwise.</p>
* <p>The GNU runtime makes a difference between method lists
* that are "free standing" and those that "attached" to classes.
* For "free standing" method lists (e.g. created with GSAllocMethodList()
* that have not been added to a class or those which have been removed
* via GSRemoveMethodList()) isFree must be passed YES.
* When manipulating "attached" method lists, specify NO.</p>
* <p>After method list manipulation you should call
* GSFlushMethodCacheForClass() for the changes to take effect.</p>
* <p><em>WARNING:</em> Manipulating the runtime structures
* can be hazardous!</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
BOOL
GSRemoveMethodFromList (GSMethodList list,
SEL sel,
BOOL isFree);
/**
* <p>Returns a method list of the class that contains the selector.
* Depending on searchInstanceMethods either instance or class methods
* are searched.
* Returns NULL if none are found.
* This function does not search the superclasses method lists.
* Call this method with the address of a <code>void *</code>
* pointing to NULL to obtain the first (active) method list
* containing the selector.
* Subsequent calls will return further method lists which contain the
* selector. If none are found, it returns NULL.
* You may instead pass NULL as the iterator in which case the first
* method list containing the selector will be returned.
* Do not call it with an uninitialized iterator.
* If either class or selector are NULL the function returns NULL.
* If subsequent calls to this function with the same non-NULL iterator yet
* different searchInstanceMethods value are called, the behavior
* is undefined.</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
GSMethodList
GSMethodListForSelector(Class cls,
SEL selector,
void **iterator,
BOOL searchInstanceMethods);
/**
* <p>Returns the (first) GSMethod contained in the supplied list
* that corresponds to sel.
* Returns NULL if none is found.</p>
* <p>The GNU runtime makes a difference between method lists
* that are "free standing" and those that "attached" to classes.
* For "free standing" method lists (e.g. created with GSAllocMethodList()
* that have not been added to a class or those which have been removed
* via GSRemoveMethodList()) isFree must be passed YES.
* When manipulating "attached" method lists, specify NO.</p>
*/
GSMethod
GSMethodFromList(GSMethodList list,
SEL sel,
BOOL isFree);
/**
* <p>Add the method list to the class as the first list to be
* searched during method invocation for the given class.
* Depending on toInstanceMethods, this list will be added as
* an instance or a class method list.
* If the list is in use by another class, behavior is undefined.
* Create a new list with GSAllocMethodList() or use GSRemoveMethodList()
* to remove a list before inserting it in a class.</p>
* <p>After method list manipulation you should call
* GSFlushMethodCacheForClass() for the changes to take effect.</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
void
GSAddMethodList(Class cls,
GSMethodList list,
BOOL toInstanceMethods);
/**
* <p>Removes the method list from the classes instance or class method
* lists depending on fromInstanceMethods.
* If the list is not part of the class, behavior is undefined.</p>
* <p>After method list manipulation you should call
* GSFlushMethodCacheForClass() for the changes to take effect.</p>
* <p>This function should currently (June 2004) be considered WIP.
* Please follow potential changes (Name, parameters, ...) closely until
* it stabilizes.</p>
*/
void
GSRemoveMethodList(Class cls,
GSMethodList list,
BOOL fromInstanceMethods);
/**
* GSObjCVersion() is deprecated ... use class_getVersion()
*/
GS_EXPORT int GSObjCVersion(Class cls);
#ifndef NeXT_Foundation_LIBRARY
#include <Foundation/NSZone.h>
#else
#include <Foundation/Foundation.h>
#endif
#import <Foundation/NSZone.h>
/**
* GSObjCZone() is deprecated ... use -zone
*/

View file

@ -186,11 +186,6 @@ GSTypesFromSelector(SEL sel)
void
GSFlushMethodCacheForClass (Class cls)
{
#if NeXT_RUNTIME
#else
extern void __objc_update_dispatch_table_for_class (Class);
__objc_update_dispatch_table_for_class (cls);
#endif
return;
}
int
@ -250,7 +245,7 @@ GSObjCFindVariable(id obj, const char *name,
* Returns nil if obj is nil.
*/
NSArray *
GSObjCMethodNames(id obj)
GSObjCMethodNames(id obj, BOOL recurse)
{
NSMutableSet *set;
NSArray *array;
@ -286,6 +281,10 @@ GSObjCMethodNames(id obj)
{
free(meth);
}
if (NO == recurse)
{
break;
}
class = class_getSuperclass(class);
}
@ -301,7 +300,7 @@ GSObjCMethodNames(id obj)
* Returns nil if obj is nil.
*/
NSArray *
GSObjCVariableNames(id obj)
GSObjCVariableNames(id obj, BOOL recurse)
{
NSMutableSet *set;
NSArray *array;
@ -337,6 +336,10 @@ GSObjCVariableNames(id obj)
{
free(ivar);
}
if (NO == recurse)
{
break;
}
class = class_getSuperclass(class);
}
@ -372,7 +375,6 @@ GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data)
GS_EXPORT unsigned int
GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
{
#ifdef NeXT_RUNTIME
int num;
if (buffer != NULL)
@ -382,68 +384,6 @@ GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
num = objc_getClassList(buffer, max);
num = (num < 0) ? 0 : num;
#else
static Class *cache = 0;
static unsigned cacheClassCount = 0;
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
unsigned int num;
pthread_mutex_lock(&cache_lock);
if (clearCache)
{
if (cache)
{
free(cache);
cache = NULL;
}
cacheClassCount = 0;
}
if (cache == NULL)
{
void *iterator = 0;
Class cls;
unsigned int i;
cacheClassCount = 0;
while ((cls = objc_next_class(&iterator)))
{
cacheClassCount++;
}
cache = malloc(sizeof(Class) * (cacheClassCount + 1));
/* Be extra careful as another thread may be loading classes. */
for (i = 0, iterator = 0, cls = objc_next_class(&iterator);
i < cacheClassCount && cls != NULL;
i++, cls = objc_next_class(&iterator))
{
cache[i] = cls;
}
cache[i] = NULL;
}
if (buffer == NULL)
{
num = cacheClassCount;
}
else
{
size_t cpySize;
unsigned int cpyCnt;
cpyCnt = MIN(max, cacheClassCount);
cpySize = sizeof(Class) * cpyCnt;
memcpy(buffer, cache, cpySize);
buffer[cpyCnt] = NULL;
num = (max > cacheClassCount) ? 0 : (cacheClassCount - max);
}
pthread_mutex_unlock(&cache_lock);
#endif
return num;
}
@ -545,203 +485,39 @@ GSObjCBehaviorDebug(int i)
behavior_debug = i;
}
#if NeXT_RUNTIME
static GSMethod search_for_method_in_class (Class cls, SEL op);
void
GSObjCAddMethods (Class cls, GSMethodList methods)
GSObjCAddMethods(Class cls, Method *list, BOOL replace)
{
static SEL initialize_sel = 0;
GSMethodList mlist;
unsigned int index = 0;
Method m;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
/* Add methods to cls->dtable and cls->methods */
mlist = methods;
if (cls == 0 || list == 0)
{
int counter;
GSMethodList new_list;
counter = mlist->method_count ? mlist->method_count - 1 : 1;
/* This is a little wasteful of memory, since not necessarily
all methods will go in here. */
new_list = (GSMethodList)
malloc (sizeof(struct objc_method_list) +
sizeof(struct objc_method[counter+1]));
new_list->method_count = 0;
while (counter >= 0)
{
GSMethod method = &(mlist->method_list[counter]);
BDBGPrintf(" processing method [%s] ... ",
GSNameFromSelector(method->method_name));
if (!search_for_method_in_class(cls, method->method_name)
&& !sel_isEqual(method->method_name, initialize_sel))
{
/* As long as the method isn't defined in the CLASS,
put the BEHAVIOR method in there. Thus, behavior
methods override the superclasses' methods. */
new_list->method_list[new_list->method_count] = *method;
(new_list->method_count)++;
BDBGPrintf("added.\n");
}
else
{
BDBGPrintf("ignored.\n");
}
counter -= 1;
}
if (new_list->method_count)
{
class_add_method_list(cls, new_list);
}
else
{
OBJC_FREE(new_list);
}
}
}
/* Search for the named method's method structure. Return a pointer
to the method's method structure if found. NULL otherwise. */
static GSMethod
search_for_method_in_class (Class cls, SEL op)
{
void *iterator = 0;
GSMethodList method_list;
if (! sel_is_mapped (op))
return NULL;
/* If not found then we'll search the list. */
while ((method_list = class_nextMethodList(cls, &iterator)))
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
GSMethod method = &method_list->method_list[i];
if (method->method_name)
{
if (sel_isEqual(method->method_name, op))
return method;
}
}
return;
}
return NULL;
}
#else /* GNU runtime */
/*
* The following two functions are implemented in the GNU objc runtime
*/
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
extern void class_add_method_list(Class, MethodList_t);
static Method_t search_for_method_in_class (Class cls, SEL op);
extern objc_mutex_t __objc_runtime_mutex;
void
GSObjCAddMethods (Class cls, GSMethodList methods)
{
static SEL initialize_sel = 0;
GSMethodList mlist;
if (initialize_sel == 0)
while ((m = list[index++]) != NULL)
{
initialize_sel = sel_register_name ("initialize");
}
SEL n = method_getName(m);
IMP i = method_getImplementation(m);
const char *t = method_getTypeEncoding(m);
objc_mutex_lock (__objc_runtime_mutex);
/* Add methods to class->dtable and class->methods */
for (mlist = methods; mlist; mlist = mlist->method_next)
{
int counter;
GSMethodList new_list;
counter = mlist->method_count ? mlist->method_count - 1 : 1;
/* This is a little wasteful of memory, since not necessarily
all methods will go in here. */
new_list = (GSMethodList)
malloc (sizeof(struct objc_method_list) +
sizeof(struct objc_method[counter+1]));
new_list->method_count = 0;
new_list->method_next = NULL;
while (counter >= 0)
{
GSMethod method = &(mlist->method_list[counter]);
const char *name = GSNameFromSelector(method->method_name);
BDBGPrintf(" processing method [%s] ... ", name);
if (!search_for_method_in_list(cls->methods, method->method_name)
&& !sel_isEqual(method->method_name, initialize_sel))
{
/* As long as the method isn't defined in the CLASS,
put the BEHAVIOR method in there. Thus, behavior
methods override the superclasses' methods. */
new_list->method_list[new_list->method_count] = *method;
/*
* HACK ... the GNU runtime implementation of
* class_add_method_list() expects the method names to be
* C-strings rather than selectors ... so we must allow
* for that.
*/
new_list->method_list[new_list->method_count].method_name
= (SEL)name;
(new_list->method_count)++;
BDBGPrintf("added.\n");
}
else
{
BDBGPrintf("ignored.\n");
}
counter -= 1;
}
if (new_list->method_count)
/* This will override a superclass method but will not replace a
* method which already exists in the class itsself.
*/
if (NO == class_addMethod(cls, n, i, t) && YES == replace)
{
class_add_method_list(cls, new_list);
}
else
{
OBJC_FREE(new_list);
}
/* If we want to replace an existing implemetation ...
*/
method_setImplementation(class_getInstanceMethod(cls, n), i);
}
}
objc_mutex_unlock (__objc_runtime_mutex);
}
static Method_t
search_for_method_in_class (Class cls, SEL op)
{
Method_t m;
objc_mutex_lock (__objc_runtime_mutex);
m = cls != NULL ? search_for_method_in_list(cls->methods, op) : NULL;
objc_mutex_unlock (__objc_runtime_mutex);
return m;
}
#endif /* NeXT runtime */
GSMethod
GSGetMethod(Class cls, SEL sel,
BOOL searchInstanceMethods,
BOOL searchSuperClasses)
BOOL searchInstanceMethods,
BOOL searchSuperClasses)
{
if (cls == 0 || sel == 0)
{
@ -750,306 +526,44 @@ GSGetMethod(Class cls, SEL sel,
if (searchSuperClasses == NO)
{
unsigned int count;
Method method = NULL;
Method *methods;
if (searchInstanceMethods == NO)
{
return search_for_method_in_class(cls->class_pointer, sel);
methods = class_copyMethodList(object_getClass(cls), &count);
}
else
{
return search_for_method_in_class(cls, sel);
methods = class_copyMethodList(cls, &count);
}
}
else
{
if (searchInstanceMethods == NO)
if (methods != NULL)
{
/*
We do not rely on the mapping supplied in objc_gnu2next.h
because we want to be explicit about the fact
that the expected parameters are different.
Therefor we refrain from simply using class_getClassMethod().
*/
#ifdef NeXT_RUNTIME
return class_getClassMethod(cls, sel);
#else
return class_get_class_method(cls->class_pointer, sel);
#endif
}
else
{
return class_get_instance_method(cls, sel);
}
}
}
unsigned int index = 0;
/* See header for documentation. */
GSMethodList
GSAllocMethodList (unsigned int count)
{
GSMethodList list;
size_t size;
size = (sizeof (struct objc_method_list) +
sizeof (struct objc_method[count]));
list = malloc (size);
memset(list, 0, size);
return list;
}
/* See header for documentation. */
void
GSAppendMethodToList (GSMethodList list,
SEL sel,
const char *types,
IMP imp,
BOOL isFree)
{
unsigned int num;
num = (list->method_count)++;
#ifdef GNU_RUNTIME
/*
Deal with typed selectors: No matter what kind of selector we get
convert it into a c-string. Cache that c-string incase the
selector isn't found, then search for corresponding typed selector.
If none is found use the cached name to register an new selector
with the corresponding types.
*/
sel = (SEL)GSNameFromSelector (sel);
if (isFree == NO)
{
const char *sel_save = (const char *)sel;
sel = sel_get_typed_uid (sel_save, types);
if (sel == 0)
{
sel = sel_register_typed_name (sel_save, types);
}
}
#endif
list->method_list[num].method_name = sel;
list->method_list[num].method_types = strdup(types);
list->method_list[num].method_imp = imp;
}
/* See header for documentation. */
BOOL
GSRemoveMethodFromList (GSMethodList list,
SEL sel,
BOOL isFree)
{
int i;
#ifdef GNU_RUNTIME
if (isFree == YES)
{
sel = (SEL)GSNameFromSelector (sel);
}
#else
/* Insure that we always use sel_isEqual on non GNU Runtimes. */
isFree = NO;
#endif
for (i = 0; i < list->method_count; i++)
{
SEL method_name = list->method_list[i].method_name;
/* For the GNU runtime we have use strcmp instead of sel_isEqual
for free standing method lists. */
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
|| (isFree == NO && sel_isEqual(method_name, sel)))
{
/* Found the list. Now fill up the gap. */
for ((list->method_count)--; i < list->method_count; i++)
{
list->method_list[i].method_name
= list->method_list[i+1].method_name;
list->method_list[i].method_types
= list->method_list[i+1].method_types;
list->method_list[i].method_imp
= list->method_list[i+1].method_imp;
}
/* Clear the last entry. */
/* NB: We may leak the types if they were previously
set by GSAppendMethodFromList. Yet as we can not
determine the origin, we shall leak. */
list->method_list[i].method_name = 0;
list->method_list[i].method_types = 0;
list->method_list[i].method_imp = 0;
return YES;
}
}
return NO;
}
/* See header for documentation. */
GSMethodList
GSMethodListForSelector(Class cls,
SEL selector,
void **iterator,
BOOL searchInstanceMethods)
{
void *local_iterator = 0;
if (cls == 0 || selector == 0)
{
return 0;
}
if (searchInstanceMethods == NO)
{
cls = cls->class_pointer;
}
if (sel_is_mapped(selector))
{
void **iterator_pointer;
GSMethodList method_list;
iterator_pointer = (iterator == 0 ? &local_iterator : iterator);
while ((method_list = class_nextMethodList(cls, iterator_pointer)))
{
/* Search the method in the current list. */
if (GSMethodFromList(method_list, selector, NO) != 0)
while ((method = methods[index++]) != NULL)
{
return method_list;
if (sel_isEqual(sel, method_getName(method)))
{
break;
}
}
}
}
return 0;
}
/* See header for documentation. */
GSMethod
GSMethodFromList(GSMethodList list,
SEL sel,
BOOL isFree)
{
unsigned i;
#ifdef GNU_RUNTIME
if (isFree)
{
sel = (SEL)GSNameFromSelector (sel);
}
#else
isFree = NO;
#endif
for (i = 0; i < list->method_count; ++i)
{
GSMethod method = &list->method_list[i];
SEL method_name = method->method_name;
/* For the GNU runtime we have use strcmp instead of sel_isEqual
for free standing method lists. */
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
|| (isFree == NO && sel_isEqual(method_name, sel)))
{
return method;
free(methods);
}
}
return 0;
}
/* See header for documentation. */
void
GSAddMethodList(Class cls,
GSMethodList list,
BOOL toInstanceMethods)
{
if (cls == 0 || list == 0)
{
return;
}
if (toInstanceMethods == NO)
{
cls = cls->class_pointer;
}
class_add_method_list(cls, list);
}
static inline void
gs_revert_selector_names_in_list(GSMethodList list)
{
int i;
const char *name;
for (i = 0; i < list->method_count; i++)
{
name = GSNameFromSelector(list->method_list[i].method_name);
if (name)
{
list->method_list[i].method_name = (SEL)name;
}
}
}
/* See header for documentation. */
void
GSRemoveMethodList(Class cls,
GSMethodList list,
BOOL fromInstanceMethods)
{
if (cls == 0 || list == 0)
{
return;
}
if (fromInstanceMethods == NO)
{
cls = cls->class_pointer;
}
#ifdef NeXT_RUNTIME
class_removeMethods(cls, list);
#else
if (list == cls->methods)
{
cls->methods = list->method_next;
list->method_next = 0;
/*
The list has become "free standing".
Replace all selector references with selector names
so the runtime can convert them again
it the list gets reinserted.
*/
gs_revert_selector_names_in_list(list);
return method;
}
else
{
GSMethodList current_list;
for (current_list = cls->methods;
current_list != 0;
current_list = current_list->method_next)
{
if (current_list->method_next == list)
{
current_list->method_next = list->method_next;
list->method_next = 0;
/*
The list has become "free standing".
Replace all selector references with selector names
so the runtime can convert them again
it the list gets reinserted.
*/
gs_revert_selector_names_in_list(list);
}
}
if (searchInstanceMethods == NO)
{
return class_getClassMethod(cls, sel);
}
else
{
return class_getInstanceMethod(cls, sel);
}
}
#endif /* NeXT_RUNTIME */
}
@ -1057,16 +571,16 @@ static inline const char *
gs_skip_type_qualifier_and_layout_info (const char *types)
{
while (*types == '+'
|| *types == '-'
|| *types == _C_CONST
|| *types == _C_IN
|| *types == _C_INOUT
|| *types == _C_OUT
|| *types == _C_BYCOPY
|| *types == _C_BYREF
|| *types == _C_ONEWAY
|| *types == _C_GCINVISIBLE
|| isdigit ((unsigned char) *types))
|| *types == '-'
|| *types == _C_CONST
|| *types == _C_IN
|| *types == _C_INOUT
|| *types == _C_OUT
|| *types == _C_BYCOPY
|| *types == _C_BYREF
|| *types == _C_ONEWAY
|| *types == _C_GCINVISIBLE
|| isdigit ((unsigned char) *types))
{
types++;
}
@ -1117,30 +631,13 @@ GSSelectorTypesMatch(const char *types1, const char *types2)
GSIVar
GSCGetInstanceVariableDefinition(Class cls, const char *name)
{
struct objc_ivar_list *list;
int i;
if (cls == 0)
return 0;
list = cls->ivars;
for (i = 0; (list != 0) && i < list->ivar_count; i++)
{
if (strcmp (list->ivar_list[i].ivar_name, name) == 0)
return &(list->ivar_list[i]);
}
cls = GSObjCSuper(cls);
if (cls != 0)
{
return GSCGetInstanceVariableDefinition(cls, name);
}
return 0;
return class_getInstanceVariable(cls, name);
}
GSIVar
GSObjCGetInstanceVariableDefinition(Class cls, NSString *name)
{
return GSCGetInstanceVariableDefinition(cls, [name cString]);
return class_getInstanceVariable(cls, [name UTF8String]);
}
@ -1342,13 +839,15 @@ GSProtocolFromName(const char *name)
void
GSObjCAddClassBehavior(Class receiver, Class behavior)
{
Class behavior_super_class = GSObjCSuper(behavior);
unsigned int count;
Method *methods;
Class behavior_super_class = class_getSuperclass(behavior);
NSCAssert(CLS_ISCLASS(receiver), NSInvalidArgumentException);
NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
NSCAssert(NO == class_isMetaClass(receiver), NSInvalidArgumentException);
NSCAssert(NO == class_isMetaClass(behavior), NSInvalidArgumentException);
/* If necessary, increase instance_size of CLASS. */
if (receiver->instance_size < behavior->instance_size)
if (class_getInstanceSize(receiver) < class_getInstanceSize(behavior))
{
#if NeXT_RUNTIME
NSCAssert2(receiver->instance_size >= behavior->instance_size,
@ -1366,44 +865,26 @@ GSObjCAddClassBehavior(Class receiver, Class behavior)
receiver->instance_size = behavior->instance_size;
}
BDBGPrintf("Adding behavior to class %s\n", receiver->name);
BDBGPrintf(" instance methods from %s\n", behavior->name);
BDBGPrintf("Adding behavior to class %s\n", class_getName(receiver));
BDBGPrintf(" instance methods from %s\n", class_getName(behavior));
/* Add instance methods */
#if NeXT_RUNTIME
{
void *iterator = 0;
GSMethodList method_list;
method_list = class_nextMethodList(behavior, &iterator);
while (method_list != 0)
{
GSObjCAddMethods (receiver, method_list);
method_list = class_nextMethodList(behavior, &iterator);
}
}
#else
GSObjCAddMethods (receiver, behavior->methods);
#endif
methods = class_copyMethodList(behavior, &count);
if (methods != NULL)
{
GSObjCAddMethods (receiver, methods, NO);
free(methods);
}
/* Add class methods */
BDBGPrintf("Adding class methods from %s\n",
behavior->class_pointer->name);
#if NeXT_RUNTIME
{
void *iterator = 0;
GSMethodList method_list;
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
while (method_list != 0)
{
GSObjCAddMethods (receiver->class_pointer, method_list);
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
}
}
#else
GSObjCAddMethods (receiver->class_pointer, behavior->class_pointer->methods);
#endif
class_getName(object_getClass(behavior)));
methods = class_copyMethodList(object_getClass(behavior), &count);
if (methods != NULL)
{
GSObjCAddMethods (object_getClass(receiver), methods, NO);
free(methods);
}
/* Add behavior's superclass, if not already there. */
if (!GSObjCIsKindOf(receiver, behavior_super_class))