]> git.saurik.com Git - apple/objc4.git/blob - test/nonpointerisa.m
objc4-680.tar.gz
[apple/objc4.git] / test / nonpointerisa.m
1 // TEST_CFLAGS -framework Foundation
2 // TEST_CONFIG MEM=mrc
3
4 #include "test.h"
5
6 #if !__OBJC2__
7
8 int main()
9 {
10 succeed(__FILE__);
11 }
12
13 #else
14
15 #include <dlfcn.h>
16
17 #include <objc/objc-gdb.h>
18 #include <Foundation/Foundation.h>
19
20 #define ISA(x) (*((uintptr_t *)(x)))
21 #define INDEXED(x) (ISA(x) & 1)
22
23 #if SUPPORT_NONPOINTER_ISA
24 # if __x86_64__
25 # define RC_ONE (1ULL<<56)
26 # elif __arm64__
27 # define RC_ONE (1ULL<<45)
28 # else
29 # error unknown architecture
30 # endif
31 #endif
32
33
34 void check_unindexed(id obj, Class cls)
35 {
36 testassert(object_getClass(obj) == cls);
37 testassert(!INDEXED(obj));
38
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);
43
44 CFRetain(obj);
45 testassert(ISA(obj) == isa);
46 testassert([obj retainCount] == 2);
47 [obj retain];
48 testassert(ISA(obj) == isa);
49 testassert([obj retainCount] == 3);
50 CFRelease(obj);
51 testassert(ISA(obj) == isa);
52 testassert([obj retainCount] == 2);
53 [obj release];
54 testassert(ISA(obj) == isa);
55 testassert([obj retainCount] == 1);
56 }
57
58
59 #if ! SUPPORT_NONPOINTER_ISA
60
61 int main()
62 {
63 testprintf("Isa with index\n");
64 id index_o = [NSObject new];
65 check_unindexed(index_o, [NSObject class]);
66
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"));
71
72 succeed(__FILE__);
73 }
74
75 #else
76 // SUPPORT_NONPOINTER_ISA
77
78 void check_indexed(id obj, Class cls)
79 {
80 testassert(object_getClass(obj) == cls);
81 testassert(INDEXED(obj));
82
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);
87
88 CFRetain(obj);
89 testassert(ISA(obj) == isa + RC_ONE);
90 testassert([obj retainCount] == 2);
91 [obj retain];
92 testassert(ISA(obj) == isa + RC_ONE*2);
93 testassert([obj retainCount] == 3);
94 CFRelease(obj);
95 testassert(ISA(obj) == isa + RC_ONE);
96 testassert([obj retainCount] == 2);
97 [obj release];
98 testassert(ISA(obj) == isa);
99 testassert([obj retainCount] == 1);
100 }
101
102
103 @interface OS_object <NSObject>
104 +(id)new;
105 @end
106
107 @interface Fake_OS_object : NSObject {
108 int refcnt;
109 int xref_cnt;
110 }
111 @end
112
113 @implementation Fake_OS_object
114 +(void)initialize {
115 static bool initialized;
116 if (!initialized) {
117 initialized = true;
118 testprintf("Indexed during +initialize\n");
119 testassert(INDEXED(self));
120 id o = [Fake_OS_object new];
121 check_indexed(o, self);
122 [o release];
123 }
124 }
125 @end
126
127 @interface Sub_OS_object : OS_object @end
128
129 @implementation Sub_OS_object
130 @end
131
132
133
134 int main()
135 {
136 uintptr_t isa;
137
138 testprintf("Isa with index\n");
139 id index_o = [Fake_OS_object new];
140 check_indexed(index_o, [Fake_OS_object class]);
141
142 testprintf("Weakly referenced\n");
143 isa = ISA(index_o);
144 id weak;
145 objc_storeWeak(&weak, index_o);
146 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
147
148 testprintf("Has associated references\n");
149 id assoc = @"thing";
150 isa = ISA(index_o);
151 objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
152 testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
153
154
155 testprintf("Isa without index\n");
156 id unindex_o = [OS_object new];
157 check_unindexed(unindex_o, [OS_object class]);
158
159
160 id buf[4];
161 id bufo = (id)buf;
162
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]);
167
168 testprintf("Change isa 0 -> indexed\n");
169 bzero(buf, sizeof(buf));
170 object_setClass(bufo, [NSObject class]);
171 check_indexed(bufo, [NSObject class]);
172
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]);
182
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]);
194
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]);
204
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]);
214
215
216 succeed(__FILE__);
217 }
218
219 // SUPPORT_NONPOINTER_ISA
220 #endif
221
222 // __OBJC2__
223 #endif