X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FMCJIT%2FMCJIT.cpp;h=e8619385635fdd9467e858abe07ed141918a5d04;hb=769accfb4d71caff9152309eaa5e704e065b5846;hp=5eda88d1a382d9e5b1b06984d1e7f7872e87fd94;hpb=7b6747ed420ef32d5c12f62833c2b5ad1c46d604;p=oota-llvm.git diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index 5eda88d1a38..e8619385635 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -1,4 +1,4 @@ -//===-- JIT.cpp - MC-based Just-in-Time Compiler --------------------------===// +//===-- MCJIT.cpp - MC-based Just-in-Time Compiler ------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,12 +8,21 @@ //===----------------------------------------------------------------------===// #include "MCJIT.h" -#include "llvm/Function.h" #include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/Support/ErrorHandling.h" +#include "llvm/ExecutionEngine/ObjectBuffer.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/DynamicLibrary.h" -#include "llvm/Target/TargetData.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MutexGuard.h" using namespace llvm; @@ -30,69 +39,179 @@ extern "C" void LLVMLinkInMCJIT() { ExecutionEngine *MCJIT::createJIT(Module *M, std::string *ErrorStr, - JITMemoryManager *JMM, - CodeGenOpt::Level OptLevel, + RTDyldMemoryManager *MemMgr, bool GVsWithCode, - CodeModel::Model CMM, - StringRef MArch, - StringRef MCPU, - const SmallVectorImpl& MAttrs) { + TargetMachine *TM) { // Try to register the program as a source of symbols to resolve against. // // FIXME: Don't do this here. sys::DynamicLibrary::LoadLibraryPermanently(0, NULL); - // Pick a target either via -march or by guessing the native arch. - // - // FIXME: This should be lifted out of here, it isn't something which should - // be part of the JIT policy, rather the burden for this selection should be - // pushed to clients. - TargetMachine *TM = MCJIT::selectTarget(M, MArch, MCPU, MAttrs, ErrorStr); - if (!TM || (ErrorStr && ErrorStr->length() > 0)) return 0; - TM->setCodeModel(CMM); - - // If the target supports JIT code generation, create the JIT. - if (TargetJITInfo *TJ = TM->getJITInfo()) - return new MCJIT(M, TM, *TJ, JMM, OptLevel, GVsWithCode); - - if (ErrorStr) - *ErrorStr = "target does not support JIT code generation"; - return 0; + return new MCJIT(M, TM, MemMgr ? MemMgr : new SectionMemoryManager(), + GVsWithCode); } -MCJIT::MCJIT(Module *m, TargetMachine *tm, TargetJITInfo &tji, - JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, +MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM, bool AllocateGVsWithCode) - : ExecutionEngine(m), TM(tm), M(m), OS(Buffer) { + : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM), + IsLoaded(false), M(m), ObjCache(0) { - PM.add(new TargetData(*TM->getTargetData())); + setDataLayout(TM->getDataLayout()); +} + +MCJIT::~MCJIT() { + if (LoadedObject) + NotifyFreeingObject(*LoadedObject.get()); + delete MemMgr; + delete TM; +} + +void MCJIT::setObjectCache(ObjectCache* NewCache) { + ObjCache = NewCache; +} + +ObjectBufferStream* MCJIT::emitObject(Module *m) { + /// Currently, MCJIT only supports a single module and the module passed to + /// this function call is expected to be the contained module. The module + /// is passed as a parameter here to prepare for multiple module support in + /// the future. + assert(M == m); + + // Get a thread lock to make sure we aren't trying to compile multiple times + MutexGuard locked(lock); + + // FIXME: Track compilation state on a per-module basis when multiple modules + // are supported. + // Re-compilation is not supported + assert(!IsLoaded); + + PassManager PM; + + PM.add(new DataLayout(*TM->getDataLayout())); + + // The RuntimeDyld will take ownership of this shortly + OwningPtr CompiledObject(new ObjectBufferStream()); // Turn the machine code intermediate representation into bytes in memory // that may be executed. - if (TM->addPassesToEmitMC(PM, Ctx, OS, CodeGenOpt::Default, false)) { + if (TM->addPassesToEmitMC(PM, Ctx, CompiledObject->getOStream(), false)) { report_fatal_error("Target does not support MC emission!"); } // Initialize passes. - ExecutionEngine::addModule(M); - // FIXME: When we support multiple modules, we'll want to move the code - // gen and finalization out of the constructor here and do it more - // on-demand as part of getPointerToFunction(). - PM.run(*M); - // Flush the output buffer so the SmallVector gets its data. - OS.flush(); + PM.run(*m); + // Flush the output buffer to get the generated code into memory + CompiledObject->flush(); + + // If we have an object cache, tell it about the new object. + // Note that we're using the compiled image, not the loaded image (as below). + if (ObjCache) { + // MemoryBuffer is a thin wrapper around the actual memory, so it's OK + // to create a temporary object here and delete it after the call. + OwningPtr MB(CompiledObject->getMemBuffer()); + ObjCache->notifyObjectCompiled(m, MB.get()); + } + + return CompiledObject.take(); } -MCJIT::~MCJIT() { +void MCJIT::loadObject(Module *M) { + + // Get a thread lock to make sure we aren't trying to load multiple times + MutexGuard locked(lock); + + // FIXME: Track compilation state on a per-module basis when multiple modules + // are supported. + // Re-compilation is not supported + if (IsLoaded) + return; + + OwningPtr ObjectToLoad; + // Try to load the pre-compiled object from cache if possible + if (0 != ObjCache) { + OwningPtr PreCompiledObject(ObjCache->getObjectCopy(M)); + if (0 != PreCompiledObject.get()) + ObjectToLoad.reset(new ObjectBuffer(PreCompiledObject.take())); + } + + // If the cache did not contain a suitable object, compile the object + if (!ObjectToLoad) { + ObjectToLoad.reset(emitObject(M)); + assert(ObjectToLoad.get() && "Compilation did not produce an object."); + } + + // Load the object into the dynamic linker. + // handing off ownership of the buffer + LoadedObject.reset(Dyld.loadObject(ObjectToLoad.take())); + if (!LoadedObject) + report_fatal_error(Dyld.getErrorString()); + + // Resolve any relocations. + Dyld.resolveRelocations(); + + // FIXME: Make this optional, maybe even move it to a JIT event listener + LoadedObject->registerWithDebugger(); + + NotifyObjectEmitted(*LoadedObject); + + // FIXME: Add support for per-module compilation state + IsLoaded = true; +} + +// FIXME: Add a parameter to identify which object is being finalized when +// MCJIT supports multiple modules. +// FIXME: Provide a way to separate code emission, relocations and page +// protection in the interface. +void MCJIT::finalizeObject() { + // If the module hasn't been compiled, just do that. + if (!IsLoaded) { + // If the call to Dyld.resolveRelocations() is removed from loadObject() + // we'll need to do that here. + loadObject(M); + } else { + // Resolve any relocations. + Dyld.resolveRelocations(); + } + + StringRef EHData = Dyld.getEHFrameSection(); + if (!EHData.empty()) + MemMgr->registerEHFrames(EHData); + + // Set page permissions. + MemMgr->finalizeMemory(); } void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) { report_fatal_error("not yet implemented"); - return 0; } void *MCJIT::getPointerToFunction(Function *F) { - return 0; + // FIXME: This should really return a uint64_t since it's a pointer in the + // target address space, not our local address space. That's part of the + // ExecutionEngine interface, though. Fix that when the old JIT finally + // dies. + + // FIXME: Add support for per-module compilation state + if (!IsLoaded) + loadObject(M); + + if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { + bool AbortOnFailure = !F->hasExternalWeakLinkage(); + void *Addr = getPointerToNamedFunction(F->getName(), AbortOnFailure); + addGlobalMapping(F, Addr); + return Addr; + } + + // FIXME: Should the Dyld be retaining module information? Probably not. + // FIXME: Should we be using the mangler for this? Probably. + // + // This is the accessor for the target address, so make sure to check the + // load address of the symbol, not the local address. + StringRef BaseName = F->getName(); + if (BaseName[0] == '\1') + return (void*)Dyld.getSymbolLoadAddress(BaseName.substr(1)); + return (void*)Dyld.getSymbolLoadAddress((TM->getMCAsmInfo()->getGlobalPrefix() + + BaseName).str()); } void *MCJIT::recompileAndRelinkFunction(Function *F) { @@ -105,10 +224,154 @@ void MCJIT::freeMachineCodeForFunction(Function *F) { GenericValue MCJIT::runFunction(Function *F, const std::vector &ArgValues) { - assert(ArgValues.size() == 0 && "JIT arg passing not supported yet"); + assert(F && "Function *F was null at entry to run()"); + void *FPtr = getPointerToFunction(F); - if (!FPtr) - report_fatal_error("Unable to locate function: '" + F->getName() + "'"); - ((void(*)(void))(intptr_t)FPtr)(); - return GenericValue(); + assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); + FunctionType *FTy = F->getFunctionType(); + Type *RetTy = FTy->getReturnType(); + + assert((FTy->getNumParams() == ArgValues.size() || + (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && + "Wrong number of arguments passed into function!"); + assert(FTy->getNumParams() == ArgValues.size() && + "This doesn't support passing arguments through varargs (yet)!"); + + // Handle some common cases first. These cases correspond to common `main' + // prototypes. + if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { + switch (ArgValues.size()) { + case 3: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy() && + FTy->getParamType(2)->isPointerTy()) { + int (*PF)(int, char **, const char **) = + (int(*)(int, char **, const char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]), + (const char **)GVTOP(ArgValues[2]))); + return rv; + } + break; + case 2: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy()) { + int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]))); + return rv; + } + break; + case 1: + if (FTy->getNumParams() == 1 && + FTy->getParamType(0)->isIntegerTy(32)) { + GenericValue rv; + int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); + return rv; + } + break; + } + } + + // Handle cases where no arguments are passed first. + if (ArgValues.empty()) { + GenericValue rv; + switch (RetTy->getTypeID()) { + default: llvm_unreachable("Unknown return type for function call!"); + case Type::IntegerTyID: { + unsigned BitWidth = cast(RetTy)->getBitWidth(); + if (BitWidth == 1) + rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 8) + rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 16) + rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 32) + rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 64) + rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); + else + llvm_unreachable("Integer types > 64 bits not supported"); + return rv; + } + case Type::VoidTyID: + rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); + return rv; + case Type::FloatTyID: + rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); + return rv; + case Type::DoubleTyID: + rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); + return rv; + case Type::X86_FP80TyID: + case Type::FP128TyID: + case Type::PPC_FP128TyID: + llvm_unreachable("long double not supported yet"); + case Type::PointerTyID: + return PTOGV(((void*(*)())(intptr_t)FPtr)()); + } + } + + llvm_unreachable("Full-featured argument passing not supported yet!"); +} + +void *MCJIT::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { + // FIXME: Add support for per-module compilation state + if (!IsLoaded) + loadObject(M); + + if (!isSymbolSearchingDisabled() && MemMgr) { + void *ptr = MemMgr->getPointerToNamedFunction(Name, false); + if (ptr) + return ptr; + } + + /// If a LazyFunctionCreator is installed, use it to get/create the function. + if (LazyFunctionCreator) + if (void *RP = LazyFunctionCreator(Name)) + return RP; + + if (AbortOnFailure) { + report_fatal_error("Program used external function '"+Name+ + "' which could not be resolved!"); + } + return 0; +} + +void MCJIT::RegisterJITEventListener(JITEventListener *L) { + if (L == NULL) + return; + MutexGuard locked(lock); + EventListeners.push_back(L); +} +void MCJIT::UnregisterJITEventListener(JITEventListener *L) { + if (L == NULL) + return; + MutexGuard locked(lock); + SmallVector::reverse_iterator I= + std::find(EventListeners.rbegin(), EventListeners.rend(), L); + if (I != EventListeners.rend()) { + std::swap(*I, EventListeners.back()); + EventListeners.pop_back(); + } +} +void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) { + MutexGuard locked(lock); + for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { + EventListeners[I]->NotifyObjectEmitted(Obj); + } +} +void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) { + MutexGuard locked(lock); + for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { + EventListeners[I]->NotifyFreeingObject(Obj); + } }