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