]> git.saurik.com Git - apple/objc4.git/blobdiff - test/rr-autorelease2.m
objc4-646.tar.gz
[apple/objc4.git] / test / rr-autorelease2.m
index b3a8aaac166a6bfeeb6e8f417e1e2931ff52e998..fd004419b011ad9740af72f23af3f53b8672b5bf 100644 (file)
@@ -1,25 +1,29 @@
 // Define FOUNDATION=1 for NSObject and NSAutoreleasePool
 // Define FOUNDATION=0 for _objc_root* and _objc_autoreleasePool*
 
+#include "test.h"
+
 #if FOUNDATION
-#   define PUSH() [[NSAutoreleasePool alloc] init]
-#   define POP(p) [(id)p release]
-#   define RETAIN(o) [o retain]
-#   define RELEASE(o) [o release]
-#   define AUTORELEASE(o) [o autorelease]
+#   define RR_PUSH() [[NSAutoreleasePool alloc] init]
+#   define RR_POP(p) [(id)p release]
+#   define RR_RETAIN(o) [o retain]
+#   define RR_RELEASE(o) [o release]
+#   define RR_AUTORELEASE(o) [o autorelease]
+#   define RR_RETAINCOUNT(o) [o retainCount]
 #else
-#   define PUSH() _objc_autoreleasePoolPush()
-#   define POP(p) _objc_autoreleasePoolPop(p)
-#   define RETAIN(o) _objc_rootRetain((id)o)
-#   define RELEASE(o) _objc_rootRelease((id)o)
-#   define AUTORELEASE(o) _objc_rootAutorelease((id)o)
+#   define RR_PUSH() _objc_autoreleasePoolPush()
+#   define RR_POP(p) _objc_autoreleasePoolPop(p)
+#   define RR_RETAIN(o) _objc_rootRetain((id)o)
+#   define RR_RELEASE(o) _objc_rootRelease((id)o)
+#   define RR_AUTORELEASE(o) _objc_rootAutorelease((id)o)
+#   define RR_RETAINCOUNT(o) _objc_rootRetainCount((id)o)
 #endif
 
-#include "test.h"
 #include <objc/objc-internal.h>
 #include <Foundation/Foundation.h>
 
 static int state;
+static pthread_attr_t smallstack;
 
 #define NESTED_COUNT 8
 
@@ -38,7 +42,7 @@ static int state;
 -(void) dealloc
 {
     state++;
-    AUTORELEASE([[Deallocator alloc] init]);
+    RR_AUTORELEASE([[Deallocator alloc] init]);
     [super dealloc];
 }
 @end
@@ -49,19 +53,19 @@ static int state;
 {
     // caller's pool
     for (int i = 0; i < NESTED_COUNT; i++) {
-        AUTORELEASE([[Deallocator alloc] init]);
+        RR_AUTORELEASE([[Deallocator alloc] init]);
     }
 
     // local pool, popped
-    void *pool = PUSH();
+    void *pool = RR_PUSH();
     for (int i = 0; i < NESTED_COUNT; i++) {
-        AUTORELEASE([[Deallocator alloc] init]);
+        RR_AUTORELEASE([[Deallocator alloc] init]);
     }
-    POP(pool);
+    RR_POP(pool);
 
     // caller's pool again
     for (int i = 0; i < NESTED_COUNT; i++) {
-        AUTORELEASE([[Deallocator alloc] init]);
+        RR_AUTORELEASE([[Deallocator alloc] init]);
     }
 
 #if FOUNDATION
@@ -73,9 +77,9 @@ static int state;
     state += NESTED_COUNT;
 #else
     // local pool, not popped
-    PUSH();
+    RR_PUSH();
     for (int i = 0; i < NESTED_COUNT; i++) {
-        AUTORELEASE([[Deallocator alloc] init]);
+        RR_AUTORELEASE([[Deallocator alloc] init]);
     }
 #endif
 
@@ -83,14 +87,6 @@ static int state;
 }
 @end
 
