Fix PR5291, in which a SmallPtrSet iterator was held across an insertion into

the set.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97720 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jeffrey Yasskin 2010-03-04 06:50:01 +00:00
parent 9763f709e2
commit e57898ce55
2 changed files with 64 additions and 23 deletions

View File

@ -348,9 +348,6 @@ namespace {
/// MMI - Machine module info for exception informations
MachineModuleInfo* MMI;
// GVSet - a set to keep track of which globals have been seen
SmallPtrSet<const GlobalVariable*, 8> GVSet;
// CurFn - The llvm function being emitted. Only valid during
// finishFunction().
const Function *CurFn;
@ -507,8 +504,14 @@ namespace {
bool MayNeedFarStub);
void *getPointerToGVIndirectSym(GlobalValue *V, void *Reference);
unsigned addSizeOfGlobal(const GlobalVariable *GV, unsigned Size);
unsigned addSizeOfGlobalsInConstantVal(const Constant *C, unsigned Size);
unsigned addSizeOfGlobalsInInitializer(const Constant *Init, unsigned Size);
unsigned addSizeOfGlobalsInConstantVal(
const Constant *C, unsigned Size,
SmallPtrSet<const GlobalVariable*, 8> &SeenGlobals,
SmallVectorImpl<const GlobalVariable*> &Worklist);
unsigned addSizeOfGlobalsInInitializer(
const Constant *Init, unsigned Size,
SmallPtrSet<const GlobalVariable*, 8> &SeenGlobals,
SmallVectorImpl<const GlobalVariable*> &Worklist);
unsigned GetSizeOfGlobalsInBytes(MachineFunction &MF);
};
}
@ -968,11 +971,14 @@ unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV, unsigned Size) {
}
/// addSizeOfGlobalsInConstantVal - find any globals that we haven't seen yet
/// but are referenced from the constant; put them in GVSet and add their
/// size into the running total Size.
/// but are referenced from the constant; put them in SeenGlobals and the
/// Worklist, and add their size into the running total Size.
unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
unsigned Size) {
unsigned JITEmitter::addSizeOfGlobalsInConstantVal(
const Constant *C,
unsigned Size,
SmallPtrSet<const GlobalVariable*, 8> &SeenGlobals,
SmallVectorImpl<const GlobalVariable*> &Worklist) {
// If its undefined, return the garbage.
if (isa<UndefValue>(C))
return Size;
@ -994,7 +1000,7 @@ unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::BitCast: {
Size = addSizeOfGlobalsInConstantVal(Op0, Size);
Size = addSizeOfGlobalsInConstantVal(Op0, Size, SeenGlobals, Worklist);
break;
}
case Instruction::Add:
@ -1010,8 +1016,9 @@ unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
Size = addSizeOfGlobalsInConstantVal(Op0, Size);
Size = addSizeOfGlobalsInConstantVal(CE->getOperand(1), Size);
Size = addSizeOfGlobalsInConstantVal(Op0, Size, SeenGlobals, Worklist);
Size = addSizeOfGlobalsInConstantVal(CE->getOperand(1), Size,
SeenGlobals, Worklist);
break;
}
default: {
@ -1025,8 +1032,10 @@ unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
if (C->getType()->getTypeID() == Type::PointerTyID)
if (const GlobalVariable* GV = dyn_cast<GlobalVariable>(C))
if (GVSet.insert(GV))
if (SeenGlobals.insert(GV)) {
Worklist.push_back(GV);
Size = addSizeOfGlobal(GV, Size);
}
return Size;
}
@ -1034,15 +1043,18 @@ unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
/// addSizeOfGLobalsInInitializer - handle any globals that we haven't seen yet
/// but are referenced from the given initializer.
unsigned JITEmitter::addSizeOfGlobalsInInitializer(const Constant *Init,
unsigned Size) {
unsigned JITEmitter::addSizeOfGlobalsInInitializer(
const Constant *Init,
unsigned Size,
SmallPtrSet<const GlobalVariable*, 8> &SeenGlobals,
SmallVectorImpl<const GlobalVariable*> &Worklist) {
if (!isa<UndefValue>(Init) &&
!isa<ConstantVector>(Init) &&
!isa<ConstantAggregateZero>(Init) &&
!isa<ConstantArray>(Init) &&
!isa<ConstantStruct>(Init) &&
Init->getType()->isFirstClassType())
Size = addSizeOfGlobalsInConstantVal(Init, Size);
Size = addSizeOfGlobalsInConstantVal(Init, Size, SeenGlobals, Worklist);
return Size;
}
@ -1053,7 +1065,7 @@ unsigned JITEmitter::addSizeOfGlobalsInInitializer(const Constant *Init,
unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
unsigned Size = 0;
GVSet.clear();
SmallPtrSet<const GlobalVariable*, 8> SeenGlobals;
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
MBB != E; ++MBB) {
@ -1077,7 +1089,7 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
// assuming the addresses of the new globals in this module
// start at 0 (or something) and adjusting them after codegen
// complete. Another possibility is to grab a marker bit in GV.
if (GVSet.insert(GV))
if (SeenGlobals.insert(GV))
// A variable as yet unseen. Add in its size.
Size = addSizeOfGlobal(GV, Size);
}
@ -1086,12 +1098,14 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
}
DEBUG(dbgs() << "JIT: About to look through initializers\n");
// Look for more globals that are referenced only from initializers.
// GVSet.end is computed each time because the set can grow as we go.
for (SmallPtrSet<const GlobalVariable *, 8>::iterator I = GVSet.begin();
I != GVSet.end(); I++) {
const GlobalVariable* GV = *I;
SmallVector<const GlobalVariable*, 8> Worklist(
SeenGlobals.begin(), SeenGlobals.end());
while (!Worklist.empty()) {
const GlobalVariable* GV = Worklist.back();
Worklist.pop_back();
if (GV->hasInitializer())
Size = addSizeOfGlobalsInInitializer(GV->getInitializer(), Size);
Size = addSizeOfGlobalsInInitializer(GV->getInitializer(), Size,
SeenGlobals, Worklist);
}
return Size;

View File

@ -65,6 +65,8 @@ public:
stubsAllocated = 0;
}
void setSizeRequired(bool Required) { SizeRequired = Required; }
virtual void setMemoryWritable() { Base->setMemoryWritable(); }
virtual void setMemoryExecutable() { Base->setMemoryExecutable(); }
virtual void setPoisonMemory(bool poison) { Base->setPoisonMemory(poison); }
@ -628,6 +630,31 @@ TEST_F(JITTest, AvailableExternallyFunctionIsntCompiled) {
<< " not 7 from the IR version.";
}
TEST_F(JITTest, NeedsExactSizeWithManyGlobals) {
// PR5291: When the JMM needed the exact size of function bodies before
// starting to emit them, the JITEmitter would modify a set while iterating
// over it.
TheJIT->DisableLazyCompilation(true);
RJMM->setSizeRequired(true);
LoadAssembly("@A = global i32 42 "
"@B = global i32* @A "
"@C = global i32** @B "
"@D = global i32*** @C "
"@E = global i32**** @D "
"@F = global i32***** @E "
"@G = global i32****** @F "
"@H = global i32******* @G "
"@I = global i32******** @H "
"define i32********* @test() { "
" ret i32********* @I "
"}");
Function *testIR = M->getFunction("test");
int32_t********* (*test)() = reinterpret_cast<int32_t*********(*)()>(
(intptr_t)TheJIT->getPointerToFunction(testIR));
EXPECT_EQ(42, *********test());
}
// Converts the LLVM assembly to bitcode and returns it in a std::string. An
// empty string indicates an error.
std::string AssembleToBitcode(LLVMContext &Context, const char *Assembly) {