]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
In libobjc/: 2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com>
authorNicola Pero <nicola.pero@meta-innovation.com>
Tue, 12 Oct 2010 02:43:25 +0000 (02:43 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Tue, 12 Oct 2010 02:43:25 +0000 (02:43 +0000)
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

libobjc/ChangeLog
libobjc/Makefile.in
libobjc/class.c
libobjc/init.c
libobjc/objc-private/module-abi-8.h
libobjc/objc-private/protocols.h [new file with mode: 0644]
libobjc/objc-private/runtime.h
libobjc/objc/deprecated/struct_objc_class.h
libobjc/objc/runtime.h
libobjc/protocols.c [new file with mode: 0644]
libobjc/selector.c

index e66df6a9836330acff3e6f7e31c1d40923b0ab5f..569d6a69c3afbc96527afc1e9e4b7d368b4a25a0 100644 (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
index 86f65bad844ff849210c088f366456109d4f87a3..4790f952b9dce4c3ebebe4bec83c7642c6f6e546 100644 (file)
@@ -177,6 +177,7 @@ C_SOURCE_FILES = \
    objc-foreach.c \
    objc-sync.c \
    objects.c \
+   protocols.c \
    sarray.c \
    selector.c \
    sendmsg.c \
index 216d6ace0dc6f8fbd7205262832370f8297ffb17..727b26f4b97773781388229dbe7e0ecebf666439 100644 (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)
 
index deb089d7e16a83b5a7e02e2806f334eb11dc2d89..9384f5865c35c8125b829e1751b0ffc5ddd1d6b2 100644 (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)
index a20e3a3ae6e533acebddef1020e1afc08c81018c..120f5139d045c16c22b330cd06f25581b155cc77 100644 (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
diff --git a/libobjc/objc-private/protocols.h b/libobjc/objc-private/protocols.h
new file mode 100644 (file)
index 0000000..49a2d92
--- /dev/null
@@ -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 */
index 690427ed5a3207ceefb93b3043c6c4e17784a4e8..3917c3ef3b03c1de2ef0df3d2b7dfbb1c414f318 100644 (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;
index 5a4859cbd656650ba0346e3d86e2a16bd04a6f9b..07927feb69d7679568cdf711e2c4324330bbf356 100644 (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.  
index f3a19ec0b237c288e3e8798dc5ced8603bd8e351..b5ae87bc7c82489f55d6cd02e622cd3f3f992c6a 100644 (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.  */
 
diff --git a/libobjc/protocols.c b/libobjc/protocols.c
new file mode 100644 (file)
index 0000000..af62a2d
--- /dev/null
@@ -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;
+}
index e51dd20bd9b46daca485f0b12e26a52fbb405318..0c12130ae3807dcaaaefb5906a6f881d8557a9de 100644 (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 */