1 /* GNU Objective C Runtime protocol related functions.
2 Copyright (C) 2010-2024 Free Software Foundation, Inc.
3 Contributed by Nicola Pero
5 This file is part of GCC.
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.
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
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.
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/>. */
25 #include "objc-private/common.h"
26 #include "objc/runtime.h"
27 #include "objc-private/module-abi-8.h" /* For runtime structures */
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. */
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
39 static cache_ptr __protocols_hashtable
;
41 /* A mutex protecting the protocol_hashtable. */
42 static objc_mutex_t __protocols_hashtable_lock
= NULL
;
44 /* Called at startup by init.c. */
46 __objc_protocols_init (void)
48 __protocols_hashtable_lock
= objc_mutex_allocate ();
50 /* The keys in the table are strings, and the values are Protocol
52 __protocols_hashtable
= objc_hash_new (64, (hash_func_type
) objc_hash_string
,
53 (compare_func_type
) objc_compare_strings
);
56 /* Add a protocol to the hashtable. */
58 __objc_protocols_add_protocol (const char *name
, struct objc_protocol
*object
)
60 objc_mutex_lock (__protocols_hashtable_lock
);
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
);
74 objc_mutex_unlock (__protocols_hashtable_lock
);
78 objc_getProtocol (const char *name
)
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
);
93 objc_copyProtocolList (unsigned int *numberOfReturnedProtocols
)
95 unsigned int count
= 0;
96 Protocol
**returnValue
= NULL
;
99 objc_mutex_lock (__protocols_hashtable_lock
);
101 /* Count how many protocols we have. */
102 node
= objc_hash_next (__protocols_hashtable
, NULL
);
106 node
= objc_hash_next (__protocols_hashtable
, node
);
113 /* Allocate enough memory to hold them. */
114 returnValue
= (Protocol
**)(malloc (sizeof (Protocol
*) * (count
+ 1)));
116 /* Copy the protocols. */
117 node
= objc_hash_next (__protocols_hashtable
, NULL
);
120 returnValue
[i
] = node
->value
;
122 node
= objc_hash_next (__protocols_hashtable
, node
);
125 returnValue
[i
] = NULL
;
127 objc_mutex_unlock (__protocols_hashtable_lock
);
129 if (numberOfReturnedProtocols
)
130 *numberOfReturnedProtocols
= count
;
136 class_addProtocol (Class class_
, Protocol
*protocol
)
138 struct objc_protocol_list
*protocols
;
140 if (class_
== Nil
|| protocol
== NULL
)
143 if (class_conformsToProtocol (class_
, protocol
))
146 /* Check that it is a Protocol object before casting it to (struct
148 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
151 objc_mutex_lock (__objc_runtime_mutex
);
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
;
158 /* Attach it to the list of class protocols. */
159 protocols
->next
= class_
->protocols
;
160 class_
->protocols
= protocols
;
162 objc_mutex_unlock (__objc_runtime_mutex
);
168 class_conformsToProtocol (Class class_
, Protocol
*protocol
)
170 struct objc_protocol_list
* proto_list
;
172 if (class_
== Nil
|| protocol
== NULL
)
175 /* Check that it is a Protocol object before casting it to (struct
177 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
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
;
190 for (i
= 0; i
< proto_list
->count
; i
++)
192 if (proto_list
->list
[i
] == (struct objc_protocol
*)protocol
193 || protocol_conformsToProtocol ((Protocol
*)proto_list
->list
[i
],
196 objc_mutex_unlock (__objc_runtime_mutex
);
200 proto_list
= proto_list
->next
;
203 objc_mutex_unlock (__objc_runtime_mutex
);
208 class_copyProtocolList (Class class_
, unsigned int *numberOfReturnedProtocols
)
210 unsigned int count
= 0;
211 Protocol
**returnValue
= NULL
;
212 struct objc_protocol_list
* proto_list
;
216 if (numberOfReturnedProtocols
)
217 *numberOfReturnedProtocols
= 0;
221 /* Lock the runtime mutex because the class protocols may be
222 concurrently modified. */
223 objc_mutex_lock (__objc_runtime_mutex
);
225 /* Count how many protocols we have. */
226 proto_list
= class_
->protocols
;
230 count
= count
+ proto_list
->count
;
231 proto_list
= proto_list
->next
;
238 /* Allocate enough memory to hold them. */
239 returnValue
= (Protocol
**)(malloc (sizeof (Protocol
*) * (count
+ 1)));
241 /* Copy the protocols. */
242 proto_list
= class_
->protocols
;
247 for (j
= 0; j
< proto_list
->count
; j
++)
249 returnValue
[i
] = (Protocol
*)proto_list
->list
[j
];
252 proto_list
= proto_list
->next
;
255 returnValue
[i
] = NULL
;
257 objc_mutex_unlock (__objc_runtime_mutex
);
259 if (numberOfReturnedProtocols
)
260 *numberOfReturnedProtocols
= count
;
266 protocol_conformsToProtocol (Protocol
*protocol
, Protocol
*anotherProtocol
)
268 struct objc_protocol_list
* proto_list
;
270 if (protocol
== NULL
|| anotherProtocol
== NULL
)
273 if (protocol
== anotherProtocol
)
276 /* Check that the objects are Protocol objects before casting them
277 to (struct objc_protocol *). */
278 if (protocol
->class_pointer
!= anotherProtocol
->class_pointer
)
281 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
284 if (strcmp (((struct objc_protocol
*)protocol
)->protocol_name
,
285 ((struct objc_protocol
*)anotherProtocol
)->protocol_name
) == 0)
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
;
295 for (i
= 0; i
< proto_list
->count
; i
++)
297 if (protocol_conformsToProtocol ((Protocol
*)proto_list
->list
[i
], anotherProtocol
))
300 proto_list
= proto_list
->next
;
307 protocol_isEqual (Protocol
*protocol
, Protocol
*anotherProtocol
)
309 if (protocol
== anotherProtocol
)
312 if (protocol
== NULL
|| anotherProtocol
== NULL
)
315 /* Check that the objects are Protocol objects before casting them
316 to (struct objc_protocol *). */
317 if (protocol
->class_pointer
!= anotherProtocol
->class_pointer
)
320 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
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
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)
345 protocol_getName (Protocol
*protocol
)
347 /* Check that it is a Protocol object before casting it to (struct
349 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
352 return ((struct objc_protocol
*)protocol
)->protocol_name
;
355 struct objc_method_description
protocol_getMethodDescription (Protocol
*protocol
,
360 struct objc_method_description no_result
= { NULL
, NULL
};
361 struct objc_method_description_list
*methods
;
365 /* The current ABI does not have any information on optional protocol methods. */
366 if (! requiredMethod
)
369 /* Check that it is a Protocol object before casting it to (struct
371 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
375 methods
= ((struct objc_protocol
*)protocol
)->instance_methods
;
377 methods
= ((struct objc_protocol
*)protocol
)->class_methods
;
381 for (i
= 0; i
< methods
->count
; i
++)
383 if (sel_isEqual (methods
->list
[i
].name
, selector
))
384 return methods
->list
[i
];
386 if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
387 return methods->list[i];
395 struct objc_method_description
*protocol_copyMethodDescriptionList (Protocol
*protocol
,
398 unsigned int *numberOfReturnedMethods
)
400 struct objc_method_description_list
*methods
;
401 unsigned int count
= 0;
402 struct objc_method_description
*returnValue
= NULL
;
405 /* The current ABI does not have any information on optional protocol methods. */
406 if (! requiredMethod
)
408 if (numberOfReturnedMethods
)
409 *numberOfReturnedMethods
= 0;
414 /* Check that it is a Protocol object before casting it to (struct
416 if (protocol
== NULL
|| protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
418 if (numberOfReturnedMethods
)
419 *numberOfReturnedMethods
= 0;
424 /* We do not acquire any lock because protocols are currently
425 immutable. We can freely iterate over a protocol structure. */
428 methods
= ((struct objc_protocol
*)protocol
)->instance_methods
;
430 methods
= ((struct objc_protocol
*)protocol
)->class_methods
;
435 count
= methods
->count
;
437 /* Allocate enough memory to hold them. */
438 returnValue
= (struct objc_method_description
*)(malloc (sizeof (struct objc_method_description
) * (count
+ 1)));
441 for (i
= 0; i
< count
; i
++)
443 returnValue
[i
].name
= methods
->list
[i
].name
;
444 returnValue
[i
].types
= methods
->list
[i
].types
;
446 returnValue
[i
].name
= NULL
;
447 returnValue
[i
].types
= NULL
;
450 if (numberOfReturnedMethods
)
451 *numberOfReturnedMethods
= count
;
456 Property
protocol_getProperty (Protocol
*protocol
, const char *propertyName
,
457 BOOL requiredProperty
, BOOL instanceProperty
)
459 if (protocol
== NULL
|| propertyName
== NULL
)
462 if (!requiredProperty
|| !instanceProperty
)
465 /* Check that it is a Protocol object before casting it to (struct
467 if (protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
471 /* The current ABI does not have any information on protocol properties. */
475 Property
*protocol_copyPropertyList (Protocol
*protocol
, unsigned int *numberOfReturnedProperties
)
477 unsigned int count
= 0;
478 Property
*returnValue
= NULL
;
480 /* Check that it is a Protocol object before casting it to (struct
482 if (protocol
== NULL
|| protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
484 if (numberOfReturnedProperties
)
485 *numberOfReturnedProperties
= 0;
490 /* We do not acquire any lock because protocols are currently
491 immutable. We can freely iterate over a protocol structure. */
494 /* The current ABI does not have any information on protocol properties. */
495 if (numberOfReturnedProperties
)
496 *numberOfReturnedProperties
= count
;
501 Protocol
**protocol_copyProtocolList (Protocol
*protocol
, unsigned int *numberOfReturnedProtocols
)
503 unsigned int count
= 0;
504 Protocol
**returnValue
= NULL
;
505 struct objc_protocol_list
* proto_list
;
507 /* Check that it is a Protocol object before casting it to (struct
509 if (protocol
== NULL
|| protocol
->class_pointer
!= objc_lookUpClass ("Protocol"))
511 if (numberOfReturnedProtocols
)
512 *numberOfReturnedProtocols
= 0;
517 /* We do not acquire any lock because protocols are currently
518 immutable. We can freely iterate over a protocol structure. */
520 /* Count how many protocols we have. */
521 proto_list
= ((struct objc_protocol
*)protocol
)->protocol_list
;
525 count
= count
+ proto_list
->count
;
526 proto_list
= proto_list
->next
;
533 /* Allocate enough memory to hold them. */
534 returnValue
= (Protocol
**)(malloc (sizeof (Protocol
*) * (count
+ 1)));
536 /* Copy the protocols. */
537 proto_list
= ((struct objc_protocol
*)protocol
)->protocol_list
;
542 for (j
= 0; j
< proto_list
->count
; j
++)
544 returnValue
[i
] = (Protocol
*)proto_list
->list
[j
];
547 proto_list
= proto_list
->next
;
550 returnValue
[i
] = NULL
;
553 if (numberOfReturnedProtocols
)
554 *numberOfReturnedProtocols
= count
;