In libobjc/: 2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com>

In libobjc/:
2010-10-12  Nicola Pero  <nicola.pero@meta-innovation.com>

        * Makefile.in (C_SOURCE_FILES): Added protocols.c.
        * objc-private/protocols.h: New.
        * protocols.c: New.
        * init.c: Include objc-private/protocols.h.
        (__objc_exec_class): Call __objc_protocols_init on startup.
        (__objc_init_protocols): Call __objc_protocols_add_protocol.
        * objc-private/runtime.h: Use (struct objc_method_list *) instead
        of MethodList_t, and (struct objc_method *) instead of Method_t.
        * objc/deprecated/struct_objc_class.h: Define
        __objc_STRUCT_OBJC_CLASS_defined.
        * objc-private/module-abi-8.h (struct
        objc_method_description_list): New.
        (struct objc_class): Only define if
        __objc_STRUCT_OBJC_CLASS_defined is undefined.
        * objc/runtime.h (class_getName): New.
        (objc_getProtocol): New.
        (objc_copyProtocolList): New.
        (class_addProtocol): New.
        (class_conformsToProtocol): New.
        (class_copyProtocolList): New.
        (protocol_conformsToProtocol): New.
        (protocol_isEqual): New.
        (protocol_getName): New.
        (protocol_getMethodDescription): New.
        (protocol_copyMethodDescriptionList): New.
        (protocol_getProperty): New.
        (protocol_copyPropertyList): New.
        (protocol_copyProtocolList): New.
        * class.c (class_getName): New.
        * selector.c (sel_isEqual): New.

From-SVN: r165349
This commit is contained in:
Nicola Pero 2010-10-12 02:43:25 +00:00 committed by Nicola Pero
parent 524660d2e3
commit debfbfeefc
11 changed files with 822 additions and 7 deletions

View file

@ -1,3 +1,36 @@
2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com>
* Makefile.in (C_SOURCE_FILES): Added protocols.c.
* objc-private/protocols.h: New.
* protocols.c: New.
* init.c: Include objc-private/protocols.h.
(__objc_exec_class): Call __objc_protocols_init on startup.
(__objc_init_protocols): Call __objc_protocols_add_protocol.
* objc-private/runtime.h: Use (struct objc_method_list *) instead
of MethodList_t, and (struct objc_method *) instead of Method_t.
* objc/deprecated/struct_objc_class.h: Define
__objc_STRUCT_OBJC_CLASS_defined.
* objc-private/module-abi-8.h (struct
objc_method_description_list): New.
(struct objc_class): Only define if
__objc_STRUCT_OBJC_CLASS_defined is undefined.
* objc/runtime.h (class_getName): New.
(objc_getProtocol): New.
(objc_copyProtocolList): New.
(class_addProtocol): New.
(class_conformsToProtocol): New.
(class_copyProtocolList): New.
(protocol_conformsToProtocol): New.
(protocol_isEqual): New.
(protocol_getName): New.
(protocol_getMethodDescription): New.
(protocol_copyMethodDescriptionList): New.
(protocol_getProperty): New.
(protocol_copyPropertyList): New.
(protocol_copyProtocolList): New.
* class.c (class_getName): New.
* selector.c (sel_isEqual): New.
2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com>
* selector.c (sel_getName): Return "<null selector>" for a NULL

View file

@ -177,6 +177,7 @@ C_SOURCE_FILES = \
objc-foreach.c \
objc-sync.c \
objects.c \
protocols.c \
sarray.c \
selector.c \
sendmsg.c \

View file

