Handle mutation while enumerating correctly. Fix some bugs.

llvm-svn: 55583
This commit is contained in:
Anders Carlsson 2008-08-31 04:05:03 +00:00
parent aebd2662d3
commit 3f35a266da
4 changed files with 79 additions and 7 deletions

View File

@ -281,10 +281,10 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy), llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy),
"state.ptr"); "state.ptr");
StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3); StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);
EmitMemSetToZero(StatePtr,StateTy); EmitMemSetToZero(StatePtr, StateTy);
// Number of elements in the items array. // Number of elements in the items array.
static const unsigned NumItems = 2; static const unsigned NumItems = 16;
// Get selector // Get selector
llvm::SmallVector<IdentifierInfo*, 3> II; llvm::SmallVector<IdentifierInfo*, 3> II;
@ -323,23 +323,64 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
llvm::BasicBlock *NoElements = llvm::BasicBlock::Create("noelements"); 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 *Limit = Builder.CreateLoad(LimitPtr);
llvm::Value *Zero = llvm::Constant::getNullValue(UnsignedLongLTy); llvm::Value *Zero = llvm::Constant::getNullValue(UnsignedLongLTy);
llvm::Value *IsZero = Builder.CreateICmpEQ(Limit, Zero, "iszero"); 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); EmitBlock(LoopStart);
llvm::BasicBlock *LoopBody = llvm::BasicBlock::Create("loopbody");
llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr"); llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr");
Builder.CreateStore(Zero, CounterPtr); Builder.CreateStore(Zero, CounterPtr);
llvm::BasicBlock *LoopBody = llvm::BasicBlock::Create("loopbody");
EmitBlock(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 = llvm::Value *StateItemsPtr =
Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr"); Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
@ -384,7 +425,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S)
llvm::BasicBlock *FetchMore = llvm::BasicBlock::Create("fetchmore"); llvm::BasicBlock *FetchMore = llvm::BasicBlock::Create("fetchmore");
llvm::Value *IsLess = Builder.CreateICmpULT(Counter, Limit, "isless"); llvm::Value *IsLess = Builder.CreateICmpULT(Counter, Limit, "isless");
Builder.CreateCondBr(IsLess, LoopBody, FetchMore); Builder.CreateCondBr(IsLess, LoopStart, FetchMore);
// Fetch more elements. // Fetch more elements.
EmitBlock(FetchMore); EmitBlock(FetchMore);

View File

@ -120,6 +120,7 @@ public:
const ObjCProtocolDecl *PD); const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD); virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction(); virtual llvm::Function *ModuleInitFunction();
virtual llvm::Function *EnumerationMutationFunction();
}; };
} // end anonymous namespace } // end anonymous namespace
@ -958,6 +959,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD) {
return Method; 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){ CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){
return new CGObjCGNU(CGM); return new CGObjCGNU(CGM);
} }

View File

@ -130,6 +130,7 @@ public:
/// MethodListPtrTy - LLVM type for struct objc_method_list *. /// MethodListPtrTy - LLVM type for struct objc_method_list *.
const llvm::Type *MethodListPtrTy; const llvm::Type *MethodListPtrTy;
llvm::Function *EnumerationMutationFn;
public: public:
ObjCTypesHelper(CodeGen::CodeGenModule &cgm); ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCTypesHelper(); ~ObjCTypesHelper();
@ -370,6 +371,7 @@ public:
virtual void GenerateProtocol(const ObjCProtocolDecl *PD); virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction(); virtual llvm::Function *ModuleInitFunction();
virtual llvm::Function *EnumerationMutationFunction();
}; };
} // end anonymous namespace } // end anonymous namespace
@ -1379,6 +1381,11 @@ llvm::Function *CGObjCMac::ModuleInitFunction() {
return NULL; return NULL;
} }
llvm::Function *CGObjCMac::EnumerationMutationFunction()
{
return ObjCTypes.EnumerationMutationFn;
}
/* *** Private Interface *** */ /* *** Private Interface *** */
/// EmitImageInfo - Emit the image info marker used to encode some module /// EmitImageInfo - Emit the image info marker used to encode some module
@ -1934,6 +1941,18 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
llvm::Function::ExternalLinkage, llvm::Function::ExternalLinkage,
"objc_msgSendSuper_stret", "objc_msgSendSuper_stret",
&CGM.getModule()); &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() { ObjCTypesHelper::~ObjCTypesHelper() {

View File

@ -122,6 +122,10 @@ public:
virtual llvm::Value *GetClass(BuilderType &Builder, virtual llvm::Value *GetClass(BuilderType &Builder,
const ObjCInterfaceDecl *OID) = 0; 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 /// If instance variable addresses are determined at runtime then this should
/// return true, otherwise instance variables will be accessed directly from /// return true, otherwise instance variables will be accessed directly from
/// the structure. If this returns true then @defs is invalid for this /// the structure. If this returns true then @defs is invalid for this