1 // TEST_CFLAGS -framework Foundation
17 #include <objc/objc-gdb.h>
18 #include <Foundation/Foundation.h>
20 #define ISA(x) (*((uintptr_t *)(x)))
21 #define INDEXED(x) (ISA(x) & 1)
23 #if SUPPORT_NONPOINTER_ISA
25 # define RC_ONE (1ULL<<56)
27 # define RC_ONE (1ULL<<45)
29 # error unknown architecture
34 void check_unindexed(id obj, Class cls)
36 testassert(object_getClass(obj) == cls);
37 testassert(!INDEXED(obj));
39 uintptr_t isa = ISA(obj);
40 testassert((Class)isa == cls);
41 testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
42 testassert((Class)(isa & ~objc_debug_isa_class_mask) == 0);
45 testassert(ISA(obj) == isa);
46 testassert([obj retainCount] == 2);
48 testassert(ISA(obj) == isa);
49 testassert([obj retainCount] == 3);
51 testassert(ISA(obj) == isa);
52 testassert([obj retainCount] == 2);
54 testassert(ISA(obj) == isa);
55 testassert([obj retainCount] == 1);
59 #if ! SUPPORT_NONPOINTER_ISA
63 testprintf("Isa with index\n");
64 id index_o = [NSObject new];
65 check_unindexed(index_o, [NSObject class]);
67 // These variables DO exist even without non-pointer isa support
68 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_class_mask"));
69 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_mask"));
70 testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_value"));
76 // SUPPORT_NONPOINTER_ISA
78 void check_indexed(id obj, Class cls)
80 testassert(object_getClass(obj) == cls);
81 testassert(INDEXED(obj));
83 uintptr_t isa = ISA(obj);
84 testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
85 testassert((Class)(isa & ~objc_debug_isa_class_mask) != 0);
86 testassert((isa & objc_debug_isa_magic_mask) == objc_debug_isa_magic_value);
89 testassert(ISA(obj) == isa + RC_ONE);
90 testassert([obj retainCount] == 2);
92 testassert(ISA(obj) == isa + RC_ONE*2);
93 testassert([obj retainCount] == 3);
95 testassert(ISA(obj) == isa + RC_ONE);
96 testassert([obj retainCount] == 2);
98 testassert(ISA(obj) == isa);
99 testassert([obj retainCount] == 1);
103 @interface OS_object <NSObject>
107 @interface Fake_OS_object : NSObject {
113 @implementation Fake_OS_object
115 static bool initialized;
118 testprintf("Indexed during +initialize\n");
119 testassert(INDEXED(self));
120 id o = [Fake_OS_object new];
121 check_indexed(o, self);
127 @interface Sub_OS_object : OS_object @end
129 @implementation Sub_OS_object
138 testprintf("Isa with index\n");
139 id index_o = [Fake_OS_object new];
140 check_indexed(index_o, [Fake_OS_object class]);
142 testprintf("Weakly referenced\n");
145 objc_storeWeak(&weak, index_o);
146 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
148 testprintf("Has associated references\n");
151 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
152 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
155 testprintf("Isa without index\n");
156 id unindex_o = [OS_object new];
157 check_unindexed(unindex_o, [OS_object class]);
163 testprintf("Change isa 0 -> unindexed\n");
164 bzero(buf, sizeof(buf));
165 object_setClass(bufo, [OS_object class]);
166 check_unindexed(bufo, [OS_object class]);
168 testprintf("Change isa 0 -> indexed\n");
169 bzero(buf, sizeof(buf));
170 object_setClass(bufo, [NSObject class]);
171 check_indexed(bufo, [NSObject class]);
173 testprintf("Change isa indexed -> indexed\n");
174 testassert(INDEXED(bufo));
175 _objc_rootRetain(bufo);
176 testassert(_objc_rootRetainCount(bufo) == 2);
177 object_setClass(bufo, [Fake_OS_object class]);
178 testassert(_objc_rootRetainCount(bufo) == 2);
179 _objc_rootRelease(bufo);
180 testassert(_objc_rootRetainCount(bufo) == 1);
181 check_indexed(bufo, [Fake_OS_object class]);
183 testprintf("Change isa indexed -> unindexed\n");
184 // Retain count must be preserved.
185 // Use root* to avoid OS_object's overrides.
186 testassert(INDEXED(bufo));
187 _objc_rootRetain(bufo);
188 testassert(_objc_rootRetainCount(bufo) == 2);
189 object_setClass(bufo, [OS_object class]);
190 testassert(_objc_rootRetainCount(bufo) == 2);
191 _objc_rootRelease(bufo);
192 testassert(_objc_rootRetainCount(bufo) == 1);
193 check_unindexed(bufo, [OS_object class]);
195 testprintf("Change isa unindexed -> indexed (doesn't happen)\n");
196 testassert(!INDEXED(bufo));
197 _objc_rootRetain(bufo);
198 testassert(_objc_rootRetainCount(bufo) == 2);
199 object_setClass(bufo, [Fake_OS_object class]);
200 testassert(_objc_rootRetainCount(bufo) == 2);
201 _objc_rootRelease(bufo);
202 testassert(_objc_rootRetainCount(bufo) == 1);
203 check_unindexed(bufo, [Fake_OS_object class]);
205 testprintf("Change isa unindexed -> unindexed\n");
206 testassert(!INDEXED(bufo));
207 _objc_rootRetain(bufo);
208 testassert(_objc_rootRetainCount(bufo) == 2);
209 object_setClass(bufo, [Sub_OS_object class]);
210 testassert(_objc_rootRetainCount(bufo) == 2);
211 _objc_rootRelease(bufo);
212 testassert(_objc_rootRetainCount(bufo) == 1);
213 check_unindexed(bufo, [Sub_OS_object class]);
219 // SUPPORT_NONPOINTER_ISA