@ -139,7 +139,8 @@ static class_node_ptr class_table_array[CLASS_TABLE_SIZE];
/* The table writing mutex - we lock on writing to avoid conflicts
between different writers, but we read without locks. That is
possible because we assume pointer assignment to be an atomic
operation. */
operation. TODO: This is only true under certain circumstances,
which should be clarified. */
static objc_mutex_t __class_table_lock = NULL;
/* CLASS_TABLE_HASH is how we compute the hash of a class name. It is
@ -730,7 +731,14 @@ __objc_resolve_class_links (void)
objc_mutex_unlock (__objc_runtime_mutex);
}
const char *
class_getName (Class class_)
{
if (class_ == Nil)
return "nil";
return class_->name;
}
#define CLASSOF(c) ((c)->class_pointer)

View file

@ -33,6 +33,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc-private/objc-list.h"
#include "objc-private/runtime.h"
#include "objc-private/objc-sync.h" /* For __objc_sync_init() */
#include "objc-private/protocols.h" /* For __objc_protocols_init() and __objc_protocols_add_protocol() */
/* The version number of this runtime. This must match the number
defined in gcc (objc-act.c). */
@ -48,7 +49,17 @@ static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */
/* List of unresolved static instances. */
static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */
/* Global runtime "write" mutex. */
/* Global runtime "write" mutex. Having a single mutex prevents
deadlocks, but reduces concurrency. To improve concurrency, some
groups of functions in the runtime have their own separate mutex
(eg, __class_table_lock in class.c); to avoid deadlocks, these
routines must make sure that they never acquire any other lock
while holding their own local lock. Ie, they should lock, execute
some C code that does not perform any calls to other runtime
functions which may potentially lock different locks, then unlock.
If they need to perform any calls to other runtime functions that
may potentially lock other locks, then they should use the global
__objc_runtime_mutex. */
objc_mutex_t __objc_runtime_mutex = 0;
/* Number of threads that are alive. */
@ -551,6 +562,7 @@ __objc_exec_class (Module_t module)
__objc_load_methods = objc_hash_new (128,
(hash_func_type)objc_hash_ptr,
objc_compare_ptrs);
__objc_protocols_init ();
__objc_sync_init ();
previous_constructors = 1;
}
@ -862,10 +874,14 @@ __objc_init_protocols (struct objc_protocol_list *protos)
struct objc_protocol *aProto = protos->list[i];
if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
{
/* assign class pointer */
/* Assign class pointer */
aProto->class_pointer = proto_class;
/* init super protocols */
/* Register the protocol in the hashtable or protocols by
name. */
__objc_protocols_add_protocol (aProto->protocol_name, aProto);
/* Init super protocols */
__objc_init_protocols (aProto->protocol_list);
}
else if (protos->list[i]->class_pointer != proto_class)

View file

