diff options
author | Pierre Habouzit <phabouzit@apple.com> | 2020-01-14 18:56:26 -0800 |
---|---|---|
committer | Pierre Habouzit <phabouzit@apple.com> | 2020-01-14 19:48:33 -0800 |
commit | d18fbfc09720009c0dc6a1ddf315402ee0a7751d (patch) | |
tree | ac2281f464f0bf4e6df2dc53a5ac06f879519d96 /clang/lib/CodeGen/CGObjC.cpp | |
parent | 0dbcb3639451a7c20e2d5133b459552281e64455 (diff) | |
download | bcm5719-llvm-d18fbfc09720009c0dc6a1ddf315402ee0a7751d.tar.gz bcm5719-llvm-d18fbfc09720009c0dc6a1ddf315402ee0a7751d.zip |
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...];
}
@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 <phabouzit@apple.com>
Diffstat (limited to 'clang/lib/CodeGen/CGObjC.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 40 |
1 files changed, 19 insertions, 21 deletions
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index c52aa6bb549..90fca2836d9 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -461,38 +461,39 @@ tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) { Sel.getNameForSlot(0) != "init") return None; - // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or - // we are in an ObjC class method and 'receiver' is '[self alloc]'. + // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' + // with 'cls' a Class. auto *SubOME = dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts()); if (!SubOME) return None; Selector SubSel = SubOME->getSelector(); - // Check if we are in an ObjC class method and the receiver expression is - // 'self'. - const Expr *SelfInClassMethod = nullptr; - if (const auto *CurMD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl)) - if (CurMD->isClassMethod()) - if ((SelfInClassMethod = SubOME->getInstanceReceiver())) - if (!SelfInClassMethod->isObjCSelfExpr()) - SelfInClassMethod = nullptr; - - if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class && - !SelfInClassMethod) || !SubOME->getType()->isObjCObjectPointerType() || + if (!SubOME->getType()->isObjCObjectPointerType() || !SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc") return None; - llvm::Value *Receiver; - if (SelfInClassMethod) { - Receiver = CGF.EmitScalarExpr(SelfInClassMethod); - } else { + llvm::Value *Receiver = nullptr; + switch (SubOME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + if (!SubOME->getInstanceReceiver()->getType()->isObjCClassType()) + return None; + Receiver = CGF.EmitScalarExpr(SubOME->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: { QualType ReceiverType = SubOME->getClassReceiver(); const ObjCObjectType *ObjTy = ReceiverType->castAs<ObjCObjectType>(); const ObjCInterfaceDecl *ID = ObjTy->getInterface(); assert(ID && "null interface should be impossible here"); Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID); + break; + } + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + return None; } + return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType())); } @@ -540,10 +541,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, switch (E->getReceiverKind()) { case ObjCMessageExpr::Instance: ReceiverType = E->getInstanceReceiver()->getType(); - if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl)) - if (OMD->isClassMethod()) - if (E->getInstanceReceiver()->isObjCSelfExpr()) - isClassMessage = true; + isClassMessage = ReceiverType->isObjCClassType(); if (retainSelf) { TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, E->getInstanceReceiver()); |