1 /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
10 #import "objc_protocol.h"
11 #import "objc_malloc.h"
13 #import "ObjCModule.h"
15 #import "objc_cache.h"
16 #import <objc/deprecated.h>
17 #import <objc/message.h>
30 //static pthread_mutex_t classTableLock=PTHREAD_MUTEX_INITIALIZER;
32 typedef unsigned int OSSpinLock
;
34 #import <Foundation/NSAtomicCompareAndSwap.h>
36 static objc_lock classTableLock
= 0;
38 #define INITIAL_CLASS_HASHTABLE_SIZE 256
40 static inline OBJCHashTable
*OBJCClassTable(void) {
41 static OBJCHashTable
*allClasses
= NULL
;
43 if(allClasses
== NULL
)
44 allClasses
= OBJCCreateHashTable(INITIAL_CLASS_HASHTABLE_SIZE
);
49 static inline OBJCHashTable
*OBJCFutureClassTable(void) {
50 static OBJCHashTable
*allFutureClasses
= NULL
;
52 if(allFutureClasses
== NULL
)
53 allFutureClasses
= OBJCCreateHashTable(INITIAL_CLASS_HASHTABLE_SIZE
);
55 return allFutureClasses
;
58 id
objc_lookUpClass(const char *className
) {
61 objc_lock_lock(&classTableLock
);
62 result
= OBJCHashValueForKey(OBJCClassTable(), className
);
63 objc_lock_unlock(&classTableLock
);
68 id
objc_lookup_class(const char *className
) {
69 return objc_lookUpClass(className
);
72 id
objc_getClass(const char *name
) {
75 // technically, this should call a class lookup callback if class not found (unlike objc_lookUpClass)
76 objc_lock_lock(&classTableLock
);
77 result
= OBJCHashValueForKey(OBJCClassTable(), name
);
78 objc_lock_unlock(&classTableLock
);
83 int objc_getClassList(Class
*buffer
, int bufferLen
) {
84 objc_lock_lock(&classTableLock
);
85 OBJCHashEnumerator classes
= OBJCEnumerateHashTable(OBJCClassTable());
91 for(; i
< bufferLen
&& (entry
= (Class
)OBJCNextHashEnumeratorValue(&classes
)) != Nil
; i
++)
95 for(; OBJCNextHashEnumeratorValue(&classes
) != 0; i
++)
97 objc_lock_unlock(&classTableLock
);
101 Class
objc_getFutureClass(const char *name
) {
102 // first find if class is already defined
103 struct objc_class
*ret
= OBJCHashValueForKey(OBJCClassTable(), name
);
105 // maybe there's a future class
107 ret
= OBJCHashValueForKey(OBJCFutureClassTable(), name
);
110 // no future class; build one
111 ret
= objc_calloc(1, sizeof(struct objc_class
));
112 ret
->name
= strdup(name
);
113 OBJCHashInsertValueForKey(OBJCFutureClassTable(), ret
->name
, ret
);
118 id
objc_getMetaClass(const char *name
) {
119 Class c
= objc_getClass(name
);
120 return object_getClass(c
);
123 id
objc_getRequiredClass(const char *name
) {
124 id result
= objc_getClass(name
);
132 Protocol
*objc_getProtocol(const char *name
) {
137 Protocol
**objc_copyProtocolList(unsigned int *countp
) {
142 void objc_addClass(Class
class) {
143 OBJCRegisterClass(class);
146 void objc_registerClassPair(Class new_class
) {
147 objc_addClass(new_class
);
150 void objc_setFutureClass(Class cls
, const char *name
) {
151 OBJCHashInsertValueForKey(OBJCFutureClassTable(), strdup(name
), cls
);
154 Class
objc_allocateClassPair(Class super_class
, const char *name
, size_t extraBytes
) {
155 struct objc_class
*meta_class
;
156 struct objc_class
*new_class
;
157 struct objc_class
*root_class
;
159 // Ensure that the superclass exists and that someone
160 // hasn't already implemented a class with the same name
162 if(super_class
== Nil
) {
166 if(objc_lookUpClass(name
) != Nil
) {
170 // Find the root class
172 root_class
= super_class
;
173 while(root_class
->super_class
!= nil
) {
174 root_class
= root_class
->super_class
;
177 // Allocate space for the class and its metaclass
179 new_class
= calloc(2, sizeof(struct objc_class
) + extraBytes
);
180 meta_class
= &new_class
[1];
183 new_class
->isa
= meta_class
;
184 new_class
->info
= CLS_CLASS
;
185 meta_class
->info
= CLS_META
;
187 // Create a copy of the class name.
188 // For efficiency, we have the metaclass and the class itself
189 // to share this copy of the name, but this is not a requirement
190 // imposed by the runtime.
192 new_class
->name
= malloc(strlen(name
) + 1);
193 strcpy((char *)new_class
->name
, name
);
194 meta_class
->name
= new_class
->name
;
196 // Connect the class definition to the class hierarchy:
197 // Connect the class to the superclass.
198 // Connect the metaclass to the metaclass of the superclass.
199 // Connect the metaclass of the metaclass to the metaclass of the root class.
201 new_class
->super_class
= super_class
;
202 meta_class
->super_class
= super_class
->isa
;
203 meta_class
->isa
= (void *)root_class
->isa
;
205 // Set the sizes of the class and the metaclass.
207 new_class
->instance_size
= super_class
->instance_size
;
208 meta_class
->instance_size
= meta_class
->super_class
->instance_size
;
210 // Finally, register the class with the runtime.
215 const char *class_getName(Class cls
) {
219 BOOL
class_isMetaClass(Class
class) {
220 return (class->info
& CLASS_INFO_META
) ? YES
: NO
;
223 Class
class_getSuperclass(Class
class) {
224 struct objc_class
*cls
= class;
225 return cls
->super_class
;
228 int class_getVersion(Class
class) {
229 struct objc_class
*cls
= class;
230 return (int)(cls
->version
); // FIXME: NSObject uses NSInteger (long), object format uses log, API is int. wtf. am I missing something?
233 Method
class_getClassMethod(Class
class, SEL selector
) {
237 return class_getInstanceMethod(class->isa
, selector
);
240 Ivar
class_getClassVariable(Class cls
, const char *name
) {
245 static inline struct objc_method
*OBJCLookupUniqueIdInMethodList(struct objc_method_list
*list
, SEL uniqueId
) {
248 for(i
= 0; i
< list
->method_count
; i
++) {
249 if(((SEL
)list
->method_list
[i
].method_name
) == sel_getSelector(uniqueId
))
250 return list
->method_list
+ i
;
256 struct objc_method
*OBJCLookupUniqueIdInOnlyThisClass(Class
class, SEL uniqueId
) {
258 struct objc_method_list
*check
;
259 struct objc_method
*result
= NULL
;
261 while((check
= class_nextMethodList(class, &iterator
))) {
262 if((result
= OBJCLookupUniqueIdInMethodList(check
, uniqueId
))) {
269 struct objc_method
*class_getInstanceMethod(Class
class, SEL uniqueId
) {
270 struct objc_method
*result
= NULL
;
272 for(; class != NULL
; class = class->super_class
) {
273 if((result
= OBJCLookupUniqueIdInOnlyThisClass(class, uniqueId
)) != NULL
)
279 size_t class_getInstanceSize(Class
class) {
280 struct objc_class
*cls
= class;
281 return cls
->instance_size
;
284 Ivar
class_getInstanceVariable(Class
class, const char *variableName
) {
285 for(;; class = class->super_class
) {
288 struct objc_ivar_list
*ivarList
= class->ivars
;
291 for(i
= 0; ivarList
!= NULL
&& i
< ivarList
->ivar_count
; i
++) {
292 if(strcmp(ivarList
->ivar_list
[i
].ivar_name
, variableName
) == 0)
293 return &(ivarList
->ivar_list
[i
]);
300 const char *class_getIvarLayout(Class cls
) {
305 static inline void OBJCInitializeCacheEntryOffset(OBJCMethodCacheEntry
*entry
) {
306 entry
->offsetToNextEntry
= -((intptr_t)entry
);
309 // FIXME, better allocator
310 static inline OBJCMethodCacheEntry
*allocateCacheEntry() {
311 OBJCMethodCacheEntry
*result
= objc_malloc(sizeof(OBJCMethodCacheEntry
));
313 OBJCInitializeCacheEntryOffset(result
);
318 static inline void OBJCCacheMethodInClass(Class
class, struct objc_method
*method
) {
319 SEL uniqueId
= method
->method_name
;
320 uintptr_t index
= (uintptr_t)uniqueId
& OBJCMethodCacheMask
;
321 OBJCMethodCacheEntry
*check
= ((void *)class->cache
->table
) + index
;
323 if(check
->method
->method_name
== NULL
)
324 check
->method
= method
;
330 check
= ((void *)check
) + offset
;
331 if(method
== check
->method
) {
335 } while(offset
= check
->offsetToNextEntry
, ((void *)check
) + offset
!= NULL
);
337 OBJCMethodCacheEntry
*entry
= allocateCacheEntry();
339 entry
->method
= method
;
341 success
= __sync_bool_compare_and_swap(&check
->offsetToNextEntry
, offset
, ((void *)entry
) - ((void *)check
));
346 static struct objc_method empty_method
= {
349 static int msg_tracing
= 0;
350 static int msgLoggingCount
= 0;
352 OBJC_EXPORT
void objc_enableMessageLoggingWithCount(int count
) {
354 msgLoggingCount
= count
;
356 int i
, capacity
= objc_getClassList(NULL
, 0);
357 Class list
[capacity
];
359 objc_getClassList(list
, capacity
);
361 for(i
= 0; i
< capacity
; i
++) {
362 OBJCMethodCache
*cache
= list
[i
]->cache
;
365 // FIXME: this leaks because it does not free entries in the linked list
367 for(j
= 0; j
< OBJCMethodCacheNumberOfEntries
; j
++) {
368 OBJCInitializeCacheEntryOffset(cache
->table
+ j
);
369 cache
->table
[j
].method
= &empty_method
;
373 OBJCLog("msg tracing ENABLED count=%d", count
);
376 void OBJCEnableMsgTracing() {
377 objc_enableMessageLoggingWithCount(0x7FFFFFFF);
380 void OBJCDisableMsgTracing() {
382 OBJCLog("msg tracing DISABLED");
385 void objc_logMsgSend(id object
, SEL selector
) {
387 if(msgLoggingCount
< 0)
391 objc_log_format("objc_msgSend %x %s self=%p", selector
, sel_getName(selector
), object
);
392 objc_log_format(" isa %x name %s", (object
!= nil
) ? object_getClass(object
) : Nil
, (object
!= nil
) ? object_getClass(object
)->name
: "");
396 void objc_logMsgSendSuper(struct objc_super
*super
, SEL selector
) {
398 if(msgLoggingCount
< 0)
402 objc_log_format("objc_msgSendSuper %x %s", selector
, sel_getName(selector
));
403 id object
= super
->receiver
;
404 objc_log_format("self=%p isa %x name %s", object
, (object
!= nil
) ? object_getClass(object
) : Nil
, (object
!= nil
) ? object_getClass(object
)->name
: "");
408 static inline IMP
OBJCLookupAndCacheUniqueIdInClass(Class
class, SEL selector
) {
409 struct objc_method
*method
;
411 if((method
= class_getInstanceMethod(class, selector
)) != NULL
) {
413 // When msg_tracing is on we don't cache the result so there is always a cache miss
414 // and we always get the chance to log the msg
417 OBJCCacheMethodInClass(class, method
);
419 return method
->method_imp
;
425 void default_handler() {
426 printf("OBJC default handler");
430 void *objc_forwardHandler
= default_handler
;
431 void *objc_forwardHandler_stret
= default_handler
;
433 IMP
class_getMethodImplementation(Class cls
, SEL selector
) {
434 IMP result
= OBJCLookupAndCacheUniqueIdInClass(cls
, selector
);
437 result
= objc_forwardHandler
;
442 IMP
class_getMethodImplementation_stret(Class cls
, SEL selector
) {
443 IMP result
= OBJCLookupAndCacheUniqueIdInClass(cls
, selector
);
446 result
= objc_forwardHandler_stret
;
451 objc_property_t
class_getProperty(Class cls
, const char *name
) {
456 const char *class_getWeakIvarLayout(Class cls
) {
461 Ivar
*class_copyIvarList(Class cls
, unsigned int *countp
) {
463 struct objc_ivar_list
*ivars
= cls
->ivars
;
467 *countp
= ivars
->ivar_count
;
474 result
= malloc(sizeof(Ivar
) * ivars
->ivar_count
);
476 for(int i
= 0; i
< ivars
->ivar_count
; i
++) {
477 result
[i
] = &ivars
->ivar_list
[i
];
484 Method
*class_copyMethodList(Class cls
, unsigned int *countp
) {
487 struct objc_method_list
*list
;
488 Method
*result
= NULL
;
491 while((list
= class_nextMethodList(cls
, &iterator
)) != NULL
) {
492 methodCount
+= list
->method_count
;
496 *countp
= methodCount
;
499 result
= malloc(sizeof(Method
) * methodCount
);
502 while((list
= class_nextMethodList(cls
, &iterator
)) != NULL
) {
503 int mCount
= list
->method_count
;
504 for(int i
= 0; i
< mCount
; i
++) {
505 result
[j
] = &list
->method_list
[i
];
513 objc_property_t
*class_copyPropertyList(Class cls
, unsigned int *countp
) {
514 struct objc_class_extension
*ext
= cls
->ext
;
520 if(ext
->properties
== NULL
) {
525 uint32_t i
, propertyCount
= ext
->properties
->prop_count
;
527 if(propertyCount
== 0) {
532 objc_property_t
*result
= malloc(sizeof(struct objc_property
) * propertyCount
);
534 for(i
= 0; i
< propertyCount
; i
++) {
535 result
[i
] = &(ext
->properties
->prop_list
[i
]);
538 *countp
= propertyCount
;
543 Protocol
**class_copyProtocolList(Class cls
, unsigned int *countp
) {
545 OBJCLog("class_copyProtocolList unimplemented");
550 Class
class_setSuperclass(Class cls
, Class parent
) {
551 Class result
= cls
->super_class
;
552 cls
->super_class
= parent
;
556 void class_setVersion(Class
class, int version
) {
557 struct objc_class
*cls
= class;
558 cls
->version
= version
;
561 void class_setIvarLayout(Class cls
, const char *layout
) {
565 void class_setWeakIvarLayout(Class cls
, const char *layout
) {
569 BOOL
class_addIvar(Class cls
, const char *name
, size_t size
, uint8_t alignment
, const char *type
) {
570 struct objc_ivar_list
*ivars
;
571 struct objc_ivar
*ivar
;
574 char *namecopy
, *typecopy
;
576 if(cls
->info
& CLS_META
) {
579 if(objc_lookUpClass(cls
->name
) != Nil
) {
582 for(class = cls
; (class != Nil
); class = class->super_class
) {
583 ivars
= class->ivars
;
585 for(i
= 0; i
< ivars
->ivar_count
; i
++) {
586 if(strcmp(ivars
->ivar_list
[i
].ivar_name
, name
) == 0) {
587 return NO
; // name exists
593 namecopy
= malloc(strlen(name
) + 1);
594 if(namecopy
== NULL
) {
597 strcpy(namecopy
, name
);
598 typecopy
= malloc(strlen(type
) + 1);
599 if(typecopy
== NULL
) {
606 ivars
= (struct objc_ivar_list
*)malloc(sizeof(struct objc_ivar_list
));
612 ivars
->ivar_count
= 1;
613 ivar
= &(ivars
->ivar_list
[0]);
615 i
= ivars
->ivar_count
;
616 ivars
= (struct objc_ivar_list
*)realloc(ivars
, sizeof(struct objc_ivar_list
) + (i
* sizeof(struct objc_ivar
)));
622 ivars
->ivar_count
= i
+ 1;
623 ivar
= &(ivars
->ivar_list
[i
]);
625 ivar
->ivar_name
= namecopy
;
626 ivar
->ivar_type
= typecopy
;
627 mask
= (1 << alignment
) - 1;
628 i
= (cls
->instance_size
+ mask
) & ~mask
;
629 ivar
->ivar_offset
= i
;
630 cls
->instance_size
= i
+ size
;
636 void class_addMethods(Class
class, struct objc_method_list
*methodList
) {
637 struct objc_method_list
**methodLists
= class->methodLists
;
638 struct objc_method_list
**newLists
= NULL
;
642 // no method list yet: create one
643 newLists
= calloc(sizeof(struct objc_method_list
*), 2);
644 newLists
[0] = methodList
;
646 // we have a method list: measure it out
647 for(i
= 0; methodLists
[i
] != NULL
; i
++) {
649 // allocate new method list array
650 newLists
= calloc(sizeof(struct objc_method_list
*), i
+ 2);
652 newLists
[0] = methodList
;
653 for(i
= 0; methodLists
[i
] != NULL
; i
++) {
654 newLists
[i
+ 1] = methodLists
[i
];
658 class->methodLists
= newLists
;
659 // free old ones (FIXME: thread safety)
664 BOOL
class_addMethod(Class cls
, SEL name
, IMP imp
, const char *types
) {
665 struct objc_method
*newMethod
= calloc(sizeof(struct objc_method
), 1);
666 struct objc_method_list
*methodList
= calloc(sizeof(struct objc_method_list
) + sizeof(struct objc_method
), 1);
667 char *typescopy
= (char *)malloc(strlen(types
) + 1);
669 newMethod
->method_name
= sel_getSelector(name
);
670 strcpy(typescopy
, (char *)types
);
671 newMethod
->method_types
= typescopy
;
672 newMethod
->method_imp
= imp
;
674 methodList
->method_count
= 1;
675 memcpy(methodList
->method_list
, newMethod
, sizeof(struct objc_method
));
677 class_addMethods(cls
, methodList
);
678 return YES
; // TODO: check if method exists
681 BOOL
class_addProtocol(Class cls
, Protocol
*protocol
) {
682 //TODO: check if protocol already exists
684 struct objc_protocol_list
*protocolList
= malloc(sizeof(struct objc_protocol_list
));
685 protocolList
->next
= 0;
686 protocolList
->list
[0] = protocol
;
687 protocolList
->count
= 1;
688 if(cls
->protocols
!= NULL
) {
689 struct objc_protocol_list
*protoList
= cls
->protocols
;
690 struct objc_protocol_list
*lastList
= protoList
;
691 while((protoList
= protoList
->next
) != NULL
) {
692 lastList
= protoList
;
694 lastList
->next
= protocolList
;
696 cls
->protocols
= protocolList
;
702 BOOL
class_conformsToProtocol(Class
class, Protocol
*protocol
) {
707 for(;; class = class->super_class
) {
711 struct objc_protocol_list
*protoList
= class->protocols
;
713 for(; protoList
!= NULL
; protoList
= protoList
->next
) {
716 for(i
= 0; i
< protoList
->count
; i
++) {
717 if(protocol_conformsToProtocol(protoList
->list
[i
], protocol
))
726 id
class_createInstance(Class cls
, size_t extraBytes
) {
730 id obj
= malloc(cls
->instance_size
+ extraBytes
);
735 IMP
class_replaceMethod(Class cls
, SEL selector
, IMP imp
, const char *types
) {
740 BOOL
class_respondsToSelector(Class cls
, SEL selector
) {
741 return (class_getInstanceMethod(cls
, selector
) != NULL
) ? YES
: NO
;
744 static SEL
OBJCRegisterMethod(struct objc_method
*method
) {
745 return sel_registerNameNoCopy((const char *)method
->method_name
);
748 static void OBJCRegisterSelectorsInMethodList(struct objc_method_list
*list
) {
751 for(i
= 0; i
< list
->method_count
; i
++)
752 list
->method_list
[i
].method_name
= OBJCRegisterMethod(list
->method_list
+ i
);
755 static void OBJCRegisterSelectorsInClass(Class
class) {
756 struct objc_method_list
*cur
= NULL
;
758 if(class->info
& CLASS_NO_METHOD_ARRAY
) {
759 // we have been called by via OBJCSymbolTableRegisterClasses; the methodLists pointer really
760 // points to a single method list.
762 // remember direct-style method lists
763 struct objc_method_list
*methodLists
= (struct objc_method_list
*)class->methodLists
;
765 class->methodLists
= NULL
;
766 // just in case this is really an old-style method list setup with a linked list, walk it.
767 for(cur
= methodLists
; cur
; cur
= cur
->obsolete
) {
768 OBJCRegisterSelectorsInMethodList(cur
);
769 class_addMethods(class, cur
);
771 class->info
&= ~CLASS_NO_METHOD_ARRAY
;
773 // this is a properly setup class; just walk through all method lists and register the selectors
775 while((cur
= class_nextMethodList(class, &iterator
))) {
776 OBJCRegisterSelectorsInMethodList(cur
);
781 static void OBJCCreateCacheForClass(Class
class) {
782 if(class->cache
== NULL
) {
785 class->cache
= objc_calloc(1, sizeof(OBJCMethodCache
));
787 for(i
= 0; i
< OBJCMethodCacheNumberOfEntries
; i
++) {
788 OBJCMethodCacheEntry
*entry
= class->cache
->table
+ i
;
789 OBJCInitializeCacheEntryOffset(entry
);
790 entry
->method
= &empty_method
;
795 void OBJCRegisterClass(Class
class) {
798 struct objc_class
*futureClass
= OBJCHashValueForKey(OBJCFutureClassTable(), class->name
);
801 memcpy(futureClass
, class, sizeof(struct objc_class
));
806 objc_lock_lock(&classTableLock
);
807 OBJCHashInsertValueForKey(OBJCClassTable(), class->name
, class);
808 objc_lock_unlock(&classTableLock
);
810 OBJCRegisterSelectorsInClass(class);
811 OBJCRegisterSelectorsInClass(class->isa
);
814 struct objc_protocol_list
*protocols
;
816 for(protocols
= class->protocols
; protocols
!= NULL
; protocols
= protocols
->next
) {
819 for(i
= 0; i
< protocols
->count
; i
++) {
820 OBJCProtocolTemplate
*template = (OBJCProtocolTemplate
*)protocols
->list
[i
];
822 OBJCRegisterProtocol(template);
827 OBJCCreateCacheForClass(class);
828 OBJCCreateCacheForClass(class->isa
);
830 if(class->super_class
== NULL
) {
832 class->isa
->isa
= class->isa
;
833 class->isa
->super_class
= class;
834 class->info
|= CLASS_INFO_LINKED
;
838 static void OBJCAppendMethodListToClass(Class
class, struct objc_method_list
*methodList
) {
839 OBJCRegisterSelectorsInMethodList(methodList
);
840 class_addMethods(class, methodList
);
843 void OBJCRegisterCategoryInClass(Category category
, Class
class) {
844 struct objc_protocol_list
*protos
;
846 if(category
->instanceMethods
!= NULL
)
847 OBJCAppendMethodListToClass(class, category
->instanceMethods
);
848 if(category
->classMethods
!= NULL
)
849 OBJCAppendMethodListToClass(class->isa
, category
->classMethods
);
851 for(protos
= category
->protocols
; protos
!= NULL
; protos
= protos
->next
) {
854 for(i
= 0; i
< protos
->count
; i
++) {
855 OBJCRegisterProtocol((OBJCProtocolTemplate
*)protos
->list
[i
]);
856 //add protocols from category to class
857 class_addProtocol(class, protos
->list
[i
]);
862 static void OBJCLinkClass(Class
class) {
863 if(!(class->info
& CLASS_INFO_LINKED
)) {
864 Class superClass
= (class->super_class
== NULL
) ? NULL
: objc_lookUpClass((const char *)class->super_class
);
865 Class metaRoot
= (class->isa
->isa
== NULL
) ? NULL
: objc_lookUpClass((const char *)class->isa
->isa
);
867 if(superClass
!= NULL
) {
868 class->super_class
= superClass
;
869 class->info
|= CLASS_INFO_LINKED
;
870 class->isa
->super_class
= class->super_class
->isa
;
871 class->isa
->info
|= CLASS_INFO_LINKED
;
872 class->isa
->isa
= (metaRoot
== NULL
) ? NULL
: metaRoot
->isa
;
877 void OBJCLinkClassTable(void) {
878 OBJCHashTable
*hashTable
= OBJCClassTable();
880 OBJCHashEnumerator state
= OBJCEnumerateHashTable(hashTable
);
882 while((class = OBJCNextHashEnumeratorValue(&state
)) != Nil
)
883 OBJCLinkClass(class);
886 void OBJCInitializeClass(Class
class) {
887 if(!(class->info
& CLASS_INFO_INITIALIZED
)) {
888 if(class->super_class
!= NULL
)
889 OBJCInitializeClass(class->super_class
);
891 if(!(class->info
& CLASS_INFO_INITIALIZED
)) {
892 static SEL selector
= NULL
;
895 selector
= sel_getUid("initialize");
897 /* "If a particular class does not implement initialize, the initialize
898 method of its superclass is invoked twice, once for the superclass and
899 once for the non-implementing subclass." */
900 struct objc_method
*method
= class_getClassMethod(class, selector
);
902 class->info
|= CLASS_INFO_INITIALIZED
;
903 class->isa
->info
|= CLASS_INFO_INITIALIZED
;
906 method
->method_imp((id
) class, selector
);
911 void objc_setForwardHandler(void *handler
, void *handler_stret
) {
912 objc_forwardHandler
= handler
;
913 objc_forwardHandler_stret
= handler_stret
;
916 IMP
OBJCLookupAndCacheUniqueIdForSuper(struct objc_super
*super
, SEL selector
) {
918 objc_logMsgSendSuper(super
, selector
);
920 IMP result
= class_getMethodImplementation(super
->super_class
, selector
);
925 IMP
OBJCInitializeLookupAndCacheUniqueIdForObject(id object
, SEL selector
) {
927 objc_logMsgSend(object
, selector
);
929 Class
class = object
->isa
;
931 if(!(class->info
& CLASS_INFO_INITIALIZED
)) {
932 Class checkInit
= (class->info
& CLASS_INFO_META
) ? (Class
)object
: class;
933 OBJCInitializeClass(checkInit
);
936 IMP result
= class_getMethodImplementation(class, selector
);
941 struct objc_method_list
*class_nextMethodList(Class
class, void **iterator
) {
942 int *it
= (int *)iterator
;
943 struct objc_method_list
*ret
= NULL
;
944 if(!class->methodLists
)
947 ret
= class->methodLists
[*it
];