]> git.saurik.com Git - apple/objc4.git/blob - test/nonpointerisa.m
objc4-781.tar.gz
[apple/objc4.git] / test / nonpointerisa.m
1 // TEST_CFLAGS -framework Foundation
2 // TEST_CONFIG MEM=mrc
3
4 #include "test.h"
5 #include <dlfcn.h>
6
7 #include <objc/objc-gdb.h>
8 #include <Foundation/Foundation.h>
9
10 #define ISA(x) (*((uintptr_t *)(x)))
11 #define NONPOINTER(x) (ISA(x) & 1)
12
13 #if SUPPORT_NONPOINTER_ISA
14 # if __x86_64__
15 # define RC_ONE (1ULL<<56)
16 # elif __arm64__ && __LP64__
17 # define RC_ONE (1ULL<<45)
18 # elif __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
19 # define RC_ONE (1ULL<<25)
20 # else
21 # error unknown architecture
22 # endif
23 #endif
24
25
26 void check_raw_pointer(id obj, Class cls)
27 {
28 testassert(object_getClass(obj) == cls);
29 testassert(!NONPOINTER(obj));
30
31 uintptr_t isa = ISA(obj);
32 testassert((Class)isa == cls);
33 testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
34 testassert((Class)(isa & ~objc_debug_isa_class_mask) == 0);
35
36 CFRetain(obj);
37 testassert(ISA(obj) == isa);
38 testassert([obj retainCount] == 2);
39 [obj retain];
40 testassert(ISA(obj) == isa);
41 testassert([obj retainCount] == 3);
42 CFRelease(obj);
43 testassert(ISA(obj) == isa);
44 testassert([obj retainCount] == 2);
45 [obj release];
46 testassert(ISA(obj) == isa);
47 testassert([obj retainCount] == 1);
48 }
49
50
51 #if ! SUPPORT_NONPOINTER_ISA
52
53 int main()
54 {
55 #if OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
56 # error wrong
57 #endif
58
59 testprintf("Isa with index\n");
60 id index_o = [NSObject new];
61 check_raw_pointer(index_o, [NSObject class]);
62
63 // These variables DO NOT exist without non-pointer isa support.
64 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
65 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
66 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
67 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
68 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
69
70 // These variables DO exist even without non-pointer isa support.
71 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_class_mask"));
72 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_mask"));
73 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_value"));
74
75 succeed(__FILE__);
76 }
77
78 #else
79 // SUPPORT_NONPOINTER_ISA
80
81 void check_nonpointer(id obj, Class cls)
82 {
83 testassert(object_getClass(obj) == cls);
84 testassert(NONPOINTER(obj));
85
86 uintptr_t isa = ISA(obj);
87
88 if (objc_debug_indexed_isa_magic_mask != 0) {
89 // Indexed isa.
90 testassert((isa & objc_debug_indexed_isa_magic_mask) == objc_debug_indexed_isa_magic_value);
91 testassert((isa & ~objc_debug_indexed_isa_index_mask) != 0);
92 uintptr_t index = (isa & objc_debug_indexed_isa_index_mask) >> objc_debug_indexed_isa_index_shift;
93 testassert(index < objc_indexed_classes_count);
94 testassert(objc_indexed_classes[index] == cls);
95 } else {
96 // Packed isa.
97 testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
98 testassert((Class)(isa & ~objc_debug_isa_class_mask) != 0);
99 testassert((isa & objc_debug_isa_magic_mask) == objc_debug_isa_magic_value);
100 }
101
102 CFRetain(obj);
103 testassert(ISA(obj) == isa + RC_ONE);
104 testassert([obj retainCount] == 2);
105 [obj retain];
106 testassert(ISA(obj) == isa + RC_ONE*2);
107 testassert([obj retainCount] == 3);
108 CFRelease(obj);
109 testassert(ISA(obj) == isa + RC_ONE);
110 testassert([obj retainCount] == 2);
111 [obj release];
112 testassert(ISA(obj) == isa);
113 testassert([obj retainCount] == 1);
114 }
115
116
117 @interface OS_object <NSObject>
118 +(id)alloc;
119 @end
120
121 @interface Fake_OS_object : NSObject {
122 int refcnt;
123 int xref_cnt;
124 }
125 @end
126
127 @implementation Fake_OS_object
128 +(void)initialize {
129 static bool initialized;
130 if (!initialized) {
131 initialized = true;
132 testprintf("Nonpointer during +initialize\n");
133 testassert(!NONPOINTER(self));
134 id o = [Fake_OS_object new];
135 check_nonpointer(o, self);
136 [o release];
137 }
138 }
139 @end
140
141 @interface Sub_OS_object : OS_object @end
142
143 @implementation Sub_OS_object
144 @end
145
146
147
148 int main()
149 {
150 uintptr_t isa;
151
152 #if SUPPORT_PACKED_ISA
153 # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
154 # error wrong
155 # endif
156 testassert(objc_debug_isa_class_mask == (uintptr_t)&objc_absolute_packed_isa_class_mask);
157
158 // Indexed isa variables DO NOT exist on packed-isa platforms
159 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
160 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
161 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
162 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
163
164 #elif SUPPORT_INDEXED_ISA
165 # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
166 # error wrong
167 # endif
168 testassert(objc_debug_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_mask);
169 testassert(objc_debug_indexed_isa_magic_value == (uintptr_t)&objc_absolute_indexed_isa_magic_value);
170 testassert(objc_debug_indexed_isa_index_mask == (uintptr_t)&objc_absolute_indexed_isa_index_mask);
171 testassert(objc_debug_indexed_isa_index_shift == (uintptr_t)&objc_absolute_indexed_isa_index_shift);
172
173 // Packed isa variable DOES NOT exist on indexed-isa platforms.
174 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
175
176 #else
177 # error unknown nonpointer isa format
178 #endif
179
180 testprintf("Isa with index\n");
181 id index_o = [Fake_OS_object new];
182 check_nonpointer(index_o, [Fake_OS_object class]);
183
184 testprintf("Weakly referenced\n");
185 isa = ISA(index_o);
186 id weak;
187 objc_storeWeak(&weak, index_o);
188 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
189
190 testprintf("Has associated references\n");
191 id assoc = @"thing";
192 isa = ISA(index_o);
193 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
194 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
195
196
197 testprintf("Isa without index\n");
198 id raw_o = [OS_object alloc];
199 check_raw_pointer(raw_o, [OS_object class]);
200
201
202 id buf[4];
203 id bufo = (id)buf;
204
205 testprintf("Change isa 0 -> raw pointer\n");
206 bzero(buf, sizeof(buf));
207 object_setClass(bufo, [OS_object class]);
208 check_raw_pointer(bufo, [OS_object class]);
209
210 testprintf("Change isa 0 -> nonpointer\n");
211 bzero(buf, sizeof(buf));
212 object_setClass(bufo, [NSObject class]);
213 check_nonpointer(bufo, [NSObject class]);
214
215 testprintf("Change isa nonpointer -> nonpointer\n");
216 testassert(NONPOINTER(bufo));
217 _objc_rootRetain(bufo);
218 testassert(_objc_rootRetainCount(bufo) == 2);
219 object_setClass(bufo, [Fake_OS_object class]);
220 testassert(_objc_rootRetainCount(bufo) == 2);
221 _objc_rootRelease(bufo);
222 testassert(_objc_rootRetainCount(bufo) == 1);
223 check_nonpointer(bufo, [Fake_OS_object class]);
224
225 testprintf("Change isa nonpointer -> raw pointer\n");
226 // Retain count must be preserved.
227 // Use root* to avoid OS_object's overrides.
228 testassert(NONPOINTER(bufo));
229 _objc_rootRetain(bufo);
230 testassert(_objc_rootRetainCount(bufo) == 2);
231 object_setClass(bufo, [OS_object class]);
232 testassert(_objc_rootRetainCount(bufo) == 2);
233 _objc_rootRelease(bufo);
234 testassert(_objc_rootRetainCount(bufo) == 1);
235 check_raw_pointer(bufo, [OS_object class]);
236
237 testprintf("Change isa raw pointer -> nonpointer (doesn't happen)\n");
238 testassert(!NONPOINTER(bufo));
239 _objc_rootRetain(bufo);
240 testassert(_objc_rootRetainCount(bufo) == 2);
241 object_setClass(bufo, [Fake_OS_object class]);
242 testassert(_objc_rootRetainCount(bufo) == 2);
243 _objc_rootRelease(bufo);
244 testassert(_objc_rootRetainCount(bufo) == 1);
245 check_raw_pointer(bufo, [Fake_OS_object class]);
246
247 testprintf("Change isa raw pointer -> raw pointer\n");
248 testassert(!NONPOINTER(bufo));
249 _objc_rootRetain(bufo);
250 testassert(_objc_rootRetainCount(bufo) == 2);
251 object_setClass(bufo, [Sub_OS_object class]);
252 testassert(_objc_rootRetainCount(bufo) == 2);
253 _objc_rootRelease(bufo);
254 testassert(_objc_rootRetainCount(bufo) == 1);
255 check_raw_pointer(bufo, [Sub_OS_object class]);
256
257
258 succeed(__FILE__);
259 }
260
261 // SUPPORT_NONPOINTER_ISA
262 #endif