dyld-750.5.tar.gz
[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 #include "test_support.h"
18
19 // All the libraries have a copy of DyldClass
20 @interface DyldClass : NSObject
21 @end
22
23 @implementation DyldClass
24 @end
25
26 // Only the main executable has DyldMainClass
27 @interface DyldMainClass : NSObject
28 @end
29
30 @implementation DyldMainClass
31 @end
32
33 extern Class OBJC_CLASS_$_DyldClass;
34 extern Class OBJC_CLASS_$_DyldMainClass;
35
36 Class getMainDyldClass() {
37   return (Class)&OBJC_CLASS_$_DyldClass;
38 }
39
40 Class getMainDyldMainClass() {
41   return (Class)&OBJC_CLASS_$_DyldMainClass;
42 }
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(int argc, const char* argv[], const char* envp[], const char* apple[]) {
60   // This API is only available with dyld3 and shared caches.  If we have dyld2 then don't do anything
61   const char* testDyldMode = getenv("TEST_DYLD_MODE");
62   assert(testDyldMode);
63
64   size_t unusedCacheLen;
65   bool haveSharedCache = _dyld_get_shared_cache_range(&unusedCacheLen) != 0;
66   if (!strcmp(testDyldMode, "2") || !haveSharedCache) {
67     __block bool sawClass = false;
68     _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
69       sawClass = true;
70     });
71     if (sawClass) {
72       FAIL("dyld2 shouldn't see any classes");
73     }
74     PASS("dyld2 or no shared cache)");
75   }
76
77   // Check that DyldClass comes from liblinked2 as it is last in load order
78   id runtimeDyldClass = objc_getClass("DyldClass");
79   if (runtimeDyldClass != getLinked2DyldClass()) {
80     FAIL("DyldClass should have come from liblinked2");
81   }
82
83   // Check that DyldLinkedClass comes from liblinked2 as it is last in load order
84   id runtimeDyldLinkedClass = objc_getClass("DyldLinkedClass");
85   if (runtimeDyldLinkedClass != getLinked2DyldLinkedClass()) {
86     FAIL("DyldLinkedClass should have come from liblinked2");
87   }
88
89   // Walk all the implementations of "DyldClass"
90   _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
91     // We should walk these in the order liblinked2, liblinked, main exe
92     if (!gotDyldClassLinked2) {
93       if (classPtr != getLinked2DyldClass()) {
94         FAIL("Optimized DyldClass should have come from liblinked2");
95       }
96       if (!isLoaded) {
97         FAIL("Optimized DyldClass isLoaded should have been set on liblinked2");
98       }
99       gotDyldClassLinked2 = true;
100       return;
101     }
102     if (!gotDyldClassLinked) {
103       if (classPtr != getLinked1DyldClass()) {
104         FAIL("Optimized DyldClass should have come from liblinked");
105       }
106       if (!isLoaded) {
107         FAIL("Optimized DyldClass isLoaded should have been set on liblinked");
108       }
109       gotDyldClassLinked = true;
110       return;
111     }
112     if (!gotDyldClassMain) {
113       if (classPtr != getMainDyldClass()) {
114         FAIL("Optimized DyldClass should have come from main exe");
115       }
116       if (!isLoaded) {
117         FAIL("Optimized DyldClass isLoaded should have been set on main exe");
118       }
119       gotDyldClassMain = true;
120       return;
121     }
122     FAIL("Unexpected Optimized DyldClass");
123   });
124
125   if ( !gotDyldClassLinked2 || !gotDyldClassLinked || !gotDyldClassMain) {
126     FAIL("Failed to find all duplicates of 'DyldClass'");
127   }
128
129   // Visit again, and return liblinked2's DyldClass
130   __block void* dyldClassImpl = nil;
131   _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
132     dyldClassImpl = classPtr;
133     *stop = true;
134   });
135   if (dyldClassImpl != getLinked2DyldClass()) {
136     FAIL("_dyld_for_each_objc_class should have returned DyldClass from liblinked2");
137   }
138
139   // Visit DyldMainClass and make sure it makes the callback for just the result from main.exe
140   __block void* dyldMainClassImpl = nil;
141   _dyld_for_each_objc_class("DyldMainClass", ^(void* classPtr, bool isLoaded, bool* stop) {
142     dyldMainClassImpl = classPtr;
143     *stop = true;
144   });
145   if (dyldMainClassImpl != getMainDyldMainClass()) {
146     FAIL("_dyld_for_each_objc_class should have returned DyldMainClass from main.exe");
147   }
148
149   PASS("Success");
150 }