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; }