]>
Commit | Line | Data |
---|---|---|
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 |
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 *); | |
390d5862 | 188 | |
13d88034 | 189 | |
13d88034 | 190 | /*********************************************************************** |
41c8faa5 A |
191 | * Function prototypes internal to this module. |
192 | **********************************************************************/ | |
13d88034 | 193 | |
41c8faa5 | 194 | static void _freedHandler (id self, SEL sel); |
13d88034 | 195 | static void _nonexistentHandler (id self, SEL sel); |
13d88034 | 196 | static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector); |
2bfd4448 | 197 | static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel); |
b3962a83 A |
198 | static 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 |
206 | typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL); | |
207 | ||
13d88034 A |
208 | static int objcMsgLogFD = (-1); |
209 | static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend; | |
210 | static 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 | **********************************************************************/ | |
227 | Class 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 | **********************************************************************/ | |
237 | Class 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 | 252 | const 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 | 261 | void *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 | ||
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; | |
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 | **********************************************************************/ | |
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 | ||
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 | **********************************************************************/ | |
372 | static 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 | 427 | static 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 | 477 | static 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 | 517 | static 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 |
547 | static 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 | 572 | Method 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 | 584 | Method 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 | 595 | Ivar 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 | 606 | Ivar 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 |
615 | property_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 |
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; | |
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 |
650 | const char *property_getName(Property prop) |
651 | { | |
652 | return prop->name; | |
13d88034 A |
653 | } |
654 | ||
655 | ||
b3962a83 | 656 | const 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 | 668 | void _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 | 677 | static 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 | 686 | static 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 | 696 | BOOL 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 | |
704 | BOOL 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 | 727 | IMP 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 |
739 | IMP 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 | 757 | IMP 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 |
772 | static 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 | 805 | void 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 |
848 | static void |
849 | log_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 | **********************************************************************/ | |
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 | ||
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 | |
982 | void * _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 | 1067 | const char *class_getName(Class cls) |
13d88034 | 1068 | { |
b3962a83 | 1069 | return _class_getName(cls); |
41c8faa5 A |
1070 | } |
1071 | ||
b3962a83 | 1072 | Class class_getSuperclass(Class cls) |
41c8faa5 | 1073 | { |
b3962a83 | 1074 | return _class_getSuperclass(cls); |
13d88034 | 1075 | } |
13d88034 | 1076 | |
b3962a83 | 1077 | BOOL class_isMetaClass(Class cls) |
2bfd4448 | 1078 | { |
b3962a83 | 1079 | return _class_isMetaClass(cls); |
2bfd4448 A |
1080 | } |
1081 | ||
2bfd4448 | 1082 | |
b3962a83 | 1083 | size_t class_getInstanceSize(Class cls) |
2bfd4448 | 1084 | { |
b3962a83 | 1085 | return _class_getInstanceSize(cls); |
2bfd4448 A |
1086 | } |
1087 | ||
b3962a83 | 1088 | void 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 | 1101 | unsigned 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 | 1108 | unsigned 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 |
1116 | unsigned 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 | 1126 | void 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 | 1132 | char * method_copyReturnType(Method m) |
13d88034 | 1133 | { |
b3962a83 | 1134 | return encoding_copyReturnType(method_getTypeEncoding(m)); |
41c8faa5 A |
1135 | } |
1136 | ||
41c8faa5 | 1137 | |
b3962a83 A |
1138 | void 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 | 1146 | char * 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 |