Merge pull request #10 from gunyarakun/fix-invalid-return
[cocotron.git] / objc / objc_class.c
blob1d7367455a12e90a0164f0126ccb183bf80627e8
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. */
8 #import "objc_class.h"
9 #import "objc_sel.h"
10 #import "objc_protocol.h"
11 #import "objc_malloc.h"
12 #import "objc_log.h"
13 #import "ObjCModule.h"
14 #import <stdio.h>
15 #import "objc_cache.h"
16 #import <objc/deprecated.h>
17 #import <objc/message.h>
18 #import "objc_lock.h"
20 #ifdef SOLARIS
21 #import <stdarg.h>
22 #endif
24 #ifndef WIN32
25 #include <unistd.h>
26 #endif
28 #import <pthread.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);
46 return allClasses;
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) {
59 id result;
61 objc_lock_lock(&classTableLock);
62 result = OBJCHashValueForKey(OBJCClassTable(), className);
63 objc_lock_unlock(&classTableLock);
65 return result;
68 id objc_lookup_class(const char *className) {
69 return objc_lookUpClass(className);
72 id objc_getClass(const char *name) {
73 id result;
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);
80 return result;
83 int objc_getClassList(Class *buffer, int bufferLen) {
84 objc_lock_lock(&classTableLock);
85 OBJCHashEnumerator classes = OBJCEnumerateHashTable(OBJCClassTable());
86 int i = 0;
88 if(buffer != NULL) {
89 Class entry;
91 for(; i < bufferLen && (entry = (Class)OBJCNextHashEnumeratorValue(&classes)) != Nil; i++)
92 buffer[i] = entry;
95 for(; OBJCNextHashEnumeratorValue(&classes) != 0; i++)
97 objc_lock_unlock(&classTableLock);
98 return i;
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
106 if(!ret) {
107 ret = OBJCHashValueForKey(OBJCFutureClassTable(), name);
109 if(!ret) {
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);
115 return 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);
126 if(result == Nil)
127 exit(1);
129 return result;
132 Protocol *objc_getProtocol(const char *name) {
133 // UNIMPLEMENTED
134 return NULL;
137 Protocol **objc_copyProtocolList(unsigned int *countp) {
138 // UNIMPLEMENTED
139 return NULL;
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) {
163 return Nil;
166 if(objc_lookUpClass(name) != Nil) {
167 return 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];
182 // setup class
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.
212 return new_class;
215 const char *class_getName(Class cls) {
216 return cls->name;
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) {
234 if(class == Nil) {
235 return NULL;
237 return class_getInstanceMethod(class->isa, selector);
240 Ivar class_getClassVariable(Class cls, const char *name) {
241 // UNIMPLEMENTED
242 return NULL;
245 static inline struct objc_method *OBJCLookupUniqueIdInMethodList(struct objc_method_list *list, SEL uniqueId) {
246 int i;
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;
253 return NULL;
256 struct objc_method *OBJCLookupUniqueIdInOnlyThisClass(Class class, SEL uniqueId) {
257 void *iterator = 0;
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))) {
263 return result;
266 return NULL;
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)
274 break;
276 return result;
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) {
286 if(class == Nil)
287 break;
288 struct objc_ivar_list *ivarList = class->ivars;
289 int i;
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]);
297 return NULL;
300 const char *class_getIvarLayout(Class cls) {
301 // UNIMPLEMENTED
302 return NULL;
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);
315 return 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;
325 else {
326 BOOL success = NO;
327 while(!success) {
328 intptr_t offset = 0;
329 do {
330 check = ((void *)check) + offset;
331 if(method == check->method) {
332 // already cached
333 return;
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 = {
347 0, NULL, NULL};
349 static int msg_tracing = 0;
350 static int msgLoggingCount = 0;
352 OBJC_EXPORT void objc_enableMessageLoggingWithCount(int count) {
353 msg_tracing = 1;
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;
363 int j;
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() {
381 msg_tracing = 0;
382 OBJCLog("msg tracing DISABLED");
385 void objc_logMsgSend(id object, SEL selector) {
386 msgLoggingCount--;
387 if(msgLoggingCount < 0)
388 msg_tracing = 0;
390 objc_log_threadid();
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 : "");
393 objc_log_newline();
396 void objc_logMsgSendSuper(struct objc_super *super, SEL selector) {
397 msgLoggingCount--;
398 if(msgLoggingCount < 0)
399 msg_tracing = 0;
401 objc_log_threadid();
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 : "");
405 objc_log_newline();
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
416 if(!msg_tracing)
417 OBJCCacheMethodInClass(class, method);
419 return method->method_imp;
422 return NULL;
425 void default_handler() {
426 printf("OBJC default handler");
427 exit(1);
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);
436 if(result == NULL)
437 result = objc_forwardHandler;
439 return result;
442 IMP class_getMethodImplementation_stret(Class cls, SEL selector) {
443 IMP result = OBJCLookupAndCacheUniqueIdInClass(cls, selector);
445 if(result == NULL)
446 result = objc_forwardHandler_stret;
448 return result;
451 objc_property_t class_getProperty(Class cls, const char *name) {
452 // UNIMPLEMENTED
453 return NULL;
456 const char *class_getWeakIvarLayout(Class cls) {
457 // UNIMPLEMENTED
458 return NULL;
461 Ivar *class_copyIvarList(Class cls, unsigned int *countp) {
462 Ivar *result = NULL;
463 struct objc_ivar_list *ivars = cls->ivars;
465 if(countp != NULL) {
466 if(ivars != NULL) {
467 *countp = ivars->ivar_count;
468 } else {
469 *countp = 0;
473 if(ivars != NULL) {
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];
481 return result;
484 Method *class_copyMethodList(Class cls, unsigned int *countp) {
485 int methodCount = 0;
486 void *iterator = 0;
487 struct objc_method_list *list;
488 Method *result = NULL;
489 int j = 0;
491 while((list = class_nextMethodList(cls, &iterator)) != NULL) {
492 methodCount += list->method_count;
495 if(countp != NULL) {
496 *countp = methodCount;
499 result = malloc(sizeof(Method) * methodCount);
500 iterator = 0;
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];
506 j++;
510 return result;
513 objc_property_t *class_copyPropertyList(Class cls, unsigned int *countp) {
514 struct objc_class_extension *ext = cls->ext;
516 if(ext == NULL) {
517 *countp = 0;
518 return NULL;
520 if(ext->properties == NULL) {
521 *countp = 0;
522 return NULL;
525 uint32_t i, propertyCount = ext->properties->prop_count;
527 if(propertyCount == 0) {
528 *countp = 0;
529 return NULL;
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;
540 return result;
543 Protocol **class_copyProtocolList(Class cls, unsigned int *countp) {
544 *countp = 0;
545 OBJCLog("class_copyProtocolList unimplemented");
546 // UNIMPLEMENTED
547 return NULL;
550 Class class_setSuperclass(Class cls, Class parent) {
551 Class result = cls->super_class;
552 cls->super_class = parent;
553 return result;
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) {
562 // UNIMPLEMENTED
565 void class_setWeakIvarLayout(Class cls, const char *layout) {
566 // UNIMPLEMENTED
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;
572 Class class;
573 int i, mask;
574 char *namecopy, *typecopy;
576 if(cls->info & CLS_META) {
577 return NO;
579 if(objc_lookUpClass(cls->name) != Nil) {
580 return NO;
582 for(class = cls; (class != Nil); class = class->super_class) {
583 ivars = class->ivars;
584 if(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) {
595 return NO;
597 strcpy(namecopy, name);
598 typecopy = malloc(strlen(type) + 1);
599 if(typecopy == NULL) {
600 free(namecopy);
601 return NO;
603 ivars = cls->ivars;
605 if(ivars == NULL) {
606 ivars = (struct objc_ivar_list *)malloc(sizeof(struct objc_ivar_list));
607 if(ivars == NULL) {
608 free(namecopy);
609 free(typecopy);
610 return NO;
612 ivars->ivar_count = 1;
613 ivar = &(ivars->ivar_list[0]);
614 } else {
615 i = ivars->ivar_count;
616 ivars = (struct objc_ivar_list *)realloc(ivars, sizeof(struct objc_ivar_list) + (i * sizeof(struct objc_ivar)));
617 if(ivars == NULL) {
618 free(namecopy);
619 free(typecopy);
620 return NO;
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;
631 cls->ivars = ivars;
633 return YES;
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;
639 int i;
641 if(!methodLists) {
642 // no method list yet: create one
643 newLists = calloc(sizeof(struct objc_method_list *), 2);
644 newLists[0] = methodList;
645 } else {
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);
651 // copy over
652 newLists[0] = methodList;
653 for(i = 0; methodLists[i] != NULL; i++) {
654 newLists[i + 1] = methodLists[i];
657 // set new lists
658 class->methodLists = newLists;
659 // free old ones (FIXME: thread safety)
660 if(methodLists)
661 free(methodLists);
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));
676 free(newMethod);
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;
695 } else {
696 cls->protocols = protocolList;
699 return YES;
702 BOOL class_conformsToProtocol(Class class, Protocol *protocol) {
704 if(class == Nil) {
705 return NO;
707 for(;; class = class->super_class) {
708 if(class == Nil)
709 break;
711 struct objc_protocol_list *protoList = class->protocols;
713 for(; protoList != NULL; protoList = protoList->next) {
714 int i;
716 for(i = 0; i < protoList->count; i++) {
717 if(protocol_conformsToProtocol(protoList->list[i], protocol))
718 return YES;
723 return NO;
726 id class_createInstance(Class cls, size_t extraBytes) {
727 if(Nil == cls) {
728 return nil;
730 id obj = malloc(cls->instance_size + extraBytes);
731 obj->isa = cls;
732 return obj;
735 IMP class_replaceMethod(Class cls, SEL selector, IMP imp, const char *types) {
736 // UNIMPLEMENTED
737 return NULL;
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) {
749 int i;
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;
772 } else {
773 // this is a properly setup class; just walk through all method lists and register the selectors
774 void *iterator = 0;
775 while((cur = class_nextMethodList(class, &iterator))) {
776 OBJCRegisterSelectorsInMethodList(cur);
781 static void OBJCCreateCacheForClass(Class class) {
782 if(class->cache == NULL) {
783 int i;
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);
800 if(futureClass) {
801 memcpy(futureClass, class, sizeof(struct objc_class));
802 class = futureClass;
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) {
817 unsigned i;
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) {
831 // Root class
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) {
852 unsigned i;
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();
879 Class class;
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;
894 if(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;
905 if(method != NULL)
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) {
917 if(msg_tracing)
918 objc_logMsgSendSuper(super, selector);
920 IMP result = class_getMethodImplementation(super->super_class, selector);
922 return result;
925 IMP OBJCInitializeLookupAndCacheUniqueIdForObject(id object, SEL selector) {
926 if(msg_tracing)
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);
938 return result;
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)
945 return NULL;
947 ret = class->methodLists[*it];
948 *it = *it + 1;
950 return ret;