diff --git a/init.c b/init.c index 35e843b..27588ea 100644 --- a/init.c +++ b/init.c @@ -938,6 +938,7 @@ init_check_module_version (Module_t module) } } +struct objc_protocol *__objc_unique_protocol(struct objc_protocol*); static void __objc_init_protocols (struct objc_protocol_list *protos) { @@ -955,7 +956,8 @@ __objc_init_protocols (struct objc_protocol_list *protos) if (! proto_class2) proto_class2 = objc_lookup_class ("Protocol2"); - if (! proto_class) + /* Protocol2 will always exist if Protocol exists */ + if (! proto_class2) { unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); UNLOCK(__objc_runtime_mutex); @@ -988,7 +990,7 @@ __objc_init_protocols (struct objc_protocol_list *protos) aProto->class_pointer = proto_class2; /* init super protocols */ __objc_init_protocols (aProto->protocol_list); - //__objc_unique_protocol (aProto); + protos->list[i] = __objc_unique_protocol (aProto); } default: { diff --git a/protocol.c b/protocol.c index f3a000f..7e8003a 100644 --- a/protocol.c +++ b/protocol.c @@ -1,9 +1,52 @@ -#include -#include +#include "objc/objc.h" +#include "objc/objc-api.h" +#include "lock.h" +#include -static cache_ptr Protocols = 0; +// Get the functions for string hashing +#include "string_hash.h" -struct objc_method_description_list +static int protocol_compare(const char *name, + const struct objc_protocol2 *protocol) +{ + return string_compare(name, protocol->protocol_name); +} +static int protocol_hash(const struct objc_protocol2 *protocol) +{ + return string_hash(protocol->protocol_name); +} +#define MAP_TABLE_NAME protocol +#define MAP_TABLE_COMPARE_FUNCTION protocol_compare +#define MAP_TABLE_HASH_KEY string_hash +#define MAP_TABLE_HASH_VALUE protocol_hash +// This defines the maximum number of classes that the runtime supports. +#define MAP_TABLE_STATIC_SIZE 2048 +#include "hash_table.h" + +static protocol_table known_protocol_table; + +static mutex_t protocol_table_lock; + +void __objc_init_protocol_table(void) +{ + LOCK(__objc_runtime_mutex); + INIT_LOCK(protocol_table_lock); + UNLOCK(__objc_runtime_mutex); +} + +static void protocol_table_insert(const struct objc_protocol2 *protocol) +{ + LOCK(&protocol_table_lock); + protocol_insert(&known_protocol_table, protocol->protocol_name, (void*)protocol); + UNLOCK(&protocol_table_lock); +} + +struct objc_protocol2 *protocol_for_name(const char *protocol_name) +{ + return protocol_table_get(&known_protocol_table, protocol_name); +} + +struct objc_method_description_list { int count; struct objc_method_description list[1]; @@ -11,15 +54,7 @@ struct objc_method_description_list static Class ObjC2ProtocolClass = 0; -void __objc_init_protocol_table(void) -{ - Protocols = objc_hash_new(128, - (hash_func_type)objc_hash_string, - (compare_func_type)objc_compare_strings); -} - - -static int isEmptyProtocol(struct objc_protocol *aProto) +static int isEmptyProtocol(struct objc_protocol2 *aProto) { int isEmpty = (aProto->instance_methods->count == 0) && (aProto->class_methods->count == 0) && @@ -36,34 +71,51 @@ static int isEmptyProtocol(struct objc_protocol *aProto) } // FIXME: Make p1 adopt all of the stuff in p2 -static void makeProtocolEqualToProtocol(struct objc_protocol *p1, - struct objc_protocol *p2) {} +static void makeProtocolEqualToProtocol(struct objc_protocol2 *p1, + struct objc_protocol2 *p2) +{ +#define COPY(x) p1->x = p2->x + COPY(instance_methods); + COPY(class_methods); + COPY(protocol_list); + if (p1->class_pointer == ObjC2ProtocolClass && + p2->class_pointer == ObjC2ProtocolClass) + { + COPY(optional_instance_methods); + COPY(optional_class_methods); + COPY(properties); + COPY(optional_properties); + } +#undef COPY +} -void __objc_unique_protocol(struct objc_protocol *aProto) +struct objc_protocol2 *__objc_unique_protocol(struct objc_protocol2 *aProto) { if (ObjC2ProtocolClass == 0) { ObjC2ProtocolClass = objc_get_class("Protocol2"); } - struct objc_protocol *oldProtocol = - objc_hash_value_for_key(Protocols, aProto->protocol_name); + struct objc_protocol2 *oldProtocol = + protocol_for_name(aProto->protocol_name); if (NULL == oldProtocol) { // This is the first time we've seen this protocol, so add it to the // hash table and ignore it. - objc_hash_add(&Protocols, aProto, aProto->protocol_name); - return; + protocol_table_insert(aProto); + return aProto; } if (isEmptyProtocol(oldProtocol)) { if (isEmptyProtocol(aProto)) { + return aProto; // Add protocol to a list somehow. } else { // This protocol is not empty, so we use its definitions makeProtocolEqualToProtocol(oldProtocol, aProto); + return aProto; } } else @@ -71,9 +123,11 @@ void __objc_unique_protocol(struct objc_protocol *aProto) if (isEmptyProtocol(aProto)) { makeProtocolEqualToProtocol(aProto, oldProtocol); + return oldProtocol; } else { + return oldProtocol; //FIXME: We should really perform a check here to make sure the //protocols are actually the same. }