4 #define SUPERCLASS NSObject
5 #define FILENAME "nscdtors.mm"
7 #define SUPERCLASS TestRoot
8 #define FILENAME "cdtors.mm"
14 #include "objc/objc-internal.h"
17 static unsigned ctors1 = 0;
18 static unsigned dtors1 = 0;
19 static unsigned ctors2 = 0;
20 static unsigned dtors2 = 0;
27 cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
36 cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
48 This has two cxx-wielding classes, and a class in between without cxx.
52 @interface CXXBase : SUPERCLASS {
56 @implementation CXXBase @end
58 @interface NoCXXSub : CXXBase {
62 @implementation NoCXXSub @end
64 @interface CXXSub : NoCXXSub {
68 @implementation CXXSub @end
71 void test_single(void)
75 ctors1 = dtors1 = ctors2 = dtors2 = 0;
77 id o = [TestRoot new];
78 testassert(ctors1 == 0 && dtors1 == 0 &&
79 ctors2 == 0 && dtors2 == 0);
80 testassert([o class] == [TestRoot class]);
84 testassert(ctors1 == 0 && dtors1 == 0 &&
85 ctors2 == 0 && dtors2 == 0);
87 ctors1 = dtors1 = ctors2 = dtors2 = 0;
90 testassert(ctors1 == 1 && dtors1 == 0 &&
91 ctors2 == 0 && dtors2 == 0);
92 testassert([o class] == [CXXBase class]);
96 testassert(ctors1 == 1 && dtors1 == 1 &&
97 ctors2 == 0 && dtors2 == 0);
99 ctors1 = dtors1 = ctors2 = dtors2 = 0;
101 id o = [NoCXXSub new];
102 testassert(ctors1 == 1 && dtors1 == 0 &&
103 ctors2 == 0 && dtors2 == 0);
104 testassert([o class] == [NoCXXSub class]);
108 testassert(ctors1 == 1 && dtors1 == 1 &&
109 ctors2 == 0 && dtors2 == 0);
111 ctors1 = dtors1 = ctors2 = dtors2 = 0;
114 testassert(ctors1 == 1 && dtors1 == 0 &&
115 ctors2 == 1 && dtors2 == 0);
116 testassert([o class] == [CXXSub class]);
120 testassert(ctors1 == 1 && dtors1 == 1 &&
121 ctors2 == 1 && dtors2 == 1);
124 void test_inplace(void)
126 __unsafe_unretained volatile id o;
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");
132 // In-place allocation
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;
141 testassert(ctors1 == 0 && dtors1 == 0 &&
142 ctors2 == 0 && dtors2 == 0);
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;
151 testassert(ctors1 == 1 && dtors1 == 1 &&
152 ctors2 == 0 && dtors2 == 0);
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;
161 testassert(ctors1 == 1 && dtors1 == 1 &&
162 ctors2 == 0 && dtors2 == 0);
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;
171 testassert(ctors1 == 1 && dtors1 == 1 &&
172 ctors2 == 1 && dtors2 == 1);
176 #if __has_feature(objc_arc)
178 void test_batch(void)
180 // not converted to ARC yet
186 // Like class_createInstances(), but refuses to accept zero allocations
188 reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
191 while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
192 testprintf("class_createInstances created nothing; retrying\n");
193 RELEASE_VALUE([[TestRoot alloc] init]);
198 void test_batch(void)
201 unsigned int count, i;
205 for (i = 0; i < 100; i++) {
206 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
208 for (i = 0; i < 100; i++) {
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;
220 testassert(ctors1 == 0 && dtors1 == 0 &&
221 ctors2 == 0 && dtors2 == 0);
223 for (i = 0; i < 100; i++) {
224 // prime batch allocator
225 free(malloc(class_getInstanceSize([TestRoot class])));
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;
236 testassert(ctors1 == count && dtors1 == count &&
237 ctors2 == 0 && dtors2 == 0);
239 for (i = 0; i < 100; i++) {
240 // prime batch allocator
241 free(malloc(class_getInstanceSize([TestRoot class])));
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;
252 testassert(ctors1 == count && dtors1 == count &&
253 ctors2 == 0 && dtors2 == 0);
255 for (i = 0; i < 100; i++) {
256 // prime batch allocator
257 free(malloc(class_getInstanceSize([TestRoot class])));
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;
268 testassert(ctors1 == count && dtors1 == count &&
269 ctors2 == count && dtors2 == count);
278 for (int i = 0; i < 1000; i++) {
279 testonthread(^{ test_single(); });
280 testonthread(^{ test_inplace(); });
281 testonthread(^{ test_batch(); });
284 testonthread(^{ test_single(); });
285 testonthread(^{ test_inplace(); });
286 testonthread(^{ test_batch(); });
290 for (int i = 0; i < 1000; i++) {
291 testonthread(^{ test_single(); });
292 testonthread(^{ test_inplace(); });
293 testonthread(^{ test_batch(); });
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