Relax the rules around objc_alloc and objc_alloc_init optimizations.

Authored by MadCoder on Jan 14 2020, 6:56 PM.

Unpublished Commit ยท Learn More

Not On Permanent Ref: This commit is not an ancestor of any permanent ref.


Relax the rules around objc_alloc and objc_alloc_init optimizations.

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...];


... 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:

  1. 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,
  1. if the Clas 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).

Differential Revision: https://reviews.llvm.org/D71682
Radar-Id: rdar://problem/58058316
Reviewed-By: Akira Hatanaka
Signed-off-by: Pierre Habouzit <phabouzit@apple.com>