]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-class.m
objc4-371.2.tar.gz
[apple/objc4.git] / runtime / objc-class.m
CommitLineData
13d88034 1/*
b3962a83 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
390d5862 3 *
b3962a83 4 * @APPLE_LICENSE_HEADER_START@
390d5862
A
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 *
13d88034 13 * The Original Code and all software distributed under the License are
390d5862 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
13d88034
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
390d5862
A
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 *
13d88034
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/***********************************************************************
41c8faa5
A
24* objc-class.m
25* Copyright 1988-1997, Apple Computer, Inc.
26* Author: s. naroff
27**********************************************************************/
13d88034 28
1f20c7a7 29
2bfd4448
A
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
b3962a83 124 * CLS_FLUSH_CACHE: class load and messaging
2bfd4448
A
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
cacad474 134 * CLS_HAS_LOAD_METHOD: class load
2bfd4448
A
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
13d88034 155/***********************************************************************
41c8faa5
A
156* Imports.
157**********************************************************************/
13d88034 158
b3962a83
A
159#include <mach/mach.h>
160#include <mach/thread_status.h>
41c8faa5
A
161#include <mach-o/ldsyms.h>
162#include <mach-o/dyld.h>
41c8faa5
A
163#include <sys/types.h>
164#include <unistd.h>
165#include <stdlib.h>
166#include <sys/uio.h>
167#include <sys/fcntl.h>
b3962a83 168#include <sys/mman.h>
41c8faa5 169
b3962a83
A
170#import "objc.h"
171#import "Object.h"
13d88034
A
172#import "objc-private.h"
173#import "hashtable2.h"
174#import "maptable.h"
b3962a83
A
175#import "objc-initialize.h"
176#import "objc-auto.h"
13d88034 177
13d88034 178
b3962a83 179/* overriding the default object allocation and error handling routines */
13d88034 180
b3962a83
A
181OBJC_EXPORT id (*_alloc)(Class, size_t);
182OBJC_EXPORT id (*_copy)(id, size_t);
183OBJC_EXPORT id (*_realloc)(id, size_t);
184OBJC_EXPORT id (*_dealloc)(id);
185OBJC_EXPORT id (*_zoneAlloc)(Class, size_t, void *);
186OBJC_EXPORT id (*_zoneRealloc)(id, size_t, void *);
187OBJC_EXPORT id (*_zoneCopy)(id, size_t, void *);
390d5862 188
13d88034 189
13d88034 190/***********************************************************************
41c8faa5
A
191* Function prototypes internal to this module.
192**********************************************************************/
13d88034 193
41c8faa5 194static void _freedHandler (id self, SEL sel);
13d88034 195static void _nonexistentHandler (id self, SEL sel);
13d88034 196static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
2bfd4448 197static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
b3962a83
A
198static Method look_up_method(Class cls, SEL sel, BOOL withCache, BOOL withResolver);
199
13d88034
A
200
201/***********************************************************************
41c8faa5
A
202* Static data internal to this module.
203**********************************************************************/
13d88034 204
13d88034
A
205// Method call logging
206typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
207
13d88034
A
208static int objcMsgLogFD = (-1);
209static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
210static int objcMsgLogEnabled = 0;
211
41c8faa5
A
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***********************************************************************/
13d88034 221
2bfd4448 222
13d88034 223
b3962a83
A
224/***********************************************************************
225* object_getClass.
226**********************************************************************/
227Class object_getClass(id obj)
13d88034 228{
b3962a83
A
229 if (obj) return obj->isa;
230 else return Nil;
231}
232
233
234/***********************************************************************
235* object_setClass.
236**********************************************************************/
237Class object_setClass(id obj, Class cls)
13d88034 238{
b3962a83
A
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
13d88034
A
248
249/***********************************************************************
41c8faa5
A
250* object_getClassName.
251**********************************************************************/
b3962a83 252const char *object_getClassName(id obj)
13d88034 253{
b3962a83
A
254 if (obj) return _class_getName(obj->isa);
255 else return "nil";
13d88034
A
256}
257
258/***********************************************************************
41c8faa5
A
259* object_getIndexedIvars.
260**********************************************************************/
b3962a83 261void *object_getIndexedIvars(id obj)
13d88034 262{
41c8faa5 263 // ivars are tacked onto the end of the object
b3962a83
A
264 if (obj) return ((char *) obj) + _class_getInstanceSize(obj->isa);
265 else return NULL;
266}
267
268
269Ivar 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
284Ivar 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
300void 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
308id 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;
13d88034
A
315}
316
317
2bfd4448
A
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**********************************************************************/
325static void object_cxxDestructFromClass(id obj, Class cls)
326{
327 void (*dtor)(id);
328
329 // Call cls's dtor first, then superclasses's dtors.
330
b3962a83
A
331 for ( ; cls != NULL; cls = _class_getSuperclass(cls)) {
332 if (!_class_hasCxxStructorsNoSuper(cls)) continue;
2bfd4448
A
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",
b3962a83 338 _class_getName(cls));
2bfd4448
A
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**********************************************************************/
b3962a83 351__private_extern__ void object_cxxDestruct(id obj)
2bfd4448
A
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**********************************************************************/
372static BOOL object_cxxConstructFromClass(id obj, Class cls)
373{
374 id (*ctor)(id);
b3962a83 375 Class supercls = _class_getSuperclass(cls);
2bfd4448
A
376
377 // Call superclasses' ctors first, if any.
b3962a83
A
378 if (supercls) {
379 BOOL ok = object_cxxConstructFromClass(obj, supercls);
2bfd4448
A
380 if (!ok) return NO; // some superclass's ctor failed - give up
381 }
382
383 // Find this class's ctor, if any.
b3962a83 384 if (!_class_hasCxxStructorsNoSuper(cls)) return YES; // no ctor - ok
2bfd4448
A
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) {
b3962a83 390 _objc_inform("CXX: calling C++ constructors for class %s", _class_getName(cls));
2bfd4448
A
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.
b3962a83 396 if (supercls) object_cxxDestructFromClass(obj, supercls);
2bfd4448
A
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**********************************************************************/
b3962a83 409__private_extern__ BOOL object_cxxConstruct(id obj)
2bfd4448
A
410{
411 if (!obj) return YES;
412 return object_cxxConstructFromClass(obj, obj->isa);
413}
414
415
b3962a83
A
416@interface objc_resolver
417+(BOOL)resolveClassMethod:(SEL)sel;
418+(BOOL)resolveInstanceMethod:(SEL)sel;
419@end
420
13d88034 421/***********************************************************************
b3962a83
A
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.
41c8faa5 426**********************************************************************/
b3962a83 427static Method _class_resolveClassMethod(Class cls, SEL sel)
41c8faa5 428{
b3962a83
A
429 BOOL resolved;
430 Method meth = NULL;
431 Class clsInstance;
41c8faa5 432
b3962a83
A
433 if (!look_up_method(cls, @selector(resolveClassMethod:),
434 YES /*cache*/, NO /*resolver*/))
41c8faa5 435 {
b3962a83 436 return NULL;
41c8faa5
A
437 }
438
b3962a83
A
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));
41c8faa5 447 }
b3962a83
A
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 }
2bfd4448
A
465 }
466
b3962a83 467 return meth;
41c8faa5
A
468}
469
b3962a83 470
41c8faa5 471/***********************************************************************
b3962a83
A
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.
41c8faa5 476**********************************************************************/
b3962a83 477static Method _class_resolveInstanceMethod(Class cls, SEL sel)
13d88034 478{
b3962a83
A
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;
41c8faa5 508}
13d88034 509
13d88034
A
510
511/***********************************************************************
b3962a83
A
512* _class_resolveMethod
513* Call +resolveClassMethod or +resolveInstanceMethod and return
514* the method added or NULL.
515* Assumes the method doesn't exist already.
41c8faa5 516**********************************************************************/
b3962a83 517static Method _class_resolveMethod(Class cls, SEL sel)
13d88034 518{
b3962a83
A
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;
41c8faa5 536}
13d88034 537
b3962a83 538
13d88034 539/***********************************************************************
b3962a83
A
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.
41c8faa5 546**********************************************************************/
b3962a83
A
547static Method look_up_method(Class cls, SEL sel,
548 BOOL withCache, BOOL withResolver)
13d88034 549{
b3962a83
A
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;
41c8faa5 565}
13d88034 566
b3962a83 567
13d88034 568/***********************************************************************
b3962a83
A
569* class_getInstanceMethod. Return the instance method for the
570* specified class and selector.
41c8faa5 571**********************************************************************/
b3962a83 572Method class_getInstanceMethod(Class cls, SEL sel)
13d88034 573{
b3962a83
A
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*/);
13d88034
A
578}
579
580/***********************************************************************
b3962a83
A
581* class_getClassMethod. Return the class method for the specified
582* class and selector.
41c8faa5 583**********************************************************************/
b3962a83 584Method class_getClassMethod(Class cls, SEL sel)
13d88034 585{
b3962a83 586 if (!cls || !sel) return NULL;
13d88034 587
b3962a83 588 return class_getInstanceMethod(_class_getMeta(cls), sel);
13d88034
A
589}
590
2bfd4448
A
591
592/***********************************************************************
b3962a83 593* class_getInstanceVariable. Return the named instance variable.
2bfd4448 594**********************************************************************/
b3962a83 595Ivar class_getInstanceVariable(Class cls, const char *name)
2bfd4448 596{
b3962a83
A
597 if (!cls || !name) return NULL;
598
599 return _class_getVariable(cls, name);
2bfd4448
A
600}
601
602
603/***********************************************************************
b3962a83 604* class_getClassVariable. Return the named class variable.
2bfd4448 605**********************************************************************/
b3962a83 606Ivar class_getClassVariable(Class cls, const char *name)
2bfd4448 607{
b3962a83 608 if (!cls) return NULL;
2bfd4448 609
b3962a83 610 return class_getInstanceVariable(((id)cls)->isa, name);
2bfd4448
A
611}
612
613
b3962a83
A
614__private_extern__ Property
615property_list_nth(const struct objc_property_list *plist, uint32_t i)
616{
617 return (Property)(i*plist->entsize + (char *)&plist->first);
13d88034
A
618}
619
b3962a83
A
620__private_extern__ size_t
621property_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 *
627copyPropertyList(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;
2bfd4448 634 }
b3962a83
A
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);
2bfd4448 642 }
b3962a83 643 result[i] = NULL;
13d88034 644 }
b3962a83
A
645
646 if (outCount) *outCount = count;
647 return result;
13d88034
A
648}
649
b3962a83
A
650const char *property_getName(Property prop)
651{
652 return prop->name;
13d88034
A
653}
654
655
b3962a83 656const char *property_getAttributes(Property prop)
2bfd4448 657{
b3962a83 658 return prop->attributes;
2bfd4448
A
659}
660
b3962a83 661
13d88034 662/***********************************************************************
b3962a83
A
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.
41c8faa5 667**********************************************************************/
b3962a83 668void _objc_flush_caches(Class cls)
13d88034 669{
b3962a83 670 flush_caches (cls, YES);
13d88034
A
671}
672
b3962a83 673
13d88034 674/***********************************************************************
b3962a83 675* _freedHandler.
41c8faa5 676**********************************************************************/
b3962a83 677static void _freedHandler(id obj, SEL sel)
13d88034 678{
b3962a83
A
679 __objc_error (obj, "message %s sent to freed object=%p",
680 sel_getName(sel), obj);
13d88034
A
681}
682
683/***********************************************************************
b3962a83 684* _nonexistentHandler.
41c8faa5 685**********************************************************************/
b3962a83 686static void _nonexistentHandler(id obj, SEL sel)
41c8faa5 687{
b3962a83
A
688 __objc_error (obj, "message %s sent to non-existent object=%p",
689 sel_getName(sel), obj);
13d88034
A
690}
691
b3962a83 692
13d88034 693/***********************************************************************
b3962a83 694* class_respondsToSelector.
41c8faa5 695**********************************************************************/
b3962a83 696BOOL class_respondsToMethod(Class cls, SEL sel)
13d88034 697{
b3962a83 698 OBJC_WARN_DEPRECATED;
13d88034 699
b3962a83 700 return class_respondsToSelector(cls, sel);
13d88034
A
701}
702
b3962a83
A
703
704BOOL class_respondsToSelector(Class cls, SEL sel)
13d88034 705{
b3962a83 706 Method meth;
13d88034 707
b3962a83 708 if (!sel || !cls) return NO;
41c8faa5 709
b3962a83
A
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;
41c8faa5 718 }
b3962a83 719}
41c8faa5 720
13d88034
A
721
722/***********************************************************************
b3962a83
A
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.
41c8faa5 726**********************************************************************/
b3962a83 727IMP class_lookupMethod(Class cls, SEL sel)
41c8faa5 728{
b3962a83 729 OBJC_WARN_DEPRECATED;
41c8faa5
A
730
731 // No one responds to zero!
732 if (!sel) {
b3962a83 733 __objc_error(cls, "invalid selector (null)");
41c8faa5 734 }
41c8faa5 735
b3962a83
A
736 return class_getMethodImplementation(cls, sel);
737}
41c8faa5 738
b3962a83
A
739IMP class_getMethodImplementation(Class cls, SEL sel)
740{
741 IMP imp;
41c8faa5 742
b3962a83 743 if (!cls || !sel) return NULL;
13d88034 744
b3962a83
A
745 // fixme _objc_msgForward does not conform to ABI and cannot be
746 // called externally
41c8faa5 747
b3962a83
A
748 imp = _cache_getImp(cls, sel);
749 if (!imp) {
750 // Handle cache miss
751 imp = _class_lookupMethodAndLoadCache (cls, sel);
752 }
753 return imp;
13d88034
A
754}
755
13d88034 756
b3962a83 757IMP class_getMethodImplementation_stret(Class cls, SEL sel)
13d88034 758{
b3962a83
A
759 IMP imp = class_getMethodImplementation(cls, sel);
760 // fixme check for forwarding and use stret forwarder instead
761 return imp;
13d88034
A
762}
763
1f20c7a7 764
b3962a83
A
765// Ignored selectors get method->imp = &_objc_ignored_method
766__private_extern__ id _objc_ignored_method(id self, SEL _cmd) { return self; }
1f20c7a7
A
767
768
769/***********************************************************************
b3962a83 770* instrumentObjcMessageSends/logObjcMessageSends.
1f20c7a7 771**********************************************************************/
b3962a83
A
772static int LogObjCMessageSend (BOOL isClassMethod,
773 const char * objectsClass,
774 const char * implementingClass,
775 SEL selector)
1f20c7a7 776{
b3962a83 777 char buf[ 1024 ];
1f20c7a7 778
b3962a83
A
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;
1f20c7a7
A
789 }
790 }
791
b3962a83
A
792 // Make the log entry
793 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
794 isClassMethod ? '+' : '-',
795 objectsClass,
796 implementingClass,
797 (char *) selector);
1f20c7a7 798
b3962a83 799 write (objcMsgLogFD, buf, strlen(buf));
1f20c7a7 800
b3962a83
A
801 // Tell caller to not cache the method
802 return 0;
1f20c7a7
A
803}
804
b3962a83 805void instrumentObjcMessageSends (BOOL flag)
1f20c7a7 806{
b3962a83 807 int enabledValue = (flag) ? 1 : 0;
1f20c7a7 808
b3962a83
A
809 // Shortcut NOP
810 if (objcMsgLogEnabled == enabledValue)
811 return;
1f20c7a7 812
b3962a83
A
813 // If enabling, flush all method caches so we get some traces
814 if (flag)
815 flush_caches (Nil, YES);
1f20c7a7 816
b3962a83
A
817 // Sync our log file
818 if (objcMsgLogFD != (-1))
819 fsync (objcMsgLogFD);
1f20c7a7 820
b3962a83 821 objcMsgLogEnabled = enabledValue;
1f20c7a7
A
822}
823
b3962a83 824__private_extern__ void logObjcMessageSends (ObjCLogProc logProc)
1f20c7a7 825{
b3962a83
A
826 if (logProc)
827 {
828 objcMsgLogProc = logProc;
829 objcMsgLogEnabled = 1;
830 }
831 else
832 {
833 objcMsgLogProc = logProc;
834 objcMsgLogEnabled = 0;
1f20c7a7
A
835 }
836
b3962a83
A
837 if (objcMsgLogFD != (-1))
838 fsync (objcMsgLogFD);
1f20c7a7
A
839}
840
841
842/***********************************************************************
b3962a83
A
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.
1f20c7a7 847**********************************************************************/
b3962a83
A
848static void
849log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
1f20c7a7 850{
b3962a83 851 BOOL cacheIt = YES;
1f20c7a7 852
b3962a83
A
853 if (objcMsgLogEnabled) {
854 cacheIt = objcMsgLogProc (_class_isMetaClass(implementer) ? YES : NO,
855 _class_getName(cls),
856 _class_getName(implementer),
857 sel);
1f20c7a7 858 }
b3962a83
A
859 if (cacheIt) {
860 _cache_fill (cls, meth, sel);
861 }
1f20c7a7
A
862}
863
864
13d88034 865/***********************************************************************
41c8faa5
A
866* _class_lookupMethodAndLoadCache.
867*
868* Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
869**********************************************************************/
b3962a83 870__private_extern__ IMP _class_lookupMethodAndLoadCache(Class cls, SEL sel)
41c8faa5 871{
b3962a83 872 Class curClass;
1f20c7a7 873 IMP methodPC = NULL;
41c8faa5 874
41c8faa5 875 // Check for freed class
b3962a83 876 if (cls == _class_getFreedObjectClass())
41c8faa5
A
877 return (IMP) _freedHandler;
878
879 // Check for nonexistent class
b3962a83 880 if (cls == _class_getNonexistentObjectClass())
41c8faa5
A
881 return (IMP) _nonexistentHandler;
882
b3962a83
A
883#if __OBJC2__
884 // fixme hack
885 _class_realize(cls);
886#endif
41c8faa5 887
b3962a83
A
888 if (!_class_isInitialized(cls)) {
889 _class_initialize (cls);
890 // If sel == initialize, _class_initialize will send +initialize and
1f20c7a7
A
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 }
41c8faa5 895
41c8faa5
A
896 // Outer loop - search the caches and method lists of the
897 // class and its super-classes
b3962a83 898 for (curClass = cls; curClass; curClass = _class_getSuperclass(curClass))
41c8faa5 899 {
1f20c7a7
A
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.
b3962a83 904 Method meth = _cache_getMethod(curClass, sel, &_objc_msgForward);
1f20c7a7
A
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) {
1f20c7a7 910 _cache_fill (cls, meth, sel);
41c8faa5
A
911 }
912
b3962a83 913 methodPC = method_getImplementation(meth);
41c8faa5
A
914 break;
915 }
916
1f20c7a7 917 // Cache scan failed. Search method list.
41c8faa5 918
b3962a83 919 meth = _class_getMethodNoSuper(curClass, sel);
1f20c7a7 920 if (meth) {
b3962a83
A
921 log_and_fill_cache(cls, curClass, meth, sel);
922 methodPC = method_getImplementation(meth);
1f20c7a7 923 break;
41c8faa5 924 }
41c8faa5
A
925 }
926
b3962a83
A
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 }
41c8faa5 936
b3962a83
A
937 if (methodPC == NULL) {
938 // Class and superclasses do not respond and
939 // resolve handler didn't help -- use forwarding
1f20c7a7 940 _cache_addForwardEntry(cls, sel);
41c8faa5
A
941 methodPC = &_objc_msgForward;
942 }
943
41c8faa5 944 return methodPC;
13d88034
A
945}
946
1f20c7a7 947
2bfd4448
A
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**********************************************************************/
953static 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
b3962a83 962 // Cache miss. Search method list.
41c8faa5 963
b3962a83 964 meth = _class_getMethodNoSuper(cls, sel);
41c8faa5 965
b3962a83
A
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;
41c8faa5 974 }
13d88034
A
975}
976
b3962a83 977
13d88034 978/***********************************************************************
41c8faa5
A
979* _objc_create_zone.
980**********************************************************************/
13d88034
A
981
982void * _objc_create_zone (void)
983{
2bfd4448
A
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();
41c8faa5
A
1003 }
1004 }
2bfd4448 1005 return z;
13d88034
A
1006}
1007
2bfd4448
A
1008
1009/***********************************************************************
1010* _malloc_internal
1011* _calloc_internal
1012* _realloc_internal
1013* _strdup_internal
b3962a83
A
1014* _strdupcat_internal
1015* _memdup_internal
2bfd4448
A
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{
b3962a83 1036 if (!str) return NULL;
2bfd4448
A
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
b3962a83
A
1043// allocate a new string that concatenates s1+s2.
1044__private_extern__ char *_strdupcat_internal(const char *s1, const char *s2)
2bfd4448 1045{
b3962a83
A
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;
2bfd4448
A
1052}
1053
b3962a83 1054__private_extern__ void *_memdup_internal(const void *mem, size_t len)
13d88034 1055{
b3962a83
A
1056 void *dup = malloc_zone_malloc(_objc_internal_zone(), len);
1057 memcpy(dup, mem, len);
1058 return dup;
13d88034 1059}
13d88034 1060
b3962a83 1061__private_extern__ void _free_internal(void *ptr)
13d88034 1062{
b3962a83 1063 malloc_zone_free(_objc_internal_zone(), ptr);
41c8faa5
A
1064}
1065
13d88034 1066
b3962a83 1067const char *class_getName(Class cls)
13d88034 1068{
b3962a83 1069 return _class_getName(cls);
41c8faa5
A
1070}
1071
b3962a83 1072Class class_getSuperclass(Class cls)
41c8faa5 1073{
b3962a83 1074 return _class_getSuperclass(cls);
13d88034 1075}
13d88034 1076
b3962a83 1077BOOL class_isMetaClass(Class cls)
2bfd4448 1078{
b3962a83 1079 return _class_isMetaClass(cls);
2bfd4448
A
1080}
1081
2bfd4448 1082
b3962a83 1083size_t class_getInstanceSize(Class cls)
2bfd4448 1084{
b3962a83 1085 return _class_getInstanceSize(cls);
2bfd4448
A
1086}
1087
b3962a83 1088void method_exchangeImplementations(Method m1, Method m2)
2bfd4448 1089{
b3962a83
A
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));
2bfd4448
A
1095}
1096
1097
1098/***********************************************************************
b3962a83 1099* method_getNumberOfArguments.
2bfd4448 1100**********************************************************************/
b3962a83 1101unsigned int method_getNumberOfArguments(Method m)
2bfd4448 1102{
b3962a83
A
1103 if (!m) return 0;
1104 return encoding_getNumberOfArguments(method_getTypeEncoding(m));
2bfd4448
A
1105}
1106
1107
b3962a83 1108unsigned int method_getSizeOfArguments(Method m)
2bfd4448 1109{
b3962a83
A
1110 OBJC_WARN_DEPRECATED;
1111 if (!m) return 0;
1112 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
2bfd4448
A
1113}
1114
1115
b3962a83
A
1116unsigned int method_getArgumentInfo(Method m, int arg,
1117 const char **type, int *offset)
2bfd4448 1118{
b3962a83
A
1119 OBJC_WARN_DEPRECATED;
1120 if (!m) return 0;
1121 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1122 arg, type, offset);
2bfd4448
A
1123}
1124
1125
b3962a83 1126void method_getReturnType(Method m, char *dst, size_t dst_len)
2bfd4448 1127{
b3962a83 1128 return encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
2bfd4448
A
1129}
1130
1131
b3962a83 1132char * method_copyReturnType(Method m)
13d88034 1133{
b3962a83 1134 return encoding_copyReturnType(method_getTypeEncoding(m));
41c8faa5
A
1135}
1136
41c8faa5 1137
b3962a83
A
1138void method_getArgumentType(Method m, unsigned int index,
1139 char *dst, size_t dst_len)
41c8faa5 1140{
b3962a83
A
1141 return encoding_getArgumentType(method_getTypeEncoding(m),
1142 index, dst, dst_len);
41c8faa5
A
1143}
1144
13d88034 1145
b3962a83 1146char * method_copyArgumentType(Method m, unsigned int index)
13d88034 1147{
b3962a83 1148 return encoding_copyArgumentType(method_getTypeEncoding(m), index);
13d88034
A
1149}
1150
13d88034
A
1151
1152/***********************************************************************
b3962a83
A
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.
41c8faa5 1157**********************************************************************/
b3962a83
A
1158__private_extern__ id
1159_internal_class_createInstanceFromZone(Class cls, size_t extraBytes,
1160 void *zone)
13d88034 1161{
b3962a83
A
1162 id obj;
1163 size_t size;
41c8faa5 1164
b3962a83
A
1165 // Can't create something for nothing
1166 if (!cls) return nil;
41c8faa5 1167
b3962a83
A
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);
41c8faa5 1177 }
b3962a83 1178 if (!obj) return nil;
41c8faa5 1179
b3962a83
A
1180 // Set the isa pointer
1181 obj->isa = cls;
41c8faa5 1182
b3962a83
A
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
41c8faa5 1188 }
b3962a83
A
1189 free(obj);
1190 return nil;
41c8faa5 1191 }
b3962a83
A
1192
1193 return obj;
13d88034
A
1194}
1195
41c8faa5 1196
b3962a83
A
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;
13d88034
A
1210}
1211