]> git.saurik.com Git - apple/objc4.git/blob - test/nonpointerisa.m
objc4-787.1.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 Fake_OS_object : NSObject {
118 int refcnt;
119 int xref_cnt;
120 }
121 @end
122
123 @implementation Fake_OS_object
124 +(void)initialize {
125 static bool initialized;
126 if (!initialized) {
127 initialized = true;
128 testprintf("Nonpointer during +initialize\n");
129 testassert(!NONPOINTER(self));
130 id o = [Fake_OS_object new];
131 check_nonpointer(o, self);
132 [o release];
133 }
134 }
135 @end
136
137 @interface Sub_OS_object : NSObject @end
138
139 @implementation Sub_OS_object
140 @end
141
142
143
144 int main()
145 {
146 Class OS_object = objc_getClass("OS_object");
147 class_setSuperclass([Sub_OS_object class], OS_object);
148
149 uintptr_t isa;
150
151 #if SUPPORT_PACKED_ISA
152 # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
153 # error wrong
154 # endif
155 testassert(objc_debug_isa_class_mask == (uintptr_t)&objc_absolute_packed_isa_class_mask);
156
157 // Indexed isa variables DO NOT exist on packed-isa platforms
158 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
159 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
160 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
161 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
162
163 #elif SUPPORT_INDEXED_ISA
164 # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
165 # error wrong
166 # endif
167 testassert(objc_debug_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_mask);
168 testassert(objc_debug_indexed_isa_magic_value == (uintptr_t)&objc_absolute_indexed_isa_magic_value);
169 testassert(objc_debug_indexed_isa_index_mask == (uintptr_t)&objc_absolute_indexed_isa_index_mask);
170 testassert(objc_debug_indexed_isa_index_shift == (uintptr_t)&objc_absolute_indexed_isa_index_shift);
171
172 // Packed isa variable DOES NOT exist on indexed-isa platforms.
173 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
174
175 #else
176 # error unknown nonpointer isa format
177 #endif
178
179 testprintf("Isa with index\n");
180 id index_o = [Fake_OS_object new];
181 check_nonpointer(index_o, [Fake_OS_object class]);
182
183 testprintf("Weakly referenced\n");
184 isa = ISA(index_o);
185 id weak;
186 objc_storeWeak(&weak, index_o);
187 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
188
189 testprintf("Has associated references\n");
190 id assoc = @"thing";
191 isa = ISA(index_o);
192 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
193 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
194
195 testprintf("Isa without index\n");
196 id raw_o = [OS_object alloc];
197 check_raw_pointer(raw_o, [OS_object class]);
198
199
200 id buf[4];
201 id bufo = (id)buf;
202
203 testprintf("Change isa 0 -> raw pointer\n");
204 bzero(buf, sizeof(buf));
205 object_setClass(bufo, [OS_object class]);
206 check_raw_pointer(bufo, [OS_object class]);
207
208 testprintf("Change isa 0 -> nonpointer\n");
209 bzero(buf, sizeof(buf));
210 object_setClass(bufo, [NSObject class]);
211 check_nonpointer(bufo, [NSObject class]);
212
213 testprintf("Change isa nonpointer -> nonpointer\n");
214 testassert(NONPOINTER(bufo));
215 _objc_rootRetain(bufo);
216 testassert(_objc_rootRetainCount(bufo) == 2);
217 object_setClass(bufo, [Fake_OS_object class]);
218 testassert(_objc_rootRetainCount(bufo) == 2);
219 _objc_rootRelease(bufo);
220 testassert(_objc_rootRetainCount(bufo) == 1);
221 check_nonpointer(bufo, [Fake_OS_object class]);
222
223 testprintf("Change isa nonpointer -> raw pointer\n");
224 // Retain count must be preserved.
225 // Use root* to avoid OS_object's overrides.
226 testassert(NONPOINTER(bufo));
227 _objc_rootRetain(bufo);
228 testassert(_objc_rootRetainCount(bufo) == 2);
229 object_setClass(bufo, [OS_object class]);
230 testassert(_objc_rootRetainCount(bufo) == 2);
231 _objc_rootRelease(bufo);
232 testassert(_objc_rootRetainCount(bufo) == 1);
233 check_raw_pointer(bufo, [OS_object class]);
234
235 testprintf("Change isa raw pointer -> nonpointer (doesn't happen)\n");
236 testassert(!NONPOINTER(bufo));
237 _objc_rootRetain(bufo);
238 testassert(_objc_rootRetainCount(bufo) == 2);
239 object_setClass(bufo, [Fake_OS_object class]);
240 testassert(_objc_rootRetainCount(bufo) == 2);
241 _objc_rootRelease(bufo);
242 testassert(_objc_rootRetainCount(bufo) == 1);
243 check_raw_pointer(bufo, [Fake_OS_object class]);
244
245 testprintf("Change isa raw pointer -> raw pointer\n");
246 testassert(!NONPOINTER(bufo));
247 _objc_rootRetain(bufo);
248 testassert(_objc_rootRetainCount(bufo) == 2);
249 object_setClass(bufo, [Sub_OS_object class]);
250 testassert(_objc_rootRetainCount(bufo) == 2);
251 _objc_rootRelease(bufo);
252 testassert(_objc_rootRetainCount(bufo) == 1);
253 check_raw_pointer(bufo, [Sub_OS_object class]);
254
255
256 succeed(__FILE__);
257 }
258
259 // SUPPORT_NONPOINTER_ISA
260 #endif