]> git.saurik.com Git - apple/objc4.git/blob - test/cdtors.mm
objc4-646.tar.gz
[apple/objc4.git] / test / cdtors.mm
1 // TEST_CONFIG
2
3 #if USE_FOUNDATION
4 #define SUPERCLASS NSObject
5 #define FILENAME "nscdtors.mm"
6 #else
7 #define SUPERCLASS TestRoot
8 #define FILENAME "cdtors.mm"
9 #endif
10
11 #include "test.h"
12
13 #include <pthread.h>
14 #include "objc/objc-internal.h"
15 #include "testroot.i"
16
17 static unsigned ctors1 = 0;
18 static unsigned dtors1 = 0;
19 static unsigned ctors2 = 0;
20 static unsigned dtors2 = 0;
21
22 class cxx1 {
23 unsigned & ctors;
24 unsigned& dtors;
25
26 public:
27 cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
28
29 ~cxx1() { dtors++; }
30 };
31 class cxx2 {
32 unsigned& ctors;
33 unsigned& dtors;
34
35 public:
36 cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
37
38 ~cxx2() { dtors++; }
39 };
40
41 /*
42 Class hierarchy:
43 TestRoot
44 CXXBase
45 NoCXXSub
46 CXXSub
47
48 This has two cxx-wielding classes, and a class in between without cxx.
49 */
50
51
52 @interface CXXBase : SUPERCLASS {
53 cxx1 baseIvar;
54 }
55 @end
56 @implementation CXXBase @end
57
58 @interface NoCXXSub : CXXBase {
59 int nocxxIvar;
60 }
61 @end
62 @implementation NoCXXSub @end
63
64 @interface CXXSub : NoCXXSub {
65 cxx2 subIvar;
66 }
67 @end
68 @implementation CXXSub @end
69
70
71 void test_single(void)
72 {
73 // Single allocation
74
75 ctors1 = dtors1 = ctors2 = dtors2 = 0;
76 testonthread(^{
77 id o = [TestRoot new];
78 testassert(ctors1 == 0 && dtors1 == 0 &&
79 ctors2 == 0 && dtors2 == 0);
80 testassert([o class] == [TestRoot class]);
81 RELEASE_VAR(o);
82 });
83 testcollect();
84 testassert(ctors1 == 0 && dtors1 == 0 &&
85 ctors2 == 0 && dtors2 == 0);
86
87 ctors1 = dtors1 = ctors2 = dtors2 = 0;
88 testonthread(^{
89 id o = [CXXBase new];
90 testassert(ctors1 == 1 && dtors1 == 0 &&
91 ctors2 == 0 && dtors2 == 0);
92 testassert([o class] == [CXXBase class]);
93 RELEASE_VAR(o);
94 });
95 testcollect();
96 testassert(ctors1 == 1 && dtors1 == 1 &&
97 ctors2 == 0 && dtors2 == 0);
98
99 ctors1 = dtors1 = ctors2 = dtors2 = 0;
100 testonthread(^{
101 id o = [NoCXXSub new];
102 testassert(ctors1 == 1 && dtors1 == 0 &&
103 ctors2 == 0 && dtors2 == 0);
104 testassert([o class] == [NoCXXSub class]);
105 RELEASE_VAR(o);
106 });
107 testcollect();
108 testassert(ctors1 == 1 && dtors1 == 1 &&
109 ctors2 == 0 && dtors2 == 0);
110
111 ctors1 = dtors1 = ctors2 = dtors2 = 0;
112 testonthread(^{
113 id o = [CXXSub new];
114 testassert(ctors1 == 1 && dtors1 == 0 &&
115 ctors2 == 1 && dtors2 == 0);
116 testassert([o class] == [CXXSub class]);
117 RELEASE_VAR(o);
118 });
119 testcollect();
120 testassert(ctors1 == 1 && dtors1 == 1 &&
121 ctors2 == 1 && dtors2 == 1);
122 }
123
124 void test_inplace(void)
125 {
126 __unsafe_unretained volatile id o;
127 char o2[64];
128
129 id (*objc_constructInstance_fn)(Class, void*) = (id(*)(Class, void*))dlsym(RTLD_DEFAULT, "objc_constructInstance");
130 void (*objc_destructInstance_fn)(id) = (void(*)(id))dlsym(RTLD_DEFAULT, "objc_destructInstance");
131
132 // In-place allocation
133
134 ctors1 = dtors1 = ctors2 = dtors2 = 0;
135 o = objc_constructInstance_fn([TestRoot class], o2);
136 testassert(ctors1 == 0 && dtors1 == 0 &&
137 ctors2 == 0 && dtors2 == 0);
138 testassert([o class] == [TestRoot class]);
139 objc_destructInstance_fn(o), o = nil;
140 testcollect();
141 testassert(ctors1 == 0 && dtors1 == 0 &&
142 ctors2 == 0 && dtors2 == 0);
143
144 ctors1 = dtors1 = ctors2 = dtors2 = 0;
145 o = objc_constructInstance_fn([CXXBase class], o2);
146 testassert(ctors1 == 1 && dtors1 == 0 &&
147 ctors2 == 0 && dtors2 == 0);
148 testassert([o class] == [CXXBase class]);
149 objc_destructInstance_fn(o), o = nil;
150 testcollect();
151 testassert(ctors1 == 1 && dtors1 == 1 &&
152 ctors2 == 0 && dtors2 == 0);
153
154 ctors1 = dtors1 = ctors2 = dtors2 = 0;
155 o = objc_constructInstance_fn([NoCXXSub class], o2);
156 testassert(ctors1 == 1 && dtors1 == 0 &&
157 ctors2 == 0 && dtors2 == 0);
158 testassert([o class] == [NoCXXSub class]);
159 objc_destructInstance_fn(o), o = nil;
160 testcollect();
161 testassert(ctors1 == 1 && dtors1 == 1 &&
162 ctors2 == 0 && dtors2 == 0);
163
164 ctors1 = dtors1 = ctors2 = dtors2 = 0;
165 o = objc_constructInstance_fn([CXXSub class], o2);
166 testassert(ctors1 == 1 && dtors1 == 0 &&
167 ctors2 == 1 && dtors2 == 0);
168 testassert([o class] == [CXXSub class]);
169 objc_destructInstance_fn(o), o = nil;
170 testcollect();
171 testassert(ctors1 == 1 && dtors1 == 1 &&
172 ctors2 == 1 && dtors2 == 1);
173 }
174
175
176 #if __has_feature(objc_arc)
177
178 void test_batch(void)
179 {
180 // not converted to ARC yet
181 return;
182 }
183
184 #else
185
186 // Like class_createInstances(), but refuses to accept zero allocations
187 static unsigned
188 reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
189 {
190 unsigned count;
191 while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
192 testprintf("class_createInstances created nothing; retrying\n");
193 RELEASE_VALUE([[TestRoot alloc] init]);
194 }
195 return count;
196 }
197
198 void test_batch(void)
199 {
200 id o2[100];
201 unsigned int count, i;
202
203 // Batch allocation
204
205 for (i = 0; i < 100; i++) {
206 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
207 }
208 for (i = 0; i < 100; i++) {
209 free(o2[i]);
210 }
211
212 ctors1 = dtors1 = ctors2 = dtors2 = 0;
213 count = reallyCreateInstances([TestRoot class], 0, o2, 10);
214 testassert(count > 0);
215 testassert(ctors1 == 0 && dtors1 == 0 &&
216 ctors2 == 0 && dtors2 == 0);
217 for (i = 0; i < count; i++) testassert([o2[i] class] == [TestRoot class]);
218 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
219 testcollect();
220 testassert(ctors1 == 0 && dtors1 == 0 &&
221 ctors2 == 0 && dtors2 == 0);
222
223 for (i = 0; i < 100; i++) {
224 // prime batch allocator
225 free(malloc(class_getInstanceSize([TestRoot class])));
226 }
227
228 ctors1 = dtors1 = ctors2 = dtors2 = 0;
229 count = reallyCreateInstances([CXXBase class], 0, o2, 10);
230 testassert(count > 0);
231 testassert(ctors1 == count && dtors1 == 0 &&
232 ctors2 == 0 && dtors2 == 0);
233 for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXBase class]);
234 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
235 testcollect();
236 testassert(ctors1 == count && dtors1 == count &&
237 ctors2 == 0 && dtors2 == 0);
238
239 for (i = 0; i < 100; i++) {
240 // prime batch allocator
241 free(malloc(class_getInstanceSize([TestRoot class])));
242 }
243
244 ctors1 = dtors1 = ctors2 = dtors2 = 0;
245 count = reallyCreateInstances([NoCXXSub class], 0, o2, 10);
246 testassert(count > 0);
247 testassert(ctors1 == count && dtors1 == 0 &&
248 ctors2 == 0 && dtors2 == 0);
249 for (i = 0; i < count; i++) testassert([o2[i] class] == [NoCXXSub class]);
250 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
251 testcollect();
252 testassert(ctors1 == count && dtors1 == count &&
253 ctors2 == 0 && dtors2 == 0);
254
255 for (i = 0; i < 100; i++) {
256 // prime batch allocator
257 free(malloc(class_getInstanceSize([TestRoot class])));
258 }
259
260 ctors1 = dtors1 = ctors2 = dtors2 = 0;
261 count = reallyCreateInstances([CXXSub class], 0, o2, 10);
262 testassert(count > 0);
263 testassert(ctors1 == count && dtors1 == 0 &&
264 ctors2 == count && dtors2 == 0);
265 for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXSub class]);
266 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
267 testcollect();
268 testassert(ctors1 == count && dtors1 == count &&
269 ctors2 == count && dtors2 == count);
270 }
271
272 // not ARC
273 #endif
274
275
276 int main()
277 {
278 for (int i = 0; i < 1000; i++) {
279 testonthread(^{ test_single(); });
280 testonthread(^{ test_inplace(); });
281 testonthread(^{ test_batch(); });
282 }
283
284 testonthread(^{ test_single(); });
285 testonthread(^{ test_inplace(); });
286 testonthread(^{ test_batch(); });
287
288 leak_mark();
289
290 for (int i = 0; i < 1000; i++) {
291 testonthread(^{ test_single(); });
292 testonthread(^{ test_inplace(); });
293 testonthread(^{ test_batch(); });
294 }
295
296 leak_check(0);
297
298 // fixme ctor exceptions aren't caught inside .cxx_construct ?
299 // Single allocation, ctors fail
300 // In-place allocation, ctors fail
301 // Batch allocation, ctors fail for every object
302 // Batch allocation, ctors fail for every other object
303
304 succeed(FILENAME);
305 }