]> granicus.if.org Git - clang/commitdiff
Handle mutation while enumerating correctly. Fix some bugs.
authorAnders Carlsson <andersca@mac.com>
Sun, 31 Aug 2008 04:05:03 +0000 (04:05 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 31 Aug 2008 04:05:03 +0000 (04:05 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55583 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CGObjCRuntime.h

index 26f678cc4eb0d22e4875b149b1f394d1f5ec6bd3..5376d0f3c77d31dc6db3246359fe6fb63be8068a 100644 (file)
@@ -281,10 +281,10 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
   llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy), 
                                                 "state.ptr");
   StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);  
-  EmitMemSetToZero(StatePtr,StateTy);
+  EmitMemSetToZero(StatePtr, StateTy);
   
   // Number of elements in the items array.
-  static const unsigned NumItems = 2;
+  static const unsigned NumItems = 16;
   
   // Get selector
   llvm::SmallVector<IdentifierInfo*, 3> II;
@@ -323,23 +323,64 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
   Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
   
   llvm::BasicBlock *NoElements = llvm::BasicBlock::Create("noelements");
-  llvm::BasicBlock *LoopStart = llvm::BasicBlock::Create("loopstart");
+  llvm::BasicBlock *SetStartMutations = 
+    llvm::BasicBlock::Create("setstartmutations");
   
   llvm::Value *Limit = Builder.CreateLoad(LimitPtr);
   llvm::Value *Zero = llvm::Constant::getNullValue(UnsignedLongLTy);
 
   llvm::Value *IsZero = Builder.CreateICmpEQ(Limit, Zero, "iszero");
-  Builder.CreateCondBr(IsZero, NoElements, LoopStart);
+  Builder.CreateCondBr(IsZero, NoElements, SetStartMutations);
 
+  EmitBlock(SetStartMutations);
+  
+  llvm::Value *StartMutationsPtr = 
+    CreateTempAlloca(UnsignedLongLTy);
+  
+  llvm::Value *StateMutationsPtrPtr = 
+    Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
+  llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, 
+                                                      "mutationsptr");
+  
+  llvm::Value *StateMutations = Builder.CreateLoad(StateMutationsPtr, 
+                                                   "mutations");
+  
+  Builder.CreateStore(StateMutations, StartMutationsPtr);
+  
+  llvm::BasicBlock *LoopStart = llvm::BasicBlock::Create("loopstart");
   EmitBlock(LoopStart);
 
-  llvm::BasicBlock *LoopBody = llvm::BasicBlock::Create("loopbody");
-
   llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr");
   Builder.CreateStore(Zero, CounterPtr);
   
+  llvm::BasicBlock *LoopBody = llvm::BasicBlock::Create("loopbody"); 
   EmitBlock(LoopBody);
 
+  StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
+  StateMutations = Builder.CreateLoad(StateMutationsPtr, "statemutations");
+
+  llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr, 
+                                                   "mutations");
+  llvm::Value *MutationsEqual = Builder.CreateICmpEQ(StateMutations, 
+                                                     StartMutations,
+                                                     "tobool");
+  
+  
+  llvm::BasicBlock *WasMutated = llvm::BasicBlock::Create("wasmutated");
+  llvm::BasicBlock *WasNotMutated = llvm::BasicBlock::Create("wasnotmutated");
+  
+  Builder.CreateCondBr(MutationsEqual, WasNotMutated, WasMutated);
+  
+  EmitBlock(WasMutated);
+  llvm::Value *V =
+    Builder.CreateBitCast(Collection, 
+                          ConvertType(getContext().getObjCIdType()),
+                          "tmp");
+  Builder.CreateCall(CGM.getObjCRuntime().EnumerationMutationFunction(),
+                     V);
+  
+  EmitBlock(WasNotMutated);
+  
   llvm::Value *StateItemsPtr = 
     Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
 
@@ -384,7 +425,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
   llvm::BasicBlock *FetchMore = llvm::BasicBlock::Create("fetchmore");
   
   llvm::Value *IsLess = Builder.CreateICmpULT(Counter, Limit, "isless");
-  Builder.CreateCondBr(IsLess, LoopBody, FetchMore);
+  Builder.CreateCondBr(IsLess, LoopStart, FetchMore);
 
   // Fetch more elements.
   EmitBlock(FetchMore);
index 4565fbfeb0efb67e1c0c7a33d6171a803ab3e88e..4d69aed8160f5ca73b947c770fbe7c4a3b3b8caf 100644 (file)
@@ -120,6 +120,7 @@ public:
                                            const ObjCProtocolDecl *PD);
   virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
   virtual llvm::Function *ModuleInitFunction();
+  virtual llvm::Function *EnumerationMutationFunction();
 };
 } // end anonymous namespace
 
@@ -958,6 +959,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD) {
   return Method;
 }
 
+llvm::Function *CGObjCGNU::EnumerationMutationFunction()
+{
+  assert(0 && "No enumeration mutation function in the GNU runtime!");
+  
+  return 0;
+}
+
 CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){
   return new CGObjCGNU(CGM);
 }
index ef4196e11fcdc655abff2114d61dd073ccdb80a5..798c9d3c4be8eda431012afe09cf0d5be74795ed 100644 (file)
@@ -130,6 +130,7 @@ public:
   /// MethodListPtrTy - LLVM type for struct objc_method_list *.
   const llvm::Type *MethodListPtrTy;
 
+  llvm::Function *EnumerationMutationFn;
 public:
   ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
   ~ObjCTypesHelper();
@@ -370,6 +371,7 @@ public:
   virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
 
   virtual llvm::Function *ModuleInitFunction();
+  virtual llvm::Function *EnumerationMutationFunction();
 };
 } // end anonymous namespace
 
@@ -1379,6 +1381,11 @@ llvm::Function *CGObjCMac::ModuleInitFunction() {
   return NULL;
 }
 
+llvm::Function *CGObjCMac::EnumerationMutationFunction()
+{
+  return ObjCTypes.EnumerationMutationFn;
+}
+
 /* *** Private Interface *** */
 
 /// EmitImageInfo - Emit the image info marker used to encode some module
@@ -1934,6 +1941,18 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
                            llvm::Function::ExternalLinkage,
                            "objc_msgSendSuper_stret",
                            &CGM.getModule());
+  
+  // Enumeration mutation.
+  
+  Params.clear();
+  Params.push_back(ObjectPtrTy);
+  EnumerationMutationFn = 
+    llvm::Function::Create(llvm::FunctionType::get(llvm::Type::VoidTy,
+                                                   Params,
+                                                   false),
+                           llvm::Function::ExternalLinkage,
+                           "objc_enumerationMutation",
+                           &CGM.getModule());
 }
 
 ObjCTypesHelper::~ObjCTypesHelper() {
index c0044e9a94d1a02b2517c11e879e281a2016594d..4bc293afacbb4266c3964350672fadc813532e57 100644 (file)
@@ -122,6 +122,10 @@ public:
   virtual llvm::Value *GetClass(BuilderType &Builder, 
                                 const ObjCInterfaceDecl *OID) = 0;
 
+  /// EnumerationMutationFunction - Return the function that's called by the
+  /// compiler when a mutation is detected during foreach iteration.
+  virtual llvm::Function *EnumerationMutationFunction() = 0;
+    
   /// If instance variable addresses are determined at runtime then this should
   /// return true, otherwise instance variables will be accessed directly from
   /// the structure.  If this returns true then @defs is invalid for this