From bf62fec6b1ad7e3ee3bee5f33cf157eba4632cfd Mon Sep 17 00:00:00 2001 From: Todd White Date: Tue, 11 Aug 2026 17:58:01 -0400 Subject: [PATCH] Choose the autorelease pool implementation once initAutorelease guarded its work with a test of AutoreleasePool, which stays Nil in a program that has no NSAutoreleasePool. The search was therefore repeated on every objc_autoreleasePoolPush and on every objc_autorelease of a fast ARC object, and objc_getClass hashes a string and walks the class table. Callgrind over a loop of push and pop in a program with no Foundation gives 516 instructions per pair, 65 percent of them in that lookup. Timed inside the process, ns per push and pop pair: 27.53 against 5.17 with no Foundation, and 5.17 either way with it, where the class is found on the first call and the guard closes. The implementation is chosen once rather than on the first call that finds the class. A pool is pushed and popped through whichever implementation is in force, so a program that pushed an ARC pool and then loaded Foundation would pop through NSAutoreleasePool a pool the ARC path had pushed. The suite passes, 198 of 198. --- arc.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arc.mm b/arc.mm index 459a3fb8..899b7e15 100644 --- a/arc.mm +++ b/arc.mm @@ -552,7 +552,11 @@ static inline void release(id obj) static inline void initAutorelease(void) { - if (Nil == AutoreleasePool) + // The pool implementation is chosen once. A pool is pushed and popped + // through whichever one is in force, so a later switch would pop through + // the implementation that did not push. + static BOOL chosen; + if (!chosen) { AutoreleasePool = objc_getClass("NSAutoreleasePool"); if (Nil == AutoreleasePool) @@ -574,6 +578,7 @@ static inline void initAutorelease(void) SELECTOR(addObject:)); } } + chosen = YES; } }