diff options
author | Michael Gottesman <mgottesman@apple.com> | 2013-01-12 01:25:15 +0000 |
---|---|---|
committer | Michael Gottesman <mgottesman@apple.com> | 2013-01-12 01:25:15 +0000 |
commit | c9656faf1e73998b0ca0f0aff6652fec69c02c64 (patch) | |
tree | 234b8723a4012673e6580cce670537e3d4534ea2 /llvm/lib/Transforms | |
parent | e274088db052f89254a050c3f255bad9f92ddea5 (diff) | |
download | bcm5719-llvm-c9656faf1e73998b0ca0f0aff6652fec69c02c64.tar.gz bcm5719-llvm-c9656faf1e73998b0ca0f0aff6652fec69c02c64.zip |
Fixed a bug where we were tail calling objc_autorelease causing an object to not be placed into an autorelease pool.
The reason that this occurs is that tail calling objc_autorelease eventually
tail calls -[NSObject autorelease] which supports fast autorelease. This can
cause us to violate the semantic gaurantees of __autoreleasing variables that
assignment to an __autoreleasing variables always yields an object that is
placed into the innermost autorelease pool.
The fix included in this patch works by:
1. In the peephole optimization function OptimizeIndividualFunctions, always
remove tail call from objc_autorelease.
2. Whenever we convert to/from an objc_autorelease, set/unset the tail call
keyword as appropriate.
*NOTE* I also handled the case where objc_autorelease is converted in
OptimizeReturns to an autoreleaseRV which still violates the ARC semantics. I
will be removing that in a later patch and I wanted to make sure that the tree
is in a consistent state vis-a-vis ARC always.
Additionally some test cases are provided and all tests that have tail call marked
objc_autorelease keywords have been modified so that tail call has been removed.
*NOTE* One test fails due to a separate bug that I am going to commit soon. Thus
I marked the check line TMP: instead of CHECK: so make check does not fail.
llvm-svn: 172287
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r-- | llvm/lib/Transforms/Scalar/ObjCARC.cpp | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/llvm/lib/Transforms/Scalar/ObjCARC.cpp b/llvm/lib/Transforms/Scalar/ObjCARC.cpp index 34700ebb02c..1607e8e80a5 100644 --- a/llvm/lib/Transforms/Scalar/ObjCARC.cpp +++ b/llvm/lib/Transforms/Scalar/ObjCARC.cpp @@ -426,10 +426,20 @@ static bool IsAlwaysTail(InstructionClass Class) { // IC_RetainBlock may be given a stack argument. return Class == IC_Retain || Class == IC_RetainRV || - Class == IC_Autorelease || Class == IC_AutoreleaseRV; } +/// \brief Test if the given class represents instructions which are never safe +/// to mark with the "tail" keyword. +static bool IsNeverTail(InstructionClass Class) { + /// It is never safe to tail call objc_autorelease since by tail calling + /// objc_autorelease, we also tail call -[NSObject autorelease] which supports + /// fast autoreleasing causing our object to be potentially reclaimed from the + /// autorelease pool which violates the semantics of __autoreleasing types in + /// ARC. + return Class == IC_Autorelease; +} + /// IsNoThrow - Test if the given class represents instructions which are always /// safe to mark with the nounwind attribute.. static bool IsNoThrow(InstructionClass Class) { @@ -2306,8 +2316,10 @@ ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV) { " Old: " << *AutoreleaseRV << "\n"); - cast<CallInst>(AutoreleaseRV)-> + CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV); + AutoreleaseRVCI-> setCalledFunction(getAutoreleaseCallee(F.getParent())); + AutoreleaseRVCI->setTailCall(false); // Never tail call objc_autorelease. DEBUG(dbgs() << " New: " << *AutoreleaseRV << "\n"); @@ -2449,6 +2461,16 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { cast<CallInst>(Inst)->setTailCall(); } + // Ensure that functions that can never have a "tail" keyword due to the + // semantics of ARC truly do not do so. + if (IsNeverTail(Class)) { + Changed = true; + DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Removing tail keyword" + " from function: " << *Inst << + "\n"); + cast<CallInst>(Inst)->setTailCall(false); + } + // Set nounwind as needed. if (IsNoThrow(Class)) { Changed = true; @@ -3756,6 +3778,7 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { Autorelease->setCalledFunction(getAutoreleaseRVCallee(F.getParent())); DEBUG(dbgs() << " Out: " << *Autorelease << "\n"); + Autorelease->setTailCall(); // Always tail call autoreleaseRV. AutoreleaseClass = IC_AutoreleaseRV; } |