@ -138,6 +138,24 @@ struct objc_method_list
structure. */
};
/* Currently defined in Protocol.m (that definition should go away
once we include this file). */
struct objc_method_description_list
{
int count;
struct objc_method_description list[1];
};
/* Currently defined by objc/objc.h. */
/*
struct objc_protocol {
struct objc_class* class_pointer;
char *protocol_name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods, *class_methods;
};
*/
struct objc_protocol_list
{
struct objc_protocol_list *next;
@ -155,6 +173,7 @@ struct objc_protocol_list
some members change type. The compiler generates "char* const" and
places a string in the following member variables: super_class.
*/
#ifndef __objc_STRUCT_OBJC_CLASS_defined
struct objc_class {
struct objc_class* class_pointer; /* Pointer to the class's meta
class. */
@ -197,6 +216,7 @@ struct objc_class {
struct objc_protocol_list *protocols; /* Protocols conformed to */
void* gc_object_type;
};
#endif /* __objc_STRUCT_OBJC_CLASS_defined */
/* The compiler generates one of these structures for each category.
A class may have many categories and contain both instance and

View file

@ -0,0 +1,46 @@
/* GNU Objective C Runtime protocols - Private functions
Copyright (C) 2010 Free Software Foundation, Inc.
Contributed by Nicola Pero <nicola.pero@meta-innovation.com>
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
<http://www.gnu.org/licenses/>. */
#ifndef __objc_private_protocols_INCLUDE_GNU
#define __objc_private_protocols_INCLUDE_GNU
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* This function needs to be called at startup by init.c. */
void
__objc_protocols_init (void);
/* This function adds a protocol to the internal hashtable of
protocols by name, which allows objc_getProtocol(name) to be
implemented efficiently. */
void
__objc_protocols_add_protocol (const char *name, Protocol *object);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* not __objc_private_protocols_INCLUDE_GNU */

View file

@ -58,18 +58,18 @@ extern void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */
extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
extern void __objc_resolve_class_links(void); /* (objc-class.c) */
extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */
extern void __objc_register_selectors_from_list (MethodList_t); /* (selector.c) */
extern void __objc_register_selectors_from_list (struct objc_method_list *); /* (selector.c) */
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
extern int __objc_init_thread_system(void); /* thread.c */
extern int __objc_fini_thread_system(void); /* thread.c */
extern void __objc_print_dtable_stats(void); /* sendmsg.c */
extern void class_add_method_list(Class, MethodList_t);
extern void class_add_method_list(Class, struct objc_method_list *);
/* Registering instance methods as class methods for root classes */
extern void __objc_register_instance_methods_to_class(Class);
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
extern struct objc_method * search_for_method_in_list(struct objc_method_list * list, SEL op);
/* True when class links has been resolved */
extern BOOL __objc_class_links_resolved;

View file

@ -1,4 +1,5 @@
/* This structure used to be public, but is now private to the runtime. */
#define __objc_STRUCT_OBJC_CLASS_defined
/*
** The compiler generates one of these structures for each class.

View file

@ -356,6 +356,138 @@ objc_EXPORT int objc_getClassList (Class *returnValue, int maxNumberOfClassesToR
the documentation is unclear on what they are supposed to do, and
the GNU Objective-C Runtime currently does not provide them. */
/* Return the name of the class 'class_', or the string "nil" if the
class_ is Nil. */
objc_EXPORT const char * class_getName (Class class_);
/** Implementation: the following functions are in protocols.c. */
/* Return the protocol with name 'name', or nil if it the protocol is
not known to the runtime. */
objc_EXPORT Protocol *objc_getProtocol (const char *name);
/* Return all the protocols known to the runtime. The return value of
the function is a pointer to an area, allocated with malloc(), that
contains all the protocols known to the runtime; the list is
terminated by NULL. You should free this area using free() once
you no longer need it. Optionally, if you pass a non-NULL
'numberOfReturnedProtocols' pointer, the unsigned int that it
points to will be filled with the number of protocols returned. If
there are no protocols known to the runtime, NULL is returned. */
objc_EXPORT Protocol **objc_copyProtocolList (unsigned int *numberOfReturnedProtocols);
/* Add a protocol to a class, and return YES if it was done
succesfully, and NO if not. At the moment, NO should only happen
if class_ or protocol are nil, if the protocol is not a Protocol
object or if the class already conforms to the protocol. */
objc_EXPORT BOOL class_addProtocol (Class class_, Protocol *protocol);
/* Return YES if the class 'class_' conforms to Protocol 'protocol',
and NO if not. */
objc_EXPORT BOOL class_conformsToProtocol (Class class_, Protocol *protocol);
/* Return all the protocols that the class conforms to. The return
value of the function is a pointer to an area, allocated with
malloc(), that contains all the protocols formally adopted by the
class. It does not include protocols adopted by superclasses. The
list is terminated by NULL. Optionally, if you pass a non-NULL
'numberOfReturnedProtocols' pointer, the unsigned int that it
points to will be filled with the number of protocols returned. */
objc_EXPORT Protocol **class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols);
/* Return YES if protocol 'protocol' conforms to protocol
'anotherProtocol', and NO if not. Note that if one of the two
protocols is nil, it returns NO. */
objc_EXPORT BOOL protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol);
/* Return YES if protocol 'protocol' is the same as protocol
'anotherProtocol', and 'NO' if not. Note that it returns YES if
the two protocols are both nil. */
objc_EXPORT BOOL protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol);
/* Return the name of protocol 'protocol'. If 'protocol' is nil or is
not a Protocol, return NULL. */
objc_EXPORT const char *protocol_getName (Protocol *protocol);
/* Return the method description for the method with selector
'selector' in protocol 'protocol'; if 'requiredMethod' is YES, the
function searches the list of required methods; if NO, the list of
optional methods. If 'instanceMethod' is YES, the function search
for an instance method; if NO, for a class method. If there is no
matching method, an objc_method_description structure with both
name and types set to NULL is returned. This function will only
find methods that are directly declared in the protocol itself, not
in other protocols that this protocol adopts.
Note that the traditional ABI does not store the list of optional
methods of a protocol in a compiled module, so the traditional ABI
will always return (NULL, NULL) when requiredMethod == NO. */
objc_EXPORT struct objc_method_description protocol_getMethodDescription (Protocol *protocol,
SEL selector,
BOOL requiredMethod,
BOOL instanceMethod);
/* Return the method descriptions of all the methods of the protocol.
The return value of the function is a pointer to an area, allocated
with malloc(), that contains all the method descriptions of the
methods of the protocol. It does not recursively include methods
of the protocols adopted by this protocol. The list is terminated
by a NULL objc_method_description (one with both fields set to
NULL). Optionally, if you pass a non-NULL
'numberOfReturnedMethods' pointer, the unsigned int that it points
to will be filled with the number of properties returned.
Note that the traditional ABI does not store the list of optional
methods of a protocol in a compiled module, so the traditional ABI
will always return an empty list if requiredMethod is set to
NO. */
objc_EXPORT struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol,
BOOL requiredMethod,
BOOL instanceMethod,
unsigned int *numberOfReturnedMethods);
/* Return the property with name 'propertyName' of the protocol
'protocol'. If 'requiredProperty' is YES, the function searches
the list of required properties; if NO, the list of optional
properties. If 'instanceProperty' is YES, the function searches
the list of instance properties; if NO, the list of class
properties. At the moment, optional properties and class
properties are not part of the Objective-C language, so both
'requiredProperty' and 'instanceProperty' should be set to YES.
This function returns NULL if the required property can not be
found.
Note that the traditional ABI does not store the list of properties
of a protocol in a compiled module, so the traditional ABI will
always return NULL. */
objc_EXPORT Property protocol_getProperty (Protocol *protocol, const char *propertyName,
BOOL requiredProperty, BOOL instanceProperty);
/* Return all the properties of the protocol. The return value of the
function is a pointer to an area, allocated with malloc(), that
contains all the properties of the protocol. It does not
recursively include properties of the protocols adopted by this
protocol. The list is terminated by NULL. Optionally, if you pass
a non-NULL 'numberOfReturnedProperties' pointer, the unsigned int
that it points to will be filled with the number of properties
returned.
Note that the traditional ABI does not store the list of properties
of a protocol in a compiled module, so the traditional ABI will
always return NULL and store 0 in numberOfReturnedProperties. */
objc_EXPORT Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties);
/* Return all the protocols that the protocol conforms to. The return
value of the function is a pointer to an area, allocated with
malloc(), that contains all the protocols formally adopted by the
protocol. It does not recursively include protocols adopted by the
protocols adopted by this protocol. The list is terminated by
NULL. Optionally, if you pass a non-NULL
'numberOfReturnedProtocols' pointer, the unsigned int that it
points to will be filled with the number of protocols returned. */
objc_EXPORT Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols);
/* TODO: Add all the other functions in the API. */

