//===-- jit_context.cpp ---------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the Boost Software License. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Jit runtime - shared library part. // Defines jit context which stores evrything required for compilation. // //===----------------------------------------------------------------------===// #include "jit_context.h" #include #include "llvm/ADT/StringExtras.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/Module.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Host.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" namespace { llvm::SmallVector getHostAttrs() { llvm::SmallVector features; llvm::StringMap hostFeatures; if (llvm::sys::getHostCPUFeatures(hostFeatures)) { for (auto &&f : hostFeatures) { features.push_back(((f.second ? "+" : "-") + f.first()).str()); } } return features; } struct StaticInitHelper { StaticInitHelper() { llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetDisassembler(); llvm::InitializeNativeTargetAsmPrinter(); } }; StaticInitHelper &staticInit() { // Initialization may not be thread safe // Wrap it into static dummy object initialization static StaticInitHelper obj; return obj; } std::unique_ptr createTargetMachine() { staticInit(); std::string triple(llvm::sys::getProcessTriple()); std::string error; auto target = llvm::TargetRegistry::lookupTarget(triple, error); assert(target != nullptr); std::unique_ptr ret(target->createTargetMachine( triple, llvm::sys::getHostCPUName(), llvm::join(getHostAttrs(), ","), {}, llvm::Optional{}, #if LDC_LLVM_VER == 500 llvm::CodeModel::JITDefault #else llvm::Optional{}, llvm::CodeGenOpt::Default, /*jit*/ true #endif )); assert(ret != nullptr); return ret; } auto getSymbolInProcess(const std::string &name) -> decltype(llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name)) { assert(!name.empty()); #if defined(_WIN32) if ('_' == name[0]) { return llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name.substr(1)); } return llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name); #else return llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name); #endif } } // anon namespace DynamicCompilerContext::ListenerCleaner::ListenerCleaner( DynamicCompilerContext &o, llvm::raw_ostream *stream) : owner(o) { owner.listenerlayer.getTransform().stream = stream; } DynamicCompilerContext::ListenerCleaner::~ListenerCleaner() { owner.listenerlayer.getTransform().stream = nullptr; } DynamicCompilerContext::DynamicCompilerContext(bool isMainContext) : targetmachine(createTargetMachine()), dataLayout(targetmachine->createDataLayout()), #if LDC_LLVM_VER >= 700 stringPool(std::make_shared()), execSession(stringPool), resolver(createResolver()), objectLayer(execSession, [this](llvm::orc::VModuleKey) { return ObjectLayerT::Resources{ std::make_shared(), resolver}; }), #else objectLayer( []() { return std::make_shared(); }), #endif listenerlayer(objectLayer, ModuleListener(*targetmachine)), compileLayer(listenerlayer, llvm::orc::SimpleCompiler(*targetmachine)), mainContext(isMainContext) { llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); } DynamicCompilerContext::~DynamicCompilerContext() {} llvm::Error DynamicCompilerContext::addModule(std::unique_ptr module, llvm::raw_ostream *asmListener) { assert(nullptr != module); reset(); ListenerCleaner cleaner(*this, asmListener); // Add the set to the JIT with the resolver we created above #if LDC_LLVM_VER >= 700 auto handle = execSession.allocateVModule(); auto result = compileLayer.addModule(handle, std::move(module)); if (result) { execSession.releaseVModule(handle); return result; } if (auto err = compileLayer.emitAndFinalize(handle)) { execSession.releaseVModule(handle); return err; } moduleHandle = handle; #else auto result = compileLayer.addModule(std::move(module), createResolver()); if (!result) { return llvm::make_error("addModule failed", llvm::inconvertibleErrorCode()); } moduleHandle = result.get(); #endif compiled = true; return llvm::Error::success(); } llvm::JITSymbol DynamicCompilerContext::findSymbol(const std::string &name) { return compileLayer.findSymbol(name, false); } void DynamicCompilerContext::clearSymMap() { symMap.clear(); } void DynamicCompilerContext::addSymbol(std::string &&name, void *value) { symMap.emplace(std::make_pair(std::move(name), value)); } void DynamicCompilerContext::reset() { if (compiled) { removeModule(moduleHandle); moduleHandle = {}; compiled = false; } } void DynamicCompilerContext::registerBind( void *handle, void *originalFunc, void *exampleFunc, const llvm::ArrayRef ¶ms) { assert(bindInstances.count(handle) == 0); BindDesc::ParamsVec vec(params.begin(), params.end()); bindInstances.insert({handle, {originalFunc, exampleFunc, std::move(vec)}}); } void DynamicCompilerContext::unregisterBind(void *handle) { assert(bindInstances.count(handle) == 1); bindInstances.erase(handle); } bool DynamicCompilerContext::hasBindFunction(const void *handle) const { assert(handle != nullptr); auto it = bindInstances.find(const_cast(handle)); return it != bindInstances.end(); } bool DynamicCompilerContext::isMainContext() const { return mainContext; } void DynamicCompilerContext::removeModule(const ModuleHandleT &handle) { cantFail(compileLayer.removeModule(handle)); #if LDC_LLVM_VER >= 700 execSession.releaseVModule(handle); #endif } #if LDC_LLVM_VER >= 700 std::shared_ptr DynamicCompilerContext::createResolver() { return llvm::orc::createLegacyLookupResolver( execSession, [this](const std::string &name) -> llvm::JITSymbol { if (auto Sym = compileLayer.findSymbol(name, false)) { return Sym; } else if (auto Err = Sym.takeError()) { return std::move(Err); } auto it = symMap.find(name); if (symMap.end() != it) { return llvm::JITSymbol( reinterpret_cast(it->second), llvm::JITSymbolFlags::Exported); } if (auto SymAddr = getSymbolInProcess(name)) { return llvm::JITSymbol(SymAddr, llvm::JITSymbolFlags::Exported); } return nullptr; }, [](llvm::Error Err) { llvm::cantFail(std::move(Err), "lookupFlags failed"); }); } #else std::shared_ptr DynamicCompilerContext::createResolver() { // Build our symbol resolver: // Lambda 1: Look back into the JIT itself to find symbols that are part of // the same "logical dylib". // Lambda 2: Search for external symbols in the host process. return llvm::orc::createLambdaResolver( [this](const std::string &name) { if (auto Sym = compileLayer.findSymbol(name, false)) { return Sym; } return llvm::JITSymbol(nullptr); }, [this](const std::string &name) { auto it = symMap.find(name); if (symMap.end() != it) { return llvm::JITSymbol( reinterpret_cast(it->second), llvm::JITSymbolFlags::Exported); } if (auto SymAddr = getSymbolInProcess(name)) { return llvm::JITSymbol(SymAddr, llvm::JITSymbolFlags::Exported); } return llvm::JITSymbol(nullptr); }); } #endif