1 //TEST_CONFIG MEM=mrc ARCH=x86_64,ARM64,ARM64e
2 //TEST_ENV OBJC_DISABLE_AUTORELEASE_COALESCING=NO OBJC_DISABLE_AUTORELEASE_COALESCING_LRU=NO
5 #import <Foundation/NSObject.h>
6 #include <os/feature_private.h>
8 @interface Counter: NSObject {
15 @implementation Counter
19 return [super retain];
22 - (oneway void)release {
29 return [super autorelease];
33 testprintf("%p dealloc\n", self);
39 // Create a number of objects, autoreleasing each one a number of times in a
40 // round robin fashion. Verify that each object gets sent retain, release, and
41 // autorelease the correct number of times. Verify that the gap between
42 // autoreleasepool pointers is the given number of objects. Note: this will not
43 // work when the pool hits a page boundary, to be sure to stay under that limit.
44 void test(int objCount, int autoreleaseCount, int expectedGap) {
45 testprintf("Testing %d objects, %d autoreleases, expecting gap of %d\n",
46 objCount, autoreleaseCount, expectedGap);
48 Counter *objs[objCount];
49 for (int i = 0; i < objCount; i++)
50 objs[i] = [Counter new];
52 for (int j = 0; j < autoreleaseCount; j++)
53 for (int i = 0; i < objCount; i++)
56 for (int i = 0; i < objCount; i++) {
57 testassertequal(objs[i]->retains, autoreleaseCount);
58 testassertequal(objs[i]->releases, 0);
59 testassertequal(objs[i]->autoreleases, 0);
62 void *outer = objc_autoreleasePoolPush();
63 uintptr_t outerAddr = (uintptr_t)outer;
64 for (int j = 0; j < autoreleaseCount; j++)
65 for (int i = 0; i < objCount; i++)
66 [objs[i] autorelease];
67 for (int i = 0; i < objCount; i++) {
68 testassertequal(objs[i]->retains, autoreleaseCount);
69 testassertequal(objs[i]->releases, 0);
70 testassertequal(objs[i]->autoreleases, autoreleaseCount);
73 void *inner = objc_autoreleasePoolPush();
74 uintptr_t innerAddr = (uintptr_t)inner;
75 testprintf("outer=%p inner=%p\n", outer, inner);
76 // Do one more autorelease in the inner pool to make sure we correctly
77 // handle pool boundaries.
78 for (int i = 0; i < objCount; i++)
79 [[objs[i] retain] autorelease];
80 for (int i = 0; i < objCount; i++) {
81 testassertequal(objs[i]->retains, autoreleaseCount + 1);
82 testassertequal(objs[i]->releases, 0);
83 testassertequal(objs[i]->autoreleases, autoreleaseCount + 1);
86 objc_autoreleasePoolPop(inner);
87 for (int i = 0; i < objCount; i++) {
88 testassertequal(objs[i]->retains, autoreleaseCount + 1);
89 testassertequal(objs[i]->releases, 1);
90 testassertequal(objs[i]->autoreleases, autoreleaseCount + 1);
93 objc_autoreleasePoolPop(outer);
94 for (int i = 0; i < objCount; i++) {
95 testassertequal(objs[i]->retains, autoreleaseCount + 1);
96 testassertequal(objs[i]->releases, autoreleaseCount + 1);
97 testassertequal(objs[i]->autoreleases, autoreleaseCount + 1);
100 intptr_t gap = innerAddr - outerAddr;
101 testprintf("gap=%ld\n", gap);
102 testassertequal(gap, expectedGap * sizeof(id));
104 // Destroy our test objects.
105 for (int i = 0; i < objCount; i++)
111 // Push a pool here so test() doesn't see a placeholder.
112 objc_autoreleasePoolPush();