]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/protocols.c
Move 2 mklog scripts to legacy subfolder.
[thirdparty/gcc.git] / libobjc / protocols.c
CommitLineData
debfbfee 1/* GNU Objective C Runtime protocol related functions.
8d9254fc 2 Copyright (C) 2010-2020 Free Software Foundation, Inc.
debfbfee
NP
3 Contributed by Nicola Pero
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 3, or (at your option) any later version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23<http://www.gnu.org/licenses/>. */
24
25#include "objc-private/common.h"
debfbfee
NP
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. */
49a35931
NP
31#include "objc-private/protocols.h" /* For __objc_protocols_init() and
32 __objc_protocols_add_protocol(). */
33#include <stdlib.h> /* For malloc. */
debfbfee
NP
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. */
39static cache_ptr __protocols_hashtable;
40
41/* A mutex protecting the protocol_hashtable. */
42static objc_mutex_t __protocols_hashtable_lock = NULL;
43
44/* Called at startup by init.c. */
45void
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. */
57void
80e4b9e5 58__objc_protocols_add_protocol (const char *name, struct objc_protocol *object)
debfbfee
NP
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))
575584a9 72 objc_hash_add (&__protocols_hashtable, name, object);
debfbfee
NP
73
74 objc_mutex_unlock (__protocols_hashtable_lock);
75}
76
77Protocol *
78objc_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
92Protocol **
93objc_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
135BOOL
136class_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 *). */
6e45b376 148 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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;
80e4b9e5 156 protocols->list[0] = (struct objc_protocol *)protocol;
debfbfee
NP
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
167BOOL
168class_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 *). */
6e45b376 177 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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 {
80e4b9e5
NP
192 if (proto_list->list[i] == (struct objc_protocol *)protocol
193 || protocol_conformsToProtocol ((Protocol *)proto_list->list[i],
debfbfee
NP
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
207Protocol **
208class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols)
209{
210 unsigned int count = 0;
211 Protocol **returnValue = NULL;
212 struct objc_protocol_list* proto_list;
213
ad9eef11
NP
214 if (class_ == Nil)
215 {
216 if (numberOfReturnedProtocols)
217 *numberOfReturnedProtocols = 0;
218 return NULL;
219 }
220
debfbfee
NP
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 {
80e4b9e5 249 returnValue[i] = (Protocol *)proto_list->list[j];
debfbfee
NP
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
265BOOL
266protocol_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
6e45b376 281 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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 {
80e4b9e5 297 if (protocol_conformsToProtocol ((Protocol *)proto_list->list[i], anotherProtocol))
debfbfee
NP
298 return YES;
299 }
300 proto_list = proto_list->next;
301 }
302
303 return NO;
304}
305
306BOOL
307protocol_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
6e45b376 320 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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
344const char *
345protocol_getName (Protocol *protocol)
346{
347 /* Check that it is a Protocol object before casting it to (struct
348 objc_protocol *). */
6e45b376 349 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
350 return NULL;
351
352 return ((struct objc_protocol *)protocol)->protocol_name;
353}
354
355struct 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 };
debfbfee
NP
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 *). */
6e45b376 371 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
372 return no_result;
373
debfbfee
NP
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 {
ae422ccd
NP
383 if (sel_isEqual (methods->list[i].name, selector))
384 return methods->list[i];
385 /*
f7185d47 386 if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
debfbfee 387 return methods->list[i];
ae422ccd 388 */
debfbfee
NP
389 }
390 }
391
392 return no_result;
393}
394
395struct 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 *). */
6e45b376 416 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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
456Property 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 *). */
6e45b376 467 if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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
475Property *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 *). */
6e45b376 482 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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
501Protocol **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 *). */
6e45b376 509 if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
debfbfee
NP
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 {
80e4b9e5 544 returnValue[i] = (Protocol *)proto_list->list[j];
debfbfee
NP
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}