[llvm-commits] CVS: reopt/lib/TraceJIT/Makefile TraceJIT.cpp TraceJIT.h TraceJITEmitter.cpp TraceJITIntercept.cpp

Brian Gaeke gaeke at cs.uiuc.edu
Wed May 26 16:29:02 PDT 2004


Changes in directory reopt/lib/TraceJIT:

Makefile added (r1.1)
TraceJIT.cpp added (r1.1)
TraceJIT.h added (r1.1)
TraceJITEmitter.cpp added (r1.1)
TraceJITIntercept.cpp added (r1.1)

---
Log message:

Import TraceJIT: a new ExecutionEngine based on the JIT, designed to
reoptimize TraceFunctions at runtime.


---
Diffs of the changes:  (+689 -0)

Index: reopt/lib/TraceJIT/Makefile
diff -c /dev/null reopt/lib/TraceJIT/Makefile:1.1
*** /dev/null	Wed May 26 16:25:23 2004
--- reopt/lib/TraceJIT/Makefile	Wed May 26 16:25:13 2004
***************
*** 0 ****
--- 1,12 ----
+ ##===- lib/TraceJIT/Makefile -------------------------------*- Makefile -*-===##
+ # 
+ #                     The LLVM Compiler Infrastructure
+ #
+ # This file was developed by the LLVM research group and is distributed under
+ # the University of Illinois Open Source License. See LICENSE.TXT for details.
+ # 
+ ##===----------------------------------------------------------------------===##
+ LEVEL = ../..
+ LIBRARYNAME = tracejit
+ 
+ include $(LEVEL)/Makefile.common


