1 /* GNU Objective C Runtime protocol related functions. 2 Copyright (C) 2010 Free Software Foundation, Inc. 3 Contributed by Nicola Pero 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under the 8 terms of the GNU General Public License as published by the Free Software 9 Foundation; either version 3, or (at your option) any later version. 10 11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 details. 15 16 Under Section 7 of GPL version 3, you are granted additional 17 permissions described in the GCC Runtime Library Exception, version 18 3.1, as published by the Free Software Foundation. 19 20 You should have received a copy of the GNU General Public License and 21 a copy of the GCC Runtime Library Exception along with this program; 22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 <http://www.gnu.org/licenses/>. */ 24 25 #include "objc-private/common.h" 26 #include "objc/runtime.h" 27 #include "objc-private/module-abi-8.h" /* For runtime structures */ 28 #include "objc/thr.h" 29 #include "objc-private/runtime.h" /* the kitchen sink */ 30 #include "objc-private/hash.h" /* For the hash table of protocols. */ 31 #include "objc-private/protocols.h" /* For __objc_protocols_init() and 32 __objc_protocols_add_protocol(). */ 33 #include <stdlib.h> /* For malloc. */ 34 35 /* This is a table that maps a name to a Protocol instance with that 36 name. Because there may be multiple Protocol instances with the 37 same name (no harm in that) the table records only one 38 instance. */ 39 static cache_ptr __protocols_hashtable; 40 41 /* A mutex protecting the protocol_hashtable. */ 42 static objc_mutex_t __protocols_hashtable_lock = NULL; 43 44 /* Called at startup by init.c. */ 45 void 46 __objc_protocols_init (void) 47 { 48 __protocols_hashtable_lock = objc_mutex_allocate (); 49 50 /* The keys in the table are strings, and the values are Protocol 51 objects. */ 52 __protocols_hashtable = objc_hash_new (64, (hash_func_type) objc_hash_string, 53 (compare_func_type) objc_compare_strings); 54 } 55 56 /* Add a protocol to the hashtable. */ 57 void 58 __objc_protocols_add_protocol (const char *name, struct objc_protocol *object) 59 { 60 objc_mutex_lock (__protocols_hashtable_lock); 61 62 /* If we find a protocol with the same name already in the 63 hashtable, we do not need to add the new one, because it will be 64 identical to it. This in the reasonable assumption that two 65 protocols with the same name are identical, which is expected in 66 any sane program. If we are really paranoid, we would compare 67 the protocols and abort if they are not identical. 68 Unfortunately, this would slow down the startup of all 69 Objective-C programs while trying to catch a problem that has 70 never been seen in practice, so we don't do it. */ 71 if (! objc_hash_is_key_in_hash (__protocols_hashtable, name)) 72 objc_hash_add (&__protocols_hashtable, name, object); 73 74 objc_mutex_unlock (__protocols_hashtable_lock); 75 } 76 77 Protocol * 78 objc_getProtocol (const char *name) 79 { 80 Protocol *protocol; 81 82 if (name == NULL) 83 return NULL; 84 85 objc_mutex_lock (__protocols_hashtable_lock); 86 protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name)); 87 objc_mutex_unlock (__protocols_hashtable_lock); 88 89 return protocol; 90 } 91 92 Protocol ** 93 objc_copyProtocolList (unsigned int *numberOfReturnedProtocols) 94 { 95 unsigned int count = 0; 96 Protocol **returnValue = NULL; 97 node_ptr node; 98 99 objc_mutex_lock (__protocols_hashtable_lock); 100 101 /* Count how many protocols we have. */ 102 node = objc_hash_next (__protocols_hashtable, NULL); 103 while (node) 104 { 105 count++; 106 node = objc_hash_next (__protocols_hashtable, node); 107 } 108 109 if (count != 0) 110 { 111 unsigned int i = 0; 112 113 /* Allocate enough memory to hold them. */ 114 returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); 115 116 /* Copy the protocols. */ 117 node = objc_hash_next (__protocols_hashtable, NULL); 118 while (node) 119 { 120 returnValue[i] = node->value; 121 i++; 122 node = objc_hash_next (__protocols_hashtable, node); 123 } 124 125 returnValue[i] = NULL; 126 } 127 objc_mutex_unlock (__protocols_hashtable_lock); 128 129 if (numberOfReturnedProtocols) 130 *numberOfReturnedProtocols = count; 131 132 return returnValue; 133 } 134 135 BOOL 136 class_addProtocol (Class class_, Protocol *protocol) 137 { 138 struct objc_protocol_list *protocols; 139 140 if (class_ == Nil || protocol == NULL) 141 return NO; 142 143 if (class_conformsToProtocol (class_, protocol)) 144 return NO; 145 146 /* Check that it is a Protocol object before casting it to (struct 147 objc_protocol *). */ 148 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 149 return NO; 150 151 objc_mutex_lock (__objc_runtime_mutex); 152 153 /* Create the objc_protocol_list. */ 154 protocols = malloc (sizeof (struct objc_protocol_list)); 155 protocols->count = 1; 156 protocols->list[0] = (struct objc_protocol *)protocol; 157 158 /* Attach it to the list of class protocols. */ 159 protocols->next = class_->protocols; 160 class_->protocols = protocols; 161 162 objc_mutex_unlock (__objc_runtime_mutex); 163 164 return YES; 165 } 166 167 BOOL 168 class_conformsToProtocol (Class class_, Protocol *protocol) 169 { 170 struct objc_protocol_list* proto_list; 171 172 if (class_ == Nil || protocol == NULL) 173 return NO; 174 175 /* Check that it is a Protocol object before casting it to (struct 176 objc_protocol *). */ 177 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 178 return NO; 179 180 /* Acquire the runtime lock because the list of protocols for a 181 class may be modified concurrently, for example if another thread 182 calls class_addProtocol(), or dynamically loads from a file a 183 category of the class. */ 184 objc_mutex_lock (__objc_runtime_mutex); 185 proto_list = class_->protocols; 186 187 while (proto_list) 188 { 189 size_t i; 190 for (i = 0; i < proto_list->count; i++) 191 { 192 if (proto_list->list[i] == (struct objc_protocol *)protocol 193 || protocol_conformsToProtocol ((Protocol *)proto_list->list[i], 194 protocol)) 195 { 196 objc_mutex_unlock (__objc_runtime_mutex); 197 return YES; 198 } 199 } 200 proto_list = proto_list->next; 201 } 202 203 objc_mutex_unlock (__objc_runtime_mutex); 204 return NO; 205 } 206 207 Protocol ** 208 class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols) 209 { 210 unsigned int count = 0; 211 Protocol **returnValue = NULL; 212 struct objc_protocol_list* proto_list; 213 214 if (class_ == Nil) 215 { 216 if (numberOfReturnedProtocols) 217 *numberOfReturnedProtocols = 0; 218 return NULL; 219 } 220 221 /* Lock the runtime mutex because the class protocols may be 222 concurrently modified. */ 223 objc_mutex_lock (__objc_runtime_mutex); 224 225 /* Count how many protocols we have. */ 226 proto_list = class_->protocols; 227 228 while (proto_list) 229 { 230 count = count + proto_list->count; 231 proto_list = proto_list->next; 232 } 233 234 if (count != 0) 235 { 236 unsigned int i = 0; 237 238 /* Allocate enough memory to hold them. */ 239 returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); 240 241 /* Copy the protocols. */ 242 proto_list = class_->protocols; 243 244 while (proto_list) 245 { 246 size_t j; 247 for (j = 0; j < proto_list->count; j++) 248 { 249 returnValue[i] = (Protocol *)proto_list->list[j]; 250 i++; 251 } 252 proto_list = proto_list->next; 253 } 254 255 returnValue[i] = NULL; 256 } 257 objc_mutex_unlock (__objc_runtime_mutex); 258 259 if (numberOfReturnedProtocols) 260 *numberOfReturnedProtocols = count; 261 262 return returnValue; 263 } 264 265 BOOL 266 protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol) 267 { 268 struct objc_protocol_list* proto_list; 269 270 if (protocol == NULL || anotherProtocol == NULL) 271 return NO; 272 273 if (protocol == anotherProtocol) 274 return YES; 275 276 /* Check that the objects are Protocol objects before casting them 277 to (struct objc_protocol *). */ 278 if (protocol->class_pointer != anotherProtocol->class_pointer) 279 return NO; 280 281 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 282 return NO; 283 284 if (strcmp (((struct objc_protocol *)protocol)->protocol_name, 285 ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0) 286 return YES; 287 288 /* We do not acquire any lock because protocols are currently 289 immutable. We can freely iterate over a protocol structure. */ 290 proto_list = ((struct objc_protocol *)protocol)->protocol_list; 291 while (proto_list) 292 { 293 size_t i; 294 295 for (i = 0; i < proto_list->count; i++) 296 { 297 if (protocol_conformsToProtocol ((Protocol *)proto_list->list[i], anotherProtocol)) 298 return YES; 299 } 300 proto_list = proto_list->next; 301 } 302 303 return NO; 304 } 305 306 BOOL 307 protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol) 308 { 309 if (protocol == anotherProtocol) 310 return YES; 311 312 if (protocol == NULL || anotherProtocol == NULL) 313 return NO; 314 315 /* Check that the objects are Protocol objects before casting them 316 to (struct objc_protocol *). */ 317 if (protocol->class_pointer != anotherProtocol->class_pointer) 318 return NO; 319 320 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 321 return NO; 322 323 /* Equality between formal protocols is only formal (nothing to do 324 with actually checking the list of methods they have!). Two 325 formal Protocols are equal if and only if they have the same 326 name. 327 328 Please note (for comparisons with other implementations) that 329 checking the names is equivalent to checking that Protocol A 330 conforms to Protocol B and Protocol B conforms to Protocol A, 331 because this happens iff they have the same name. If they have 332 different names, A conforms to B if and only if A includes B, but 333 the situation where A includes B and B includes A is a circular 334 dependency between Protocols which is forbidden by the compiler, 335 so A conforms to B and B conforms to A with A and B having 336 different names is an impossible case. */ 337 if (strcmp (((struct objc_protocol *)protocol)->protocol_name, 338 ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0) 339 return YES; 340 341 return NO; 342 } 343 344 const char * 345 protocol_getName (Protocol *protocol) 346 { 347 /* Check that it is a Protocol object before casting it to (struct 348 objc_protocol *). */ 349 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 350 return NULL; 351 352 return ((struct objc_protocol *)protocol)->protocol_name; 353 } 354 355 struct objc_method_description protocol_getMethodDescription (Protocol *protocol, 356 SEL selector, 357 BOOL requiredMethod, 358 BOOL instanceMethod) 359 { 360 struct objc_method_description no_result = { NULL, NULL }; 361 struct objc_method_description_list *methods; 362 int i; 363 364 /* TODO: New ABI. */ 365 /* The current ABI does not have any information on optional protocol methods. */ 366 if (! requiredMethod) 367 return no_result; 368 369 /* Check that it is a Protocol object before casting it to (struct 370 objc_protocol *). */ 371 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 372 return no_result; 373 374 if (instanceMethod) 375 methods = ((struct objc_protocol *)protocol)->instance_methods; 376 else 377 methods = ((struct objc_protocol *)protocol)->class_methods; 378 379 if (methods) 380 { 381 for (i = 0; i < methods->count; i++) 382 { 383 if (sel_isEqual (methods->list[i].name, selector)) 384 return methods->list[i]; 385 /* 386 if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0) 387 return methods->list[i]; 388 */ 389 } 390 } 391 392 return no_result; 393 } 394 395 struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol, 396 BOOL requiredMethod, 397 BOOL instanceMethod, 398 unsigned int *numberOfReturnedMethods) 399 { 400 struct objc_method_description_list *methods; 401 unsigned int count = 0; 402 struct objc_method_description *returnValue = NULL; 403 404 /* TODO: New ABI */ 405 /* The current ABI does not have any information on optional protocol methods. */ 406 if (! requiredMethod) 407 { 408 if (numberOfReturnedMethods) 409 *numberOfReturnedMethods = 0; 410 411 return NULL; 412 } 413 414 /* Check that it is a Protocol object before casting it to (struct 415 objc_protocol *). */ 416 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol")) 417 { 418 if (numberOfReturnedMethods) 419 *numberOfReturnedMethods = 0; 420 421 return NULL; 422 } 423 424 /* We do not acquire any lock because protocols are currently 425 immutable. We can freely iterate over a protocol structure. */ 426 427 if (instanceMethod) 428 methods = ((struct objc_protocol *)protocol)->instance_methods; 429 else 430 methods = ((struct objc_protocol *)protocol)->class_methods; 431 432 if (methods) 433 { 434 unsigned int i; 435 count = methods->count; 436 437 /* Allocate enough memory to hold them. */ 438 returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1))); 439 440 /* Copy them. */ 441 for (i = 0; i < count; i++) 442 { 443 returnValue[i].name = methods->list[i].name; 444 returnValue[i].types = methods->list[i].types; 445 } 446 returnValue[i].name = NULL; 447 returnValue[i].types = NULL; 448 } 449 450 if (numberOfReturnedMethods) 451 *numberOfReturnedMethods = count; 452 453 return returnValue; 454 } 455 456 Property protocol_getProperty (Protocol *protocol, const char *propertyName, 457 BOOL requiredProperty, BOOL instanceProperty) 458 { 459 if (protocol == NULL || propertyName == NULL) 460 return NULL; 461 462 if (!requiredProperty || !instanceProperty) 463 return NULL; 464 465 /* Check that it is a Protocol object before casting it to (struct 466 objc_protocol *). */ 467 if (protocol->class_pointer != objc_lookUpClass ("Protocol")) 468 return NULL; 469 470 /* TODO: New ABI. */ 471 /* The current ABI does not have any information on protocol properties. */ 472 return NULL; 473 } 474 475 Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties) 476 { 477 unsigned int count = 0; 478 Property *returnValue = NULL; 479 480 /* Check that it is a Protocol object before casting it to (struct 481 objc_protocol *). */ 482 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol")) 483 { 484 if (numberOfReturnedProperties) 485 *numberOfReturnedProperties = 0; 486 487 return NULL; 488 } 489 490 /* We do not acquire any lock because protocols are currently 491 immutable. We can freely iterate over a protocol structure. */ 492 493 /* TODO: New ABI. */ 494 /* The current ABI does not have any information on protocol properties. */ 495 if (numberOfReturnedProperties) 496 *numberOfReturnedProperties = count; 497 498 return returnValue; 499 } 500 501 Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols) 502 { 503 unsigned int count = 0; 504 Protocol **returnValue = NULL; 505 struct objc_protocol_list* proto_list; 506 507 /* Check that it is a Protocol object before casting it to (struct 508 objc_protocol *). */ 509 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol")) 510 { 511 if (numberOfReturnedProtocols) 512 *numberOfReturnedProtocols = 0; 513 514 return NULL; 515 } 516 517 /* We do not acquire any lock because protocols are currently 518 immutable. We can freely iterate over a protocol structure. */ 519 520 /* Count how many protocols we have. */ 521 proto_list = ((struct objc_protocol *)protocol)->protocol_list; 522 523 while (proto_list) 524 { 525 count = count + proto_list->count; 526 proto_list = proto_list->next; 527 } 528 529 if (count != 0) 530 { 531 unsigned int i = 0; 532 533 /* Allocate enough memory to hold them. */ 534 returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); 535 536 /* Copy the protocols. */ 537 proto_list = ((struct objc_protocol *)protocol)->protocol_list; 538 539 while (proto_list) 540 { 541 size_t j; 542 for (j = 0; j < proto_list->count; j++) 543 { 544 returnValue[i] = (Protocol *)proto_list->list[j]; 545 i++; 546 } 547 proto_list = proto_list->next; 548 } 549 550 returnValue[i] = NULL; 551 } 552 553 if (numberOfReturnedProtocols) 554 *numberOfReturnedProtocols = count; 555 556 return returnValue; 557 } 558