6 #include "objc/objc-internal.h"
9 static unsigned ctors1 = 0;
10 static unsigned dtors1 = 0;
11 static unsigned ctors2 = 0;
12 static unsigned dtors2 = 0;
19 cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
28 cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
40 This has two cxx-wielding classes, and a class in between without cxx.
44 @interface CXXBase : TestRoot {
48 @implementation CXXBase @end
50 @interface NoCXXSub : CXXBase {
54 @implementation NoCXXSub @end
56 @interface CXXSub : NoCXXSub {
60 @implementation CXXSub @end
63 void test_single(void)
67 ctors1 = dtors1 = ctors2 = dtors2 = 0;
69 id o = [TestRoot new];
70 testassert(ctors1 == 0 && dtors1 == 0 &&
71 ctors2 == 0 && dtors2 == 0);
72 testassert([o class] == [TestRoot class]);
76 testassert(ctors1 == 0 && dtors1 == 0 &&
77 ctors2 == 0 && dtors2 == 0);
79 ctors1 = dtors1 = ctors2 = dtors2 = 0;
82 testassert(ctors1 == 1 && dtors1 == 0 &&
83 ctors2 == 0 && dtors2 == 0);
84 testassert([o class] == [CXXBase class]);
88 testassert(ctors1 == 1 && dtors1 == 1 &&
89 ctors2 == 0 && dtors2 == 0);
91 ctors1 = dtors1 = ctors2 = dtors2 = 0;
93 id o = [NoCXXSub new];
94 testassert(ctors1 == 1 && dtors1 == 0 &&
95 ctors2 == 0 && dtors2 == 0);
96 testassert([o class] == [NoCXXSub class]);
100 testassert(ctors1 == 1 && dtors1 == 1 &&
101 ctors2 == 0 && dtors2 == 0);
103 ctors1 = dtors1 = ctors2 = dtors2 = 0;
106 testassert(ctors1 == 1 && dtors1 == 0 &&
107 ctors2 == 1 && dtors2 == 0);
108 testassert([o class] == [CXXSub class]);
112 testassert(ctors1 == 1 && dtors1 == 1 &&
113 ctors2 == 1 && dtors2 == 1);
116 void test_inplace(void)
118 __unsafe_unretained volatile id o;
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");
124 // In-place allocation
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;
133 testassert(ctors1 == 0 && dtors1 == 0 &&
134 ctors2 == 0 && dtors2 == 0);
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;
143 testassert(ctors1 == 1 && dtors1 == 1 &&
144 ctors2 == 0 && dtors2 == 0);
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;
153 testassert(ctors1 == 1 && dtors1 == 1 &&
154 ctors2 == 0 && dtors2 == 0);
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;
163 testassert(ctors1 == 1 && dtors1 == 1 &&
164 ctors2 == 1 && dtors2 == 1);
168 #if __has_feature(objc_arc)
170 void test_batch(void)
172 // not converted to ARC yet
178 // Like class_createInstances(), but refuses to accept zero allocations
180 reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
183 while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
184 testprintf("class_createInstances created nothing; retrying\n");
185 RELEASE_VALUE([[TestRoot alloc] init]);
190 void test_batch(void)
193 unsigned int count, i;
197 for (i = 0; i < 100; i++) {
198 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
200 for (i = 0; i < 100; i++) {
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;
212 testassert(ctors1 == 0 && dtors1 == 0 &&
213 ctors2 == 0 && dtors2 == 0);
215 for (i = 0; i < 100; i++) {
216 // prime batch allocator
217 free(malloc(class_getInstanceSize([TestRoot class])));
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;
228 testassert(ctors1 == count && dtors1 == count &&
229 ctors2 == 0 && dtors2 == 0);
231 for (i = 0; i < 100; i++) {
232 // prime batch allocator
233 free(malloc(class_getInstanceSize([TestRoot class])));
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;
244 testassert(ctors1 == count && dtors1 == count &&
245 ctors2 == 0 && dtors2 == 0);
247 for (i = 0; i < 100; i++) {
248 // prime batch allocator
249 free(malloc(class_getInstanceSize([TestRoot class])));
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;
260 testassert(ctors1 == count && dtors1 == count &&
261 ctors2 == count && dtors2 == count);
270 for (int i = 0; i < 1000; i++) {
271 testonthread(^{ test_single(); });
272 testonthread(^{ test_inplace(); });
273 testonthread(^{ test_batch(); });
276 testonthread(^{ test_single(); });
277 testonthread(^{ test_inplace(); });
278 testonthread(^{ test_batch(); });
282 for (int i = 0; i < 1000; i++) {
283 testonthread(^{ test_single(); });
284 testonthread(^{ test_inplace(); });
285 testonthread(^{ test_batch(); });
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