forked from OSchip/llvm-project
Handle mutation while enumerating correctly. Fix some bugs.
llvm-svn: 55583
This commit is contained in:
parent
aebd2662d3
commit
3f35a266da
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue