1 // TEST_CFLAGS -framework Foundation
7 #include <objc/objc-gdb.h>
8 #include <Foundation/Foundation.h>
10 #define ISA(x) (*((uintptr_t *)(x)))
11 #define NONPOINTER(x) (ISA(x) & 1)
13 #if SUPPORT_NONPOINTER_ISA
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)
21 # error unknown architecture
26 void check_raw_pointer(id obj, Class cls)
28 testassert(object_getClass(obj) == cls);
29 testassert(!NONPOINTER(obj));
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);
37 testassert(ISA(obj) == isa);
38 testassert([obj retainCount] == 2);
40 testassert(ISA(obj) == isa);
41 testassert([obj retainCount] == 3);
43 testassert(ISA(obj) == isa);
44 testassert([obj retainCount] == 2);
46 testassert(ISA(obj) == isa);
47 testassert([obj retainCount] == 1);
51 #if ! SUPPORT_NONPOINTER_ISA
55 #if OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
59 testprintf("Isa with index\n");
60 id index_o = [NSObject new];
61 check_raw_pointer(index_o, [NSObject class]);
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"));
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"));
79 // SUPPORT_NONPOINTER_ISA
81 void check_nonpointer(id obj, Class cls)
83 testassert(object_getClass(obj) == cls);
84 testassert(NONPOINTER(obj));
86 uintptr_t isa = ISA(obj);
88 if (objc_debug_indexed_isa_magic_mask != 0) {
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);
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);
103 testassert(ISA(obj) == isa + RC_ONE);
104 testassert([obj retainCount] == 2);
106 testassert(ISA(obj) == isa + RC_ONE*2);
107 testassert([obj retainCount] == 3);
109 testassert(ISA(obj) == isa + RC_ONE);
110 testassert([obj retainCount] == 2);
112 testassert(ISA(obj) == isa);
113 testassert([obj retainCount] == 1);
117 @interface OS_object <NSObject>
121 @interface Fake_OS_object : NSObject {
127 @implementation Fake_OS_object
129 static bool initialized;
132 testprintf("Nonpointer during +initialize\n");
133 testassert(!NONPOINTER(self));
134 id o = [Fake_OS_object new];
135 check_nonpointer(o, self);
141 @interface Sub_OS_object : OS_object @end
143 @implementation Sub_OS_object
152 #if SUPPORT_PACKED_ISA
153 # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
156 testassert(objc_debug_isa_class_mask == (uintptr_t)&objc_absolute_packed_isa_class_mask);
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"));
164 #elif SUPPORT_INDEXED_ISA
165 # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
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);
173 // Packed isa variable DOES NOT exist on indexed-isa platforms.
174 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
177 # error unknown nonpointer isa format
180 testprintf("Isa with index\n");
181 id index_o = [Fake_OS_object new];
182 check_nonpointer(index_o, [Fake_OS_object class]);
184 testprintf("Weakly referenced\n");
187 objc_storeWeak(&weak, index_o);
188 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
190 testprintf("Has associated references\n");
193 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
194 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
197 testprintf("Isa without index\n");
198 id raw_o = [OS_object alloc];
199 check_raw_pointer(raw_o, [OS_object class]);
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]);
210 testprintf("Change isa 0 -> nonpointer\n");
211 bzero(buf, sizeof(buf));
212 object_setClass(bufo, [NSObject class]);
213 check_nonpointer(bufo, [NSObject class]);
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]);
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]);
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]);
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]);
261 // SUPPORT_NONPOINTER_ISA