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