-void *nopop_fn(void *arg __unused)
-{
-    PUSH();
-    AUTORELEASE([[Deallocator alloc] init]);
-    // pool not popped
-    return NULL;
-}
-
 void *autorelease_lots_fn(void *singlePool)
 {
     // Enough to blow out the stack if AutoreleasePoolPage is recursive.
@@ -99,42 +95,41 @@ void *autorelease_lots_fn(void *singlePool)
 
     int p = 0;
     void **pools = (void**)malloc((COUNT+1) * sizeof(void*));
-    pools[p++] = PUSH();
+    pools[p++] = RR_PUSH();
 
-    id obj = AUTORELEASE([[Deallocator alloc] init]);
+    id obj = RR_AUTORELEASE([[Deallocator alloc] init]);
+
+    // last pool has only 1 autorelease in it
+    pools[p++] = RR_PUSH();
 
     for (int i = 0; i < COUNT; i++) {
         if (rand() % 1000 == 0  &&  !singlePool) {
-            pools[p++] = PUSH();
+            pools[p++] = RR_PUSH();
         } else {
-            AUTORELEASE(RETAIN(obj));
+            RR_AUTORELEASE(RR_RETAIN(obj));
         }
     }
 
     testassert(state == 0);
     while (--p) {
-        POP(pools[p]);
+        RR_POP(pools[p]);
     }
     testassert(state == 0);
-    POP(pools[0]);
+    testassert(RR_RETAINCOUNT(obj) == 1);
+    RR_POP(pools[0]);
     testassert(state == 1);
     free(pools);
 
     return NULL;
 }
 
-void *pop_fn(void *arg __unused)
-{
-    void *pool = PUSH();
-    AUTORELEASE([[Deallocator alloc] init]);
-    POP(pool);
-    return NULL;
-}
-
-void *nsthread_fn(void *arg)
+void *nsthread_fn(void *arg __unused)
 {
     [NSThread currentThread];
-    return pop_fn(arg);
+    void *pool = RR_PUSH();
+    RR_AUTORELEASE([[Deallocator alloc] init]);
+    RR_POP(pool);
+    return NULL;
 }
 
 void cycle(void)
@@ -142,11 +137,11 @@ void cycle(void)
     // Normal autorelease.
     testprintf("-- Normal autorelease.\n");
     {
-        void *pool = PUSH();
+        void *pool = RR_PUSH();
         state = 0;
-        AUTORELEASE([[Deallocator alloc] init]);
+        RR_AUTORELEASE([[Deallocator alloc] init]);
         testassert(state == 0);
-        POP(pool);
+        RR_POP(pool);
         testassert(state == 1);
     }
 
@@ -154,22 +149,22 @@ void cycle(void)
     // That autorelease is handled by the popping pool, not the one above it.
     testprintf("-- Autorelease during dealloc during autoreleasepool-pop.\n");
     {
-        void *pool = PUSH();
+        void *pool = RR_PUSH();
         state = 0;
-        AUTORELEASE([[AutoreleaseDuringDealloc alloc] init]);
+        RR_AUTORELEASE([[AutoreleaseDuringDealloc alloc] init]);
         testassert(state == 0);
-        POP(pool);
+        RR_POP(pool);
         testassert(state == 2);
     }
 
     // Autorelease pool during dealloc during autoreleasepool-pop.
     testprintf("-- Autorelease pool during dealloc during autoreleasepool-pop.\n");
     {
-        void *pool = PUSH();
+        void *pool = RR_PUSH();
         state = 0;
-        AUTORELEASE([[AutoreleasePoolDuringDealloc alloc] init]);
+        RR_AUTORELEASE([[AutoreleasePoolDuringDealloc alloc] init]);
         testassert(state == 0);
-        POP(pool);
+        RR_POP(pool);
         testassert(state == 4 * NESTED_COUNT);
     }
 
@@ -177,9 +172,11 @@ void cycle(void)
     testprintf("-- Thread-level pool popped normally.\n");
     {
         state = 0;
-        pthread_t th;
-        pthread_create(&th, NULL, &pop_fn, NULL);
-        pthread_join(th, NULL);
+        testonthread(^{ 
+            void *pool = RR_PUSH();
+            RR_AUTORELEASE([[Deallocator alloc] init]);
+            RR_POP(pool);
+        });
         testassert(state == 1);
     }
 
