]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-class.m
objc4-437.1.tar.gz
[apple/objc4.git] / runtime / objc-class.m
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /***********************************************************************
24 * objc-class.m
25 * Copyright 1988-1997, Apple Computer, Inc.
26 * Author: s. naroff
27 **********************************************************************/
28
29
30 /***********************************************************************
31 * Lazy method list arrays and method list locking (2004-10-19)
32 *
33 * cls->methodLists may be in one of three forms:
34 * 1. NULL: The class has no methods.
35 * 2. non-NULL, with CLS_NO_METHOD_ARRAY set: cls->methodLists points
36 * to a single method list, which is the class's only method list.
37 * 3. non-NULL, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to
38 * an array of method list pointers. The end of the array's block
39 * is set to -1. If the actual number of method lists is smaller
40 * than that, the rest of the array is NULL.
41 *
42 * Attaching categories and adding and removing classes may change
43 * the form of the class list. In addition, individual method lists
44 * may be reallocated when fixed up.
45 *
46 * Classes are initially read as #1 or #2. If a category is attached
47 * or other methods added, the class is changed to #3. Once in form #3,
48 * the class is never downgraded to #1 or #2, even if methods are removed.
49 * Classes added with objc_addClass are initially either #1 or #3.
50 *
51 * Accessing and manipulating a class's method lists are synchronized,
52 * to prevent races when one thread restructures the list. However,
53 * if the class is not yet in use (i.e. not in class_hash), then the
54 * thread loading the class may access its method lists without locking.
55 *
56 * The following functions acquire methodListLock:
57 * class_getInstanceMethod
58 * class_getClassMethod
59 * class_nextMethodList
60 * class_addMethods
61 * class_removeMethods
62 * class_respondsToMethod
63 * _class_lookupMethodAndLoadCache
64 * lookupMethodInClassAndLoadCache
65 * _objc_add_category_flush_caches
66 *
67 * The following functions don't acquire methodListLock because they
68 * only access method lists during class load and unload:
69 * _objc_register_category
70 * _resolve_categories_for_class (calls _objc_add_category)
71 * add_class_to_loadable_list
72 * _objc_addClass
73 * _objc_remove_classes_in_image
74 *
75 * The following functions use method lists without holding methodListLock.
76 * The caller must either hold methodListLock, or be loading the class.
77 * _getMethod (called by class_getInstanceMethod, class_getClassMethod,
78 * and class_respondsToMethod)
79 * _findMethodInClass (called by _class_lookupMethodAndLoadCache,
80 * lookupMethodInClassAndLoadCache, _getMethod)
81 * _findMethodInList (called by _findMethodInClass)
82 * nextMethodList (called by _findMethodInClass and class_nextMethodList
83 * fixupSelectorsInMethodList (called by nextMethodList)
84 * _objc_add_category (called by _objc_add_category_flush_caches,
85 * resolve_categories_for_class and _objc_register_category)
86 * _objc_insertMethods (called by class_addMethods and _objc_add_category)
87 * _objc_removeMethods (called by class_removeMethods)
88 * _objcTweakMethodListPointerForClass (called by _objc_insertMethods)
89 * get_base_method_list (called by add_class_to_loadable_list)
90 * lookupNamedMethodInMethodList (called by add_class_to_loadable_list)
91 ***********************************************************************/
92
93 /***********************************************************************
94 * Thread-safety of class info bits (2004-10-19)
95 *
96 * Some class info bits are used to store mutable runtime state.
97 * Modifications of the info bits at particular times need to be
98 * synchronized to prevent races.
99 *
100 * Three thread-safe modification functions are provided:
101 * _class_setInfo() // atomically sets some bits
102 * _class_clearInfo() // atomically clears some bits
103 * _class_changeInfo() // atomically sets some bits and clears others
104 * These replace CLS_SETINFO() for the multithreaded cases.
105 *
106 * Three modification windows are defined:
107 * - compile time
108 * - class construction or image load (before +load) in one thread
109 * - multi-threaded messaging and method caches
110 *
111 * Info bit modification at compile time and class construction do not
112 * need to be locked, because only one thread is manipulating the class.
113 * Info bit modification during messaging needs to be locked, because
114 * there may be other threads simultaneously messaging or otherwise
115 * manipulating the class.
116 *
117 * Modification windows for each flag:
118 *
119 * CLS_CLASS: compile-time and class load
120 * CLS_META: compile-time and class load
121 * CLS_INITIALIZED: +initialize
122 * CLS_POSING: messaging
123 * CLS_MAPPED: compile-time
124 * CLS_FLUSH_CACHE: class load and messaging
125 * CLS_GROW_CACHE: messaging
126 * CLS_NEED_BIND: unused
127 * CLS_METHOD_ARRAY: unused
128 * CLS_JAVA_HYBRID: JavaBridge only
129 * CLS_JAVA_CLASS: JavaBridge only
130 * CLS_INITIALIZING: messaging
131 * CLS_FROM_BUNDLE: class load
132 * CLS_HAS_CXX_STRUCTORS: compile-time and class load
133 * CLS_NO_METHOD_ARRAY: class load and messaging
134 * CLS_HAS_LOAD_METHOD: class load
135 *
136 * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety
137 * constraints to support thread-safe +initialize. See "Thread safety
138 * during class initialization" for details.
139 *
140 * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge
141 * calls objc_addClass(). The JavaBridge does not use an atomic update,
142 * but the modification counts as "class construction" unless some other
143 * thread quickly finds the class via the class list. This race is
144 * small and unlikely in well-behaved code.
145 *
146 * Most info bits that may be modified during messaging are also never
147 * read without a lock. There is no general read lock for the info bits.
148 * CLS_INITIALIZED: classInitLock
149 * CLS_FLUSH_CACHE: cacheUpdateLock
150 * CLS_GROW_CACHE: cacheUpdateLock
151 * CLS_NO_METHOD_ARRAY: methodListLock
152 * CLS_INITIALIZING: classInitLock
153 ***********************************************************************/
154
155 /***********************************************************************
156 * Imports.
157 **********************************************************************/
158
159 #include "objc-private.h"
160 #include <objc/message.h>
161
162
163 /* overriding the default object allocation and error handling routines */
164
165 OBJC_EXPORT id (*_alloc)(Class, size_t);
166 OBJC_EXPORT id (*_copy)(id, size_t);
167 OBJC_EXPORT id (*_realloc)(id, size_t);
168 OBJC_EXPORT id (*_dealloc)(id);
169 OBJC_EXPORT id (*_zoneAlloc)(Class, size_t, void *);
170 OBJC_EXPORT id (*_zoneRealloc)(id, size_t, void *);
171 OBJC_EXPORT id (*_zoneCopy)(id, size_t, void *);
172
173
174 /***********************************************************************
175 * Function prototypes internal to this module.
176 **********************************************************************/
177
178 static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
179 static Method look_up_method(Class cls, SEL sel, BOOL withCache, BOOL withResolver);
180
181
182 /***********************************************************************
183 * Static data internal to this module.
184 **********************************************************************/
185
186 #if !TARGET_OS_WIN32 && !defined(__arm__)
187 # define MESSAGE_LOGGING
188 #endif
189
190 #if defined(MESSAGE_LOGGING)
191 // Method call logging
192 static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
193 typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
194
195 static int objcMsgLogFD = (-1);
196 static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
197 static int objcMsgLogEnabled = 0;
198 #endif
199
200 /***********************************************************************
201 * Information about multi-thread support:
202 *
203 * Since we do not lock many operations which walk the superclass, method
204 * and ivar chains, these chains must remain intact once a class is published
205 * by inserting it into the class hashtable. All modifications must be
206 * atomic so that someone walking these chains will always geta valid
207 * result.
208 ***********************************************************************/
209
210
211
212 /***********************************************************************
213 * object_getClass.
214 **********************************************************************/
215 Class object_getClass(id obj)
216 {
217 if (obj) return obj->isa;
218 else return Nil;
219 }
220
221
222 /***********************************************************************
223 * object_setClass.
224 **********************************************************************/
225 Class object_setClass(id obj, Class cls)
226 {
227 if (obj) {
228 Class old;
229 do {
230 old = obj->isa;
231 } while (! OSAtomicCompareAndSwapPtrBarrier(old, cls, (void*)&obj->isa));
232 return old;
233 }
234 else return Nil;
235 }
236
237
238 /***********************************************************************
239 * object_getClassName.
240 **********************************************************************/
241 const char *object_getClassName(id obj)
242 {
243 if (obj) return _class_getName(obj->isa);
244 else return "nil";
245 }
246
247 /***********************************************************************
248 * object_getIndexedIvars.
249 **********************************************************************/
250 void *object_getIndexedIvars(id obj)
251 {
252 // ivars are tacked onto the end of the object
253 if (obj) return ((char *) obj) + _class_getInstanceSize(obj->isa);
254 else return NULL;
255 }
256
257
258 Ivar object_setInstanceVariable(id obj, const char *name, void *value)
259 {
260 Ivar ivar = NULL;
261
262 if (obj && name) {
263 if ((ivar = class_getInstanceVariable(obj->isa, name))) {
264 objc_assign_ivar_internal(
265 (id)value,
266 obj,
267 ivar_getOffset(ivar));
268 }
269 }
270 return ivar;
271 }
272
273 Ivar object_getInstanceVariable(id obj, const char *name, void **value)
274 {
275 if (obj && name) {
276 Ivar ivar;
277 void **ivaridx;
278 if ((ivar = class_getInstanceVariable(obj->isa, name))) {
279 ivaridx = (void **)((char *)obj + ivar_getOffset(ivar));
280 if (value) *value = *ivaridx;
281 return ivar;
282 }
283 }
284 if (value) *value = NULL;
285 return NULL;
286 }
287
288
289 void object_setIvar(id obj, Ivar ivar, id value)
290 {
291 if (obj && ivar) {
292 objc_assign_ivar_internal(value, obj, ivar_getOffset(ivar));
293 }
294 }
295
296
297 id object_getIvar(id obj, Ivar ivar)
298 {
299 if (obj && ivar) {
300 id *idx = (id *)((char *)obj + ivar_getOffset(ivar));
301 return *idx;
302 }
303 return NULL;
304 }
305
306
307 /***********************************************************************
308 * object_cxxDestructFromClass.
309 * Call C++ destructors on obj, starting with cls's
310 * dtor method (if any) followed by superclasses' dtors (if any),
311 * stopping at cls's dtor (if any).
312 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
313 **********************************************************************/
314 static void object_cxxDestructFromClass(id obj, Class cls)
315 {
316 void (*dtor)(id);
317
318 // Call cls's dtor first, then superclasses's dtors.
319
320 for ( ; cls != NULL; cls = _class_getSuperclass(cls)) {
321 if (!_class_hasCxxStructorsNoSuper(cls)) continue;
322 dtor = (void(*)(id))
323 lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
324 if (dtor != (void(*)(id))&_objc_msgForward_internal) {
325 if (PrintCxxCtors) {
326 _objc_inform("CXX: calling C++ destructors for class %s",
327 _class_getName(cls));
328 }
329 (*dtor)(obj);
330 }
331 }
332 }
333
334
335 /***********************************************************************
336 * object_cxxDestruct.
337 * Call C++ destructors on obj, if any.
338 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
339 **********************************************************************/
340 __private_extern__ void object_cxxDestruct(id obj)
341 {
342 if (!obj) return;
343 object_cxxDestructFromClass(obj, obj->isa);
344 }
345
346
347 /***********************************************************************
348 * object_cxxConstructFromClass.
349 * Recursively call C++ constructors on obj, starting with base class's
350 * ctor method (if any) followed by subclasses' ctors (if any), stopping
351 * at cls's ctor (if any).
352 * Returns YES if construction succeeded.
353 * Returns NO if some constructor threw an exception. The exception is
354 * caught and discarded. Any partial construction is destructed.
355 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
356 *
357 * .cxx_construct returns id. This really means:
358 * return self: construction succeeded
359 * return nil: construction failed because a C++ constructor threw an exception
360 **********************************************************************/
361 static BOOL object_cxxConstructFromClass(id obj, Class cls)
362 {
363 id (*ctor)(id);
364 Class supercls = _class_getSuperclass(cls);
365
366 // Call superclasses' ctors first, if any.
367 if (supercls) {
368 BOOL ok = object_cxxConstructFromClass(obj, supercls);
369 if (!ok) return NO; // some superclass's ctor failed - give up
370 }
371
372 // Find this class's ctor, if any.
373 if (!_class_hasCxxStructorsNoSuper(cls)) return YES; // no ctor - ok
374 ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
375 if (ctor == (id(*)(id))&_objc_msgForward_internal) return YES; // no ctor - ok
376
377 // Call this class's ctor.
378 if (PrintCxxCtors) {
379 _objc_inform("CXX: calling C++ constructors for class %s", _class_getName(cls));
380 }
381 if ((*ctor)(obj)) return YES; // ctor called and succeeded - ok
382
383 // This class's ctor was called and failed.
384 // Call superclasses's dtors to clean up.
385 if (supercls) object_cxxDestructFromClass(obj, supercls);
386 return NO;
387 }
388
389
390 /***********************************************************************
391 * object_cxxConstructFromClass.
392 * Call C++ constructors on obj, if any.
393 * Returns YES if construction succeeded.
394 * Returns NO if some constructor threw an exception. The exception is
395 * caught and discarded. Any partial construction is destructed.
396 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
397 **********************************************************************/
398 __private_extern__ BOOL object_cxxConstruct(id obj)
399 {
400 if (!obj) return YES;
401 return object_cxxConstructFromClass(obj, obj->isa);
402 }
403
404
405 /***********************************************************************
406 * _class_resolveClassMethod
407 * Call +resolveClassMethod and return the method added or NULL.
408 * cls should be a metaclass.
409 * Assumes the method doesn't exist already.
410 **********************************************************************/
411 static Method _class_resolveClassMethod(Class cls, SEL sel)
412 {
413 BOOL resolved;
414 Method meth = NULL;
415 Class clsInstance;
416
417 if (!look_up_method(cls, SEL_resolveClassMethod,
418 YES /*cache*/, NO /*resolver*/))
419 {
420 return NULL;
421 }
422
423 // GrP fixme same hack as +initialize
424 if (strncmp(_class_getName(cls), "_%", 2) == 0) {
425 // Posee's meta's name is smashed and isn't in the class_hash,
426 // so objc_getClass doesn't work.
427 const char *baseName = strchr(_class_getName(cls), '%'); // get posee's real name
428 clsInstance = (Class)objc_getClass(baseName);
429 } else {
430 clsInstance = (Class)objc_getClass(_class_getName(cls));
431 }
432
433 resolved = ((BOOL(*)(id, SEL, SEL))objc_msgSend)((id)clsInstance, SEL_resolveClassMethod, sel);
434
435 if (resolved) {
436 // +resolveClassMethod adds to self->isa
437 meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
438
439 if (!meth) {
440 // Method resolver didn't add anything?
441 _objc_inform("+[%s resolveClassMethod:%s] returned YES, but "
442 "no new implementation of +[%s %s] was found",
443 class_getName(cls),
444 sel_getName(sel),
445 class_getName(cls),
446 sel_getName(sel));
447 return NULL;
448 }
449 }
450
451 return meth;
452 }
453
454
455 /***********************************************************************
456 * _class_resolveInstanceMethod
457 * Call +resolveInstanceMethod and return the method added or NULL.
458 * cls should be a non-meta class.
459 * Assumes the method doesn't exist already.
460 **********************************************************************/
461 static Method _class_resolveInstanceMethod(Class cls, SEL sel)
462 {
463 BOOL resolved;
464 Method meth = NULL;
465
466 if (!look_up_method(((id)cls)->isa, SEL_resolveInstanceMethod,
467 YES /*cache*/, NO /*resolver*/))
468 {
469 return NULL;
470 }
471
472 resolved = ((BOOL(*)(id, SEL, SEL))objc_msgSend)((id)cls, SEL_resolveInstanceMethod, sel);
473
474 if (resolved) {
475 // +resolveClassMethod adds to self
476 meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
477
478 if (!meth) {
479 // Method resolver didn't add anything?
480 _objc_inform("+[%s resolveInstanceMethod:%s] returned YES, but "
481 "no new implementation of %c[%s %s] was found",
482 class_getName(cls),
483 sel_getName(sel),
484 class_isMetaClass(cls) ? '+' : '-',
485 class_getName(cls),
486 sel_getName(sel));
487 return NULL;
488 }
489 }
490
491 return meth;
492 }
493
494
495 /***********************************************************************
496 * _class_resolveMethod
497 * Call +resolveClassMethod or +resolveInstanceMethod and return
498 * the method added or NULL.
499 * Assumes the method doesn't exist already.
500 **********************************************************************/
501 __private_extern__ Method _class_resolveMethod(Class cls, SEL sel)
502 {
503 Method meth = NULL;
504
505 if (_class_isMetaClass(cls)) {
506 meth = _class_resolveClassMethod(cls, sel);
507 }
508 if (!meth) {
509 meth = _class_resolveInstanceMethod(cls, sel);
510 }
511
512 if (PrintResolving && meth) {
513 _objc_inform("RESOLVE: method %c[%s %s] dynamically resolved to %p",
514 class_isMetaClass(cls) ? '+' : '-',
515 class_getName(cls), sel_getName(sel),
516 method_getImplementation(meth));
517 }
518
519 return meth;
520 }
521
522
523 /***********************************************************************
524 * look_up_method
525 * Look up a method in the given class and its superclasses.
526 * If withCache==YES, look in the class's method cache too.
527 * If withResolver==YES, call +resolveClass/InstanceMethod too.
528 * Returns NULL if the method is not found.
529 * +forward:: entries are not returned.
530 **********************************************************************/
531 static Method look_up_method(Class cls, SEL sel,
532 BOOL withCache, BOOL withResolver)
533 {
534 Method meth = NULL;
535
536 if (withCache) {
537 meth = _cache_getMethod(cls, sel, &_objc_msgForward_internal);
538 if (meth == (Method)1) {
539 // Cache contains forward:: . Stop searching.
540 return NULL;
541 }
542 }
543
544 if (!meth) meth = _class_getMethod(cls, sel);
545
546 if (!meth && withResolver) meth = _class_resolveMethod(cls, sel);
547
548 return meth;
549 }
550
551
552 /***********************************************************************
553 * class_getInstanceMethod. Return the instance method for the
554 * specified class and selector.
555 **********************************************************************/
556 Method class_getInstanceMethod(Class cls, SEL sel)
557 {
558 if (!cls || !sel) return NULL;
559
560 return look_up_method(cls, sel, YES/*cache*/, YES/*resolver*/);
561 }
562
563 /***********************************************************************
564 * class_getClassMethod. Return the class method for the specified
565 * class and selector.
566 **********************************************************************/
567 Method class_getClassMethod(Class cls, SEL sel)
568 {
569 if (!cls || !sel) return NULL;
570
571 return class_getInstanceMethod(_class_getMeta(cls), sel);
572 }
573
574
575 /***********************************************************************
576 * class_getInstanceVariable. Return the named instance variable.
577 **********************************************************************/
578 Ivar class_getInstanceVariable(Class cls, const char *name)
579 {
580 if (!cls || !name) return NULL;
581
582 return _class_getVariable(cls, name);
583 }
584
585
586 /***********************************************************************
587 * class_getClassVariable. Return the named class variable.
588 **********************************************************************/
589 Ivar class_getClassVariable(Class cls, const char *name)
590 {
591 if (!cls) return NULL;
592
593 return class_getInstanceVariable(((id)cls)->isa, name);
594 }
595
596
597 __private_extern__ Property
598 property_list_nth(const struct objc_property_list *plist, uint32_t i)
599 {
600 return (Property)(i*plist->entsize + (char *)&plist->first);
601 }
602
603 __private_extern__ size_t
604 property_list_size(const struct objc_property_list *plist)
605 {
606 return sizeof(struct objc_property_list) + (plist->count-1)*plist->entsize;
607 }
608
609 __private_extern__ Property *
610 copyPropertyList(struct objc_property_list *plist, unsigned int *outCount)
611 {
612 Property *result = NULL;
613 unsigned int count = 0;
614
615 if (plist) {
616 count = plist->count;
617 }
618
619 if (count > 0) {
620 unsigned int i;
621 result = malloc((count+1) * sizeof(Property));
622
623 for (i = 0; i < count; i++) {
624 result[i] = property_list_nth(plist, i);
625 }
626 result[i] = NULL;
627 }
628
629 if (outCount) *outCount = count;
630 return result;
631 }
632
633 const char *property_getName(Property prop)
634 {
635 return prop->name;
636 }
637
638
639 const char *property_getAttributes(Property prop)
640 {
641 return prop->attributes;
642 }
643
644
645 /***********************************************************************
646 * gdb_objc_class_changed
647 * Tell gdb that a class changed. Currently used for OBJC2 ivar layouts only
648 **********************************************************************/
649 void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
650 {
651 // do nothing; gdb sets a breakpoint here to listen
652 #if TARGET_OS_WIN32
653 __asm { }
654 #else
655 asm("");
656 #endif
657 }
658
659
660 /***********************************************************************
661 * _objc_flush_caches. Flush the caches of the specified class and any
662 * of its subclasses. If cls is a meta-class, only meta-class (i.e.
663 * class method) caches are flushed. If cls is an instance-class, both
664 * instance-class and meta-class caches are flushed.
665 **********************************************************************/
666 void _objc_flush_caches(Class cls)
667 {
668 flush_caches (cls, YES);
669 }
670
671
672 /***********************************************************************
673 * class_respondsToSelector.
674 **********************************************************************/
675 BOOL class_respondsToMethod(Class cls, SEL sel)
676 {
677 OBJC_WARN_DEPRECATED;
678
679 return class_respondsToSelector(cls, sel);
680 }
681
682
683 BOOL class_respondsToSelector(Class cls, SEL sel)
684 {
685 IMP imp;
686
687 if (!sel || !cls) return NO;
688
689 // Avoids +initialize because it historically did so.
690 // We're not returning a callable IMP anyway.
691 imp = lookUpMethod(cls, sel, NO/*initialize*/, YES/*cache*/);
692 return (imp != (IMP)_objc_msgForward_internal) ? YES : NO;
693 }
694
695
696 /***********************************************************************
697 * class_getMethodImplementation.
698 * Returns the IMP that would be invoked if [obj sel] were sent,
699 * where obj is an instance of class cls.
700 **********************************************************************/
701 IMP class_lookupMethod(Class cls, SEL sel)
702 {
703 OBJC_WARN_DEPRECATED;
704
705 // No one responds to zero!
706 if (!sel) {
707 __objc_error((id)cls, "invalid selector (null)");
708 }
709
710 return class_getMethodImplementation(cls, sel);
711 }
712
713 IMP class_getMethodImplementation(Class cls, SEL sel)
714 {
715 IMP imp;
716
717 if (!cls || !sel) return NULL;
718
719 imp = lookUpMethod(cls, sel, YES/*initialize*/, YES/*cache*/);
720
721 // Translate forwarding function to C-callable external version
722 if (imp == (IMP)&_objc_msgForward_internal) {
723 return (IMP)&_objc_msgForward;
724 }
725
726 return imp;
727 }
728
729
730 IMP class_getMethodImplementation_stret(Class cls, SEL sel)
731 {
732 IMP imp = class_getMethodImplementation(cls, sel);
733
734 // Translate forwarding function to struct-returning version
735 if (imp == (IMP)&_objc_msgForward /* not _internal! */) {
736 return (IMP)&_objc_msgForward_stret;
737 }
738 return imp;
739 }
740
741
742 // Ignored selectors get method->imp = &_objc_ignored_method
743 __private_extern__ id _objc_ignored_method(id self, SEL _cmd) { return self; }
744
745
746 /***********************************************************************
747 * instrumentObjcMessageSends/logObjcMessageSends.
748 **********************************************************************/
749 #if defined(MESSAGE_LOGGING)
750 static int LogObjCMessageSend (BOOL isClassMethod,
751 const char * objectsClass,
752 const char * implementingClass,
753 SEL selector)
754 {
755 char buf[ 1024 ];
756
757 // Create/open the log file
758 if (objcMsgLogFD == (-1))
759 {
760 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
761 objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
762 if (objcMsgLogFD < 0) {
763 // no log file - disable logging
764 objcMsgLogEnabled = 0;
765 objcMsgLogFD = -1;
766 return 1;
767 }
768 }
769
770 // Make the log entry
771 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
772 isClassMethod ? '+' : '-',
773 objectsClass,
774 implementingClass,
775 (char *) selector);
776
777 static OSSpinLock lock = OS_SPINLOCK_INIT;
778 OSSpinLockLock(&lock);
779 write (objcMsgLogFD, buf, strlen(buf));
780 OSSpinLockUnlock(&lock);
781
782 // Tell caller to not cache the method
783 return 0;
784 }
785
786 void instrumentObjcMessageSends (BOOL flag)
787 {
788 int enabledValue = (flag) ? 1 : 0;
789
790 // Shortcut NOP
791 if (objcMsgLogEnabled == enabledValue)
792 return;
793
794 // If enabling, flush all method caches so we get some traces
795 if (flag)
796 flush_caches (Nil, YES);
797
798 // Sync our log file
799 if (objcMsgLogFD != (-1))
800 fsync (objcMsgLogFD);
801
802 objcMsgLogEnabled = enabledValue;
803 }
804
805 __private_extern__ void logObjcMessageSends (ObjCLogProc logProc)
806 {
807 if (logProc)
808 {
809 objcMsgLogProc = logProc;
810 objcMsgLogEnabled = 1;
811 }
812 else
813 {
814 objcMsgLogProc = logProc;
815 objcMsgLogEnabled = 0;
816 }
817
818 if (objcMsgLogFD != (-1))
819 fsync (objcMsgLogFD);
820 }
821 #endif
822
823 /***********************************************************************
824 * log_and_fill_cache
825 * Log this method call. If the logger permits it, fill the method cache.
826 * cls is the method whose cache should be filled.
827 * implementer is the class that owns the implementation in question.
828 **********************************************************************/
829 __private_extern__ void
830 log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
831 {
832 #if defined(MESSAGE_LOGGING)
833 BOOL cacheIt = YES;
834
835 if (objcMsgLogEnabled) {
836 cacheIt = objcMsgLogProc (_class_isMetaClass(implementer) ? YES : NO,
837 _class_getName(cls),
838 _class_getName(implementer),
839 sel);
840 }
841 if (cacheIt)
842 #endif
843 _cache_fill (cls, meth, sel);
844 }
845
846
847 /***********************************************************************
848 * _class_lookupMethodAndLoadCache.
849 * Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpMethod().
850 * This lookup avoids optimistic cache scan because the dispatcher
851 * already tried that.
852 **********************************************************************/
853 __private_extern__ IMP _class_lookupMethodAndLoadCache(Class cls, SEL sel)
854 {
855 return lookUpMethod(cls, sel, YES/*initialize*/, NO/*cache*/);
856 }
857
858
859 /***********************************************************************
860 * lookUpMethod.
861 * The standard method lookup.
862 * initialize==NO tries to avoid +initialize (but sometimes fails)
863 * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
864 * Most callers should use initialize==YES and cache==YES.
865 * May return _objc_msgForward_internal. IMPs destined for external use
866 * must be converted to _objc_msgForward or _objc_msgForward_stret.
867 **********************************************************************/
868 __private_extern__ IMP lookUpMethod(Class cls, SEL sel,
869 BOOL initialize, BOOL cache)
870 {
871 Class curClass;
872 IMP methodPC = NULL;
873 Method meth;
874 BOOL triedResolver = NO;
875
876 // Optimistic cache lookup
877 if (cache) {
878 methodPC = _cache_getImp(cls, sel);
879 if (methodPC) return methodPC;
880 }
881
882 // realize, +initialize, and any special early exit
883 methodPC = prepareForMethodLookup(cls, sel, initialize);
884 if (methodPC) return methodPC;
885
886
887 // The lock is held to make method-lookup + cache-fill atomic
888 // with respect to method addition. Otherwise, a category could
889 // be added but ignored indefinitely because the cache was re-filled
890 // with the old value after the cache flush on behalf of the category.
891 retry:
892 lockForMethodLookup();
893
894 // Try this class's cache.
895
896 methodPC = _cache_getImp(cls, sel);
897 if (methodPC) goto done;
898
899 // Try this class's method lists.
900
901 meth = _class_getMethodNoSuper_nolock(cls, sel);
902 if (meth) {
903 log_and_fill_cache(cls, cls, meth, sel);
904 methodPC = method_getImplementation(meth);
905 goto done;
906 }
907
908 // Try superclass caches and method lists.
909
910 curClass = cls;
911 while ((curClass = _class_getSuperclass(curClass))) {
912 // Superclass cache.
913 meth = _cache_getMethod(curClass, sel, &_objc_msgForward_internal);
914 if (meth) {
915 if (meth != (Method)1) {
916 // Found the method in a superclass. Cache it in this class.
917 log_and_fill_cache(cls, curClass, meth, sel);
918 methodPC = method_getImplementation(meth);
919 goto done;
920 }
921 else {
922 // Found a forward:: entry in a superclass.
923 // Stop searching, but don't cache yet; call method
924 // resolver for this class first.
925 break;
926 }
927 }
928
929 // Superclass method list.
930 meth = _class_getMethodNoSuper_nolock(curClass, sel);
931 if (meth) {
932 log_and_fill_cache(cls, curClass, meth, sel);
933 methodPC = method_getImplementation(meth);
934 goto done;
935 }
936 }
937
938 // No implementation found. Try method resolver once.
939
940 if (!triedResolver) {
941 unlockForMethodLookup();
942 _class_resolveMethod(cls, sel);
943 // Don't cache the result; we don't hold the lock so it may have
944 // changed already. Re-do the search from scratch instead.
945 triedResolver = YES;
946 goto retry;
947 }
948
949 // No implementation found, and method resolver didn't help.
950 // Use forwarding.
951
952 _cache_addForwardEntry(cls, sel);
953 methodPC = &_objc_msgForward_internal;
954
955 done:
956 unlockForMethodLookup();
957
958 // paranoia: look for ignored selectors with non-ignored implementations
959 assert(!(sel == (SEL)kIgnore && methodPC != (IMP)&_objc_ignored_method));
960
961 return methodPC;
962 }
963
964
965 /***********************************************************************
966 * lookupMethodInClassAndLoadCache.
967 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
968 * Caches and returns objc_msgForward if the method is not found in the class.
969 **********************************************************************/
970 static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
971 {
972 Method meth;
973 IMP imp;
974
975 // fixme this still has the method list vs method cache race
976 // because it doesn't hold a lock across lookup+cache_fill,
977 // but it's only used for .cxx_construct/destruct and we assume
978 // categories don't change them.
979
980 // Search cache first.
981 imp = _cache_getImp(cls, sel);
982 if (imp) return imp;
983
984 // Cache miss. Search method list.
985
986 meth = _class_getMethodNoSuper(cls, sel);
987
988 if (meth) {
989 // Hit in method list. Cache it.
990 _cache_fill(cls, meth, sel);
991 return method_getImplementation(meth);
992 } else {
993 // Miss in method list. Cache objc_msgForward.
994 _cache_addForwardEntry(cls, sel);
995 return &_objc_msgForward_internal;
996 }
997 }
998
999
1000 /***********************************************************************
1001 * _objc_create_zone.
1002 **********************************************************************/
1003
1004 void *_objc_create_zone(void)
1005 {
1006 return malloc_default_zone();
1007 }
1008
1009
1010 /***********************************************************************
1011 * _malloc_internal
1012 * _calloc_internal
1013 * _realloc_internal
1014 * _strdup_internal
1015 * _strdupcat_internal
1016 * _memdup_internal
1017 * _free_internal
1018 * Convenience functions for the internal malloc zone.
1019 **********************************************************************/
1020 __private_extern__ void *_malloc_internal(size_t size)
1021 {
1022 return malloc_zone_malloc(_objc_internal_zone(), size);
1023 }
1024
1025 __private_extern__ void *_calloc_internal(size_t count, size_t size)
1026 {
1027 return malloc_zone_calloc(_objc_internal_zone(), count, size);
1028 }
1029
1030 __private_extern__ void *_realloc_internal(void *ptr, size_t size)
1031 {
1032 return malloc_zone_realloc(_objc_internal_zone(), ptr, size);
1033 }
1034
1035 __private_extern__ char *_strdup_internal(const char *str)
1036 {
1037 size_t len;
1038 char *dup;
1039 if (!str) return NULL;
1040 len = strlen(str);
1041 dup = malloc_zone_malloc(_objc_internal_zone(), len + 1);
1042 memcpy(dup, str, len + 1);
1043 return dup;
1044 }
1045
1046 // allocate a new string that concatenates s1+s2.
1047 __private_extern__ char *_strdupcat_internal(const char *s1, const char *s2)
1048 {
1049 size_t len1 = strlen(s1);
1050 size_t len2 = strlen(s2);
1051 char *dup = malloc_zone_malloc(_objc_internal_zone(), len1 + len2 + 1);
1052 memcpy(dup, s1, len1);
1053 memcpy(dup + len1, s2, len2 + 1);
1054 return dup;
1055 }
1056
1057 __private_extern__ void *_memdup_internal(const void *mem, size_t len)
1058 {
1059 void *dup = malloc_zone_malloc(_objc_internal_zone(), len);
1060 memcpy(dup, mem, len);
1061 return dup;
1062 }
1063
1064 __private_extern__ void _free_internal(void *ptr)
1065 {
1066 malloc_zone_free(_objc_internal_zone(), ptr);
1067 }
1068
1069
1070 __private_extern__ Class _calloc_class(size_t size)
1071 {
1072 #if !defined(NO_GC)
1073 if (UseGC) return (Class) malloc_zone_calloc(gc_zone, 1, size);
1074 #endif
1075 return (Class) _calloc_internal(1, size);
1076 }
1077
1078
1079 const char *class_getName(Class cls)
1080 {
1081 return _class_getName(cls);
1082 }
1083
1084 Class class_getSuperclass(Class cls)
1085 {
1086 return _class_getSuperclass(cls);
1087 }
1088
1089 BOOL class_isMetaClass(Class cls)
1090 {
1091 return _class_isMetaClass(cls);
1092 }
1093
1094
1095 size_t class_getInstanceSize(Class cls)
1096 {
1097 return _class_getInstanceSize(cls);
1098 }
1099
1100
1101 /***********************************************************************
1102 * method_getNumberOfArguments.
1103 **********************************************************************/
1104 unsigned int method_getNumberOfArguments(Method m)
1105 {
1106 if (!m) return 0;
1107 return encoding_getNumberOfArguments(method_getTypeEncoding(m));
1108 }
1109
1110
1111 unsigned int method_getSizeOfArguments(Method m)
1112 {
1113 OBJC_WARN_DEPRECATED;
1114 if (!m) return 0;
1115 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1116 }
1117
1118
1119 unsigned int method_getArgumentInfo(Method m, int arg,
1120 const char **type, int *offset)
1121 {
1122 OBJC_WARN_DEPRECATED;
1123 if (!m) return 0;
1124 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1125 arg, type, offset);
1126 }
1127
1128
1129 void method_getReturnType(Method m, char *dst, size_t dst_len)
1130 {
1131 encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
1132 }
1133
1134
1135 char * method_copyReturnType(Method m)
1136 {
1137 return encoding_copyReturnType(method_getTypeEncoding(m));
1138 }
1139
1140
1141 void method_getArgumentType(Method m, unsigned int index,
1142 char *dst, size_t dst_len)
1143 {
1144 encoding_getArgumentType(method_getTypeEncoding(m),
1145 index, dst, dst_len);
1146 }
1147
1148
1149 char * method_copyArgumentType(Method m, unsigned int index)
1150 {
1151 return encoding_copyArgumentType(method_getTypeEncoding(m), index);
1152 }
1153
1154
1155 /***********************************************************************
1156 * objc_constructInstance
1157 * Creates an instance of `cls` at the location pointed to by `bytes`.
1158 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
1159 * well-aligned zero-filled memory.
1160 * The new object's isa is set. Any C++ constructors are called.
1161 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
1162 * NULL, or if C++ constructors fail.
1163 **********************************************************************/
1164 id objc_constructInstance(Class cls, void *bytes)
1165 {
1166 id obj;
1167
1168 if (!cls || !bytes) return nil;
1169 obj = (id)bytes;
1170
1171 // Set the isa pointer
1172 obj->isa = cls;
1173
1174 // Call C++ constructors, if any.
1175 if (!object_cxxConstruct(obj)) {
1176 // Some C++ constructor threw an exception.
1177 return nil;
1178 }
1179
1180 return obj;
1181 }
1182
1183
1184 /***********************************************************************
1185 * objc_destructInstance
1186 * Destroys an instance without freeing memory.
1187 * Any C++ destructors are called. Any associative references are removed.
1188 * Returns `obj`. Does nothing if `obj` is nil.
1189 **********************************************************************/
1190 void *objc_destructInstance(id obj)
1191 {
1192 if (obj) {
1193 object_cxxDestruct(obj);
1194
1195 // don't call this if the class has never had associative references.
1196 if (_class_instancesHaveAssociatedObjects(obj->isa)) {
1197 _object_remove_assocations(obj);
1198 }
1199 }
1200
1201 return obj;
1202 }
1203
1204
1205 /***********************************************************************
1206 * _internal_class_createInstanceFromZone. Allocate an instance of the
1207 * specified class with the specified number of bytes for indexed
1208 * variables, in the specified zone. The isa field is set to the
1209 * class, C++ default constructors are called, and all other fields are zeroed.
1210 **********************************************************************/
1211 __private_extern__ id
1212 _internal_class_createInstanceFromZone(Class cls, size_t extraBytes,
1213 void *zone)
1214 {
1215 void *bytes;
1216 id obj;
1217 size_t size;
1218
1219 // Can't create something for nothing
1220 if (!cls) return nil;
1221
1222 // Allocate and initialize
1223 size = _class_getInstanceSize(cls) + extraBytes;
1224
1225 // CF requires all objects be at least 16 bytes.
1226 if (size < 16) size = 16;
1227
1228 #if !defined(NO_GC)
1229 if (UseGC) {
1230 bytes = auto_zone_allocate_object(gc_zone, size,
1231 AUTO_OBJECT_SCANNED, 0, 1);
1232 } else
1233 #endif
1234 if (zone) {
1235 bytes = malloc_zone_calloc (zone, 1, size);
1236 } else {
1237 bytes = calloc(1, size);
1238 }
1239 if (!bytes) return nil;
1240
1241 obj = objc_constructInstance(cls, bytes);
1242 if (!obj) {
1243 #if !defined(NO_GC)
1244 if (UseGC) {
1245 auto_zone_retain(gc_zone, bytes); // gc free expects rc==1
1246 }
1247 #endif
1248 free(bytes);
1249 return nil;
1250 }
1251
1252 return obj;
1253 }
1254
1255
1256 __private_extern__ id
1257 _internal_object_dispose(id anObject)
1258 {
1259 if (anObject==nil) return nil;
1260
1261 objc_destructInstance(anObject);
1262
1263 #if !defined(NO_GC)
1264 if (UseGC) {
1265 auto_zone_retain(gc_zone, anObject); // gc free expects rc==1
1266 } else
1267 #endif
1268 {
1269 #if !__OBJC2__
1270 // only clobber isa for non-gc
1271 anObject->isa = _objc_getFreedObjectClass ();
1272 #endif
1273 }
1274 free(anObject);
1275 return nil;
1276 }
1277
1278
1279 /***********************************************************************
1280 * inform_duplicate. Complain about duplicate class implementations.
1281 **********************************************************************/
1282 __private_extern__ void
1283 inform_duplicate(const char *name, Class oldCls, Class cls)
1284 {
1285 #if TARGET_OS_WIN32
1286 _objc_inform ("Class %s is implemented in two different images.", name);
1287 #else
1288 const header_info *oldHeader = _headerForClass(oldCls);
1289 const header_info *newHeader = _headerForClass(cls);
1290 const char *oldName = oldHeader ? _nameForHeader(oldHeader->mhdr) : "??";
1291 const char *newName = newHeader ? _nameForHeader(newHeader->mhdr) : "??";
1292
1293 _objc_inform ("Class %s is implemented in both %s and %s. "
1294 "One of the two will be used. "
1295 "Which one is undefined.",
1296 name, oldName, newName);
1297 #endif
1298 }