diff options
-rw-r--r-- | tools/jello/Callback.cpp | 62 | ||||
-rw-r--r-- | tools/jello/Emitter.cpp | 107 | ||||
-rw-r--r-- | tools/jello/GlobalVars.cpp | 110 | ||||
-rw-r--r-- | tools/jello/Makefile | 10 | ||||
-rw-r--r-- | tools/jello/VM.cpp | 106 | ||||
-rw-r--r-- | tools/jello/VM.h | 79 | ||||
-rw-r--r-- | tools/jello/jello.cpp | 70 |
7 files changed, 0 insertions, 544 deletions
diff --git a/tools/jello/Callback.cpp b/tools/jello/Callback.cpp deleted file mode 100644 index b843e10689..0000000000 --- a/tools/jello/Callback.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- Callback.cpp - Trap handler for function resolution ---------------===// -// -// This file defines the SIGSEGV handler which is invoked when a reference to a -// non-codegen'd function is found. -// -//===----------------------------------------------------------------------===// - -#include "VM.h" -#include "Support/Statistic.h" -#include <signal.h> -#include <ucontext.h> -#include <iostream> - -static VM *TheVM = 0; - -static void TrapHandler(int TN, siginfo_t *SI, ucontext_t *ucp) { - assert(TN == SIGSEGV && "Should be SIGSEGV!"); - -#ifdef REG_EIP /* this code does not compile on Sparc! */ - if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 || - ucp->uc_mcontext.gregs[REG_EIP] != 0) { - std::cerr << "Bad SEGV encountered!\n"; - abort(); - } - - // The call instruction should have pushed the return value onto the stack... - unsigned RefAddr = *(unsigned*)ucp->uc_mcontext.gregs[REG_ESP]; - RefAddr -= 4; // Backtrack to the reference itself... - - DEBUG(std::cerr << "In SEGV handler! Addr=0x" << std::hex << RefAddr - << " ESP=0x" << ucp->uc_mcontext.gregs[REG_ESP] << std::dec - << ": Resolving call to function: " - << TheVM->getFunctionReferencedName((void*)RefAddr) << "\n"); - - // Sanity check to make sure this really is a call instruction... - assert(((unsigned char*)RefAddr)[-1] == 0xE8 && "Not a call instr!"); - - unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RefAddr); - - // Rewrite the call target... so that we don't fault every time we execute - // the call. - *(unsigned*)RefAddr = NewVal-RefAddr-4; - - // Change the instruction pointer to be the real target of the call... - ucp->uc_mcontext.gregs[REG_EIP] = NewVal; - -#endif -} - - -void VM::registerCallback() { - TheVM = this; - - // Register the signal handler... - struct sigaction SA; - SA.sa_sigaction = (void (*)(int, siginfo_t*, void*))TrapHandler; - sigfillset(&SA.sa_mask); // Block all signals while codegen'ing - SA.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; // Get siginfo - sigaction(SIGSEGV, &SA, 0); // Install the handler -} - - diff --git a/tools/jello/Emitter.cpp b/tools/jello/Emitter.cpp deleted file mode 100644 index 253a229a38..0000000000 --- a/tools/jello/Emitter.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===-- Emitter.cpp - Write machine code to executable memory -------------===// -// -// This file defines a MachineCodeEmitter object that is used by Jello to write -// machine code to memory and remember where relocatable values lie. -// -//===----------------------------------------------------------------------===// - -#include "VM.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Function.h" -#include "Support/Statistic.h" - -namespace { - Statistic<> NumBytes("jello", "Number of bytes of machine code compiled"); - - class Emitter : public MachineCodeEmitter { - VM &TheVM; - - unsigned char *CurBlock; - unsigned char *CurByte; - - std::vector<std::pair<BasicBlock*, unsigned *> > BBRefs; - std::map<BasicBlock*, unsigned> BBLocations; - public: - Emitter(VM &vm) : TheVM(vm) {} - - virtual void startFunction(MachineFunction &F); - virtual void finishFunction(MachineFunction &F); - virtual void startBasicBlock(MachineBasicBlock &BB); - virtual void emitByte(unsigned char B); - virtual void emitPCRelativeDisp(Value *V); - virtual void emitGlobalAddress(GlobalValue *V); - }; -} - -MachineCodeEmitter *VM::createEmitter(VM &V) { - return new Emitter(V); -} - - -#define _POSIX_MAPPED_FILES -#include <unistd.h> -#include <sys/mman.h> - -static void *getMemory() { - return mmap(0, 4096*2, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); -} - - -void Emitter::startFunction(MachineFunction &F) { - CurBlock = (unsigned char *)getMemory(); - CurByte = CurBlock; // Start writing at the beginning of the fn. - TheVM.addGlobalMapping(F.getFunction(), CurBlock); -} - -void Emitter::finishFunction(MachineFunction &F) { - for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { - unsigned Location = BBLocations[BBRefs[i].first]; - unsigned *Ref = BBRefs[i].second; - *Ref = Location-(unsigned)Ref-4; - } - BBRefs.clear(); - BBLocations.clear(); - - NumBytes += CurByte-CurBlock; - - DEBUG(std::cerr << "Finished CodeGen of [" << std::hex << (unsigned)CurBlock - << std::dec << "] Function: " << F.getFunction()->getName() - << ": " << CurByte-CurBlock << " bytes of text\n"); -} - -void Emitter::startBasicBlock(MachineBasicBlock &BB) { - BBLocations[BB.getBasicBlock()] = (unsigned)CurByte; -} - - -void Emitter::emitByte(unsigned char B) { - *CurByte++ = B; // Write the byte to memory -} - - -// emitPCRelativeDisp - For functions, just output a displacement that will -// cause a reference to the zero page, which will cause a seg-fault, causing -// things to get resolved on demand. Keep track of these markers. -// -// For basic block references, keep track of where the references are so they -// may be patched up when the basic block is defined. -// -void Emitter::emitPCRelativeDisp(Value *V) { - if (Function *F = dyn_cast<Function>(V)) { - TheVM.addFunctionRef(CurByte, F); - unsigned ZeroAddr = -(unsigned)CurByte-4; // Calculate displacement to null - *(unsigned*)CurByte = ZeroAddr; // 4 byte offset - CurByte += 4; - } else { - BasicBlock *BB = cast<BasicBlock>(V); // Keep track of reference... - BBRefs.push_back(std::make_pair(BB, (unsigned*)CurByte)); - CurByte += 4; - } -} - -void Emitter::emitGlobalAddress(GlobalValue *V) { - *(void**)CurByte = TheVM.getPointerToGlobal(V); - CurByte += 4; -} diff --git a/tools/jello/GlobalVars.cpp b/tools/jello/GlobalVars.cpp deleted file mode 100644 index 17495953da..0000000000 --- a/tools/jello/GlobalVars.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//===-- GlobalVars.cpp - Code to emit global variables to memory ----------===// -// -// This file contains the code to generate global variables to memory. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Module.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Constants.h" -#include "llvm/Target/TargetMachine.h" -#include "Support/Statistic.h" -#include "VM.h" -#include <iostream> - -Statistic<> NumInitBytes("jello", "Number of bytes of data area initialized"); - -/// EmitGlobals - Emit all of the global variables to memory, storing their -/// addresses into GlobalAddress. This must make sure to copy the contents of -/// their initializers into the memory. -/// -void VM::emitGlobals() { - const TargetData &TD = TM.getTargetData(); - - // Loop over all of the global variables in the program, allocating the memory - // to hold them. - for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) - if (!I->isExternal()) { - // Get the type of the global... - const Type *Ty = I->getType()->getElementType(); - - // Allocate some memory for it! - GlobalAddress[I] = new char[TD.getTypeSize(Ty)]; - - DEBUG(std::cerr << "Allocated global '" << I->getName() - << "' to addr 0x" << std::hex << GlobalAddress[I] << std::dec - << "\n"); - } else { - assert(0 && "References to external globals not handled yet!"); - } - - // Now that all of the globals are set up in memory, loop through them all and - // initialize their contents. - for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) - if (!I->isExternal()) - emitConstantToMemory(I->getInitializer(), GlobalAddress[I]); -} - -/// emitConstantToMemory - Use the specified LLVM constant to initialize the -/// specified region of memory. -/// -void VM::emitConstantToMemory(Constant *Init, void *Addr) { - const TargetData &TD = TM.getTargetData(); - NumInitBytes += TD.getTypeSize (Init->getType ()); - if (ConstantIntegral *CI = dyn_cast<ConstantIntegral>(Init)) { - switch (CI->getType()->getPrimitiveID()) { - case Type::BoolTyID: - *(char*)Addr = cast<ConstantBool>(CI)->getValue(); - return; - case Type::UByteTyID: - *(unsigned char*)Addr = cast<ConstantUInt>(CI)->getValue(); - return; - case Type::SByteTyID: - *( signed char*)Addr = cast<ConstantSInt>(CI)->getValue(); - return; - case Type::UShortTyID: - *(unsigned short*)Addr = cast<ConstantUInt>(CI)->getValue(); - return; - case Type::ShortTyID: - *( signed short*)Addr = cast<ConstantSInt>(CI)->getValue(); - return; - case Type::UIntTyID: - *(unsigned int*)Addr = cast<ConstantUInt>(CI)->getValue(); - return; - case Type::IntTyID: - *( signed int*)Addr = cast<ConstantSInt>(CI)->getValue(); - return; - case Type::ULongTyID: - *(uint64_t*)Addr = cast<ConstantUInt>(CI)->getValue(); - return; - case Type::LongTyID: - *(int64_t*)Addr = cast<ConstantSInt>(CI)->getValue(); - return; - default: break; - } - } else if (ConstantFP *CF = dyn_cast <ConstantFP> (Init)) { - switch (CF->getType ()->getPrimitiveID ()) { - case Type::FloatTyID: - *(float*)Addr = CF->getValue (); - return; - case Type::DoubleTyID: - *(double*)Addr = CF->getValue (); - return; - default: break; - } - } else if (ConstantPointerNull *CP = dyn_cast <ConstantPointerNull> (Init)) { - // Fill the space with a NULL pointer. - *(void **)Addr = NULL; - return; - } else if (ConstantArray *CA = dyn_cast<ConstantArray>(Init)) { - unsigned ElementSize = TD.getTypeSize(CA->getType()->getElementType()); - for (unsigned i = 0, e = CA->getType()->getNumElements(); i != e; ++i) { - emitConstantToMemory(cast<Constant>(CA->getOperand(i)), Addr); - Addr = (char*)Addr+ElementSize; - } - return; - } - - std::cerr << "Offending constant: " << Init << "\n"; - assert(0 && "Don't know how to emit this constant to memory!"); -} diff --git a/tools/jello/Makefile b/tools/jello/Makefile deleted file mode 100644 index 77ae1a8c27..0000000000 --- a/tools/jello/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -LEVEL = ../.. -TOOLNAME = jello -USEDLIBS = bcreader vmcore codegen x86 support.a target.a scalaropts.a - -# Have gcc tell the linker to export symbols from the program so that -# dynamically loaded modules can be linked against them. -# -TOOLLINKOPTS = -ldl - -include $(LEVEL)/Makefile.common diff --git a/tools/jello/VM.cpp b/tools/jello/VM.cpp deleted file mode 100644 index e5e77c3e27..0000000000 --- a/tools/jello/VM.cpp +++ /dev/null @@ -1,106 +0,0 @@ -//===-- jello.cpp - LLVM Just in Time Compiler ----------------------------===// -// -// This tool implements a just-in-time compiler for LLVM, allowing direct -// execution of LLVM bytecode in an efficient manner. -// -//===----------------------------------------------------------------------===// - -#include "VM.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/Function.h" -#include <dlfcn.h> // dlsym access - - -VM::~VM() { - delete MCE; -} - -/// setupPassManager - Initialize the VM PassManager object with all of the -/// passes needed for the target to generate code. -/// -void VM::setupPassManager() { - // Compile LLVM Code down to machine code in the intermediate representation - if (TM.addPassesToJITCompile(PM)) { - std::cerr << ExeName << ": target '" << TM.getName() - << "' doesn't support JIT compilation!\n"; - abort(); - } - - // Turn the machine code intermediate representation into bytes in memory that - // may be executed. - // - if (TM.addPassesToEmitMachineCode(PM, *MCE)) { - std::cerr << ExeName << ": target '" << TM.getName() - << "' doesn't support machine code emission!\n"; - abort(); - } -} - -int VM::run(Function *F) { - int(*PF)(int, char**) = (int(*)(int, char**))getPointerToFunction(F); - assert(PF != 0 && "Null pointer to function?"); - - unsigned NumArgs = 0; - for (; Argv[NumArgs]; ++NumArgs) - ; - - return PF(NumArgs, Argv); -} - -void *VM::resolveFunctionReference(void *RefAddr) { - Function *F = FunctionRefs[RefAddr]; - assert(F && "Reference address not known!"); - - void *Addr = getPointerToFunction(F); - assert(Addr && "Pointer to function unknown!"); - - FunctionRefs.erase(RefAddr); - return Addr; -} - -const std::string &VM::getFunctionReferencedName(void *RefAddr) { - return FunctionRefs[RefAddr]->getName(); -} - -// getPointerToGlobal - This returns the address of the specified global -// value. This may involve code generation if it's a function. -// -void *VM::getPointerToGlobal(GlobalValue *GV) { - if (Function *F = dyn_cast<Function>(GV)) - return getPointerToFunction(F); - - assert(GlobalAddress[GV] && "Global hasn't had an address allocated yet?"); - return GlobalAddress[GV]; -} - - -static void NoopFn() {} - -/// getPointerToFunction - This method is used to get the address of the -/// specified function, compiling it if neccesary. -/// -void *VM::getPointerToFunction(Function *F) { - void *&Addr = GlobalAddress[F]; // Function already code gen'd - if (Addr) return Addr; - - if (F->isExternal()) { - // If it's an external function, look it up in the process image... - void *Ptr = dlsym(0, F->getName().c_str()); - if (Ptr == 0) { - std::cerr << "WARNING: Cannot resolve fn '" << F->getName() - << "' using a dummy noop function instead!\n"; - Ptr = (void*)NoopFn; - } - - return Addr = Ptr; - } - - // JIT all of the functions in the module. Eventually this will JIT functions - // on demand. This has the effect of populating all of the non-external - // functions into the GlobalAddress table. - PM.run(M); - - assert(Addr && "Code generation didn't add function to GlobalAddress table!"); - return Addr; -} diff --git a/tools/jello/VM.h b/tools/jello/VM.h deleted file mode 100644 index c02b4044f7..0000000000 --- a/tools/jello/VM.h +++ /dev/null @@ -1,79 +0,0 @@ -//===-- VM.h - Definitions for Virtual Machine ------------------*- C++ -*-===// -// -// This file defines the top level Virtual Machine data structure. -// -//===----------------------------------------------------------------------===// - -#ifndef VM_H -#define VM_H - -#include "llvm/PassManager.h" -#include <string> -#include <map> -#include <vector> - -class Function; -class GlobalValue; -class Constant; -class TargetMachine; -class MachineCodeEmitter; - -class VM { - std::string ExeName; - Module &M; // The LLVM program we are running - TargetMachine &TM; // The current target we are compiling to - PassManager PM; // Passes to compile a function - MachineCodeEmitter *MCE; // MCE object - char **Argv; - - // GlobalAddress - A mapping between LLVM values and their native code - // generated versions... - std::map<const GlobalValue*, void *> GlobalAddress; - - // FunctionRefs - A mapping between addresses that refer to unresolved - // functions and the LLVM function object itself. This is used by the fault - // handler to lazily patch up references... - // - std::map<void*, Function*> FunctionRefs; -public: - VM(const std::string &name, char **AV, Module &m, TargetMachine &tm) - : ExeName(name), M(m), TM(tm), Argv(AV) { - MCE = createEmitter(*this); // Initialize MCE - setupPassManager(); - registerCallback(); - emitGlobals(); - } - - ~VM(); - - int run(Function *F); - - void addGlobalMapping(const Function *F, void *Addr) { - void *&CurVal = GlobalAddress[(const GlobalValue*)F]; - assert(CurVal == 0 && "GlobalMapping already established!"); - CurVal = Addr; - } - - void addFunctionRef(void *Ref, Function *F) { - FunctionRefs[Ref] = F; - } - - const std::string &getFunctionReferencedName(void *RefAddr); - - void *resolveFunctionReference(void *RefAddr); - - // getPointerToGlobal - This returns the address of the specified global - // value. This may involve code generation if it's a function. - // - void *getPointerToGlobal(GlobalValue *GV); - -private: - static MachineCodeEmitter *createEmitter(VM &V); - void setupPassManager(); - void *getPointerToFunction(Function *F); - void registerCallback(); - void emitGlobals(); - void emitConstantToMemory(Constant *Init, void *Addr); -}; - -#endif diff --git a/tools/jello/jello.cpp b/tools/jello/jello.cpp deleted file mode 100644 index 73d40581e9..0000000000 --- a/tools/jello/jello.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- jello.cpp - LLVM Just in Time Compiler ----------------------------===// -// -// This tool implements a just-in-time compiler for LLVM, allowing direct -// execution of LLVM bytecode in an efficient manner. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Module.h" -#include "llvm/Bytecode/Reader.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineImpls.h" -#include "Support/CommandLine.h" -#include "VM.h" -#include <memory> - -namespace { - cl::opt<std::string> - InputFile(cl::desc("<input bytecode>"), cl::Positional, cl::init("-")); - - cl::list<std::string> - InputArgv(cl::ConsumeAfter, cl::desc("<program arguments>...")); - - cl::opt<std::string> - MainFunction("f", cl::desc("Function to execute"), cl::init("main"), - cl::value_desc("function name")); -} - -//===----------------------------------------------------------------------===// -// main Driver function -// -int main(int argc, char **argv) { - cl::ParseCommandLineOptions(argc, argv, " llvm just in time compiler\n"); - - // Allocate a target... in the future this will be controllable on the - // command line. - std::auto_ptr<TargetMachine> Target( - allocateX86TargetMachine(TM::PtrSize64 | TM::BigEndian)); - assert(Target.get() && "Could not allocate target machine!"); - - // Parse the input bytecode file... - std::string ErrorMsg; - std::auto_ptr<Module> M(ParseBytecodeFile(InputFile, &ErrorMsg)); - if (M.get() == 0) { - std::cerr << argv[0] << ": bytecode '" << InputFile - << "' didn't read correctly: << " << ErrorMsg << "\n"; - return 1; - } - - // Build an argv vector... - InputArgv.insert(InputArgv.begin(), InputFile); - char **Argv = new char*[InputArgv.size()+1]; - for (unsigned i = 0, e = InputArgv.size(); i != e; ++i) { - Argv[i] = new char[InputArgv[i].size()+1]; - std::copy(InputArgv[i].begin(), InputArgv[i].end(), Argv[i]); - Argv[i][InputArgv[i].size()] = 0; - } - Argv[InputArgv.size()] = 0; - - // Create the virtual machine object... - VM TheVM(argv[0], Argv, *M.get(), *Target.get()); - - Function *F = M.get()->getNamedFunction(MainFunction); - if (F == 0) { - std::cerr << "Could not find function '" << MainFunction <<"' in module!\n"; - return 1; - } - - // Run the virtual machine... - return TheVM.run(F); -} |