Skip to content

Relax the rules around objc_alloc and objc_alloc_init optimizations. #580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 15, 2020

Conversation

MadCoder
Copy link

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:

  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,

  2. 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 [email protected]

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:

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,

2. 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 <[email protected]>
@MadCoder
Copy link
Author

@swift-ci please test macos platform

@MadCoder MadCoder merged commit e16715e into apple/stable/20190619 Jan 15, 2020
@MadCoder MadCoder deleted the eng/PR-58058316-20190619 branch January 15, 2020 22:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant