]>
Commit | Line | Data |
---|---|---|
34d5b5e8 A |
1 | //TEST_CONFIG MEM=mrc ARCH=x86_64,ARM64,ARM64e |
2 | //TEST_ENV OBJC_DISABLE_AUTORELEASE_COALESCING=NO OBJC_DISABLE_AUTORELEASE_COALESCING_LRU=NO | |
3 | ||
4 | #include "test.h" | |
5 | #import <Foundation/NSObject.h> | |
6 | #include <os/feature_private.h> | |
7 | ||
8 | @interface Counter: NSObject { | |
9 | @public | |
10 | int retains; | |
11 | int releases; | |
12 | int autoreleases; | |
13 | } | |
14 | @end | |
15 | @implementation Counter | |
16 | ||
17 | - (id)retain { | |
18 | retains++; | |
19 | return [super retain]; | |
20 | } | |
21 | ||
22 | - (oneway void)release { | |
23 | releases++; | |
24 | [super release]; | |
25 | } | |
26 | ||
27 | - (id)autorelease { | |
28 | autoreleases++; | |
29 | return [super autorelease]; | |
30 | } | |
31 | ||
32 | - (void)dealloc { | |
33 | testprintf("%p dealloc\n", self); | |
34 | [super dealloc]; | |
35 | } | |
36 | ||
37 | @end | |
38 | ||
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); | |
47 | ||
48 | Counter *objs[objCount]; | |
49 | for (int i = 0; i < objCount; i++) | |
50 | objs[i] = [Counter new]; | |
51 | ||
52 | for (int j = 0; j < autoreleaseCount; j++) | |
53 | for (int i = 0; i < objCount; i++) | |
54 | [objs[i] retain]; | |
55 | ||
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); | |
60 | } | |
61 | ||
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); | |
71 | } | |
72 | ||
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); | |
84 | } | |
85 | ||
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); | |
91 | } | |
92 | ||
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); | |
98 | } | |
99 | ||
100 | intptr_t gap = innerAddr - outerAddr; | |
101 | testprintf("gap=%ld\n", gap); | |
102 | testassertequal(gap, expectedGap * sizeof(id)); | |
103 | ||
104 | // Destroy our test objects. | |
105 | for (int i = 0; i < objCount; i++) | |
106 | [objs[i] release]; | |
107 | } | |
108 | ||
109 | int main() | |
110 | { | |
111 | // Push a pool here so test() doesn't see a placeholder. | |
112 | objc_autoreleasePoolPush(); | |
113 | ||
114 | test(1, 1, 2); | |
115 | test(1, 2, 2); | |
116 | test(1, 10, 2); | |
117 | test(1, 100, 2); | |
118 | test(1, 70000, 3); | |
119 | ||
120 | test(2, 1, 3); | |
121 | test(2, 2, 3); | |
122 | test(2, 10, 3); | |
123 | test(2, 100, 3); | |
124 | test(2, 70000, 5); | |
125 | ||
126 | test(3, 1, 4); | |
127 | test(3, 2, 4); | |
128 | test(3, 10, 4); | |
129 | test(3, 100, 4); | |
130 | test(3, 70000, 7); | |
131 | ||
132 | test(4, 1, 5); | |
133 | test(4, 2, 5); | |
134 | test(4, 10, 5); | |
135 | test(4, 100, 5); | |
136 | test(4, 70000, 9); | |
137 | ||
138 | test(5, 1, 6); | |
139 | test(5, 2, 11); | |
140 | ||
141 | succeed(__FILE__); | |
142 | } |