550
libobjc/protocols.c Normal file
View file

@ -0,0 +1,550 @@
/* GNU Objective C Runtime protocol related functions.
Copyright (C) 2010 Free Software Foundation, Inc.
Contributed by Nicola Pero
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
<http://www.gnu.org/licenses/>. */
#include "objc-private/common.h"
#include "objc/objc.h"
#include "objc/runtime.h"
#include "objc-private/module-abi-8.h" /* For runtime structures */
#include "objc/thr.h"
#include "objc-private/runtime.h" /* the kitchen sink */
#include "objc-private/hash.h" /* For the hash table of protocols. */
#include "objc-private/protocols.h" /* For __objc_protocols_init() and __objc_protocols_add_protocol() */
/* This is a table that maps a name to a Protocol instance with that
name. Because there may be multiple Protocol instances with the
same name (no harm in that) the table records only one
instance. */
static cache_ptr __protocols_hashtable;
/* A mutex protecting the protocol_hashtable. */
static objc_mutex_t __protocols_hashtable_lock = NULL;
/* Called at startup by init.c. */
void
__objc_protocols_init (void)
{
__protocols_hashtable_lock = objc_mutex_allocate ();
/* The keys in the table are strings, and the values are Protocol
objects. */
__protocols_hashtable = objc_hash_new (64, (hash_func_type) objc_hash_string,
(compare_func_type) objc_compare_strings);
}
/* Add a protocol to the hashtable. */
void
__objc_protocols_add_protocol (const char *name, Protocol *object)
{
objc_mutex_lock (__protocols_hashtable_lock);
/* If we find a protocol with the same name already in the
hashtable, we do not need to add the new one, because it will be
identical to it. This in the reasonable assumption that two
protocols with the same name are identical, which is expected in
any sane program. If we are really paranoid, we would compare
the protocols and abort if they are not identical.
Unfortunately, this would slow down the startup of all
Objective-C programs while trying to catch a problem that has
never been seen in practice, so we don't do it. */
if (! objc_hash_is_key_in_hash (__protocols_hashtable, name))
{
objc_hash_add (&__protocols_hashtable, name, object);
}
objc_mutex_unlock (__protocols_hashtable_lock);
}
Protocol *
objc_getProtocol (const char *name)
{
Protocol *protocol;
if (name == NULL)
return NULL;
objc_mutex_lock (__protocols_hashtable_lock);
protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name));
objc_mutex_unlock (__protocols_hashtable_lock);
return protocol;
}
Protocol **
objc_copyProtocolList (unsigned int *numberOfReturnedProtocols)
{
unsigned int count = 0;
Protocol **returnValue = NULL;
node_ptr node;
objc_mutex_lock (__protocols_hashtable_lock);
/* Count how many protocols we have. */
node = objc_hash_next (__protocols_hashtable, NULL);
while (node)
{
count++;
node = objc_hash_next (__protocols_hashtable, node);
}
if (count != 0)
{
unsigned int i = 0;
/* Allocate enough memory to hold them. */
returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
/* Copy the protocols. */
node = objc_hash_next (__protocols_hashtable, NULL);
while (node)
{
returnValue[i] = node->value;
i++;
node = objc_hash_next (__protocols_hashtable, node);
}
returnValue[i] = NULL;
}
objc_mutex_unlock (__protocols_hashtable_lock);
if (numberOfReturnedProtocols)
*numberOfReturnedProtocols = count;
return returnValue;
}
BOOL
class_addProtocol (Class class_, Protocol *protocol)
{
struct objc_protocol_list *protocols;
if (class_ == Nil || protocol == NULL)
return NO;
if (class_conformsToProtocol (class_, protocol))
return NO;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NO;
objc_mutex_lock (__objc_runtime_mutex);
/* Create the objc_protocol_list. */
protocols = malloc (sizeof (struct objc_protocol_list));
protocols->count = 1;
protocols->list[0] = protocol;
/* Attach it to the list of class protocols. */
protocols->next = class_->protocols;
class_->protocols = protocols;
objc_mutex_unlock (__objc_runtime_mutex);
return YES;
}
BOOL
class_conformsToProtocol (Class class_, Protocol *protocol)
{
struct objc_protocol_list* proto_list;
if (class_ == Nil || protocol == NULL)
return NO;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NO;
/* Acquire the runtime lock because the list of protocols for a
class may be modified concurrently, for example if another thread
calls class_addProtocol(), or dynamically loads from a file a
category of the class. */
objc_mutex_lock (__objc_runtime_mutex);
proto_list = class_->protocols;
while (proto_list)
{
size_t i;
for (i = 0; i < proto_list->count; i++)
{
if (proto_list->list[i] == protocol
|| protocol_conformsToProtocol (proto_list->list[i],
protocol))
{
objc_mutex_unlock (__objc_runtime_mutex);
return YES;
}
}
proto_list = proto_list->next;
}
objc_mutex_unlock (__objc_runtime_mutex);
return NO;
}
Protocol **
class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols)
{
unsigned int count = 0;
Protocol **returnValue = NULL;
struct objc_protocol_list* proto_list;
/* Lock the runtime mutex because the class protocols may be
concurrently modified. */
objc_mutex_lock (__objc_runtime_mutex);
/* Count how many protocols we have. */
proto_list = class_->protocols;
while (proto_list)
{
count = count + proto_list->count;
proto_list = proto_list->next;
}
if (count != 0)
{
unsigned int i = 0;
/* Allocate enough memory to hold them. */
returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
/* Copy the protocols. */
proto_list = class_->protocols;
while (proto_list)
{
size_t j;
for (j = 0; j < proto_list->count; j++)
{
returnValue[i] = proto_list->list[j];
i++;
}
proto_list = proto_list->next;
}
returnValue[i] = NULL;
}
objc_mutex_unlock (__objc_runtime_mutex);
if (numberOfReturnedProtocols)
*numberOfReturnedProtocols = count;
return returnValue;
}
BOOL
protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol)
{
struct objc_protocol_list* proto_list;
if (protocol == NULL || anotherProtocol == NULL)
return NO;
if (protocol == anotherProtocol)
return YES;
/* Check that the objects are Protocol objects before casting them
to (struct objc_protocol *). */
if (protocol->class_pointer != anotherProtocol->class_pointer)
return NO;
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NO;
if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
return YES;
/* We do not acquire any lock because protocols are currently
immutable. We can freely iterate over a protocol structure. */
proto_list = ((struct objc_protocol *)protocol)->protocol_list;
while (proto_list)
{
size_t i;
for (i = 0; i < proto_list->count; i++)
{
if (protocol_conformsToProtocol (proto_list->list[i], anotherProtocol))
return YES;
}
proto_list = proto_list->next;
}
return NO;
}
BOOL
protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol)
{
if (protocol == anotherProtocol)
return YES;
if (protocol == NULL || anotherProtocol == NULL)
return NO;
/* Check that the objects are Protocol objects before casting them
to (struct objc_protocol *). */
if (protocol->class_pointer != anotherProtocol->class_pointer)
return NO;
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NO;
/* 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. */
if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
return YES;
return NO;
}
const char *
protocol_getName (Protocol *protocol)
{
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NULL;
return ((struct objc_protocol *)protocol)->protocol_name;
}
struct objc_method_description protocol_getMethodDescription (Protocol *protocol,
SEL selector,
BOOL requiredMethod,
BOOL instanceMethod)
{
struct objc_method_description no_result = { NULL, NULL };
const char* selector_name;
struct objc_method_description_list *methods;
int i;
/* TODO: New ABI. */
/* The current ABI does not have any information on optional protocol methods. */
if (! requiredMethod)
return no_result;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return no_result;
selector_name = sel_getName (selector);
if (instanceMethod)
methods = ((struct objc_protocol *)protocol)->instance_methods;
else
methods = ((struct objc_protocol *)protocol)->class_methods;
if (methods)
{
for (i = 0; i < methods->count; i++)
{
if (strcmp ((char*)(methods->list[i].name), selector_name) == 0)
return methods->list[i];
}
}
return no_result;
}
struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol,
BOOL requiredMethod,
BOOL instanceMethod,
unsigned int *numberOfReturnedMethods)
{
struct objc_method_description_list *methods;
unsigned int count = 0;
struct objc_method_description *returnValue = NULL;
/* TODO: New ABI */
/* The current ABI does not have any information on optional protocol methods. */
if (! requiredMethod)
{
if (numberOfReturnedMethods)
*numberOfReturnedMethods = 0;
return NULL;
}
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol"))
{
if (numberOfReturnedMethods)
*numberOfReturnedMethods = 0;
return NULL;
}
/* We do not acquire any lock because protocols are currently
immutable. We can freely iterate over a protocol structure. */
if (instanceMethod)
methods = ((struct objc_protocol *)protocol)->instance_methods;
else
methods = ((struct objc_protocol *)protocol)->class_methods;
if (methods)
{
unsigned int i;
count = methods->count;
/* Allocate enough memory to hold them. */
returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1)));
/* Copy them. */
for (i = 0; i < count; i++)
{
returnValue[i].name = methods->list[i].name;
returnValue[i].types = methods->list[i].types;
}
returnValue[i].name = NULL;
returnValue[i].types = NULL;
}
if (numberOfReturnedMethods)
*numberOfReturnedMethods = count;
return returnValue;
}
Property protocol_getProperty (Protocol *protocol, const char *propertyName,
BOOL requiredProperty, BOOL instanceProperty)
{
if (protocol == NULL || propertyName == NULL)
return NULL;
if (!requiredProperty || !instanceProperty)
return NULL;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol->class_pointer != objc_lookupClass ("Protocol"))
return NULL;
/* TODO: New ABI. */
/* The current ABI does not have any information on protocol properties. */
return NULL;
}
Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties)
{
unsigned int count = 0;
Property *returnValue = NULL;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol"))
{
if (numberOfReturnedProperties)
*numberOfReturnedProperties = 0;
return NULL;
}
/* We do not acquire any lock because protocols are currently
immutable. We can freely iterate over a protocol structure. */
/* TODO: New ABI. */
/* The current ABI does not have any information on protocol properties. */
if (numberOfReturnedProperties)
*numberOfReturnedProperties = count;
return returnValue;
}
Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols)
{
unsigned int count = 0;
Protocol **returnValue = NULL;
struct objc_protocol_list* proto_list;
/* Check that it is a Protocol object before casting it to (struct
objc_protocol *). */
if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol"))
{
if (numberOfReturnedProtocols)
*numberOfReturnedProtocols = 0;
return NULL;
}
/* We do not acquire any lock because protocols are currently
immutable. We can freely iterate over a protocol structure. */
/* Count how many protocols we have. */
proto_list = ((struct objc_protocol *)protocol)->protocol_list;
while (proto_list)
{
count = count + proto_list->count;
proto_list = proto_list->next;
}
if (count != 0)
{
unsigned int i = 0;
/* Allocate enough memory to hold them. */
returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
/* Copy the protocols. */
proto_list = ((struct objc_protocol *)protocol)->protocol_list;
while (proto_list)
{
size_t j;
for (j = 0; j < proto_list->count; j++)
{
returnValue[i] = proto_list->list[j];
i++;
}
proto_list = proto_list->next;
}
returnValue[i] = NULL;
}
if (numberOfReturnedProtocols)
*numberOfReturnedProtocols = count;
return returnValue;
}

View file

@ -163,6 +163,14 @@ void __objc_register_instance_methods_to_class (Class class)
__objc_update_dispatch_table_for_class (class->class_pointer);
}
BOOL
sel_isEqual (SEL s1, SEL s2)
{
if (s1 == 0 || s2 == 0)
return s1 == s2;
else
return s1->sel_id == s2->sel_id;
}
/* Returns YES iff t1 and t2 have same method types, but we ignore
the argframe layout */