cdtors.mm 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // TEST_CONFIG
  2. #if USE_FOUNDATION
  3. #include <Foundation/Foundation.h>
  4. #define SUPERCLASS NSObject
  5. #define FILENAME "nscdtors.mm"
  6. #else
  7. #define SUPERCLASS TestRoot
  8. #define FILENAME "cdtors.mm"
  9. #endif
  10. #include "test.h"
  11. #include <pthread.h>
  12. #include "objc/objc-internal.h"
  13. #include "testroot.i"
  14. static unsigned ctors1 = 0;
  15. static unsigned dtors1 = 0;
  16. static unsigned ctors2 = 0;
  17. static unsigned dtors2 = 0;
  18. class cxx1 {
  19. unsigned & ctors;
  20. unsigned& dtors;
  21. public:
  22. cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
  23. ~cxx1() { dtors++; }
  24. };
  25. class cxx2 {
  26. unsigned& ctors;
  27. unsigned& dtors;
  28. public:
  29. cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
  30. ~cxx2() { dtors++; }
  31. };
  32. /*
  33. Class hierarchy:
  34. TestRoot
  35. CXXBase
  36. NoCXXSub
  37. CXXSub
  38. This has two cxx-wielding classes, and a class in between without cxx.
  39. */
  40. @interface CXXBase : SUPERCLASS {
  41. cxx1 baseIvar;
  42. }
  43. @end
  44. @implementation CXXBase @end
  45. @interface NoCXXSub : CXXBase {
  46. int nocxxIvar;
  47. }
  48. @end
  49. @implementation NoCXXSub @end
  50. @interface CXXSub : NoCXXSub {
  51. cxx2 subIvar;
  52. }
  53. @end
  54. @implementation CXXSub @end
  55. void test_single(void)
  56. {
  57. // Single allocation
  58. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  59. testonthread(^{
  60. id o = [TestRoot new];
  61. testassert(ctors1 == 0 && dtors1 == 0 &&
  62. ctors2 == 0 && dtors2 == 0);
  63. testassert([o class] == [TestRoot class]);
  64. RELEASE_VAR(o);
  65. });
  66. testcollect();
  67. testassert(ctors1 == 0 && dtors1 == 0 &&
  68. ctors2 == 0 && dtors2 == 0);
  69. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  70. testonthread(^{
  71. id o = [CXXBase new];
  72. testassert(ctors1 == 1 && dtors1 == 0 &&
  73. ctors2 == 0 && dtors2 == 0);
  74. testassert([o class] == [CXXBase class]);
  75. RELEASE_VAR(o);
  76. });
  77. testcollect();
  78. testassert(ctors1 == 1 && dtors1 == 1 &&
  79. ctors2 == 0 && dtors2 == 0);
  80. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  81. testonthread(^{
  82. id o = [NoCXXSub new];
  83. testassert(ctors1 == 1 && dtors1 == 0 &&
  84. ctors2 == 0 && dtors2 == 0);
  85. testassert([o class] == [NoCXXSub class]);
  86. RELEASE_VAR(o);
  87. });
  88. testcollect();
  89. testassert(ctors1 == 1 && dtors1 == 1 &&
  90. ctors2 == 0 && dtors2 == 0);
  91. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  92. testonthread(^{
  93. id o = [CXXSub new];
  94. testassert(ctors1 == 1 && dtors1 == 0 &&
  95. ctors2 == 1 && dtors2 == 0);
  96. testassert([o class] == [CXXSub class]);
  97. RELEASE_VAR(o);
  98. });
  99. testcollect();
  100. testassert(ctors1 == 1 && dtors1 == 1 &&
  101. ctors2 == 1 && dtors2 == 1);
  102. }
  103. void test_inplace(void)
  104. {
  105. __unsafe_unretained volatile id o;
  106. char o2[64];
  107. id (*objc_constructInstance_fn)(Class, void*) = (id(*)(Class, void*))dlsym(RTLD_DEFAULT, "objc_constructInstance");
  108. void (*objc_destructInstance_fn)(id) = (void(*)(id))dlsym(RTLD_DEFAULT, "objc_destructInstance");
  109. // In-place allocation
  110. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  111. o = objc_constructInstance_fn([TestRoot class], o2);
  112. testassert(ctors1 == 0 && dtors1 == 0 &&
  113. ctors2 == 0 && dtors2 == 0);
  114. testassert([o class] == [TestRoot class]);
  115. objc_destructInstance_fn(o), o = nil;
  116. testcollect();
  117. testassert(ctors1 == 0 && dtors1 == 0 &&
  118. ctors2 == 0 && dtors2 == 0);
  119. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  120. o = objc_constructInstance_fn([CXXBase class], o2);
  121. testassert(ctors1 == 1 && dtors1 == 0 &&
  122. ctors2 == 0 && dtors2 == 0);
  123. testassert([o class] == [CXXBase class]);
  124. objc_destructInstance_fn(o), o = nil;
  125. testcollect();
  126. testassert(ctors1 == 1 && dtors1 == 1 &&
  127. ctors2 == 0 && dtors2 == 0);
  128. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  129. o = objc_constructInstance_fn([NoCXXSub class], o2);
  130. testassert(ctors1 == 1 && dtors1 == 0 &&
  131. ctors2 == 0 && dtors2 == 0);
  132. testassert([o class] == [NoCXXSub class]);
  133. objc_destructInstance_fn(o), o = nil;
  134. testcollect();
  135. testassert(ctors1 == 1 && dtors1 == 1 &&
  136. ctors2 == 0 && dtors2 == 0);
  137. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  138. o = objc_constructInstance_fn([CXXSub class], o2);
  139. testassert(ctors1 == 1 && dtors1 == 0 &&
  140. ctors2 == 1 && dtors2 == 0);
  141. testassert([o class] == [CXXSub class]);
  142. objc_destructInstance_fn(o), o = nil;
  143. testcollect();
  144. testassert(ctors1 == 1 && dtors1 == 1 &&
  145. ctors2 == 1 && dtors2 == 1);
  146. }
  147. #if __has_feature(objc_arc)
  148. void test_batch(void)
  149. {
  150. // not converted to ARC yet
  151. return;
  152. }
  153. #else
  154. // Like class_createInstances(), but refuses to accept zero allocations
  155. static unsigned
  156. reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
  157. {
  158. unsigned count;
  159. while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
  160. testprintf("class_createInstances created nothing; retrying\n");
  161. RELEASE_VALUE([[TestRoot alloc] init]);
  162. }
  163. return count;
  164. }
  165. void test_batch(void)
  166. {
  167. id o2[100];
  168. unsigned int count, i;
  169. // Batch allocation
  170. for (i = 0; i < 100; i++) {
  171. o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
  172. }
  173. for (i = 0; i < 100; i++) {
  174. free(o2[i]);
  175. }
  176. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  177. count = reallyCreateInstances([TestRoot class], 0, o2, 10);
  178. testassert(count > 0);
  179. testassert(ctors1 == 0 && dtors1 == 0 &&
  180. ctors2 == 0 && dtors2 == 0);
  181. for (i = 0; i < count; i++) testassert([o2[i] class] == [TestRoot class]);
  182. for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
  183. testcollect();
  184. testassert(ctors1 == 0 && dtors1 == 0 &&
  185. ctors2 == 0 && dtors2 == 0);
  186. for (i = 0; i < 100; i++) {
  187. // prime batch allocator
  188. free(malloc(class_getInstanceSize([TestRoot class])));
  189. }
  190. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  191. count = reallyCreateInstances([CXXBase class], 0, o2, 10);
  192. testassert(count > 0);
  193. testassert(ctors1 == count && dtors1 == 0 &&
  194. ctors2 == 0 && dtors2 == 0);
  195. for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXBase class]);
  196. for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
  197. testcollect();
  198. testassert(ctors1 == count && dtors1 == count &&
  199. ctors2 == 0 && dtors2 == 0);
  200. for (i = 0; i < 100; i++) {
  201. // prime batch allocator
  202. free(malloc(class_getInstanceSize([TestRoot class])));
  203. }
  204. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  205. count = reallyCreateInstances([NoCXXSub class], 0, o2, 10);
  206. testassert(count > 0);
  207. testassert(ctors1 == count && dtors1 == 0 &&
  208. ctors2 == 0 && dtors2 == 0);
  209. for (i = 0; i < count; i++) testassert([o2[i] class] == [NoCXXSub class]);
  210. for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
  211. testcollect();
  212. testassert(ctors1 == count && dtors1 == count &&
  213. ctors2 == 0 && dtors2 == 0);
  214. for (i = 0; i < 100; i++) {
  215. // prime batch allocator
  216. free(malloc(class_getInstanceSize([TestRoot class])));
  217. }
  218. ctors1 = dtors1 = ctors2 = dtors2 = 0;
  219. count = reallyCreateInstances([CXXSub class], 0, o2, 10);
  220. testassert(count > 0);
  221. testassert(ctors1 == count && dtors1 == 0 &&
  222. ctors2 == count && dtors2 == 0);
  223. for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXSub class]);
  224. for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
  225. testcollect();
  226. testassert(ctors1 == count && dtors1 == count &&
  227. ctors2 == count && dtors2 == count);
  228. }
  229. // not ARC
  230. #endif
  231. int main()
  232. {
  233. for (int i = 0; i < 1000; i++) {
  234. testonthread(^{ test_single(); });
  235. testonthread(^{ test_inplace(); });
  236. testonthread(^{ test_batch(); });
  237. }
  238. testonthread(^{ test_single(); });
  239. testonthread(^{ test_inplace(); });
  240. testonthread(^{ test_batch(); });
  241. leak_mark();
  242. for (int i = 0; i < 1000; i++) {
  243. testonthread(^{ test_single(); });
  244. testonthread(^{ test_inplace(); });
  245. testonthread(^{ test_batch(); });
  246. }
  247. leak_check(0);
  248. // fixme ctor exceptions aren't caught inside .cxx_construct ?
  249. // Single allocation, ctors fail
  250. // In-place allocation, ctors fail
  251. // Batch allocation, ctors fail for every object
  252. // Batch allocation, ctors fail for every other object
  253. succeed(FILENAME);
  254. }