]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-class.m
09c16ea3e19df7c8738458a97ddea776b29645f3
[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 <mach/mach.h>
160 #include <mach/thread_status.h>
161 #include <mach-o/ldsyms.h>
162 #include <mach-o/dyld.h>
163 #include <sys/types.h>
164 #include <unistd.h>
165 #include <stdlib.h>
166 #include <sys/uio.h>
167 #include <sys/fcntl.h>
168 #include <sys/mman.h>
169
170 #import "objc.h"
171 #import "Object.h"
172 #import "objc-private.h"
173 #import "hashtable2.h"
174 #import "maptable.h"
175 #import "objc-initialize.h"
176 #import "objc-auto.h"
177
178
179 /* overriding the default object allocation and error handling routines */
180
181 OBJC_EXPORT id (*_alloc)(Class, size_t);
182 OBJC_EXPORT id (*_copy)(id, size_t);
183 OBJC_EXPORT id (*_realloc)(id, size_t);
184 OBJC_EXPORT id (*_dealloc)(id);
185 OBJC_EXPORT id (*_zoneAlloc)(Class, size_t, void *);
186 OBJC_EXPORT id (*_zoneRealloc)(id, size_t, void *);
187 OBJC_EXPORT id (*_zoneCopy)(id, size_t, void *);
188
189
190 /***********************************************************************
191 * Function prototypes internal to this module.
192 **********************************************************************/
193
194 static void _freedHandler (id self, SEL sel);
195 static void _nonexistentHandler (id self, SEL sel);
196 static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
197 static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
198 static Method look_up_method(Class cls, SEL sel, BOOL withCache, BOOL withResolver);
199
200
201 /***********************************************************************
202 * Static data internal to this module.
203 **********************************************************************/
204
205 // Method call logging
206 typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
207
208 static int objcMsgLogFD = (-1);
209 static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
210 static int objcMsgLogEnabled = 0;
211
212 /***********************************************************************
213 * Information about multi-thread support:
214 *
215 * Since we do not lock many operations which walk the superclass, method
216 * and ivar chains, these chains must remain intact once a class is published
217 * by inserting it into the class hashtable. All modifications must be
218 * atomic so that someone walking these chains will always geta valid
219 * result.
220 ***********************************************************************/
221
222
223
224 /***********************************************************************
225 * object_getClass.
226 **********************************************************************/
227 Class object_getClass(id obj)
228 {
229 if (obj) return obj->isa;
230 else return Nil;
231 }
232
233
234 /***********************************************************************
235 * object_setClass.
236 **********************************************************************/
237 Class object_setClass(id obj, Class cls)
238 {
239 // fixme could check obj's block size vs. cls's instance size
240 if (obj) {
241 Class old = obj->isa;
242 obj->isa = cls;
243 return old;
244 }
245 else return Nil;
246 }
247
248
249 /***********************************************************************
250 * object_getClassName.
251 **********************************************************************/
252 const char *object_getClassName(id obj)
253 {
254 if (obj) return _class_getName(obj->isa);
255 else return "nil";
256 }
257
258 /***********************************************************************
259 * object_getIndexedIvars.
260 **********************************************************************/
261 void *object_getIndexedIvars(id obj)
262 {
263 // ivars are tacked onto the end of the object
264 if (obj) return ((char *) obj) + _class_getInstanceSize(obj->isa);
265 else return NULL;
266 }
267
268
269 Ivar object_setInstanceVariable(id obj, const char *name, void *value)
270 {
271 Ivar ivar = NULL;
272
273 if (obj && name) {
274 if ((ivar = class_getInstanceVariable(obj->isa, name))) {
275 objc_assign_ivar_internal(
276 (id)value,
277 obj,
278 ivar_getOffset(ivar));
279 }
280 }
281 return ivar;
282 }
283
284 Ivar object_getInstanceVariable(id obj, const char *name, void **value)
285 {
286 if (obj && name) {
287 Ivar ivar;
288 void **ivaridx;
289 if ((ivar = class_getInstanceVariable(obj->isa, name))) {
290 ivaridx = (void **)((char *)obj + ivar_getOffset(ivar));
291 if (value) *value = *ivaridx;
292 return ivar;
293 }
294 }
295 if (value) *value = NULL;
296 return NULL;
297 }
298
299
300 void object_setIvar(id obj, Ivar ivar, id value)
301 {
302 if (obj && ivar) {
303 objc_assign_ivar_internal(value, obj, ivar_getOffset(ivar));
304 }
305 }
306
307
308 id object_getIvar(id obj, Ivar ivar)
309 {
310 if (obj && ivar) {
311 id *idx = (id *)((char *)obj + ivar_getOffset(ivar));
312 return *idx;
313 }
314 return NULL;
315 }
316
317
318 /***********************************************************************
319 * object_cxxDestructFromClass.
320 * Call C++ destructors on obj, starting with cls's
321 * dtor method (if any) followed by superclasses' dtors (if any),
322 * stopping at cls's dtor (if any).
323 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
324 **********************************************************************/
325 static void object_cxxDestructFromClass(id obj, Class cls)
326 {
327 void (*dtor)(id);
328
329 // Call cls's dtor first, then superclasses's dtors.
330
331 for ( ; cls != NULL; cls = _class_getSuperclass(cls)) {
332 if (!_class_hasCxxStructorsNoSuper(cls)) continue;
333 dtor = (void(*)(id))
334 lookupMethodInClassAndLoadCache(cls, cxx_destruct_sel);
335 if (dtor != (void(*)(id))&_objc_msgForward) {
336 if (PrintCxxCtors) {
337 _objc_inform("CXX: calling C++ destructors for class %s",
338 _class_getName(cls));
339 }
340 (*dtor)(obj);
341 }
342 }
343 }
344
345
346 /***********************************************************************
347 * object_cxxDestruct.
348 * Call C++ destructors on obj, if any.
349 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
350 **********************************************************************/
351 __private_extern__ void object_cxxDestruct(id obj)
352 {
353 if (!obj) return;
354 object_cxxDestructFromClass(obj, obj->isa);
355 }
356
357
358 /***********************************************************************
359 * object_cxxConstructFromClass.
360 * Recursively call C++ constructors on obj, starting with base class's
361 * ctor method (if any) followed by subclasses' ctors (if any), stopping
362 * at cls's ctor (if any).
363 * Returns YES if construction succeeded.
364 * Returns NO if some constructor threw an exception. The exception is
365 * caught and discarded. Any partial construction is destructed.
366 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
367 *
368 * .cxx_construct returns id. This really means:
369 * return self: construction succeeded
370 * return nil: construction failed because a C++ constructor threw an exception
371 **********************************************************************/
372 static BOOL object_cxxConstructFromClass(id obj, Class cls)
373 {
374 id (*ctor)(id);
375 Class supercls = _class_getSuperclass(cls);
376
377 // Call superclasses' ctors first, if any.
378 if (supercls) {
379 BOOL ok = object_cxxConstructFromClass(obj, supercls);
380 if (!ok) return NO; // some superclass's ctor failed - give up
381 }
382
383 // Find this class's ctor, if any.
384 if (!_class_hasCxxStructorsNoSuper(cls)) return YES; // no ctor - ok
385 ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, cxx_construct_sel);
386 if (ctor == (id(*)(id))&_objc_msgForward) return YES; // no ctor - ok
387
388 // Call this class's ctor.
389 if (PrintCxxCtors) {
390 _objc_inform("CXX: calling C++ constructors for class %s", _class_getName(cls));
391 }
392 if ((*ctor)(obj)) return YES; // ctor called and succeeded - ok
393
394 // This class's ctor was called and failed.
395 // Call superclasses's dtors to clean up.
396 if (supercls) object_cxxDestructFromClass(obj, supercls);
397 return NO;
398 }
399
400
401 /***********************************************************************
402 * object_cxxConstructFromClass.
403 * Call C++ constructors on obj, if any.
404 * Returns YES if construction succeeded.
405 * Returns NO if some constructor threw an exception. The exception is
406 * caught and discarded. Any partial construction is destructed.
407 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
408 **********************************************************************/
409 __private_extern__ BOOL object_cxxConstruct(id obj)
410 {
411 if (!obj) return YES;
412 return object_cxxConstructFromClass(obj, obj->isa);
413 }
414
415
416 @interface objc_resolver
417 +(BOOL)resolveClassMethod:(SEL)sel;
418 +(BOOL)resolveInstanceMethod:(SEL)sel;
419 @end
420
421 /***********************************************************************
422 * _class_resolveClassMethod
423 * Call +resolveClassMethod and return the method added or NULL.
424 * cls should be a metaclass.
425 * Assumes the method doesn't exist already.
426 **********************************************************************/
427 static Method _class_resolveClassMethod(Class cls, SEL sel)
428 {
429 BOOL resolved;
430 Method meth = NULL;
431 Class clsInstance;
432
433 if (!look_up_method(cls, @selector(resolveClassMethod:),
434 YES /*cache*/, NO /*resolver*/))
435 {
436 return NULL;
437 }
438
439 // GrP fixme same hack as +initialize
440 if (strncmp(_class_getName(cls), "_%", 2) == 0) {
441 // Posee's meta's name is smashed and isn't in the class_hash,
442 // so objc_getClass doesn't work.
443 char *baseName = strchr(_class_getName(cls), '%'); // get posee's real name
444 clsInstance = objc_getClass(baseName);
445 } else {
446 clsInstance = objc_getClass(_class_getName(cls));
447 }
448
449 resolved = [clsInstance resolveClassMethod:sel];
450
451 if (resolved) {
452 // +resolveClassMethod adds to self->isa
453 meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
454
455 if (!meth) {
456 // Method resolver didn't add anything?
457 _objc_inform("+[%s resolveClassMethod:%s] returned YES, but "
458 "no new implementation of +[%s %s] was found",
459 class_getName(cls),
460 sel_getName(sel),
461 class_getName(cls),
462 sel_getName(sel));
463 return NULL;
464 }
465 }
466
467 return meth;
468 }
469
470
471 /***********************************************************************
472 * _class_resolveInstanceMethod
473 * Call +resolveInstanceMethod and return the method added or NULL.
474 * cls should be a non-meta class.
475 * Assumes the method doesn't exist already.
476 **********************************************************************/
477 static Method _class_resolveInstanceMethod(Class cls, SEL sel)
478 {
479 BOOL resolved;
480 Method meth = NULL;
481
482 if (!look_up_method(((id)cls)->isa, @selector(resolveInstanceMethod:),
483 YES /*cache*/, NO /*resolver*/))
484 {
485 return NULL;
486 }
487
488 resolved = [cls resolveInstanceMethod:sel];
489
490 if (resolved) {
491 // +resolveClassMethod adds to self
492 meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
493
494 if (!meth) {
495 // Method resolver didn't add anything?
496 _objc_inform("+[%s resolveInstanceMethod:%s] returned YES, but "
497 "no new implementation of %c[%s %s] was found",
498 class_getName(cls),
499 sel_getName(sel),
500 class_isMetaClass(cls) ? '+' : '-',
501 class_getName(cls),
502 sel_getName(sel));
503 return NULL;
504 }
505 }
506
507 return meth;
508 }
509
510
511 /***********************************************************************
512 * _class_resolveMethod
513 * Call +resolveClassMethod or +resolveInstanceMethod and return
514 * the method added or NULL.
515 * Assumes the method doesn't exist already.
516 **********************************************************************/
517 static Method _class_resolveMethod(Class cls, SEL sel)
518 {
519 Method meth = NULL;
520
521 if (_class_isMetaClass(cls)) {
522 meth = _class_resolveClassMethod(cls, sel);
523 }
524 if (!meth) {
525 meth = _class_resolveInstanceMethod(cls, sel);
526 }
527
528 if (PrintResolving && meth) {
529 _objc_inform("RESOLVE: method %c[%s %s] dynamically resolved to %p",
530 class_isMetaClass(cls) ? '+' : '-',
531 class_getName(cls), sel_getName(sel),
532 method_getImplementation(meth));
533 }
534
535 return meth;
536 }
537
538
539 /***********************************************************************
540 * look_up_method
541 * Look up a method in the given class and its superclasses.
542 * If withCache==YES, look in the class's method cache too.
543 * If withResolver==YES, call +resolveClass/InstanceMethod too.
544 * Returns NULL if the method is not found.
545 * +forward:: entries are not returned.
546 **********************************************************************/
547 static Method look_up_method(Class cls, SEL sel,
548 BOOL withCache, BOOL withResolver)
549 {
550 Method meth = NULL;
551
552 if (withCache) {
553 meth = _cache_getMethod(cls, sel, &_objc_msgForward);
554 if (!meth && (IMP)_objc_msgForward == _cache_getImp(cls, sel)) {
555 // Cache contains forward:: . Stop searching.
556 return NULL;
557 }
558 }
559
560 if (!meth) meth = _class_getMethod(cls, sel);
561
562 if (!meth && withResolver) meth = _class_resolveMethod(cls, sel);
563
564 return meth;
565 }
566
567
568 /***********************************************************************
569 * class_getInstanceMethod. Return the instance method for the
570 * specified class and selector.
571 **********************************************************************/
572 Method class_getInstanceMethod(Class cls, SEL sel)
573 {
574 if (!cls || !sel) return NULL;
575
576 /* Cache is not used because historically it wasn't. */
577 return look_up_method(cls, sel, NO/*cache*/, YES/*resolver*/);
578 }
579
580 /***********************************************************************
581 * class_getClassMethod. Return the class method for the specified
582 * class and selector.
583 **********************************************************************/
584 Method class_getClassMethod(Class cls, SEL sel)
585 {
586 if (!cls || !sel) return NULL;
587
588 return class_getInstanceMethod(_class_getMeta(cls), sel);
589 }
590
591
592 /***********************************************************************
593 * class_getInstanceVariable. Return the named instance variable.
594 **********************************************************************/
595 Ivar class_getInstanceVariable(Class cls, const char *name)
596 {
597 if (!cls || !name) return NULL;
598
599 return _class_getVariable(cls, name);
600 }
601
602
603 /***********************************************************************
604 * class_getClassVariable. Return the named class variable.
605 **********************************************************************/
606 Ivar class_getClassVariable(Class cls, const char *name)
607 {
608 if (!cls) return NULL;
609
610 return class_getInstanceVariable(((id)cls)->isa, name);
611 }
612
613
614 __private_extern__ Property
615 property_list_nth(const struct objc_property_list *plist, uint32_t i)
616 {
617 return (Property)(i*plist->entsize + (char *)&plist->first);
618 }
619
620 __private_extern__ size_t
621 property_list_size(const struct objc_property_list *plist)
622 {
623 return sizeof(struct objc_property_list) + (plist->count-1)*plist->entsize;
624 }
625
626 __private_extern__ Property *
627 copyPropertyList(struct objc_property_list *plist, unsigned int *outCount)
628 {
629 Property *result = NULL;
630 unsigned int count = 0;
631
632 if (plist) {
633 count = plist->count;
634 }
635
636 if (count > 0) {
637 unsigned int i;
638 result = malloc((count+1) * sizeof(Property));
639
640 for (i = 0; i < count; i++) {
641 result[i] = property_list_nth(plist, i);
642 }
643 result[i] = NULL;
644 }
645
646 if (outCount) *outCount = count;
647 return result;
648 }
649
650 const char *property_getName(Property prop)
651 {
652 return prop->name;
653 }
654
655
656 const char *property_getAttributes(Property prop)
657 {
658 return prop->attributes;
659 }
660
661
662 /***********************************************************************
663 * _objc_flush_caches. Flush the caches of the specified class and any
664 * of its subclasses. If cls is a meta-class, only meta-class (i.e.
665 * class method) caches are flushed. If cls is an instance-class, both
666 * instance-class and meta-class caches are flushed.
667 **********************************************************************/
668 void _objc_flush_caches(Class cls)
669 {
670 flush_caches (cls, YES);
671 }
672
673
674 /***********************************************************************
675 * _freedHandler.
676 **********************************************************************/
677 static void _freedHandler(id obj, SEL sel)
678 {
679 __objc_error (obj, "message %s sent to freed object=%p",
680 sel_getName(sel), obj);
681 }
682
683 /***********************************************************************
684 * _nonexistentHandler.
685 **********************************************************************/
686 static void _nonexistentHandler(id obj, SEL sel)
687 {
688 __objc_error (obj, "message %s sent to non-existent object=%p",
689 sel_getName(sel), obj);
690 }
691
692
693 /***********************************************************************
694 * class_respondsToSelector.
695 **********************************************************************/
696 BOOL class_respondsToMethod(Class cls, SEL sel)
697 {
698 OBJC_WARN_DEPRECATED;
699
700 return class_respondsToSelector(cls, sel);
701 }
702
703
704 BOOL class_respondsToSelector(Class cls, SEL sel)
705 {
706 Method meth;
707
708 if (!sel || !cls) return NO;
709
710 meth = look_up_method(cls, sel, YES/*cache*/, YES/*resolver*/);
711 if (meth) {
712 _cache_fill(cls, meth, sel);
713 return YES;
714 } else {
715 // Cache negative result
716 _cache_addForwardEntry(cls, sel);
717 return NO;
718 }
719 }
720
721
722 /***********************************************************************
723 * class_getMethodImplementation.
724 * Returns the IMP that would be invoked if [obj sel] were sent,
725 * where obj is an instance of class cls.
726 **********************************************************************/
727 IMP class_lookupMethod(Class cls, SEL sel)
728 {
729 OBJC_WARN_DEPRECATED;
730
731 // No one responds to zero!
732 if (!sel) {
733 __objc_error(cls, "invalid selector (null)");
734 }
735
736 return class_getMethodImplementation(cls, sel);
737 }
738
739 IMP class_getMethodImplementation(Class cls, SEL sel)
740 {
741 IMP imp;
742
743 if (!cls || !sel) return NULL;
744
745 // fixme _objc_msgForward does not conform to ABI and cannot be
746 // called externally
747
748 imp = _cache_getImp(cls, sel);
749 if (!imp) {
750 // Handle cache miss
751 imp = _class_lookupMethodAndLoadCache (cls, sel);
752 }
753 return imp;
754 }
755
756
757 IMP class_getMethodImplementation_stret(Class cls, SEL sel)
758 {
759 IMP imp = class_getMethodImplementation(cls, sel);
760 // fixme check for forwarding and use stret forwarder instead
761 return imp;
762 }
763
764
765 // Ignored selectors get method->imp = &_objc_ignored_method
766 __private_extern__ id _objc_ignored_method(id self, SEL _cmd) { return self; }
767
768
769 /***********************************************************************
770 * instrumentObjcMessageSends/logObjcMessageSends.
771 **********************************************************************/
772 static int LogObjCMessageSend (BOOL isClassMethod,
773 const char * objectsClass,
774 const char * implementingClass,
775 SEL selector)
776 {
777 char buf[ 1024 ];
778
779 // Create/open the log file
780 if (objcMsgLogFD == (-1))
781 {
782 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
783 objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
784 if (objcMsgLogFD < 0) {
785 // no log file - disable logging
786 objcMsgLogEnabled = 0;
787 objcMsgLogFD = -1;
788 return 1;
789 }
790 }
791
792 // Make the log entry
793 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
794 isClassMethod ? '+' : '-',
795 objectsClass,
796 implementingClass,
797 (char *) selector);
798
799 write (objcMsgLogFD, buf, strlen(buf));
800
801 // Tell caller to not cache the method
802 return 0;
803 }
804
805 void instrumentObjcMessageSends (BOOL flag)
806 {
807 int enabledValue = (flag) ? 1 : 0;
808
809 // Shortcut NOP
810 if (objcMsgLogEnabled == enabledValue)
811 return;
812
813 // If enabling, flush all method caches so we get some traces
814 if (flag)
815 flush_caches (Nil, YES);
816
817 // Sync our log file
818 if (objcMsgLogFD != (-1))
819 fsync (objcMsgLogFD);
820
821 objcMsgLogEnabled = enabledValue;
822 }
823
824 __private_extern__ void logObjcMessageSends (ObjCLogProc logProc)
825 {
826 if (logProc)
827 {
828 objcMsgLogProc = logProc;
829 objcMsgLogEnabled = 1;
830 }
831 else
832 {
833 objcMsgLogProc = logProc;
834 objcMsgLogEnabled = 0;
835 }
836
837 if (objcMsgLogFD != (-1))
838 fsync (objcMsgLogFD);
839 }
840
841
842 /***********************************************************************
843 * log_and_fill_cache
844 * Log this method call. If the logger permits it, fill the method cache.
845 * cls is the method whose cache should be filled.
846 * implementer is the class that owns the implementation in question.
847 **********************************************************************/
848 static void
849 log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
850 {
851 BOOL cacheIt = YES;
852
853 if (objcMsgLogEnabled) {
854 cacheIt = objcMsgLogProc (_class_isMetaClass(implementer) ? YES : NO,
855 _class_getName(cls),
856 _class_getName(implementer),
857 sel);
858 }
859 if (cacheIt) {
860 _cache_fill (cls, meth, sel);
861 }
862 }
863
864
865 /***********************************************************************
866 * _class_lookupMethodAndLoadCache.
867 *
868 * Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
869 **********************************************************************/
870 __private_extern__ IMP _class_lookupMethodAndLoadCache(Class cls, SEL sel)
871 {
872 Class curClass;
873 IMP methodPC = NULL;
874
875 // Check for freed class
876 if (cls == _class_getFreedObjectClass())
877 return (IMP) _freedHandler;
878
879 // Check for nonexistent class
880 if (cls == _class_getNonexistentObjectClass())
881 return (IMP) _nonexistentHandler;
882
883 #if __OBJC2__
884 // fixme hack
885 _class_realize(cls);
886 #endif
887
888 if (!_class_isInitialized(cls)) {
889 _class_initialize (cls);
890 // If sel == initialize, _class_initialize will send +initialize and
891 // then the messenger will send +initialize again after this
892 // procedure finishes. Of course, if this is not being called
893 // from the messenger then it won't happen. 2778172
894 }
895
896 // Outer loop - search the caches and method lists of the
897 // class and its super-classes
898 for (curClass = cls; curClass; curClass = _class_getSuperclass(curClass))
899 {
900 // Beware of thread-unsafety and double-freeing of forward::
901 // entries here! See note in "Method cache locking" above.
902 // The upshot is that _cache_getMethod() will return NULL
903 // instead of returning a forward:: entry.
904 Method meth = _cache_getMethod(curClass, sel, &_objc_msgForward);
905 if (meth) {
906 // Found the method in this class or a superclass.
907 // Cache the method in this class, unless we just found it in
908 // this class's cache.
909 if (curClass != cls) {
910 _cache_fill (cls, meth, sel);
911 }
912
913 methodPC = method_getImplementation(meth);
914 break;
915 }
916
917 // Cache scan failed. Search method list.
918
919 meth = _class_getMethodNoSuper(curClass, sel);
920 if (meth) {
921 log_and_fill_cache(cls, curClass, meth, sel);
922 methodPC = method_getImplementation(meth);
923 break;
924 }
925 }
926
927 if (methodPC == NULL) {
928 // Class and superclasses do not respond -- try resolve handler
929 Method meth = _class_resolveMethod(cls, sel);
930 if (meth) {
931 // GrP fixme this isn't quite right
932 log_and_fill_cache(cls, cls, meth, sel);
933 methodPC = method_getImplementation(meth);
934 }
935 }
936
937 if (methodPC == NULL) {
938 // Class and superclasses do not respond and
939 // resolve handler didn't help -- use forwarding
940 _cache_addForwardEntry(cls, sel);
941 methodPC = &_objc_msgForward;
942 }
943
944 return methodPC;
945 }
946
947
948 /***********************************************************************
949 * lookupMethodInClassAndLoadCache.
950 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
951 * Caches and returns objc_msgForward if the method is not found in the class.
952 **********************************************************************/
953 static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
954 {
955 Method meth;
956 IMP imp;
957
958 // Search cache first.
959 imp = _cache_getImp(cls, sel);
960 if (imp) return imp;
961
962 // Cache miss. Search method list.
963
964 meth = _class_getMethodNoSuper(cls, sel);
965
966 if (meth) {
967 // Hit in method list. Cache it.
968 _cache_fill(cls, meth, sel);
969 return method_getImplementation(meth);
970 } else {
971 // Miss in method list. Cache objc_msgForward.
972 _cache_addForwardEntry(cls, sel);
973 return &_objc_msgForward;
974 }
975 }
976
977
978 /***********************************************************************
979 * _objc_create_zone.
980 **********************************************************************/
981
982 void * _objc_create_zone (void)
983 {
984 return malloc_default_zone();
985 }
986
987
988 /***********************************************************************
989 * _objc_internal_zone.
990 * Malloc zone for internal runtime data.
991 * By default this is the default malloc zone, but a dedicated zone is
992 * used if environment variable OBJC_USE_INTERNAL_ZONE is set.
993 **********************************************************************/
994 __private_extern__ malloc_zone_t *_objc_internal_zone(void)
995 {
996 static malloc_zone_t *z = (malloc_zone_t *)-1;
997 if (z == (malloc_zone_t *)-1) {
998 if (UseInternalZone) {
999 z = malloc_create_zone(vm_page_size, 0);
1000 malloc_set_zone_name(z, "ObjC");
1001 } else {
1002 z = malloc_default_zone();
1003 }
1004 }
1005 return z;
1006 }
1007
1008
1009 /***********************************************************************
1010 * _malloc_internal
1011 * _calloc_internal
1012 * _realloc_internal
1013 * _strdup_internal
1014 * _strdupcat_internal
1015 * _memdup_internal
1016 * _free_internal
1017 * Convenience functions for the internal malloc zone.
1018 **********************************************************************/
1019 __private_extern__ void *_malloc_internal(size_t size)
1020 {
1021 return malloc_zone_malloc(_objc_internal_zone(), size);
1022 }
1023
1024 __private_extern__ void *_calloc_internal(size_t count, size_t size)
1025 {
1026 return malloc_zone_calloc(_objc_internal_zone(), count, size);
1027 }
1028
1029 __private_extern__ void *_realloc_internal(void *ptr, size_t size)
1030 {
1031 return malloc_zone_realloc(_objc_internal_zone(), ptr, size);
1032 }
1033
1034 __private_extern__ char *_strdup_internal(const char *str)
1035 {
1036 if (!str) return NULL;
1037 size_t len = strlen(str);
1038 char *dup = malloc_zone_malloc(_objc_internal_zone(), len + 1);
1039 memcpy(dup, str, len + 1);
1040 return dup;
1041 }
1042
1043 // allocate a new string that concatenates s1+s2.
1044 __private_extern__ char *_strdupcat_internal(const char *s1, const char *s2)
1045 {
1046 size_t len1 = strlen(s1);
1047 size_t len2 = strlen(s2);
1048 char *dup = malloc_zone_malloc(_objc_internal_zone(), len1 + len2 + 1);
1049 memcpy(dup, s1, len1);
1050 memcpy(dup + len1, s2, len2 + 1);
1051 return dup;
1052 }
1053
1054 __private_extern__ void *_memdup_internal(const void *mem, size_t len)
1055 {
1056 void *dup = malloc_zone_malloc(_objc_internal_zone(), len);
1057 memcpy(dup, mem, len);
1058 return dup;
1059 }
1060
1061 __private_extern__ void _free_internal(void *ptr)
1062 {
1063 malloc_zone_free(_objc_internal_zone(), ptr);
1064 }
1065
1066
1067 const char *class_getName(Class cls)
1068 {
1069 return _class_getName(cls);
1070 }
1071
1072 Class class_getSuperclass(Class cls)
1073 {
1074 return _class_getSuperclass(cls);
1075 }
1076
1077 BOOL class_isMetaClass(Class cls)
1078 {
1079 return _class_isMetaClass(cls);
1080 }
1081
1082
1083 size_t class_getInstanceSize(Class cls)
1084 {
1085 return _class_getInstanceSize(cls);
1086 }
1087
1088 void method_exchangeImplementations(Method m1, Method m2)
1089 {
1090 // fixme thread safe
1091 IMP m1_imp;
1092 if (!m1 || !m2) return;
1093 m1_imp = method_getImplementation(m1);
1094 method_setImplementation(m1, method_setImplementation(m2, m1_imp));
1095 }
1096
1097
1098 /***********************************************************************
1099 * method_getNumberOfArguments.
1100 **********************************************************************/
1101 unsigned int method_getNumberOfArguments(Method m)
1102 {
1103 if (!m) return 0;
1104 return encoding_getNumberOfArguments(method_getTypeEncoding(m));
1105 }
1106
1107
1108 unsigned int method_getSizeOfArguments(Method m)
1109 {
1110 OBJC_WARN_DEPRECATED;
1111 if (!m) return 0;
1112 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1113 }
1114
1115
1116 unsigned int method_getArgumentInfo(Method m, int arg,
1117 const char **type, int *offset)
1118 {
1119 OBJC_WARN_DEPRECATED;
1120 if (!m) return 0;
1121 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1122 arg, type, offset);
1123 }
1124
1125
1126 void method_getReturnType(Method m, char *dst, size_t dst_len)
1127 {
1128 return encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
1129 }
1130
1131
1132 char * method_copyReturnType(Method m)
1133 {
1134 return encoding_copyReturnType(method_getTypeEncoding(m));
1135 }
1136
1137
1138 void method_getArgumentType(Method m, unsigned int index,
1139 char *dst, size_t dst_len)
1140 {
1141 return encoding_getArgumentType(method_getTypeEncoding(m),
1142 index, dst, dst_len);
1143 }
1144
1145
1146 char * method_copyArgumentType(Method m, unsigned int index)
1147 {
1148 return encoding_copyArgumentType(method_getTypeEncoding(m), index);
1149 }
1150
1151
1152 /***********************************************************************
1153 * _internal_class_createInstanceFromZone. Allocate an instance of the
1154 * specified class with the specified number of bytes for indexed
1155 * variables, in the specified zone. The isa field is set to the
1156 * class, C++ default constructors are called, and all other fields are zeroed.
1157 **********************************************************************/
1158 __private_extern__ id
1159 _internal_class_createInstanceFromZone(Class cls, size_t extraBytes,
1160 void *zone)
1161 {
1162 id obj;
1163 size_t size;
1164
1165 // Can't create something for nothing
1166 if (!cls) return nil;
1167
1168 // Allocate and initialize
1169 size = _class_getInstanceSize(cls) + extraBytes;
1170 if (UseGC) {
1171 obj = (id) auto_zone_allocate_object(gc_zone, size,
1172 AUTO_OBJECT_SCANNED, false, true);
1173 } else if (zone) {
1174 obj = (id) malloc_zone_calloc (zone, 1, size);
1175 } else {
1176 obj = (id) calloc(1, size);
1177 }
1178 if (!obj) return nil;
1179
1180 // Set the isa pointer
1181 obj->isa = cls;
1182
1183 // Call C++ constructors, if any.
1184 if (!object_cxxConstruct(obj)) {
1185 // Some C++ constructor threw an exception.
1186 if (UseGC) {
1187 auto_zone_retain(gc_zone, obj); // gc free expects retain count==1
1188 }
1189 free(obj);
1190 return nil;
1191 }
1192
1193 return obj;
1194 }
1195
1196
1197 __private_extern__ id
1198 _internal_object_dispose(id anObject)
1199 {
1200 if (anObject==nil) return nil;
1201 object_cxxDestruct(anObject);
1202 if (UseGC) {
1203 auto_zone_retain(gc_zone, anObject); // gc free expects retain count==1
1204 } else {
1205 // only clobber isa for non-gc
1206 anObject->isa = _objc_getFreedObjectClass ();
1207 }
1208 free(anObject);
1209 return nil;
1210 }
1211