Today the optimization is limited to:
- [ClassName alloc]
- [self alloc] when within a class method
However it means that when code is written this way:
@interface MyObject - (id)copyWithZone:(NSZone *)zone { return [[self.class alloc] _initWith...]; } @end
... then the optimization doesn't kick in and +[NSObject alloc] ends up in IMP caches where it could have been avoided. It turns out that +alloc -> +[NSObject alloc] is the most cached SEL/IMP pair in the entire platform which is rather silly).
There's two theoretical risks allowing this optimization:
- if the receiver is nil (which it can't be today), but it turns out that objc_alloc()/objc_alloc_init() cope with a nil receiver,
- if the Class type for the receiver is a lie. However, for such a code to work today (and not fail witn an unrecognized selector anyway) you'd have to have implemented the -alloc instance method.
Fortunately, objc_alloc() doesn't assume that the receiver is a Class, it basically starts with a test that is similar to if (receiver->isa->bits & hasDefaultAWZ) { /* fastpath */ }. This bit is only set on metaclasses by the runtime, so if an instance is passed to this function by accident, its isa will fail this test, and objc_alloc() will gracefully fallback to objc_msgSend().
The one thing objc_alloc() doesn't support is tagged pointer instances. None of the tagged pointer classes implement an instance method called 'alloc' (actually there's a single class in the entire Apple codebase that has such a method).
Radar-Id: rdar://problem/58058316
Can you add a test case for [[self class] alloc] to test the code in tryGenerateSpecializedMessageSend?