111
|
1 /* GNU Objective C Runtime protocol related functions.
|
145
|
2 Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
111
|
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 }
|