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 // Quiet the warning about redefining the macro from isa.h.
19 # define RC_ONE (objc_debug_isa_magic_value == 1 ? 1ULL<<56 : 1ULL<<45)
20 # elif __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
21 # define RC_ONE (1ULL<<25)
23 # error unknown architecture
28 void check_raw_pointer(id obj, Class cls)
30 testassert(object_getClass(obj) == cls);
31 testassert(!NONPOINTER(obj));
33 uintptr_t isa = ISA(obj);
34 testassertequal(ptrauth_strip((void *)isa, ptrauth_key_process_independent_data), (void *)cls);
35 testassertequal((Class)(isa & objc_debug_isa_class_mask), cls);
36 testassertequal(ptrauth_strip((void *)(isa & ~objc_debug_isa_class_mask), ptrauth_key_process_independent_data), 0);
39 testassert(ISA(obj) == isa);
40 testassert([obj retainCount] == 2);
42 testassert(ISA(obj) == isa);
43 testassert([obj retainCount] == 3);
45 testassert(ISA(obj) == isa);
46 testassert([obj retainCount] == 2);
48 testassert(ISA(obj) == isa);
49 testassert([obj retainCount] == 1);
53 #if ! SUPPORT_NONPOINTER_ISA
57 #if OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
61 testprintf("Isa with index\n");
62 id index_o = [NSObject new];
63 check_raw_pointer(index_o, [NSObject class]);
65 // These variables DO NOT exist without non-pointer isa support.
66 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
67 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
68 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
69 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
70 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
72 // These variables DO exist even without non-pointer isa support.
73 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_class_mask"));
74 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_mask"));
75 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_value"));
81 // SUPPORT_NONPOINTER_ISA
83 void check_nonpointer(id obj, Class cls)
85 testassertequal(object_getClass(obj), cls);
86 testassert(NONPOINTER(obj));
88 uintptr_t isa = ISA(obj);
90 if (objc_debug_indexed_isa_magic_mask != 0) {
92 testassertequal((isa & objc_debug_indexed_isa_magic_mask), objc_debug_indexed_isa_magic_value);
93 testassert((isa & ~objc_debug_indexed_isa_index_mask) != 0);
94 uintptr_t index = (isa & objc_debug_indexed_isa_index_mask) >> objc_debug_indexed_isa_index_shift;
95 testassert(index < objc_indexed_classes_count);
96 testassertequal(objc_indexed_classes[index], cls);
99 testassertequal((Class)(isa & objc_debug_isa_class_mask), cls);
100 testassert((Class)(isa & ~objc_debug_isa_class_mask) != 0);
101 testassertequal((isa & objc_debug_isa_magic_mask), objc_debug_isa_magic_value);
105 testassertequal(ISA(obj), isa + RC_ONE);
106 testassertequal([obj retainCount], 2);
108 testassertequal(ISA(obj), isa + RC_ONE*2);
109 testassertequal([obj retainCount], 3);
111 testassertequal(ISA(obj), isa + RC_ONE);
112 testassertequal([obj retainCount], 2);
114 testassertequal(ISA(obj), isa);
115 testassertequal([obj retainCount], 1);
119 @interface Fake_OS_object : NSObject {
125 @implementation Fake_OS_object
127 static bool initialized;
130 testprintf("Nonpointer during +initialize\n");
131 testassert(!NONPOINTER(self));
132 id o = [Fake_OS_object new];
133 check_nonpointer(o, self);
139 @interface Sub_OS_object : NSObject @end
141 @implementation Sub_OS_object
148 Class OS_object = objc_getClass("OS_object");
149 class_setSuperclass([Sub_OS_object class], OS_object);
153 #if SUPPORT_PACKED_ISA
154 # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
157 void *absoluteMask = (void *)&objc_absolute_packed_isa_class_mask;
158 #if __has_feature(ptrauth_calls)
159 absoluteMask = ptrauth_strip(absoluteMask, ptrauth_key_process_independent_data);
161 // absoluteMask should "cover" objc_debug_isa_class_mask
162 testassert((objc_debug_isa_class_mask & (uintptr_t)absoluteMask) == objc_debug_isa_class_mask);
163 // absoluteMask should only possibly differ in the high bits
164 testassert((objc_debug_isa_class_mask & 0xffff) == ((uintptr_t)absoluteMask & 0xffff));
166 // Indexed isa variables DO NOT exist on packed-isa platforms
167 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
168 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
169 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
170 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
172 #elif SUPPORT_INDEXED_ISA
173 # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
176 testassert(objc_debug_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_mask);
177 testassert(objc_debug_indexed_isa_magic_value == (uintptr_t)&objc_absolute_indexed_isa_magic_value);
178 testassert(objc_debug_indexed_isa_index_mask == (uintptr_t)&objc_absolute_indexed_isa_index_mask);
179 testassert(objc_debug_indexed_isa_index_shift == (uintptr_t)&objc_absolute_indexed_isa_index_shift);
181 // Packed isa variable DOES NOT exist on indexed-isa platforms.
182 testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
185 # error unknown nonpointer isa format
188 testprintf("Isa with index\n");
189 id index_o = [Fake_OS_object new];
190 check_nonpointer(index_o, [Fake_OS_object class]);
192 testprintf("Weakly referenced\n");
195 objc_storeWeak(&weak, index_o);
196 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
198 testprintf("Has associated references\n");
201 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
202 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
204 testprintf("Isa without index\n");
205 id raw_o = [OS_object alloc];
206 check_raw_pointer(raw_o, [OS_object class]);
212 testprintf("Change isa 0 -> raw pointer\n");
213 bzero(buf, sizeof(buf));
214 object_setClass(bufo, [OS_object class]);
215 check_raw_pointer(bufo, [OS_object class]);
217 testprintf("Change isa 0 -> nonpointer\n");
218 bzero(buf, sizeof(buf));
219 object_setClass(bufo, [NSObject class]);
220 check_nonpointer(bufo, [NSObject class]);
222 testprintf("Change isa nonpointer -> nonpointer\n");
223 testassert(NONPOINTER(bufo));
224 _objc_rootRetain(bufo);
225 testassert(_objc_rootRetainCount(bufo) == 2);
226 object_setClass(bufo, [Fake_OS_object class]);
227 testassert(_objc_rootRetainCount(bufo) == 2);
228 _objc_rootRelease(bufo);
229 testassert(_objc_rootRetainCount(bufo) == 1);
230 check_nonpointer(bufo, [Fake_OS_object class]);
232 testprintf("Change isa nonpointer -> raw pointer\n");
233 // Retain count must be preserved.
234 // Use root* to avoid OS_object's overrides.
235 testassert(NONPOINTER(bufo));
236 _objc_rootRetain(bufo);
237 testassert(_objc_rootRetainCount(bufo) == 2);
238 object_setClass(bufo, [OS_object class]);
239 testassert(_objc_rootRetainCount(bufo) == 2);
240 _objc_rootRelease(bufo);
241 testassert(_objc_rootRetainCount(bufo) == 1);
242 check_raw_pointer(bufo, [OS_object class]);
244 testprintf("Change isa raw pointer -> nonpointer (doesn't happen)\n");
245 testassert(!NONPOINTER(bufo));
246 _objc_rootRetain(bufo);
247 testassert(_objc_rootRetainCount(bufo) == 2);
248 object_setClass(bufo, [Fake_OS_object class]);
249 testassert(_objc_rootRetainCount(bufo) == 2);
250 _objc_rootRelease(bufo);
251 testassert(_objc_rootRetainCount(bufo) == 1);
252 check_raw_pointer(bufo, [Fake_OS_object class]);
254 testprintf("Change isa raw pointer -> raw pointer\n");
255 testassert(!NONPOINTER(bufo));
256 _objc_rootRetain(bufo);
257 testassert(_objc_rootRetainCount(bufo) == 2);
258 object_setClass(bufo, [Sub_OS_object class]);
259 testassert(_objc_rootRetainCount(bufo) == 2);
260 _objc_rootRelease(bufo);
261 testassert(_objc_rootRetainCount(bufo) == 1);
262 check_raw_pointer(bufo, [Sub_OS_object class]);
268 // SUPPORT_NONPOINTER_ISA