aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libobjc/protocols.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/libobjc/protocols.c')
-rw-r--r--gcc-4.9/libobjc/protocols.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/gcc-4.9/libobjc/protocols.c b/gcc-4.9/libobjc/protocols.c
new file mode 100644
index 000000000..a0163a54f
--- /dev/null
+++ b/gcc-4.9/libobjc/protocols.c
@@ -0,0 +1,557 @@
+/* GNU Objective C Runtime protocol related functions.
+ Copyright (C) 2010-2014 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/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(). */
+#include <stdlib.h> /* For malloc. */
+
+/* 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, struct objc_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] = (struct objc_protocol *)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] == (struct objc_protocol *)protocol
+ || protocol_conformsToProtocol ((Protocol *)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;
+
+ if (class_ == Nil)
+ {
+ if (numberOfReturnedProtocols)
+ *numberOfReturnedProtocols = 0;
+ return NULL;
+ }
+
+ /* 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] = (Protocol *)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 ((Protocol *)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 };
+ 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;
+
+ 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 (sel_isEqual (methods->list[i].name, selector))
+ return methods->list[i];
+ /*
+ if (strcmp (sel_getName (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] = (Protocol *)proto_list->list[j];
+ i++;
+ }
+ proto_list = proto_list->next;
+ }
+
+ returnValue[i] = NULL;
+ }
+
+ if (numberOfReturnedProtocols)
+ *numberOfReturnedProtocols = count;
+
+ return returnValue;
+}