Fixed a bug where we were tail calling objc_autorelease causing an object to not...
[oota-llvm.git] / lib / Transforms / Scalar / ObjCARC.cpp
index 34700ebb02c653ddaa2d1572af253fc17d2acf6d..1607e8e80a5d5b6d58e3f77144048a6f8dd8acae 100644 (file)
@@ -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;
         }