From 2942c76a384e0e01291efe707d326d3d6c6fea8a Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Sun, 18 Oct 2026 12:02:21 +0100 Subject: [PATCH] Slightly rework the implementation of objc_alloc_init. This now assumes the fast paths are more likely and inlines the fast-path alloc. If we're doing the fast-path alloc, then we get back a valid id of the correct class. If not, then we have to check for some special cases (a different class or a nil return). Fixes #432 --- Test/FastPathAlloc.m | 14 ++++++++++++++ fast_paths.m | 22 +++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Test/FastPathAlloc.m b/Test/FastPathAlloc.m index f1eb6244..ee097fca 100644 --- a/Test/FastPathAlloc.m +++ b/Test/FastPathAlloc.m @@ -21,6 +21,8 @@ @interface NoAlloc : Test @end @interface NoInit : Test @end @interface NoInit2 : NoInit @end +@interface NilAlloc : NoInit @end + @interface ShouldInitSubclassed : NoInit @end @implementation ShouldAlloc @@ -100,6 +102,13 @@ + (instancetype) alloc } @end +@implementation NilAlloc ++ (instancetype)alloc +{ + return nil; +} +@end + Class getClassNamed(char *name) { return nil; @@ -147,6 +156,11 @@ int main(void) // implementations can handle receivers that are nil [getClassNamed("flibble") alloc]; [[getClassNamed("flibble") alloc] init]; + + // Check that we can handle fast-path init if alloc returns nil. + assert([[NilAlloc alloc] init] == nil); + + return 0; } #endif diff --git a/fast_paths.m b/fast_paths.m index ec2f646a..1d0ee8ec 100644 --- a/fast_paths.m +++ b/fast_paths.m @@ -62,11 +62,23 @@ - (id)init; { return nil; } - id instance = objc_alloc(cls); - // If +alloc was overwritten, it is not guaranteed that it returns - // an instance of cls. - cls = classForObject(instance); - if (objc_test_class_flag(cls, objc_class_flag_fast_alloc_init)) + id instance; + if (LIKELY(objc_test_class_flag(cls->isa, objc_class_flag_fast_alloc_init))) + { + instance = class_createInstance(cls, 0); + } + else + { + instance = [cls alloc]; + if (UNLIKELY(instance == nil)) + { + return nil; + } + // If +alloc was overwritten, it is not guaranteed that it returns + // an instance of cls. + cls = classForObject(instance); + } + if (LIKELY(objc_test_class_flag(cls, objc_class_flag_fast_alloc_init))) { return instance; }