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. */
12 #import "objc_malloc.h"
13 #import "objc_protocol.h"
14 #if defined(__APPLE__)
15 #import "OBJCRegisterModule_Darwin.h"
20 #define INITIAL_CLASS_ARRAY_SIZE 512
28 // #import <windows.h>
30 #define __USE_GNU // for dladdr()
37 #import <sys/sysctl.h>
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();
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)
74 result
= OBJCObjectFileWithPath(path
);
76 OBJCArrayAdd(array
, result
);
81 OBJCObjectFile
*OBJCObjectFileForPointer(void *ptr
) {
83 // GetModuleHandleEx would work here, but it is only available on XP and above
88 if(!dladdr(ptr
, &info
)) {
89 OBJCRaiseException("OBJCInternalInconsistencyException", "Can't resolve object file image for module");
93 return OBJCUniqueObjectFileWithPath(info
.dli_fname
);
97 void OBJCInitializeProcess() {
98 #if defined(__APPLE__)
99 OBJCRegisterModule_Darwin(NULL
);
103 OBJCObjectFile
*OBJCMainObjectFile() {
104 static OBJCObjectFile
*mainObjectFile
= NULL
;
106 if(mainObjectFile
== NULL
) {
109 _NSGetExecutablePath(NULL
, &length
);
111 char path
[length
+ 1];
113 if(_NSGetExecutablePath(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
;
138 if(ownershipQueue
== NULL
)
139 ownershipQueue
= OBJCArrayNew();
141 result
= ownershipQueue
;
144 ownershipQueue
= NULL
;
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
169 for(int i
= 0; i
< unresolvedClassesSize
; i
++) {
170 Class currentClass
= unresolvedClasses
[i
];
171 if(currentClass
== NULL
|| currentClass
== (Class
)-1) {
172 unresolvedClasses
[i
] = class;
177 if(unresolvedClassesSize
== 0) {
178 newCSize
= INITIAL_CLASS_ARRAY_SIZE
;
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) {
200 if(!(class->info
& CLASS_INFO_LINKED
)) {
203 superClass
= class_getSuperclass(class);
206 if(superClass
!= Nil
) {
207 return OBJCCheckClassIsResolved(superClass
);
212 void OBJCSendLoadMessage(Class
class) {
216 for(; i
< sentLoadMessageClassesSize
; i
++) {
217 if(sentLoadMessageClasses
[i
] == NULL
) {
219 } else if(sentLoadMessageClasses
[i
] == class) {
220 //message already sent
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
) {
233 if(sentLoadMessageClassesSize
== 0) {
234 newCSize
= INITIAL_CLASS_ARRAY_SIZE
;
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
;
245 sentLoadMessageClasses
[i
] = class;
248 SEL loadSelector
= sel_registerName("load");
249 Method m
= class_getClassMethod(class, loadSelector
);
251 IMP imp
= method_getImplementation(m
);
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
) {
264 for(int i
= 0; i
< unresolvedClassesSize
; i
++) {
265 Class
class = unresolvedClasses
[i
];
270 if(OBJCCheckClassIsResolved(class) == YES
) {
271 //remove it from unresolved
272 unresolvedClasses
[i
] = NULL
;
274 //still unresolved classes, wait for more classes
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
) {
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
);
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);
356 if(unlinkedCategories
== NULL
)
357 unlinkedCategories
= OBJCArrayNew();
359 OBJCArrayAdd(unlinkedCategories
, category
);
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
);
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
);
396 for(i
= 0; staticInstances
->instances
[i
] != nil
; i
++)
397 object_setClass(staticInstances
->instances
[i
], class);
399 if(unlinkedObjects
== NULL
)
400 unlinkedObjects
= OBJCArrayNew();
402 OBJCArrayAdd(unlinkedObjects
, staticInstances
);
408 static void OBJCSymbolTableRegisterProtocolsIfNeeded(OBJCSymbolTable
*symbolTable
) {
409 // FIX or address issue
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);
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
);
433 OBJCLinkClassTable();
435 #if !defined(__APPLE__)
436 OBJCSendLoadMessages();
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
);
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
);
466 unsigned long moduleIndex
= 0;
468 while((module
= OBJCArrayEnumerate(objectFile
->moduleArray
, &moduleIndex
)) != NULL
) {
471 if(module
->symbolTable
!= NULL
) {
472 for(classIndex
= 0; classIndex
< module
->symbolTable
->classCount
; classIndex
++) {
473 if(module
->symbolTable
->definitions
[classIndex
] == class) {
484 const char *class_getImageName(Class cls
) {
485 OBJCObjectFile
*file
= OBJCObjectFileFromClass(cls
);
493 const char *objc_mainImageName() {
494 OBJCObjectFile
*file
= OBJCMainObjectFile();
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
;