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 void test_batch(void)
170 #if __has_feature(objc_arc)
171 // not converted to ARC yet
176 unsigned int count, i;
180 for (i = 0; i < 100; i++) {
181 o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
183 for (i = 0; i < 100; i++) {
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;
195 testassert(ctors1 == 0 && dtors1 == 0 &&
196 ctors2 == 0 && dtors2 == 0);
198 for (i = 0; i < 100; i++) {
199 // prime batch allocator
200 free(malloc(class_getInstanceSize([TestRoot class])));
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;
211 testassert(ctors1 == count && dtors1 == count &&
212 ctors2 == 0 && dtors2 == 0);
214 for (i = 0; i < 100; i++) {
215 // prime batch allocator
216 free(malloc(class_getInstanceSize([TestRoot class])));
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;
227 testassert(ctors1 == count && dtors1 == count &&
228 ctors2 == 0 && dtors2 == 0);
230 for (i = 0; i < 100; i++) {
231 // prime batch allocator
232 free(malloc(class_getInstanceSize([TestRoot class])));
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;
243 testassert(ctors1 == count && dtors1 == count &&
244 ctors2 == count && dtors2 == count);
250 testonthread(^{ test_single(); });
251 testonthread(^{ test_inplace(); });
255 testonthread(^{ test_batch(); });
257 // fixme can't get this to zero; may or may not be a real leak
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