diff options
author | Dale Johannesen <dalej@apple.com> | 2008-08-07 01:30:15 +0000 |
---|---|---|
committer | Dale Johannesen <dalej@apple.com> | 2008-08-07 01:30:15 +0000 |
commit | dd947ea3c5e020c33c58a31939561265b980a3ad (patch) | |
tree | 1ed06d324e47916a3ffaecc9f5d8978562c16a56 /lib/ExecutionEngine | |
parent | 39fd6e81b1b0de8b820155dc6a0dae226c109de6 (diff) | |
download | external_llvm-dd947ea3c5e020c33c58a31939561265b980a3ad.zip external_llvm-dd947ea3c5e020c33c58a31939561265b980a3ad.tar.gz external_llvm-dd947ea3c5e020c33c58a31939561265b980a3ad.tar.bz2 |
Rewrite JIT handling of GlobalVariables so they
are allocated in the same buffer as the code,
jump tables, etc.
The default JIT memory manager does not handle buffer
overflow well. I didn't introduce this and I'm not
attempting to fix it here, but it is more likely to
be hit now since we're putting more stuff in the
buffer. This affects one test that I know of so far,
MultiSource/Benchmarks/NPB-serial/is.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@54442 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r-- | lib/ExecutionEngine/ExecutionEngine.cpp | 2 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 22 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 176 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITMemoryManager.cpp | 2 |
4 files changed, 179 insertions, 23 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 94136d5..b3dfe01 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -819,6 +819,8 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, // specified memory location... // void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { + DOUT << "Initializing " << Addr; + DEBUG(Init->dump()); if (isa<UndefValue>(Init)) { return; } else if (const ConstantVector *CP = dyn_cast<ConstantVector>(Init)) { diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 940434c..d4f190b 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -415,30 +415,22 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) { cerr << "Could not resolve external global address: " << GV->getName() << "\n"; abort(); + addGlobalMapping(GV, Ptr); } } else { - // If the global hasn't been emitted to memory yet, allocate space. We will - // actually initialize the global after current function has finished - // compilation. + // If the global hasn't been emitted to memory yet, allocate space and + // emit it into memory. It goes in the same array as the generated + // code, jump tables, etc. const Type *GlobalType = GV->getType()->getElementType(); size_t S = getTargetData()->getABITypeSize(GlobalType); size_t A = getTargetData()->getPreferredAlignment(GV); - if (A <= 8) { - Ptr = malloc(S); - } else { - // Allocate S+A bytes of memory, then use an aligned pointer within that - // space. - Ptr = malloc(S+A); - unsigned MisAligned = ((intptr_t)Ptr & (A-1)); - Ptr = (char*)Ptr + (MisAligned ? (A-MisAligned) : 0); - } - jitstate->getPendingGlobals(locked).push_back(GV); + Ptr = MCE->allocateSpace(S, A); + addGlobalMapping(GV, Ptr); + EmitGlobalVariable(GV); } - addGlobalMapping(GV, Ptr); return Ptr; } - /// recompileAndRelinkFunction - This method is used to force a function /// which has already been compiled, to be compiled again, possibly /// after it has been modified. Then the entry to the old copy is overwritten diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index cbfaa09..d38f9f9 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -15,9 +15,9 @@ #define DEBUG_TYPE "jit" #include "JIT.h" #include "JITDwarfEmitter.h" -#include "llvm/Constant.h" +#include "llvm/Constants.h" #include "llvm/Module.h" -#include "llvm/Type.h" +#include "llvm/DerivedTypes.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineConstantPool.h" @@ -25,6 +25,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRelocation.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetJITInfo.h" #include "llvm/Target/TargetMachine.h" @@ -36,6 +37,7 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/ADT/Statistic.h" #include <algorithm> +#include <set> using namespace llvm; STATISTIC(NumBytes, "Number of bytes of machine code compiled"); @@ -467,6 +469,9 @@ namespace { /// MMI - Machine module info for exception informations MachineModuleInfo* MMI; + // GVSet - a set to keep track of which globals have been seen + std::set<const GlobalVariable*> GVSet; + public: JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit) { MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager(); @@ -541,6 +546,10 @@ namespace { void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub); void *getPointerToGVLazyPtr(GlobalValue *V, void *Reference, bool NoNeedStub); + unsigned addSizeOfGlobal(const GlobalVariable *GV, unsigned Size); + unsigned addSizeOfGlobalsInConstantVal(const Constant *C, unsigned Size); + unsigned addSizeOfGlobalsInInitializer(const Constant *Init, unsigned Size); + unsigned GetSizeOfGlobalsInBytes(MachineFunction &MF); }; } @@ -618,9 +627,154 @@ static uintptr_t RoundUpToAlign(uintptr_t Size, unsigned Alignment) { return Size + Alignment; } +/// addSizeOfGlobal - add the size of the global (plus any alignment padding) +/// into the running total Size. + +unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV, unsigned Size) { + const Type *ElTy = GV->getType()->getElementType(); + size_t GVSize = (size_t)TheJIT->getTargetData()->getABITypeSize(ElTy); + size_t GVAlign = + (size_t)TheJIT->getTargetData()->getPreferredAlignment(GV); + DOUT << "Adding in size " << GVSize << " alignment " << GVAlign; + DEBUG(GV->dump()); + // Assume code section ends with worst possible alignment, so first + // variable needs maximal padding. + if (Size==0) + Size = 1; + Size = ((Size+GVAlign-1)/GVAlign)*GVAlign; + Size += GVSize; + return 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. + +unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C, + unsigned Size) { + // If its undefined, return the garbage. + if (isa<UndefValue>(C)) + return Size; + + // If the value is a ConstantExpr + if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { + Constant *Op0 = CE->getOperand(0); + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::PtrToInt: + case Instruction::IntToPtr: + case Instruction::BitCast: { + Size = addSizeOfGlobalsInConstantVal(Op0, Size); + break; + } + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: { + Size = addSizeOfGlobalsInConstantVal(Op0, Size); + Size = addSizeOfGlobalsInConstantVal(CE->getOperand(1), Size); + break; + } + default: { + cerr << "ConstantExpr not handled: " << *CE << "\n"; + abort(); + } + } + } + + if (C->getType()->getTypeID() == Type::PointerTyID) + if (const GlobalVariable* GV = dyn_cast<GlobalVariable>(C)) + if (GVSet.insert(GV).second) + Size = addSizeOfGlobal(GV, Size); + + return Size; +} + +/// 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) { + if (!isa<UndefValue>(Init) && + !isa<ConstantVector>(Init) && + !isa<ConstantAggregateZero>(Init) && + !isa<ConstantArray>(Init) && + !isa<ConstantStruct>(Init) && + Init->getType()->isFirstClassType()) + Size = addSizeOfGlobalsInConstantVal(Init, Size); + return Size; +} + +/// GetSizeOfGlobalsInBytes - walk the code for the function, looking for +/// globals; then walk the initializers of those globals looking for more. +/// If their size has not been considered yet, add it into the running total +/// Size. + +unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) { + unsigned Size = 0; + GVSet.clear(); + + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB) { + for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end(); + I != E; ++I) { + const TargetInstrDesc &Desc = I->getDesc(); + const MachineInstr &MI = *I; + unsigned NumOps = Desc.getNumOperands(); + for (unsigned CurOp = 0; CurOp < NumOps; CurOp++) { + const MachineOperand &MO = MI.getOperand(CurOp); + if (MO.isGlobalAddress()) { + GlobalValue* V = MO.getGlobal(); + const GlobalVariable *GV = dyn_cast<const GlobalVariable>(V); + if (!GV) + continue; + // If seen in previous function, it will have an entry here. + if (TheJIT->getPointerToGlobalIfAvailable(GV)) + continue; + // If seen earlier in this function, it will have an entry here. + // FIXME: it should be possible to combine these tables, by + // 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).second) + // A variable as yet unseen. Add in its size. + Size = addSizeOfGlobal(GV, Size); + } + } + } + } + DOUT << "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 (std::set<const GlobalVariable *>::iterator I = GVSet.begin(); + I != GVSet.end(); I++) { + const GlobalVariable* GV = *I; + if (GV->hasInitializer()) + Size = addSizeOfGlobalsInInitializer(GV->getInitializer(), Size); + } + + return Size; +} + void JITEmitter::startFunction(MachineFunction &F) { uintptr_t ActualSize = 0; if (MemMgr->NeedsExactSize()) { + DOUT << "ExactSize\n"; const TargetInstrInfo* TII = F.getTarget().getInstrInfo(); MachineJumpTableInfo *MJTI = F.getJumpTableInfo(); MachineConstantPool *MCP = F.getConstantPool(); @@ -647,6 +801,13 @@ void JITEmitter::startFunction(MachineFunction &F) { // Add the function size ActualSize += TII->GetFunctionSizeInBytes(F); + + DOUT << "ActualSize before globals " << ActualSize << "\n"; + // Add the size of the globals that will be allocated after this function. + // These are all the ones referenced from this function that were not + // previously allocated. + ActualSize += GetSizeOfGlobalsInBytes(F); + DOUT << "ActualSize after globals " << ActualSize << "\n"; } BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(), @@ -679,10 +840,6 @@ bool JITEmitter::finishFunction(MachineFunction &F) { // other per-function data. unsigned char *FnStart = (unsigned char *)TheJIT->getPointerToGlobalIfAvailable(F.getFunction()); - unsigned char *FnEnd = CurBufferPtr; - - MemMgr->endFunctionBody(F.getFunction(), BufferBegin, FnEnd); - NumBytes += FnEnd-FnStart; if (!Relocations.empty()) { NumRelos += Relocations.size(); @@ -734,6 +891,11 @@ bool JITEmitter::finishFunction(MachineFunction &F) { Relocations.size(), MemMgr->getGOTBase()); } + unsigned char *FnEnd = CurBufferPtr; + + MemMgr->endFunctionBody(F.getFunction(), BufferBegin, FnEnd); + NumBytes += FnEnd-FnStart; + // Update the GOT entry for F to point to the new code. if (MemMgr->isManagingGOT()) { unsigned idx = Resolver.getGOTIndexForAddr((void*)BufferBegin); @@ -962,7 +1124,7 @@ void *JIT::getPointerToFunctionOrStub(Function *F) { /// freeMachineCodeForFunction - release machine code memory for given Function. /// void JIT::freeMachineCodeForFunction(Function *F) { - + // Delete translation for this from the ExecutionEngine, so it will get // retranslated next time it is used. void *OldPtr = updateGlobalMapping(F, 0); diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 2482916..d2d5c2f 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -290,7 +290,7 @@ namespace { assert(FunctionEnd > FunctionStart); assert(FunctionStart == (unsigned char *)(CurBlock+1) && "Mismatched function start/end!"); - + uintptr_t BlockSize = FunctionEnd - (unsigned char *)CurBlock; FunctionBlocks[F] = CurBlock; |