Index: reopt/lib/TraceJIT/TraceJIT.cpp
diff -c /dev/null reopt/lib/TraceJIT/TraceJIT.cpp:1.1
*** /dev/null	Wed May 26 16:25:23 2004
--- reopt/lib/TraceJIT/TraceJIT.cpp	Wed May 26 16:25:13 2004
***************
*** 0 ****
--- 1,268 ----
+ //===-- TraceJIT.cpp - LLVM Just in Time Compiler -------------------------===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // This tool implements a just-in-time compiler for LLVM, allowing direct
+ // execution of LLVM bytecode in an efficient manner.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "TraceJIT.h"
+ #include "../LightWtProfiling/ReoptimizerInternal.h"
+ #include "reopt/TraceToFunction.h"
+ #include "reopt/UnpackTraceFunction.h"
+ #include "llvm/CodeGen/MachineCodeEmitter.h"
+ #include "llvm/CodeGen/MachineFunction.h"
+ #include "llvm/DerivedTypes.h"
+ #include "llvm/ExecutionEngine/GenericValue.h"
+ #include "llvm/Function.h"
+ #include "llvm/GlobalVariable.h"
+ #include "llvm/Module.h"
+ #include "llvm/ModuleProvider.h"
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/Assembly/PrintModulePass.h"
+ #include "llvm/CodeGen/Passes.h"
+ #include "llvm/Target/TargetMachine.h"
+ #include "llvm/Target/TargetMachineImpls.h"
+ #include "llvm/Target/TargetJITInfo.h"
+ #include "Support/CommandLine.h"
+ #include "Support/DynamicLinker.h"
+ #include "Support/Debug.h"
+ using namespace llvm;
+ 
+ namespace llvm {
+   extern bool SaveStateToModule;
+   extern bool SaveRegAllocState;
+   extern MachineCodeEmitter *createTraceJITEmitter (TraceJIT *JIT);
+ } // end namespace llvm
+ 
+ void TraceJIT::addPassesToReoptimizeTrace (FunctionPassManager &PM) {
+   // Verify that the generated function's bytecode is good, then compile it
+   // down to machine code. Then, "unpack" it back into its matrix function.
+   // FIXME: Register allocation hints also need to be added to the PassManager,
+   // so that we do not get clobbered by the overhead of adding copies in
+   // UnpackTraceFunction.
+   DEBUG (PM.add (new PrintFunctionPass ("Function created from trace:\n",
+                                         &std::cerr)));
+   DEBUG (PM.add (createVerifierPass ()));
+   TJI.addPassesToJITCompile (PM);
+   DEBUG (PM.add (createMachineFunctionPrinterPass (&std::cerr,
+                                                    "Before unpacking:\n")));
+   PM.add (UTF);
+   DEBUG (PM.add (createMachineFunctionPrinterPass (&std::cerr,
+                                                    "After unpacking:\n")));
+ 
+   // Force the SPARCv9 register allocator to save its state into a global
+   // variable where UTF can read it.
+   SaveRegAllocState = true;
+   SaveStateToModule = false;
+ }
+ 
+ TraceJIT::TraceJIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
+   : ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
+   setTargetData(TM.getTargetData());
+ 
+   // Initialize MCE & trace-function unpacker
+   MCE = createTraceJITEmitter (this);
+   UTF = new UnpackTraceFunction (&TM);
+ 
+   PM.add (new TargetData (getTargetData ()));
+ 
+   // Compile LLVM Code down to machine code in the intermediate representation
+   addPassesToReoptimizeTrace (PM);
+ 
+   // Turn the machine code intermediate representation into bytes in memory that
+   // may be executed.
+   if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
+     std::cerr << "Target '" << TM.getName()
+               << "' doesn't support machine code emission!\n";
+     abort();
+   }
+ }
+ 
+ TraceJIT::~TraceJIT() {
+   delete MCE;
+   delete &TM;
+ }
+ 
+ /// run - Start execution with the specified function and arguments.
+ ///
+ GenericValue TraceJIT::runFunction(Function *F,
+                               const std::vector<GenericValue> &ArgValues) {
+   assert (F && "Function *F was null at entry to run()");
+   GenericValue rv;
+ 
+   if (ArgValues.size() == 3) {
+     int (*PF)(int, char **, const char **) =
+       (int(*)(int, char **, const char **))getPointerToFunction(F);
+     assert(PF && "Pointer to fn's code was null after getPointerToFunction");
+     
+     // Call the function.
+     int ExitCode = PF(ArgValues[0].IntVal, (char **) GVTOP (ArgValues[1]),
+                       (const char **) GVTOP (ArgValues[2]));
+     
+     rv.IntVal = ExitCode;
+   } else {
+     // FIXME: This code should handle a couple of common cases efficiently, but
+     // it should also implement the general case by code-gening a new anonymous
+     // nullary function to call.
+     assert(ArgValues.size() == 1);
+     void (*PF)(int) = (void(*)(int))getPointerToFunction(F);
+     assert(PF && "Pointer to fn's code was null after getPointerToFunction");
+     PF(ArgValues[0].IntVal);
+   }
+ 
+   return rv;
+ }
+ 
+ /// runJITOnFunction - Run the FunctionPassManager full of
+ /// just-in-time compilation passes on F, hopefully filling in
+ /// GlobalAddress[F] with the address of F's machine code.
+ ///
+ void TraceJIT::runJITOnFunction(Function *F) {
+   static bool isAlreadyCodeGenerating = false;
+   assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
+ 
+   // TraceJIT the function
+   isAlreadyCodeGenerating = true;
+   PM.run(*F);
+   isAlreadyCodeGenerating = false;
+ 
+   // If the function referred to a global variable that had not yet been
+   // emitted, it allocates memory for the global, but doesn't emit it yet.  Emit
+   // all of these globals now.
+   while (!PendingGlobals.empty()) {
+     const GlobalVariable *GV = PendingGlobals.back();
+     PendingGlobals.pop_back();
+     EmitGlobalVariable(GV);
+   }
+ }
+ 
+ /// getPointerToFunction - This method is used to get the address of the
+ /// specified function, compiling it if neccesary.
+ ///
+ void *TraceJIT::getPointerToFunction(Function *F) {
+   if (void *Addr = getPointerToGlobalIfAvailable(F))
+     return Addr;   // Check if function already code gen'd
+ 
+   // Make sure we read in the function if it exists in this Module
+   try {
+     MP->materializeFunction(F);
+   } catch (...) {
+     std::cerr << "Error parsing bytecode file!\n";
+     abort();
+   }
+ 
+   // First try to see if we can dig it out of the executable.
+   void *Addr = getPointerToNamedFunction(F->getName());
+   if (Addr) {
+     addGlobalMapping(F, Addr);
+     return Addr;
+   }
+ 
+   if (!F->isExternal()) {
+     // Try to compile it
+     runJITOnFunction(F);
+     Addr = getPointerToGlobalIfAvailable(F);
+   }
+ 
+   assert(Addr && "Can't find function");
+   return Addr;
+ }
+ 
+ // getPointerToFunctionOrStub - If the specified function has been
+ // code-gen'd, return a pointer to the function.  If not, compile it, or use
+ // a stub to implement lazy compilation if available.
+ //
+ void *TraceJIT::getPointerToFunctionOrStub(Function *F) {
+   // If we have already code generated the function, just return the address.
+   if (void *Addr = getPointerToGlobalIfAvailable(F))
+     return Addr;
+ 
+   // Otherwise, codegen the function.
+   return getPointerToFunction(F);
+ }
+ 
+ /// getOrEmitGlobalVariable - Return the address of the specified global
+ /// variable, possibly emitting it to memory if needed.  This is used by the
+ /// Emitter.
+ void *TraceJIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
+   void *Ptr = getPointerToGlobalIfAvailable(GV);
+   if (Ptr) return Ptr;
+ 
+   // If the global is external, just remember the address.
+   if (GV->isExternal()) {
+     Ptr = GetAddressOfSymbol(GV->getName().c_str());
+     if (Ptr == 0) {
+       std::cerr << "Could not resolve external global address: "
+                 << GV->getName() << "\n";
+       abort();
+     }
+   } 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.
+     Ptr =new char[getTargetData().getTypeSize(GV->getType()->getElementType())];
+     PendingGlobals.push_back(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
+ /// with a branch to the new copy. If there was no old copy, this acts
+ /// just like TraceJIT::getPointerToFunction().
+ ///
+ void *TraceJIT::recompileAndRelinkFunction(Function *F) {
+   void *OldAddr = getPointerToGlobalIfAvailable(F);
+ 
+   // If it's not already compiled there is no reason to patch it up.
+   if (OldAddr == 0) { return getPointerToFunction(F); }
+ 
+   // Delete the old function mapping.
+   addGlobalMapping(F, 0);
+ 
+   // Recodegen the function
+   runJITOnFunction(F);
+ 
+   // Update state, forward the old function to the new function.
+   void *Addr = getPointerToGlobalIfAvailable(F);
+   assert(Addr && "Code generation didn't add function to GlobalAddress table!");
+   TJI.replaceMachineCodeForFunction(OldAddr, Addr);
+   return Addr;
+ }
+ 
+ /// create - Create and return a new SparcV9 TraceJIT compiler, or 0 if
+ /// there is an error.
+ ///
+ TraceJIT *TraceJIT::create(ModuleProvider *MP, IntrinsicLowering *IL) {
+   // Allocate a SparcV9 target.
+   TargetMachine *Target = allocateSparcV9TargetMachine(*MP->getModule(), IL);
+   assert(Target && "Could not allocate target machine!");
+ 
+   // If the target supports TraceJIT code generation, return a new TraceJIT now.
+   if (TargetJITInfo *TJ = Target->getJITInfo())
+     return new TraceJIT(MP, *Target, *TJ);
+ 
+   // Fail...
+   return 0;
+ }
+ 
+ uint64_t TraceJIT::compileTraceFunction (TraceFunction *TF) {
+   // Pass out-of-band information to UTF.
+   UTF->setTraceFunction (TF);
+ 
+   // Compile & unpack the TraceFunction.
+   uint64_t traceStartAddr = (uint64_t) getPointerToFunction (TF->TraceFn);
+   assert (traceStartAddr && "Address of code for TraceFn was NULL after JIT?!");
+   return traceStartAddr;
+ }
+ 


Index: reopt/lib/TraceJIT/TraceJIT.h
diff -c /dev/null reopt/lib/TraceJIT/TraceJIT.h:1.1
*** /dev/null	Wed May 26 16:25:23 2004
--- reopt/lib/TraceJIT/TraceJIT.h	Wed May 26 16:25:13 2004
***************
*** 0 ****
--- 1,106 ----
+ //===-- TraceJIT.h - Class definition for the TraceJIT ----------*- C++ -*-===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // This file defines the top-level TraceJIT data structure.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #ifndef TRACEJIT_H
+ #define TRACEJIT_H
+ 
+ #include "llvm/ExecutionEngine/ExecutionEngine.h"
+ #include "llvm/PassManager.h"
+ #include <map>
+ 
+ namespace llvm {
+ 
+ class Function;
+ class GlobalValue;
+ class Constant;
+ class TargetMachine;
+ class TargetJITInfo;
+ class MachineCodeEmitter;
+ class TraceFunction;
+ class UnpackTraceFunction;
+ 
+ class TraceJIT : public ExecutionEngine {
+   TargetMachine &TM;       // The current target we are compiling to
+   TargetJITInfo &TJI;      // The TargetJITInfo for the current target
+   
+   FunctionPassManager PM;   // Passes to compile a TraceFunction
+   MachineCodeEmitter *MCE;  // Optimized trace code emitter
+   UnpackTraceFunction *UTF; // TraceFunction unpacker
+ 
+   /// PendingGlobals - Global variables which have had memory allocated for them
+   /// while a function was code generated, but which have not been initialized
+   /// yet.
+   std::vector<const GlobalVariable*> PendingGlobals;
+ 
+   TraceJIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
+ public:
+   ~TraceJIT();
+ 
+   /// create - Create an return a new TraceJIT compiler if there is one available
+   /// for the current target.  Otherwise, return null.  If the TraceJIT is created
+   /// successfully, it takes responsibility for deleting the specified
+   /// IntrinsicLowering implementation.
+   ///
+   static TraceJIT *create(ModuleProvider *MP, IntrinsicLowering *IL = 0);
+ 
+   /// run - Start execution with the specified function and arguments.
+   ///
+   virtual GenericValue runFunction(Function *F,
+                                    const std::vector<GenericValue> &ArgValues);
+ 
+   /// getPointerToNamedFunction - This method returns the address of the
+   /// specified function by using the dlsym function call.  As such it is only
+   /// useful for resolving library symbols, not code generated symbols.
+   ///
+   void *getPointerToNamedFunction(const std::string &Name);
+ 
+   // CompilationCallback - Invoked the first time that a call site is found,
+   // which causes lazy compilation of the target function.
+   // 
+   static void CompilationCallback();
+ 
+   /// getPointerToFunction - This returns the address of the specified function,
+   /// compiling it if necessary.
+   ///
+   void *getPointerToFunction(Function *F);
+ 
+   /// getOrEmitGlobalVariable - Return the address of the specified global
+   /// variable, possibly emitting it to memory if needed.  This is used by the
+   /// Emitter.
+   void *getOrEmitGlobalVariable(const GlobalVariable *GV);
+ 
+   /// getPointerToFunctionOrStub - If the specified function has been
+   /// code-gen'd, return a pointer to the function.  If not, compile it, or use
+   /// a stub to implement lazy compilation if available.
+   ///
+   void *getPointerToFunctionOrStub(Function *F);
+ 
+   /// 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
+   /// with a branch to the new copy. If there was no old copy, this acts
+   /// just like TraceJIT::getPointerToFunction().
+   ///
+   void *recompileAndRelinkFunction(Function *F);
+ 
+   uint64_t compileTraceFunction (TraceFunction *TF);
+ 
+   MachineCodeEmitter *getEmitter() { return MCE; }
+ private:
+   void addPassesToReoptimizeTrace (FunctionPassManager &PM);
+   void runJITOnFunction (Function *F);
+ };
+ 
+ } // End llvm namespace
+ 
+ #endif


Index: reopt/lib/TraceJIT/TraceJITEmitter.cpp
diff -c /dev/null reopt/lib/TraceJIT/TraceJITEmitter.cpp:1.1
*** /dev/null	Wed May 26 16:25:23 2004
--- reopt/lib/TraceJIT/TraceJITEmitter.cpp	Wed May 26 16:25:13 2004
***************
*** 0 ****
--- 1,212 ----
+ //===-- TraceJITEmitter.cpp - Write machine code to executable memory -----===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // The trace reoptimizer uses this MachineCodeEmitter to output
+ // optimized machine code to memory, so that it can be executed instead of
+ // the corresponding unoptimized code.
+ // 
+ // Currently, it uses the same executable memory segment that the
+ // TraceCache would use, but the TraceCache is unaware of it, so they can
+ // not be used together.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "TraceJIT.h"
+ #include "reopt/ScratchMemory.h"
+ #include "reopt/VirtualMem.h"
+ #include "reopt/InstrUtils.h"
+ #include "../LightWtProfiling/ReoptimizerInternal.h"
+ #include "llvm/Constant.h"
+ #include "llvm/Module.h"
+ #include "llvm/CodeGen/MachineCodeEmitter.h"
+ #include "llvm/CodeGen/MachineFunction.h"
+ #include "llvm/CodeGen/MachineConstantPool.h"
+ #include "llvm/Target/TargetData.h"
+ #include "Support/Debug.h"
+ #include "Support/DynamicLinker.h"
+ using namespace llvm;
+ 
+ namespace {
+   /// TraceJITEmitter - The trace reoptimizer's MachineCodeEmitter,
+   /// which is used to output functions to memory for execution.
+   ///
+   class TraceJITEmitter : public MachineCodeEmitter {
+     TraceJIT *TheJIT;
+ 
+     // CurBlock - The start of the current block of memory.  CurByte - The
+     // current byte being emitted to.
+     uint64_t CurBlock, CurByte;
+     uint64_t FunctionBase, CurFunctionPtr;
+ 
+     // ConstantPoolAddresses - Contains the location for each entry in the
+     // constant pool.
+     std::vector<void*> ConstantPoolAddresses;
+   public:
+     TraceJITEmitter (TraceJIT *JIT_) : TheJIT (JIT_) {
+       // Re-use the existing DummyFunction area for code emission in the
+       // Reoptimizer.  No memory is reserved for stubs.
+       FunctionBase = (uint64_t) OptimizedTraceTextArea;
+       // Allocate functions forward from the function base.
+       CurFunctionPtr = FunctionBase;
+     }
+ 
+     virtual void startFunction(MachineFunction &F);
+     virtual void finishFunction(MachineFunction &F);
+     virtual void emitConstantPool(MachineConstantPool *MCP);
+     virtual void startFunctionStub(const Function &F, unsigned StubSize) {
+       abort ();
+     }
+     virtual void* finishFunctionStub(const Function &F) {
+       abort ();
+     }
+     virtual void emitByte(unsigned char B);
+     virtual void emitWord(unsigned W);
+     virtual void emitWordAt(unsigned W, unsigned *Ptr);
+ 
+     virtual uint64_t getGlobalValueAddress(GlobalValue *V);
+     virtual uint64_t getGlobalValueAddress(const std::string &Name);
+     virtual uint64_t getConstantPoolEntryAddress(unsigned Entry);
+     virtual uint64_t getCurrentPCValue();
+ 
+     // forceCompilationOf - Force the compilation of the specified function, and
+     // return its address, because we REALLY need the address now.
+     //
+     // FIXME: This is JIT specific!
+     //
+     virtual uint64_t forceCompilationOf(Function *F);
+   };
+ } // end anonymous namespace
+ 
+ namespace llvm {
+ 
+ MachineCodeEmitter *createTraceJITEmitter(TraceJIT *JIT) {
+   return new TraceJITEmitter(JIT);
+ }
+ 
+ } // end namespace llvm
+ 
+ void TraceJITEmitter::startFunction(MachineFunction &F) {
+   // Round up to a 64-bit word boundary.
+   CurBlock = (CurFunctionPtr + 7) & ~7;
+   CurByte = CurBlock;
+ 
+   // Remember where we started generating this function.
+   TheJIT->addGlobalMapping(F.getFunction(), (void*)CurBlock);
+ }
+ 
+ void TraceJITEmitter::finishFunction(MachineFunction &F) {
+   assert(CurByte > CurFunctionPtr);
+   CurFunctionPtr = CurByte;
+ 
+   ConstantPoolAddresses.clear();
+ 
+   DEBUG(std::cerr << "Finished CodeGen of [" << (void*)CurBlock
+                   << "] Function: " << F.getFunction()->getName()
+                   << ": " << CurByte-CurBlock << " bytes of text\n");
+ }
+ 
+ void TraceJITEmitter::emitConstantPool(MachineConstantPool *MCP) {
+   const std::vector<Constant*> &Constants = MCP->getConstants();
+   if (Constants.empty()) return;
+ 
+   std::vector<unsigned> ConstantOffset;
+   ConstantOffset.reserve(Constants.size());
+ 
+   // Calculate how much space we will need for all the constants, and the offset
+   // each one will live in.
+   unsigned TotalSize = 0;
+   for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
+     const Type *Ty = Constants[i]->getType();
+     unsigned Size      = TheJIT->getTargetData().getTypeSize(Ty);
+     unsigned Alignment = TheJIT->getTargetData().getTypeAlignment(Ty);
+     // Make sure to take into account the alignment requirements of the type.
+     TotalSize = (TotalSize + Alignment-1) & ~(Alignment-1);
+ 
+     // Remember the offset this element lives at.
+     ConstantOffset.push_back(TotalSize);
+     TotalSize += Size;   // Reserve space for the constant.
+   }
+ 
+   // Now that we know how much memory to allocate, do so.
+   char *Pool = new char[TotalSize];
+ 
+   // Actually output all of the constants, and remember their addresses.
+   for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
+     void *Addr = Pool + ConstantOffset[i];
+     TheJIT->InitializeMemory(Constants[i], Addr);
+     ConstantPoolAddresses.push_back(Addr);
+   }
+ }
+ 
+ void TraceJITEmitter::emitByte(unsigned char B) {
+   std::cerr << "TraceJITEmitter: attempt to emit a single byte: 0x"
+             << std::hex << (unsigned)B << std::dec << " at cursor: "
+             << CurByte << "\n";
+   abort ();
+   // *CurByte = W;
+   ++CurByte;
+ }
+ 
+ void TraceJITEmitter::emitWord(unsigned W) {
+   // This won't work if the endianness of the host and target don't agree!  (For
+   // a JIT this can't happen though.  :)
+   DEBUG (std::cerr << "TraceJITEmitter: emitting word 0x" << std::hex << W
+     << " at cursor: " << CurByte << std::dec << "\n");
+   vm->writeInstToVM (CurByte, W);  // does: *(unsigned*)CurByte = W;
+   doFlush (CurByte - sizeof (unsigned), (uint64_t) CurByte + sizeof (unsigned));
+   CurByte += sizeof(unsigned);
+ }
+ 
+ void TraceJITEmitter::emitWordAt(unsigned W, unsigned *Ptr) {
+   DEBUG (std::cerr << "TraceJITEmitter: emitting word 0x" << std::hex << W
+     << std::dec << " at pointer: " << Ptr << "\n");
+   vm->writeInstToVM ((uint64_t) Ptr, W);  // does: *Ptr = W;
+   doFlush ((uint64_t) Ptr - sizeof (unsigned),
+            (uint64_t) Ptr + sizeof (unsigned));
+ }
+ 
+ uint64_t TraceJITEmitter::getGlobalValueAddress(GlobalValue *V) {
+   // Try looking up the function to see if it is already compiled, if not return
+   // 0.
+   if (isa<Function>(V)) {
+     if (V->hasName ()) {
+       uint64_t where = (uint64_t) GetAddressOfSymbol (V->getName ());
+       if (where)
+         return where;
+     }
+     return (uint64_t)TheJIT->getPointerToGlobalIfAvailable(V);
+   } else {
+     return (uint64_t)TheJIT->getOrEmitGlobalVariable(cast<GlobalVariable>(V));
+   }
+ }
+ 
+ uint64_t TraceJITEmitter::getGlobalValueAddress(const std::string &Name) {
+   return (uint64_t)TheJIT->getPointerToNamedFunction(Name);
+ }
+ 
+ // getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry
+ // in the constant pool that was last emitted with the 'emitConstantPool'
+ // method.
+ //
+ uint64_t TraceJITEmitter::getConstantPoolEntryAddress(unsigned ConstantNum) {
+   assert(ConstantNum < ConstantPoolAddresses.size() &&
+ 	 "Invalid ConstantPoolIndex!");
+   return (uint64_t)ConstantPoolAddresses[ConstantNum];
+ }
+ 
+ // getCurrentPCValue - This returns the address that the next emitted byte
+ // will be output to.
+ //
+ uint64_t TraceJITEmitter::getCurrentPCValue() {
+   return CurByte;
+ }
+ 
+ uint64_t TraceJITEmitter::forceCompilationOf(Function *F) {
+   return (uint64_t)TheJIT->getPointerToFunction(F);
+ }


