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 Fake_OS_object : NSObject {
123 @implementation Fake_OS_object
125 static bool initialized;
128 testprintf("Nonpointer during +initialize\n");
129 testassert(!NONPOINTER(self));
130 id o = [Fake_OS_object new];
131 check_nonpointer(o, self);
137 @interface Sub_OS_object : NSObject @end
139 @implementation Sub_OS_object
146 Class OS_object = objc_getClass("OS_object");
147 class_setSuperclass([Sub_OS_object class], OS_object);
151 #if SUPPORT_PACKED_ISA
152 # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
155 testassert(objc_debug_isa_class_mask == (uintptr_t)&objc_absolute_packed_isa_class_mask);
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"));
163 #elif SUPPORT_INDEXED_ISA
164 # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
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);
172 // Packed isa variable DOES NOT exist on indexed-isa platforms.
173 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
176 # error unknown nonpointer isa format
179 testprintf("Isa with index\n");
180 id index_o = [Fake_OS_object new];
181 check_nonpointer(index_o, [Fake_OS_object class]);
183 testprintf("Weakly referenced\n");
186 objc_storeWeak(&weak, index_o);
187 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
189 testprintf("Has associated references\n");
192 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
193 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
195 testprintf("Isa without index\n");
196 id raw_o = [OS_object alloc];
197 check_raw_pointer(raw_o, [OS_object class]);
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]);
208 testprintf("Change isa 0 -> nonpointer\n");
209 bzero(buf, sizeof(buf));
210 object_setClass(bufo, [NSObject class]);
211 check_nonpointer(bufo, [NSObject class]);
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]);
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]);
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]);
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]);
259 // SUPPORT_NONPOINTER_ISA