@@ -195,9 +192,11 @@ void cycle(void)
     testprintf("-- Thread-level pool not popped.\n");
     {
         state = 0;
-        pthread_t th;
-        pthread_create(&th, NULL, &nopop_fn, NULL);
-        pthread_join(th, NULL);
+        testonthread(^{
+            RR_PUSH();
+            RR_AUTORELEASE([[Deallocator alloc] init]);
+            // pool not popped
+        });
         testassert(state == 1);
     }
 #endif
@@ -213,12 +212,12 @@ void cycle(void)
 #else
     testprintf("-- Intermediate pool not popped.\n");
     {
-        void *pool = PUSH();
-        void *pool2 = PUSH();
-        AUTORELEASE([[Deallocator alloc] init]);
+        void *pool = RR_PUSH();
+        void *pool2 = RR_PUSH();
+        RR_AUTORELEASE([[Deallocator alloc] init]);
         state = 0;
         (void)pool2; // pool2 not popped
-        POP(pool);
+        RR_POP(pool);
         testassert(state == 1);
     }
 #endif
@@ -235,29 +234,58 @@ void cycle(void)
     /*
     testprintf("-- pop(0).\n");
     {
-        PUSH();
+        RR_PUSH();
         state = 0;
-        AUTORELEASE([[AutoreleaseDuringDealloc alloc] init]);
+        RR_AUTORELEASE([[AutoreleaseDuringDealloc alloc] init]);
         testassert(state == 0);
-        POP(0);
+        RR_POP(0);
         testassert(state == 2);
     }
     */
 #endif
 }
 
+
+static void
+slow_cycle(void)
+{
+    // Large autorelease stack.
+    // Do this only once because it's slow.
+    testprintf("-- Large autorelease stack.\n");
+    {
+        // limit stack size: autorelease pop should not be recursive
+        pthread_t th;
+        pthread_create(&th, &smallstack, &autorelease_lots_fn, NULL);
+        pthread_join(th, NULL);
+    }
+
+    // Single large autorelease pool.
+    // Do this only once because it's slow.
+    testprintf("-- Large autorelease pool.\n");
+    {
+        // limit stack size: autorelease pop should not be recursive
+        pthread_t th;
+        pthread_create(&th, &smallstack, &autorelease_lots_fn, (void*)1);
+        pthread_join(th, NULL);
+    }
+}
+
+
 int main()
 {
+    pthread_attr_init(&smallstack);
+    pthread_attr_setstacksize(&smallstack, 16384);
+
     // inflate the refcount side table so it doesn't show up in leak checks
     {
         int count = 10000;
         id *objs = (id *)malloc(count*sizeof(id));
         for (int i = 0; i < count; i++) {
-            objs[i] = RETAIN([NSObject new]);
+            objs[i] = RR_RETAIN([NSObject new]);
         }
         for (int i = 0; i < count; i++) {
-            RELEASE(objs[i]);
-            RELEASE(objs[i]);
+            RR_RELEASE(objs[i]);
+            RR_RELEASE(objs[i]);
         }
         free(objs);
     }
@@ -279,14 +307,12 @@ int main()
 #endif
 
 
-    pthread_attr_t smallstack;
-    pthread_attr_init(&smallstack);
-    pthread_attr_setstacksize(&smallstack, 4096*4);
-
     for (int i = 0; i < 100; i++) {
         cycle();
     }
 
+    slow_cycle();
+    
     leak_mark();
 
     for (int i = 0; i < 1000; i++) {
@@ -295,28 +321,9 @@ int main()
 
     leak_check(0);
 
-    // Large autorelease stack.
-    // Do this only once because it's slow.
-    testprintf("-- Large autorelease stack.\n");
-    {
-        // limit stack size: autorelease pop should not be recursive
-        pthread_t th;
-        pthread_create(&th, &smallstack, &autorelease_lots_fn, NULL);
-        pthread_join(th, NULL);
-    }
-
-    // Single large autorelease pool.
-    // Do this only once because it's slow.
-    testprintf("-- Large autorelease pool.\n");
-    {
-        // limit stack size: autorelease pop should not be recursive
-        pthread_t th;
-        pthread_create(&th, &smallstack, &autorelease_lots_fn, (void*)1);
-        pthread_join(th, NULL);
-    }
+    slow_cycle();
 
-    testwarn("rdar://9158789 leak slop due to false in-use from malloc");
-    leak_check(8192 /* should be 0 */);
+    leak_check(0);
 
 
     // NSThread.