]> git.saurik.com Git - apple/objc4.git/blob - test/cdtors.mm
objc4-532.2.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 void test_batch(void)
169 {
170 #if __has_feature(objc_arc)
171 // not converted to ARC yet
172 return;
173 #else
174
175 id o2[100];
176 unsigned int count, i;
177
178 // Batch allocation
179
180 for (i = 0; i < 100; i++) {
181 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
182 }
183 for (i = 0; i < 100; i++) {
184 free(o2[i]);
185 }
186
187 ctors1 = dtors1 = ctors2 = dtors2 = 0;
188 count = class_createInstances([TestRoot class], 0, o2, 10);
189 testassert(count > 0);
190 testassert(ctors1 == 0 && dtors1 == 0 &&
191 ctors2 == 0 && dtors2 == 0);
192 for (i = 0; i < count; i++) testassert([o2[i] class] == [TestRoot class]);
193 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
194 testcollect();
195 testassert(ctors1 == 0 && dtors1 == 0 &&
196 ctors2 == 0 && dtors2 == 0);
197
198 for (i = 0; i < 100; i++) {
199 // prime batch allocator
200 free(malloc(class_getInstanceSize([TestRoot class])));
201 }
202
203 ctors1 = dtors1 = ctors2 = dtors2 = 0;
204 count = class_createInstances([CXXBase class], 0, o2, 10);
205 testassert(count > 0);
206 testassert(ctors1 == count && dtors1 == 0 &&
207 ctors2 == 0 && dtors2 == 0);
208 for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXBase class]);
209 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
210 testcollect();
211 testassert(ctors1 == count && dtors1 == count &&
212 ctors2 == 0 && dtors2 == 0);
213
214 for (i = 0; i < 100; i++) {
215 // prime batch allocator
216 free(malloc(class_getInstanceSize([TestRoot class])));
217 }
218
219 ctors1 = dtors1 = ctors2 = dtors2 = 0;
220 count = class_createInstances([NoCXXSub class], 0, o2, 10);
221 testassert(count > 0);
222 testassert(ctors1 == count && dtors1 == 0 &&
223 ctors2 == 0 && dtors2 == 0);
224 for (i = 0; i < count; i++) testassert([o2[i] class] == [NoCXXSub class]);
225 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
226 testcollect();
227 testassert(ctors1 == count && dtors1 == count &&
228 ctors2 == 0 && dtors2 == 0);
229
230 for (i = 0; i < 100; i++) {
231 // prime batch allocator
232 free(malloc(class_getInstanceSize([TestRoot class])));
233 }
234
235 ctors1 = dtors1 = ctors2 = dtors2 = 0;
236 count = class_createInstances([CXXSub class], 0, o2, 10);
237 testassert(count > 0);
238 testassert(ctors1 == count && dtors1 == 0 &&
239 ctors2 == count && dtors2 == 0);
240 for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXSub class]);
241 for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
242 testcollect();
243 testassert(ctors1 == count && dtors1 == count &&
244 ctors2 == count && dtors2 == count);
245 #endif
246 }
247
248 int main()
249 {
250 testonthread(^{ test_single(); });
251 testonthread(^{ test_inplace(); });
252
253 leak_mark();
254
255 testonthread(^{ test_batch(); });
256
257 // fixme can't get this to zero; may or may not be a real leak
258 leak_check(64);
259
260 // fixme ctor exceptions aren't caught inside .cxx_construct ?
261 // Single allocation, ctors fail
262 // In-place allocation, ctors fail
263 // Batch allocation, ctors fail for every object
264 // Batch allocation, ctors fail for every other object
265
266 succeed(__FILE__);
267 }