4 #include <Foundation/Foundation.h>
5 #define SUPERCLASS NSObject
6 #define FILENAME "nscdtors.mm"
8 #define SUPERCLASS TestRoot
9 #define FILENAME "cdtors.mm"
15 #include "objc/objc-internal.h"
18 static unsigned ctors1 = 0;
19 static unsigned dtors1 = 0;
20 static unsigned ctors2 = 0;
21 static unsigned dtors2 = 0;
28 cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
37 cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
49 This has two cxx-wielding classes, and a class in between without cxx.
53 @interface CXXBase : SUPERCLASS {
57 @implementation CXXBase @end
59 @interface NoCXXSub : CXXBase {
63 @implementation NoCXXSub @end
65 @interface CXXSub : NoCXXSub {
69 @implementation CXXSub @end
72 void test_single(void)
76 ctors1 = dtors1 = ctors2 = dtors2 = 0;
78 id o = [TestRoot new];
79 testassert(ctors1 == 0 && dtors1 == 0 &&
80 ctors2 == 0 && dtors2 == 0);
81 testassert([o class] == [TestRoot class]);
85 testassert(ctors1 == 0 && dtors1 == 0 &&
86 ctors2 == 0 && dtors2 == 0);
88 ctors1 = dtors1 = ctors2 = dtors2 = 0;
91 testassert(ctors1 == 1 && dtors1 == 0 &&
92 ctors2 == 0 && dtors2 == 0);
93 testassert([o class] == [CXXBase class]);
97 testassert(ctors1 == 1 && dtors1 == 1 &&
98 ctors2 == 0 && dtors2 == 0);
100 ctors1 = dtors1 = ctors2 = dtors2 = 0;
102 id o = [NoCXXSub new];
103 testassert(ctors1 == 1 && dtors1 == 0 &&
104 ctors2 == 0 && dtors2 == 0);
105 testassert([o class] == [NoCXXSub class]);
109 testassert(ctors1 == 1 && dtors1 == 1 &&
110 ctors2 == 0 && dtors2 == 0);
112 ctors1 = dtors1 = ctors2 = dtors2 = 0;
115 testassert(ctors1 == 1 && dtors1 == 0 &&
116 ctors2 == 1 && dtors2 == 0);
117 testassert([o class] == [CXXSub class]);
121 testassert(ctors1 == 1 && dtors1 == 1 &&
122 ctors2 == 1 && dtors2 == 1);
125 void test_inplace(void)
127 __unsafe_unretained volatile id o;
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");
133 // In-place allocation
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;
142 testassert(ctors1 == 0 && dtors1 == 0 &&
143 ctors2 == 0 && dtors2 == 0);
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;
152 testassert(ctors1 == 1 && dtors1 == 1 &&
153 ctors2 == 0 && dtors2 == 0);
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;
162 testassert(ctors1 == 1 && dtors1 == 1 &&
163 ctors2 == 0 && dtors2 == 0);
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;
172 testassert(ctors1 == 1 && dtors1 == 1 &&
173 ctors2 == 1 && dtors2 == 1);
177 #if __has_feature(objc_arc)
179 void test_batch(void)
181 // not converted to ARC yet
187 // Like class_createInstances(), but refuses to accept zero allocations
189 reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
192 while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
193 testprintf("class_createInstances created nothing; retrying\n");
194 RELEASE_VALUE([[TestRoot alloc] init]);
199 void test_batch(void)
202 unsigned int count, i;
206 for (i = 0; i < 100; i++) {
207 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
209 for (i = 0; i < 100; i++) {
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;
221 testassert(ctors1 == 0 && dtors1 == 0 &&
222 ctors2 == 0 && dtors2 == 0);
224 for (i = 0; i < 100; i++) {
225 // prime batch allocator
226 free(malloc(class_getInstanceSize([TestRoot class])));
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;
237 testassert(ctors1 == count && dtors1 == count &&
238 ctors2 == 0 && dtors2 == 0);
240 for (i = 0; i < 100; i++) {
241 // prime batch allocator
242 free(malloc(class_getInstanceSize([TestRoot class])));
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;
253 testassert(ctors1 == count && dtors1 == count &&
254 ctors2 == 0 && dtors2 == 0);
256 for (i = 0; i < 100; i++) {
257 // prime batch allocator
258 free(malloc(class_getInstanceSize([TestRoot class])));
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;
269 testassert(ctors1 == count && dtors1 == count &&
270 ctors2 == count && dtors2 == count);
279 for (int i = 0; i < 1000; i++) {
280 testonthread(^{ test_single(); });
281 testonthread(^{ test_inplace(); });
282 testonthread(^{ test_batch(); });
285 testonthread(^{ test_single(); });
286 testonthread(^{ test_inplace(); });
287 testonthread(^{ test_batch(); });
291 for (int i = 0; i < 1000; i++) {
292 testonthread(^{ test_single(); });
293 testonthread(^{ test_inplace(); });
294 testonthread(^{ test_batch(); });
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