Merge pull request #10 from gunyarakun/fix-invalid-return
[cocotron.git] / objc / ObjCModule.c
blob02914fa11cb933080e0820932d746296693e3820
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 "ObjCModule.h"
9 #import "objc_class.h"
10 #import "objc_sel.h"
11 #import "objc_log.h"
12 #import "objc_malloc.h"
13 #import "objc_protocol.h"
14 #if defined(__APPLE__)
15 #import "OBJCRegisterModule_Darwin.h"
16 #endif
18 #import <string.h>
20 #define INITIAL_CLASS_ARRAY_SIZE 512
22 #ifdef SOLARIS
23 #import <stdio.h>
24 #define PATH_MAX 1024
25 #endif
27 #ifdef WIN32
28 // #import <windows.h>
29 #else
30 #define __USE_GNU // for dladdr()
31 #import <dlfcn.h>
32 #import <unistd.h>
33 #import <sys/param.h>
34 #import <limits.h>
35 #endif
36 #ifdef BSD
37 #import <sys/sysctl.h>
38 #endif
40 static Class *unresolvedClasses = NULL;
41 static int unresolvedClassesSize = 0;
42 static Class *sentLoadMessageClasses = NULL;
43 static int sentLoadMessageClassesSize = 0;
45 static OBJCArray *OBJCObjectFileImageArray(void) {
46 static OBJCArray *objectFileImageArray = NULL;
48 if(objectFileImageArray == NULL)
49 objectFileImageArray = OBJCArrayNew();
51 return objectFileImageArray;
54 static OBJCObjectFile *OBJCObjectFileWithPath(const char *path) {
55 OBJCObjectFile *result = objc_calloc(1, sizeof(OBJCObjectFile));
57 result->path = objc_calloc(strlen(path) + 1, sizeof(char));
58 strcpy(result->path, path);
59 result->moduleArray = OBJCArrayNew();
61 return result;
64 OBJCObjectFile *OBJCUniqueObjectFileWithPath(const char *path) {
65 OBJCObjectFile *result;
66 OBJCArray *array = OBJCObjectFileImageArray();
67 unsigned long arrayIndex = 0;
69 while((result = OBJCArrayEnumerate(array, &arrayIndex)) != NULL) {
70 if(strcmp(result->path, path) == 0)
71 return result;
74 result = OBJCObjectFileWithPath(path);
76 OBJCArrayAdd(array, result);
78 return result;
81 OBJCObjectFile *OBJCObjectFileForPointer(void *ptr) {
82 #ifdef WIN32
83 // GetModuleHandleEx would work here, but it is only available on XP and above
84 return NULL;
85 #else
86 Dl_info info;
88 if(!dladdr(ptr, &info)) {
89 OBJCRaiseException("OBJCInternalInconsistencyException", "Can't resolve object file image for module");
90 return NULL;
93 return OBJCUniqueObjectFileWithPath(info.dli_fname);
94 #endif
97 void OBJCInitializeProcess() {
98 #if defined(__APPLE__)
99 OBJCRegisterModule_Darwin(NULL);
100 #endif
103 OBJCObjectFile *OBJCMainObjectFile() {
104 static OBJCObjectFile *mainObjectFile = NULL;
106 if(mainObjectFile == NULL) {
107 uint32_t length = 0;
109 _NSGetExecutablePath(NULL, &length);
111 char path[length + 1];
113 if(_NSGetExecutablePath(path, &length) < 0)
114 path[0] = '\0';
115 else
116 path[length] = '\0';
118 mainObjectFile = OBJCUniqueObjectFileWithPath(path);
121 return mainObjectFile;
124 void OBJCLinkModuleToActiveObjectFile(OBJCModule *module) {
125 OBJCObjectFile *objectFile = OBJCObjectFileForPointer(module);
127 if(objectFile == NULL)
128 objectFile = OBJCMainObjectFile();
130 if(objectFile != NULL)
131 OBJCArrayAdd(objectFile->moduleArray, module);
134 static OBJCArray *OBJCModuleQueueWithReset(BOOL reset) {
135 static OBJCArray *ownershipQueue = NULL;
136 OBJCArray *result;
138 if(ownershipQueue == NULL)
139 ownershipQueue = OBJCArrayNew();
141 result = ownershipQueue;
143 if(reset)
144 ownershipQueue = NULL;
146 return result;
149 static OBJCArray *OBJCModuleQueue() {
150 return OBJCModuleQueueWithReset(NO);
153 static void OBJCSymbolTableRegisterSelectors(OBJCSymbolTable *symbolTable) {
154 objc_selector_internal *selectorReferences = symbolTable->selectorReferences;
156 if(selectorReferences != NULL) {
157 while(objc_getSelectorReferenceName(selectorReferences) != NULL) {
158 objc_setSelectorReferenceName(&selectorReferences, sel_registerNameNoCopy(objc_getSelectorReferenceName(selectorReferences)));
159 selectorReferences++;
164 void OBJCAddToUnResolvedClasses(Class class) {
165 Class superClass = class->super_class;
167 //check for root object
168 if(superClass) {
169 for(int i = 0; i < unresolvedClassesSize; i++) {
170 Class currentClass = unresolvedClasses[i];
171 if(currentClass == NULL || currentClass == (Class)-1) {
172 unresolvedClasses[i] = class;
173 return;
176 int newCSize = 0;
177 if(unresolvedClassesSize == 0) {
178 newCSize = INITIAL_CLASS_ARRAY_SIZE;
179 } else {
180 newCSize = 2 * unresolvedClassesSize;
182 unresolvedClasses = (Class *)realloc(unresolvedClasses, newCSize * sizeof(Class));
184 for(int i = unresolvedClassesSize; i < newCSize; i++) {
185 unresolvedClasses[i] = NULL;
187 unresolvedClasses[unresolvedClassesSize] = class;
189 unresolvedClassesSize = newCSize;
193 BOOL OBJCCheckClassIsResolved(Class class) {
194 if(class->super_class == 0) {
195 //root object
196 return YES;
199 Class superClass;
200 if(!(class->info & CLASS_INFO_LINKED)) {
201 return NO;
202 } else {
203 superClass = class_getSuperclass(class);
206 if(superClass != Nil) {
207 return OBJCCheckClassIsResolved(superClass);
208 } else {
209 return NO;
212 void OBJCSendLoadMessage(Class class) {
214 int i = 0;
216 for(; i < sentLoadMessageClassesSize; i++) {
217 if(sentLoadMessageClasses[i] == NULL) {
218 break;
219 } else if(sentLoadMessageClasses[i] == class) {
220 //message already sent
221 return;
225 if(class->super_class != 0) {
226 //send load first to the superclass
227 OBJCSendLoadMessage(class->super_class);
230 //check for space and increase size if neeeded
231 if(i == sentLoadMessageClassesSize) {
232 int newCSize = 0;
233 if(sentLoadMessageClassesSize == 0) {
234 newCSize = INITIAL_CLASS_ARRAY_SIZE;
235 } else {
236 newCSize = 2 * sentLoadMessageClassesSize;
238 sentLoadMessageClasses = (Class *)realloc(sentLoadMessageClasses, newCSize * sizeof(Class));
239 for(int j = sentLoadMessageClassesSize; j < newCSize; j++) {
240 sentLoadMessageClasses[j] = NULL;
242 sentLoadMessageClasses[sentLoadMessageClassesSize] = class;
243 sentLoadMessageClassesSize = newCSize;
244 } else {
245 sentLoadMessageClasses[i] = class;
248 SEL loadSelector = sel_registerName("load");
249 Method m = class_getClassMethod(class, loadSelector);
250 if(m) {
251 IMP imp = method_getImplementation(m);
252 if(imp) {
253 (*imp)((id) class, loadSelector);
257 void OBJCSendLoadMessages() {
259 //until NSObject is not in runtime we don't need to check
260 if(objc_lookUpClass("NSObject") == Nil) {
261 return;
264 for(int i = 0; i < unresolvedClassesSize; i++) {
265 Class class = unresolvedClasses[i];
266 if(class == NULL) {
267 continue;
270 if(OBJCCheckClassIsResolved(class) == YES) {
271 //remove it from unresolved
272 unresolvedClasses[i] = NULL;
273 } else {
274 //still unresolved classes, wait for more classes
275 return;
279 int i, capacity = objc_getClassList(NULL, 0);
280 Class list[capacity];
282 objc_getClassList(list, capacity);
284 for(i = 0; i < capacity; i++) {
286 OBJCSendLoadMessage(list[i]);
290 static void OBJCSymbolTableRegisterClasses(OBJCSymbolTable *symbolTable) {
291 unsigned i, count = symbolTable->classCount;
293 for(i = 0; i < count; i++) {
294 struct objc_class *class = (struct objc_class *)symbolTable->definitions[i];
296 // mark class and metaclass as having a direct method list pointer
297 class->info |= CLASS_NO_METHOD_ARRAY;
298 class->isa->info |= CLASS_NO_METHOD_ARRAY;
300 OBJCRegisterClass(class);
301 OBJCAddToUnResolvedClasses(class);
303 if(strcmp(class_getName(class), "Protocol") == 0) {
304 // Fix protocol classes where isa is not yet set. This is the case for all
305 // classes loaded before Protocol class is loaded.
306 int i, capacity = objc_getClassList(NULL, 0);
307 Class list[capacity];
309 objc_getClassList(list, capacity);
311 for(i = 0; i < capacity; i++) {
312 Class class = list[i];
313 struct objc_protocol_list *protocols;
315 for(protocols = class->protocols; protocols != NULL; protocols = protocols->next) {
316 unsigned i;
318 for(i = 0; i < protocols->count; i++) {
319 OBJCProtocolTemplate *template = (OBJCProtocolTemplate *)protocols->list[i];
321 OBJCRegisterProtocol(template);
329 static void OBJCSymbolTableRegisterCategories(OBJCSymbolTable *symbolTable) {
330 static OBJCArray *unlinkedCategories = NULL;
332 unsigned offset = symbolTable->classCount;
333 unsigned i, count = symbolTable->categoryCount;
335 if(unlinkedCategories != NULL && objc_lookUpClass("Protocol") != Nil) {
336 int unlinkedIndex = unlinkedCategories->count;
338 while(--unlinkedIndex >= 0) {
339 Category category = OBJCArrayItemAtIndex(unlinkedCategories, unlinkedIndex);
340 Class class = (Class)objc_lookUpClass(category->className);
342 if(class != Nil) {
343 OBJCRegisterCategoryInClass(category, class);
344 OBJCArrayRemoveItemAtIndex(unlinkedCategories, unlinkedIndex);
349 for(i = 0; i < count; i++) {
350 Category category = (Category)symbolTable->definitions[offset + i];
351 Class class = (Class)objc_lookUpClass(category->className);
353 if(class != Nil && objc_lookUpClass("Protocol") != Nil)
354 OBJCRegisterCategoryInClass(category, class);
355 else {
356 if(unlinkedCategories == NULL)
357 unlinkedCategories = OBJCArrayNew();
359 OBJCArrayAdd(unlinkedCategories, category);
364 // GNU style for now
365 static void OBJCSymbolTableRegisterStringsIfNeeded(OBJCSymbolTable *symbolTable) {
366 static OBJCArray *unlinkedObjects = NULL;
368 unsigned long offset = symbolTable->classCount + symbolTable->categoryCount;
369 OBJCStaticInstanceList **listOfLists = symbolTable->definitions[offset];
371 if(unlinkedObjects != NULL) {
372 int count = unlinkedObjects->count;
374 while(--count >= 0) {
375 OBJCStaticInstanceList *staticInstances = OBJCArrayItemAtIndex(unlinkedObjects, count);
376 Class class = (Class)objc_lookUpClass(staticInstances->name);
378 if(class != Nil) {
379 unsigned i;
381 for(i = 0; staticInstances->instances[i] != nil; i++)
382 object_setClass(staticInstances->instances[i], class);
384 OBJCArrayRemoveItemAtIndex(unlinkedObjects, count);
389 if(listOfLists != NULL) {
390 for(; *listOfLists != NULL; listOfLists++) {
391 OBJCStaticInstanceList *staticInstances = *listOfLists;
392 Class class = (Class)objc_lookUpClass(staticInstances->name);
393 unsigned i;
395 if(class != Nil) {
396 for(i = 0; staticInstances->instances[i] != nil; i++)
397 object_setClass(staticInstances->instances[i], class);
398 } else {
399 if(unlinkedObjects == NULL)
400 unlinkedObjects = OBJCArrayNew();
402 OBJCArrayAdd(unlinkedObjects, staticInstances);
408 static void OBJCSymbolTableRegisterProtocolsIfNeeded(OBJCSymbolTable *symbolTable) {
409 // FIX or address issue
410 #if 0
411 // this needs to handle unknown protocol class
412 unsigned offset=symbolTable->classCount+symbolTable->categoryCount+symbolTable->objectDefCount;
413 unsigned i,count=symbolTable->protocolDefCount;
415 for(i=0;i<count;i++){
416 OBJCProtocolTemplate *template=(OBJCProtocolTemplate *)symbolTable->definitions[offset+i];
417 OBJCRegisterProtocol(template);
419 #endif
422 void OBJCQueueModule(OBJCModule *module) {
423 if(module->symbolTable != NULL) {
424 OBJCArrayAdd(OBJCModuleQueue(), module);
425 OBJCLinkModuleToActiveObjectFile(module);
426 OBJCSymbolTableRegisterSelectors(module->symbolTable);
427 OBJCSymbolTableRegisterClasses(module->symbolTable);
428 OBJCSymbolTableRegisterCategories(module->symbolTable);
429 #if !defined(__APPLE__)
430 OBJCSymbolTableRegisterStringsIfNeeded(module->symbolTable);
431 OBJCSymbolTableRegisterProtocolsIfNeeded(module->symbolTable);
432 #endif
433 OBJCLinkClassTable();
435 #if !defined(__APPLE__)
436 OBJCSendLoadMessages();
437 #endif
441 void OBJCResetModuleQueue(void) {
442 OBJCArray *queue = OBJCModuleQueueWithReset(YES);
444 OBJCArrayDealloc(queue);
447 void OBJCLinkQueuedModulesToObjectFileWithPath(const char *path) {
448 OBJCObjectFile *objectFile = OBJCUniqueObjectFileWithPath(path);
449 OBJCArray *queue = OBJCModuleQueueWithReset(YES);
450 OBJCModule *module;
451 unsigned long state = 0;
453 while((module = OBJCArrayEnumerate(queue, &state)) != NULL)
454 OBJCArrayAdd(objectFile->moduleArray, module);
456 OBJCArrayDealloc(queue);
459 OBJCObjectFile *OBJCObjectFileFromClass(Class class) {
460 OBJCArray *array = OBJCObjectFileImageArray();
461 int count = array->count;
463 while(--count >= 0) {
464 OBJCObjectFile *objectFile = OBJCArrayItemAtIndex(array, count);
465 OBJCModule *module;
466 unsigned long moduleIndex = 0;
468 while((module = OBJCArrayEnumerate(objectFile->moduleArray, &moduleIndex)) != NULL) {
469 unsigned classIndex;
471 if(module->symbolTable != NULL) {
472 for(classIndex = 0; classIndex < module->symbolTable->classCount; classIndex++) {
473 if(module->symbolTable->definitions[classIndex] == class) {
474 return objectFile;
481 return NULL;
484 const char *class_getImageName(Class cls) {
485 OBJCObjectFile *file = OBJCObjectFileFromClass(cls);
487 if(file)
488 return file->path;
490 return NULL;
493 const char *objc_mainImageName() {
494 OBJCObjectFile *file = OBJCMainObjectFile();
496 if(file != NULL)
497 return file->path;
499 return NULL;
502 const char **objc_copyImageNames(unsigned *countp) {
503 OBJCArray *array = OBJCObjectFileImageArray();
504 unsigned long arrayIndex = 0, count = OBJCArrayCount(array);
505 const char **result = malloc(count * sizeof(char *));
506 OBJCObjectFile *objectFile;
508 while((objectFile = OBJCArrayEnumerate(array, &arrayIndex)) != NULL)
509 result[arrayIndex - 1] = objectFile->path;
511 *countp = count;
513 return result;