123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- // TEST_CONFIG
- #if USE_FOUNDATION
- #include <Foundation/Foundation.h>
- #define SUPERCLASS NSObject
- #define FILENAME "nscdtors.mm"
- #else
- #define SUPERCLASS TestRoot
- #define FILENAME "cdtors.mm"
- #endif
- #include "test.h"
- #include <pthread.h>
- #include "objc/objc-internal.h"
- #include "testroot.i"
- static unsigned ctors1 = 0;
- static unsigned dtors1 = 0;
- static unsigned ctors2 = 0;
- static unsigned dtors2 = 0;
- class cxx1 {
- unsigned & ctors;
- unsigned& dtors;
- public:
- cxx1() : ctors(ctors1), dtors(dtors1) { ctors++; }
- ~cxx1() { dtors++; }
- };
- class cxx2 {
- unsigned& ctors;
- unsigned& dtors;
- public:
- cxx2() : ctors(ctors2), dtors(dtors2) { ctors++; }
- ~cxx2() { dtors++; }
- };
- /*
- Class hierarchy:
- TestRoot
- CXXBase
- NoCXXSub
- CXXSub
- This has two cxx-wielding classes, and a class in between without cxx.
- */
- @interface CXXBase : SUPERCLASS {
- cxx1 baseIvar;
- }
- @end
- @implementation CXXBase @end
- @interface NoCXXSub : CXXBase {
- int nocxxIvar;
- }
- @end
- @implementation NoCXXSub @end
- @interface CXXSub : NoCXXSub {
- cxx2 subIvar;
- }
- @end
- @implementation CXXSub @end
- void test_single(void)
- {
- // Single allocation
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- testonthread(^{
- id o = [TestRoot new];
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [TestRoot class]);
- RELEASE_VAR(o);
- });
- testcollect();
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- testonthread(^{
- id o = [CXXBase new];
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [CXXBase class]);
- RELEASE_VAR(o);
- });
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- testonthread(^{
- id o = [NoCXXSub new];
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [NoCXXSub class]);
- RELEASE_VAR(o);
- });
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- testonthread(^{
- id o = [CXXSub new];
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 1 && dtors2 == 0);
- testassert([o class] == [CXXSub class]);
- RELEASE_VAR(o);
- });
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 1 && dtors2 == 1);
- }
- void test_inplace(void)
- {
- __unsafe_unretained volatile id o;
- char o2[64];
- id (*objc_constructInstance_fn)(Class, void*) = (id(*)(Class, void*))dlsym(RTLD_DEFAULT, "objc_constructInstance");
- void (*objc_destructInstance_fn)(id) = (void(*)(id))dlsym(RTLD_DEFAULT, "objc_destructInstance");
- // In-place allocation
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- o = objc_constructInstance_fn([TestRoot class], o2);
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [TestRoot class]);
- objc_destructInstance_fn(o), o = nil;
- testcollect();
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- o = objc_constructInstance_fn([CXXBase class], o2);
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [CXXBase class]);
- objc_destructInstance_fn(o), o = nil;
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- o = objc_constructInstance_fn([NoCXXSub class], o2);
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- testassert([o class] == [NoCXXSub class]);
- objc_destructInstance_fn(o), o = nil;
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 0 && dtors2 == 0);
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- o = objc_constructInstance_fn([CXXSub class], o2);
- testassert(ctors1 == 1 && dtors1 == 0 &&
- ctors2 == 1 && dtors2 == 0);
- testassert([o class] == [CXXSub class]);
- objc_destructInstance_fn(o), o = nil;
- testcollect();
- testassert(ctors1 == 1 && dtors1 == 1 &&
- ctors2 == 1 && dtors2 == 1);
- }
- #if __has_feature(objc_arc)
- void test_batch(void)
- {
- // not converted to ARC yet
- return;
- }
- #else
- // Like class_createInstances(), but refuses to accept zero allocations
- static unsigned
- reallyCreateInstances(Class cls, size_t extraBytes, id *dst, unsigned want)
- {
- unsigned count;
- while (0 == (count = class_createInstances(cls, extraBytes, dst, want))) {
- testprintf("class_createInstances created nothing; retrying\n");
- RELEASE_VALUE([[TestRoot alloc] init]);
- }
- return count;
- }
- void test_batch(void)
- {
- id o2[100];
- unsigned int count, i;
- // Batch allocation
- for (i = 0; i < 100; i++) {
- o2[i] = (id)malloc(class_getInstanceSize([TestRoot class]));
- }
- for (i = 0; i < 100; i++) {
- free(o2[i]);
- }
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- count = reallyCreateInstances([TestRoot class], 0, o2, 10);
- testassert(count > 0);
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < count; i++) testassert([o2[i] class] == [TestRoot class]);
- for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
- testcollect();
- testassert(ctors1 == 0 && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < 100; i++) {
- // prime batch allocator
- free(malloc(class_getInstanceSize([TestRoot class])));
- }
-
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- count = reallyCreateInstances([CXXBase class], 0, o2, 10);
- testassert(count > 0);
- testassert(ctors1 == count && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXBase class]);
- for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
- testcollect();
- testassert(ctors1 == count && dtors1 == count &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < 100; i++) {
- // prime batch allocator
- free(malloc(class_getInstanceSize([TestRoot class])));
- }
-
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- count = reallyCreateInstances([NoCXXSub class], 0, o2, 10);
- testassert(count > 0);
- testassert(ctors1 == count && dtors1 == 0 &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < count; i++) testassert([o2[i] class] == [NoCXXSub class]);
- for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
- testcollect();
- testassert(ctors1 == count && dtors1 == count &&
- ctors2 == 0 && dtors2 == 0);
- for (i = 0; i < 100; i++) {
- // prime batch allocator
- free(malloc(class_getInstanceSize([TestRoot class])));
- }
-
- ctors1 = dtors1 = ctors2 = dtors2 = 0;
- count = reallyCreateInstances([CXXSub class], 0, o2, 10);
- testassert(count > 0);
- testassert(ctors1 == count && dtors1 == 0 &&
- ctors2 == count && dtors2 == 0);
- for (i = 0; i < count; i++) testassert([o2[i] class] == [CXXSub class]);
- for (i = 0; i < count; i++) object_dispose(o2[i]), o2[i] = nil;
- testcollect();
- testassert(ctors1 == count && dtors1 == count &&
- ctors2 == count && dtors2 == count);
- }
- // not ARC
- #endif
- int main()
- {
- for (int i = 0; i < 1000; i++) {
- testonthread(^{ test_single(); });
- testonthread(^{ test_inplace(); });
- testonthread(^{ test_batch(); });
- }
- testonthread(^{ test_single(); });
- testonthread(^{ test_inplace(); });
- testonthread(^{ test_batch(); });
- leak_mark();
- for (int i = 0; i < 1000; i++) {
- testonthread(^{ test_single(); });
- testonthread(^{ test_inplace(); });
- testonthread(^{ test_batch(); });
- }
- leak_check(0);
- // fixme ctor exceptions aren't caught inside .cxx_construct ?
- // Single allocation, ctors fail
- // In-place allocation, ctors fail
- // Batch allocation, ctors fail for every object
- // Batch allocation, ctors fail for every other object
- succeed(FILENAME);
- }
|