Rewrite JIT handling of GlobalVariables so they
authorDale Johannesen <dalej@apple.com>
Thu, 7 Aug 2008 01:30:15 +0000 (01:30 +0000)
committerDale Johannesen <dalej@apple.com>
Thu, 7 Aug 2008 01:30:15 +0000 (01:30 +0000)
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

lib/ExecutionEngine/ExecutionEngine.cpp
lib/ExecutionEngine/JIT/JIT.cpp
lib/ExecutionEngine/JIT/JITEmitter.cpp
lib/ExecutionEngine/JIT/JITMemoryManager.cpp

index 94136d54af0c5e150f3d518f4f85104026e5d3ba..b3dfe01069d0cdbdd70923b68f4d604df05997a3 100644 (file)
@@ -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)) {
index 940434c731ce711d7fa0b06afdaed7a3ea762320..d4f190bfc76538076f8742e2e3a82341356ebd8e 100644 (file)
@@ -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
index cbfaa09e36dfd08da344792f984bd0f41090b8eb..d38f9f90e20773fa36c59d26db0458c5f4ea399c 100644 (file)
@@ -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);
index 248291634cc4c92cf30e28b02faba2ff63aaf68d..d2d5c2f8e0d4789193332c989db92efda53ffe96 100644 (file)
@@ -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;