mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
ARCAnalysis: Teach ARC analysis about certain objective c methods that are not may-release
This enables it to move retain about critical objective c method calls such as objectAtIndex and count used by Array. Improves DeltaBlue by 35% at -O. radar://20147568 Swift SVN r26082
This commit is contained in:
@@ -29,6 +29,56 @@ using namespace swift;
|
||||
// Decrement Analysis
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// \brief Test whether this is an Objective C method of a specific protocol.
|
||||
static bool isObjCProtocolMethod(WitnessMethodInst *WMI, ProtocolDecl *Protocol,
|
||||
StringRef MethodName) {
|
||||
|
||||
// Must be an objc method.
|
||||
auto Member = WMI->getMember();
|
||||
if (!Member.isForeign)
|
||||
return false;
|
||||
|
||||
if (Protocol != WMI->getLookupProtocol())
|
||||
return false;
|
||||
|
||||
auto *Method = Member.getFuncDecl();
|
||||
|
||||
if (!Method || Method->getName().empty())
|
||||
return false;
|
||||
|
||||
if (!Method->getName().str().equals(MethodName))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Test whether this is an Objective C getter of a specific protocol.
|
||||
static bool isObjCProtocolGetter(WitnessMethodInst *WMI, ProtocolDecl *Protocol,
|
||||
StringRef VarName) {
|
||||
// Must be an objc method.
|
||||
auto Member = WMI->getMember();
|
||||
if (!Member.isForeign)
|
||||
return false;
|
||||
|
||||
if (Protocol != WMI->getLookupProtocol())
|
||||
return false;
|
||||
|
||||
auto *Method = Member.getFuncDecl();
|
||||
|
||||
if (!Method || !Method->isGetter())
|
||||
return false;
|
||||
|
||||
auto *Storage = Method->getAccessorStorageDecl();
|
||||
if (!Storage || Storage->getName().empty())
|
||||
return false;
|
||||
|
||||
if (!Storage->getName().str().equals(VarName))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
|
||||
return llvm::StringSwitch<bool>(FRI->getReferencedFunction()->getName())
|
||||
.Case("swift_keepAlive", true)
|
||||
@@ -36,6 +86,37 @@ static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
/// \brief Check whether this is an Objective C method that only has balanced
|
||||
/// retain/releases. The method is known not to decrement a reference count
|
||||
/// before incrementing it.
|
||||
static bool isObjCMethodKnownToNotDecrementRefCount(ApplyInst *AI) {
|
||||
auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee());
|
||||
if (!WMI)
|
||||
return false;
|
||||
|
||||
auto &Ctx = AI->getFunction()->getModule().getASTContext();
|
||||
|
||||
auto *ArrayProtocol = Ctx.getProtocol(KnownProtocolKind::_NSArrayCoreType);
|
||||
// If we don't have the _NSArrayCoreType we will not have an
|
||||
// _NSDictionaryCoreType either.
|
||||
if (!ArrayProtocol)
|
||||
return false;
|
||||
|
||||
if (isObjCProtocolMethod(WMI, ArrayProtocol, "objectAtIndex"))
|
||||
return true;
|
||||
if (isObjCProtocolGetter(WMI, ArrayProtocol, "count"))
|
||||
return true;
|
||||
|
||||
auto *DictionaryProtocol =
|
||||
Ctx.getProtocol(KnownProtocolKind::_NSDictionaryCoreType);
|
||||
if (isObjCProtocolMethod(WMI, DictionaryProtocol, "objectForKey"))
|
||||
return true;
|
||||
if (isObjCProtocolGetter(WMI, DictionaryProtocol, "count"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool canApplyDecrementRefCount(OperandValueArrayRef Ops, SILValue Ptr,
|
||||
AliasAnalysis *AA) {
|
||||
// Ok, this apply *MAY* decrement ref counts. Now our strategy is to attempt
|
||||
@@ -91,6 +172,9 @@ static bool canApplyDecrementRefCount(ApplyInst *AI, SILValue Ptr,
|
||||
if (Call && !Call.isMayRelease())
|
||||
return false;
|
||||
|
||||
if (isObjCMethodKnownToNotDecrementRefCount(AI))
|
||||
return false;
|
||||
|
||||
return canApplyDecrementRefCount(AI->getArgumentsWithoutIndirectResult(),
|
||||
Ptr, AA);
|
||||
}
|
||||
@@ -432,6 +516,9 @@ mayGuaranteedUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) {
|
||||
if (Call && !Call.isMayRelease())
|
||||
return false;
|
||||
|
||||
if (isObjCMethodKnownToNotDecrementRefCount(AI))
|
||||
return false;
|
||||
|
||||
// Ok, we have an apply with arguments. Look at the function type and iterate
|
||||
// through the function parameters. If any of the parameters are guaranteed,
|
||||
// attempt to prove that the passed in parameter can not alias Ptr. If we
|
||||
|
||||
Reference in New Issue
Block a user