diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libobjc/protocols.c | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libobjc/protocols.c')
-rw-r--r-- | libobjc/protocols.c | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/libobjc/protocols.c b/libobjc/protocols.c new file mode 100644 index 000000000..3ff6fbaa1 --- /dev/null +++ b/libobjc/protocols.c @@ -0,0 +1,557 @@ +/* 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/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, 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; + + 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] = 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 }; + 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] = proto_list->list[j]; + i++; + } + proto_list = proto_list->next; + } + + returnValue[i] = NULL; + } + + if (numberOfReturnedProtocols) + *numberOfReturnedProtocols = count; + + return returnValue; +} |