Index: reopt/lib/TraceJIT/TraceJITIntercept.cpp
diff -c /dev/null reopt/lib/TraceJIT/TraceJITIntercept.cpp:1.1
*** /dev/null	Wed May 26 16:25:23 2004
--- reopt/lib/TraceJIT/TraceJITIntercept.cpp	Wed May 26 16:25:13 2004
***************
*** 0 ****
--- 1,91 ----
+ //===-- Intercept.cpp - System function interception routines -------------===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // If a function call occurs to an external function, the TraceJIT is designed to use
+ // the dynamic loader interface to find a function to call.  This is useful for
+ // calling system calls and library functions that are not available in LLVM.
+ // Some system calls, however, need to be handled specially.  For this reason,
+ // we intercept some of them here and use our own stubs to handle them.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "TraceJIT.h"
+ #include "Support/DynamicLinker.h"
+ #include <iostream>
+ #include <sys/stat.h>
+ using namespace llvm;
+ 
+ // AtExitHandlers - List of functions to call when the program exits,
+ // registered with the atexit() library function.
+ static std::vector<void (*)()> AtExitHandlers;
+ 
+ /// runAtExitHandlers - Run any functions registered by the program's
+ /// calls to atexit(3), which we intercept and store in
+ /// AtExitHandlers.
+ ///
+ static void runAtExitHandlers() {
+   while (!AtExitHandlers.empty()) {
+     void (*Fn)() = AtExitHandlers.back();
+     AtExitHandlers.pop_back();
+     Fn();
+   }
+ }
+ 
+ //===----------------------------------------------------------------------===//
+ // Function stubs that are invoked instead of certain library calls
+ //===----------------------------------------------------------------------===//
+ 
+ // Force the following functions to be linked in to anything that uses the
+ // TraceJIT. This is a hack designed to work around the all-too-clever Glibc
+ // strategy of making these functions work differently when inlined vs. when
+ // not inlined, and hiding their real definitions in a separate archive file
+ // that the dynamic linker can't see. For more info, search for
+ // 'libc_nonshared.a' on Google, or read http://llvm.cs.uiuc.edu/PR274.
+ #if defined(__linux__)
+ void *FunctionPointers[] = {
+   (void *) stat,
+   (void *) fstat,
+   (void *) lstat,
+   (void *) stat64,
+   (void *) fstat64,
+   (void *) lstat64,
+   (void *) atexit,
+   (void *) mknod
+ };
+ #endif // __linux__
+ 
+ // NoopFn - Used if we have nothing else to call...
+ static void NoopFn() {}
+ 
+ // jit_exit - Used to intercept the "exit" library call.
+ static void jit_exit(int Status) {
+   runAtExitHandlers();   // Run atexit handlers...
+   exit(Status);
+ }
+ 
+ // jit_atexit - Used to intercept the "atexit" library call.
+ static int jit_atexit(void (*Fn)(void)) {
+   AtExitHandlers.push_back(Fn);    // Take note of atexit handler...
+   return 0;  // Always successful
+ }
+ 
+ //===----------------------------------------------------------------------===//
+ // 
+ /// getPointerToNamedFunction - This method returns the address of the specified
+ /// function by using the dynamic loader interface.  As such it is only useful 
+ /// for resolving library symbols, not code generated symbols.
+ ///
+ void *TraceJIT::getPointerToNamedFunction(const std::string &Name) {
+   // Check to see if this is one of the functions we want to intercept...
+   if (Name == "exit") return (void*)&jit_exit;
+   if (Name == "atexit") return (void*)&jit_atexit;
+ 
+   // Try to look it up in the process image.
+   return GetAddressOfSymbol(Name);
+ }





More information about the llvm-commits mailing list