]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/_dyld_for_each_objc_class.dtest/main.m
517dfdee0a2916bc96fb5f230db440b58f5bd956
[apple/dyld.git] / testing / test-cases / _dyld_for_each_objc_class.dtest / main.m
1
2 // BUILD: $CC linked1.m -dynamiclib -o $BUILD_DIR/liblinked1.dylib -install_name $RUN_DIR/liblinked1.dylib -lobjc
3 // BUILD: $CC linked2.m -dynamiclib -o $BUILD_DIR/liblinked2.dylib -install_name $RUN_DIR/liblinked2.dylib -lobjc
4 // BUILD: $CC main.m -o $BUILD_DIR/_dyld_for_each_objc_class.exe $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib -lobjc
5
6 // RUN: ./_dyld_for_each_objc_class.exe
7
8 // The preoptimized objc class information is available via _dyld_for_each_objc_class().
9 // This test ensures that we match the objc behaviour when there are duplicates.
10 // For objc today, it walks the images in reverse load order, so the deepest library will be
11 // the canonical definition of a class.
12
13 #include <mach-o/dyld_priv.h>
14
15 #import <Foundation/Foundation.h>
16
17 // All the libraries have a copy of DyldClass
18 @interface DyldClass : NSObject
19 @end
20
21 @implementation DyldClass
22 @end
23
24 // Only the main executable has DyldMainClass
25 @interface DyldMainClass : NSObject
26 @end
27
28 @implementation DyldMainClass
29 @end
30
31 extern Class OBJC_CLASS_$_DyldClass;
32 extern Class OBJC_CLASS_$_DyldMainClass;
33
34 Class getMainDyldClass() {
35 return (Class)&OBJC_CLASS_$_DyldClass;
36 }
37
38 Class getMainDyldMainClass() {
39 return (Class)&OBJC_CLASS_$_DyldMainClass;
40 }
41
42 extern int printf(const char*, ...);
43
44 extern id objc_getClass(const char *name);
45
46 // Get the DyldClass from liblinked1.dylib
47 extern Class getLinked1DyldClass();
48
49 // Get the DyldClass from liblinked2.dylib
50 extern Class getLinked2DyldClass();
51
52 // Get the DyldLinkedClass from liblinked2.dylib
53 extern Class getLinked2DyldLinkedClass();
54
55 static bool gotDyldClassMain = false;
56 static bool gotDyldClassLinked = false;
57 static bool gotDyldClassLinked2 = false;
58
59 int main() {
60 printf("[BEGIN] _dyld_for_each_objc_class\n");
61
62 // This API is only available with dyld3 and shared caches. If we have dyld2 then don't do anything
63 const char* testDyldMode = getenv("TEST_DYLD_MODE");
64 assert(testDyldMode);
65
66 size_t unusedCacheLen;
67 bool haveSharedCache = _dyld_get_shared_cache_range(&unusedCacheLen) != 0;
68 if (!strcmp(testDyldMode, "2") || !haveSharedCache) {
69 __block bool sawClass = false;
70 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
71 sawClass = true;
72 });
73 if (sawClass) {
74 printf("[FAIL] _dyld_for_each_objc_class: dyld2 shouldn't see any classes\n");
75 return 0;
76 }
77 printf("[PASS] _dyld_for_each_objc_class (dyld2 or no shared cache)\n");
78 return 0;
79 }
80
81 // Check that DyldClass comes from liblinked2 as it is last in load order
82 id runtimeDyldClass = objc_getClass("DyldClass");
83 if (runtimeDyldClass != getLinked2DyldClass()) {
84 printf("[FAIL] _dyld_for_each_objc_class: DyldClass should have come from liblinked2\n");
85 return 0;
86 }
87
88 // Check that DyldLinkedClass comes from liblinked2 as it is last in load order
89 id runtimeDyldLinkedClass = objc_getClass("DyldLinkedClass");
90 if (runtimeDyldLinkedClass != getLinked2DyldLinkedClass()) {
91 printf("[FAIL] _dyld_for_each_objc_class: DyldLinkedClass should have come from liblinked2\n");
92 return 0;
93 }
94
95 // Walk all the implementations of "DyldClass"
96 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
97 // We should walk these in the order liblinked2, liblinked, main exe
98 if (!gotDyldClassLinked2) {
99 if (classPtr != getLinked2DyldClass()) {
100 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass should have come from liblinked2\n");
101 *stop = true;
102 return;
103 }
104 if (!isLoaded) {
105 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass isLoaded should have been set on liblinked2\n");
106 *stop = true;
107 return;
108 }
109 gotDyldClassLinked2 = true;
110 return;
111 }
112 if (!gotDyldClassLinked) {
113 if (classPtr != getLinked1DyldClass()) {
114 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass should have come from liblinked\n");
115 *stop = true;
116 return;
117 }
118 if (!isLoaded) {
119 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass isLoaded should have been set on liblinked\n");
120 *stop = true;
121 return;
122 }
123 gotDyldClassLinked = true;
124 return;
125 }
126 if (!gotDyldClassMain) {
127 if (classPtr != getMainDyldClass()) {
128 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass should have come from main exe\n");
129 *stop = true;
130 return;
131 }
132 if (!isLoaded) {
133 printf("[FAIL] _dyld_for_each_objc_class: Optimized DyldClass isLoaded should have been set on main exe\n");
134 *stop = true;
135 return;
136 }
137 gotDyldClassMain = true;
138 return;
139 }
140 printf("[FAIL] _dyld_for_each_objc_class: Unexpected Optimized DyldClass\n");
141 return;
142 });
143
144 if ( !gotDyldClassLinked2 || !gotDyldClassLinked || !gotDyldClassMain) {
145 printf("[FAIL] _dyld_for_each_objc_class: Failed to find all duplicates of 'DyldClass'\n");
146 return 0;
147 }
148
149 // Visit again, and return liblinked2's DyldClass
150 __block void* dyldClassImpl = nil;
151 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
152 dyldClassImpl = classPtr;
153 *stop = true;
154 });
155 if (dyldClassImpl != getLinked2DyldClass()) {
156 printf("[FAIL] _dyld_for_each_objc_class: _dyld_for_each_objc_class should have returned DyldClass from liblinked2\n");
157 return 0;
158 }
159
160 // Visit DyldMainClass and make sure it makes the callback for just the result from main.exe
161 __block void* dyldMainClassImpl = nil;
162 _dyld_for_each_objc_class("DyldMainClass", ^(void* classPtr, bool isLoaded, bool* stop) {
163 dyldMainClassImpl = classPtr;
164 *stop = true;
165 });
166 if (dyldMainClassImpl != getMainDyldMainClass()) {
167 printf("[FAIL] _dyld_for_each_objc_class: _dyld_for_each_objc_class should have returned DyldMainClass from main.exe\n");
168 return 0;
169 }
170
171 printf("[PASS] _dyld_for_each_objc_class\n");
172
173 return 0;
174 }