Index: examples/clang-interpreter/CMakeLists.txt =================================================================== --- examples/clang-interpreter/CMakeLists.txt +++ examples/clang-interpreter/CMakeLists.txt @@ -12,8 +12,6 @@ add_clang_executable(clang-interpreter main.cpp - Invoke.cpp - Manager.cpp ) add_dependencies(clang-interpreter Index: examples/clang-interpreter/Invoke.h =================================================================== --- examples/clang-interpreter/Invoke.h +++ /dev/null @@ -1,34 +0,0 @@ -//===-- examples/clang-interpreter/Invoke.h - Clang C Interpreter Example -===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_EXAMPLE_INTERPRETER_INVOKE_H -#define CLANG_EXAMPLE_INTERPRETER_INVOKE_H - -namespace llvm { - class ExecutionEngine; - class Function; -} - -#include -#include - -namespace interpreter { - -typedef std::vector InvokeArgs; - -typedef int (*Invoker)(llvm::ExecutionEngine *EE, llvm::Function *EntryFn, - const InvokeArgs &Args, char *const *EnvP); - -int TryIt(llvm::ExecutionEngine *EE, llvm::Function *EntryFn, - const InvokeArgs &Args, char *const *EnvP, - Invoker Invoke); - -} // interpreter - -#endif // CLANG_EXAMPLE_INTERPRETER_INVOKE_H Index: examples/clang-interpreter/Invoke.cpp =================================================================== --- examples/clang-interpreter/Invoke.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//==-- examples/clang-interpreter/Invoke.cpp - Clang C Interpreter Example -==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Invoke.h" - -#include -#include - -namespace interpreter { - -int TryIt(llvm::ExecutionEngine *EE, llvm::Function *EntryFn, - const std::vector &Args, char *const *EnvP, - Invoker Invoke) { - int Res = -1; - try { - Res = Invoke(EE, EntryFn, Args, EnvP); - } catch (const std::exception &E) { - std::cout << "Caught '" << E.what() << "'\n"; - } catch (...) { - std::cout << "Unknown exception\n"; - } - return Res; -} - -} Index: examples/clang-interpreter/Manager.h =================================================================== --- examples/clang-interpreter/Manager.h +++ /dev/null @@ -1,59 +0,0 @@ -//===-- examples/clang-interpreter/Manager.h - Clang C Interpreter Example -==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_EXAMPLE_INTERPRETER_MANAGER_H -#define CLANG_EXAMPLE_INTERPRETER_MANAGER_H - -#include "llvm/ExecutionEngine/SectionMemoryManager.h" - -#if defined(LLVM_ON_WIN32) && defined(_WIN64) -#define CLANG_INTERPRETER_COFF_FORMAT -#define CLANG_INTERPRETER_WIN_EXCEPTIONS -#endif - -namespace interpreter { - -class SingleSectionMemoryManager : public llvm::SectionMemoryManager { - struct Block { - uint8_t *Addr = nullptr, *End = nullptr; - void Reset(uint8_t *Ptr, uintptr_t Size); - uint8_t *Next(uintptr_t Size, unsigned Alignment); - }; - Block Code, ROData, RWData; - -public: - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Align, unsigned ID, - llvm::StringRef Name) final; - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Align, unsigned ID, - llvm::StringRef Name, bool RO) final; - - void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, - uintptr_t ROSize, uint32_t ROAlign, - uintptr_t RWSize, uint32_t RWAlign) final; - - bool needsToReserveAllocationSpace() override { return true; } - -#ifdef CLANG_INTERPRETER_WIN_EXCEPTIONS - using llvm::SectionMemoryManager::EHFrameInfos; - - SingleSectionMemoryManager(); - - void deregisterEHFrames() override; - - bool finalizeMemory(std::string *ErrMsg) override; - -private: - uintptr_t ImageBase = 0; -#endif -}; - -} - -#endif // CLANG_EXAMPLE_INTERPRETER_MANAGER_H Index: examples/clang-interpreter/Manager.cpp =================================================================== --- examples/clang-interpreter/Manager.cpp +++ /dev/null @@ -1,328 +0,0 @@ -//==-- examples/clang-interpreter/Manager.cpp - Clang C Interpreter Example -=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Manager.h" - -#ifdef CLANG_INTERPRETER_WIN_EXCEPTIONS -#include "llvm/Support/DynamicLibrary.h" - -#define WIN32_LEAN_AND_MEAN -#define NOGDI -#define NOMINMAX -#include -#endif - -namespace interpreter { - -using namespace llvm; - -void SingleSectionMemoryManager::Block::Reset(uint8_t *Ptr, uintptr_t Size) { - assert(Ptr != nullptr && "Bad allocation"); - Addr = Ptr; - End = Ptr ? Ptr + Size : nullptr; -} - -uint8_t *SingleSectionMemoryManager::Block::Next(uintptr_t Size, - unsigned Alignment) { - uintptr_t Out = (uintptr_t)Addr; - - // Align the out pointer properly - if (!Alignment) - Alignment = 16; - Out = (Out + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - // RuntimeDyld should have called reserveAllocationSpace with an amount that - // will fit all required alignemnts...but assert on this to make sure. - assert((Out + Size) <= (uintptr_t)End && "Out of bounds"); - - // Set the next Addr to deliver at the end of this one. - Addr = (uint8_t *)(Out + Size); - return (uint8_t *)Out; -} - -uint8_t *SingleSectionMemoryManager::allocateCodeSection(uintptr_t Size, - unsigned Align, - unsigned ID, - StringRef Name) { - return Code.Next(Size, Align); -} - -uint8_t *SingleSectionMemoryManager::allocateDataSection( - uintptr_t Size, unsigned Align, unsigned ID, StringRef Name, bool RO) { - return RO ? ROData.Next(Size, Align) : RWData.Next(Size, Align); -} - -void SingleSectionMemoryManager::reserveAllocationSpace( - uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t ROSize, uint32_t ROAlign, - uintptr_t RWSize, uint32_t RWAlign) { - // FIXME: Ideally this should be one contiguous block, with Code, ROData, - // and RWData pointing to sub-blocks within, but setting the correct - // permissions for that wouldn't work unless we over-allocated to have each - // Block.Base aligned on a page boundary. - const unsigned SecID = 0; - Code.Reset(SectionMemoryManager::allocateCodeSection(CodeSize, CodeAlign, - SecID, "code"), - CodeSize); - - ROData.Reset(SectionMemoryManager::allocateDataSection(ROSize, ROAlign, SecID, - "rodata", true/*RO*/), - ROSize); - - RWData.Reset(SectionMemoryManager::allocateDataSection(RWSize, RWAlign, SecID, - "rwdata", false/*RO*/), - RWSize); - -#ifdef CLANG_INTERPRETER_WIN_EXCEPTIONS - ImageBase = - (uintptr_t)std::min(std::min(Code.Addr, ROData.Addr), RWData.Addr); -#endif -} - -#ifdef CLANG_INTERPRETER_WIN_EXCEPTIONS - -// Map an "ImageBase" to a range of adresses that can throw. -// -class SEHFrameHandler { - typedef SingleSectionMemoryManager::EHFrameInfos EHFrameInfos; - typedef std::vector> ImageRanges; - typedef std::map ImageBaseMap; - ImageBaseMap m_Map; - - static void MergeRanges(ImageRanges &Ranges); - uintptr_t FindEHFrame(uintptr_t Caller); - -public: - static __declspec(noreturn) void __stdcall RaiseSEHException(void *, void *); - void RegisterEHFrames(uintptr_t ImageBase, const EHFrameInfos &Frames, - bool Block = true); - void DeRegisterEHFrames(uintptr_t ImageBase, const EHFrameInfos &Frames); -}; - -// Merge overlaping ranges for faster searching with throwing PC -void SEHFrameHandler::MergeRanges(ImageRanges &Ranges) { - std::sort(Ranges.begin(), Ranges.end()); - - ImageRanges Merged; - ImageRanges::iterator It = Ranges.begin(); - auto Current = *(It)++; - while (It != Ranges.end()) { - if (Current.second + 1 < It->first) { - Merged.push_back(Current); - Current = *(It); - } else - Current.second = std::max(Current.second, It->second); - ++It; - } - Merged.emplace_back(Current); - Ranges.swap(Merged); -} - -// Find the "ImageBase" for Caller/PC who is throwing an exception -uintptr_t SEHFrameHandler::FindEHFrame(uintptr_t Caller) { - for (auto &&Itr : m_Map) { - const uintptr_t ImgBase = Itr.first; - for (auto &&Rng : Itr.second) { - if (Caller >= (ImgBase + Rng.first) && Caller <= (ImgBase + Rng.second)) - return ImgBase; - } - } - return 0; -} - -// Register a range of adresses for a single section that -void SEHFrameHandler::RegisterEHFrames(uintptr_t ImageBase, - const EHFrameInfos &Frames, bool Block) { - if (Frames.empty()) - return; - assert(m_Map.find(ImageBase) == m_Map.end()); - - ImageBaseMap::mapped_type &Ranges = m_Map[ImageBase]; - ImageRanges::value_type *BlockRange = nullptr; - if (Block) { - // Merge all unwind adresses into a single contiguous block for faster - // searching later. - Ranges.emplace_back(std::numeric_limits::max(), - std::numeric_limits::min()); - BlockRange = &Ranges.back(); - } - - for (auto &&Frame : Frames) { - assert(m_Map.find(DWORD64(Frame.Addr)) == m_Map.end() && - "Runtime function should not be a key!"); - - PRUNTIME_FUNCTION RFunc = reinterpret_cast(Frame.Addr); - const size_t N = Frame.Size / sizeof(RUNTIME_FUNCTION); - if (BlockRange) { - for (PRUNTIME_FUNCTION It = RFunc, End = RFunc + N; It < End; ++It) { - BlockRange->first = std::min(BlockRange->first, It->BeginAddress); - BlockRange->second = std::max(BlockRange->second, It->EndAddress); - } - } else { - for (PRUNTIME_FUNCTION It = RFunc, End = RFunc + N; It < End; ++It) - Ranges.emplace_back(It->BeginAddress, It->EndAddress); - } - - ::RtlAddFunctionTable(RFunc, N, ImageBase); - } - - if (!Block) - MergeRanges(Ranges); // Initial sort and merge -} - -void SEHFrameHandler::DeRegisterEHFrames(uintptr_t ImageBase, - const EHFrameInfos &Frames) { - if (Frames.empty()) - return; - - auto Itr = m_Map.find(ImageBase); - if (Itr != m_Map.end()) { - // Remove the ImageBase from lookup - m_Map.erase(Itr); - - // Unregister all the PRUNTIME_FUNCTIONs - for (auto &&Frame : Frames) - ::RtlDeleteFunctionTable(reinterpret_cast(Frame.Addr)); - } -} - -// FIXME: Rather than this static and overriding _CxxThrowException via -// DynamicLibrary::AddSymbol, a better route would be to transform the call -// to _CxxThrowException(Arg0, Arg1) -> RaiseSEHException(Arg0, Arg1, this) -// where 'this' is the SingleSectionMemoryManager instance. This could probably -// be done with clang, and definitely possible by injecting an llvm-IR function -// into the module with the name '_CxxThrowException' -// -static SEHFrameHandler sFrameHandler; - -void SingleSectionMemoryManager::deregisterEHFrames() { - sFrameHandler.DeRegisterEHFrames(ImageBase, EHFrames); - EHFrameInfos().swap(EHFrames); -} - -bool SingleSectionMemoryManager::finalizeMemory(std::string *ErrMsg) { - sFrameHandler.RegisterEHFrames(ImageBase, EHFrames); - ImageBase = 0; - return SectionMemoryManager::finalizeMemory(ErrMsg); -} - -SingleSectionMemoryManager::SingleSectionMemoryManager() { - // Override Windows _CxxThrowException to call into our local version that - // can throw to and from the JIT. - sys::DynamicLibrary::AddSymbol( - "_CxxThrowException", - (void *)(uintptr_t)&SEHFrameHandler::RaiseSEHException); -} - -// Adapted from VisualStudio/VC/crt/src/vcruntime/throw.cpp -#ifdef _WIN64 -#define _EH_RELATIVE_OFFSETS 1 -#endif -// The NT Exception # that we use -#define EH_EXCEPTION_NUMBER ('msc' | 0xE0000000) -// The magic # identifying this version -#define EH_MAGIC_NUMBER1 0x19930520 -#define EH_PURE_MAGIC_NUMBER1 0x01994000 -// Number of parameters in exception record -#define EH_EXCEPTION_PARAMETERS 4 - -// A generic exception record -struct EHExceptionRecord { - DWORD ExceptionCode; - DWORD ExceptionFlags; // Flags determined by NT - _EXCEPTION_RECORD *ExceptionRecord; // Extra exception record (unused) - void *ExceptionAddress; // Address at which exception occurred - DWORD NumberParameters; // No. of parameters = EH_EXCEPTION_PARAMETERS - struct EHParameters { - DWORD magicNumber; // = EH_MAGIC_NUMBER1 - void *pExceptionObject; // Pointer to the actual object thrown - struct ThrowInfo *pThrowInfo; // Description of thrown object -#if _EH_RELATIVE_OFFSETS - DWORD64 pThrowImageBase; // Image base of thrown object -#endif - } params; -}; - -__declspec(noreturn) void __stdcall -SEHFrameHandler::RaiseSEHException(void *CxxExcept, void *Info) { - uintptr_t Caller; - static_assert(sizeof(Caller) == sizeof(PVOID), "Size mismatch"); - - USHORT Frames = CaptureStackBackTrace(1, 1, (PVOID *)&Caller, NULL); - assert(Frames && "No frames captured"); - (void)Frames; - - const DWORD64 BaseAddr = sFrameHandler.FindEHFrame(Caller); - if (BaseAddr == 0) - _CxxThrowException(CxxExcept, (_ThrowInfo *)Info); - - // A generic exception record - EHExceptionRecord Exception = { - EH_EXCEPTION_NUMBER, // Exception number - EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume) - nullptr, // Additional record (none) - nullptr, // Address of exception (OS fills in) - EH_EXCEPTION_PARAMETERS, // Number of parameters - {EH_MAGIC_NUMBER1, CxxExcept, (struct ThrowInfo *)Info, -#if _EH_RELATIVE_OFFSETS - BaseAddr -#endif - }}; - -// const ThrowInfo* pTI = (const ThrowInfo*)Info; - -#ifdef THROW_ISWINRT - if (pTI && (THROW_ISWINRT((*pTI)))) { - // The pointer to the ExceptionInfo structure is stored sizeof(void*) - // infront of each WinRT Exception Info. - ULONG_PTR *EPtr = *reinterpret_cast(CxxExcept); - EPtr--; - - WINRTEXCEPTIONINFO **ppWei = reinterpret_cast(EPtr); - pTI = (*ppWei)->throwInfo; - (*ppWei)->PrepareThrow(ppWei); - } -#endif - - // If the throw info indicates this throw is from a pure region, - // set the magic number to the Pure one, so only a pure-region - // catch will see it. - // - // Also use the Pure magic number on Win64 if we were unable to - // determine an image base, since that was the old way to determine - // a pure throw, before the TI_IsPure bit was added to the FuncInfo - // attributes field. - if (Info != nullptr) { -#ifdef THROW_ISPURE - if (THROW_ISPURE(*pTI)) - Exception.params.magicNumber = EH_PURE_MAGIC_NUMBER1; -#if _EH_RELATIVE_OFFSETS - else -#endif // _EH_RELATIVE_OFFSETS -#endif // THROW_ISPURE - - // Not quite sure what this is about, but pThrowImageBase can never be 0 - // here, as that is used to mark when an "ImageBase" was not found. -#if 0 && _EH_RELATIVE_OFFSETS - if (Exception.params.pThrowImageBase == 0) - Exception.params.magicNumber = EH_PURE_MAGIC_NUMBER1; -#endif // _EH_RELATIVE_OFFSETS - } - -// Hand it off to the OS: -#if defined(_M_X64) && defined(_NTSUBSET_) - RtlRaiseException((PEXCEPTION_RECORD)&Exception); -#else - RaiseException(Exception.ExceptionCode, Exception.ExceptionFlags, - Exception.NumberParameters, (PULONG_PTR)&Exception.params); -#endif -} - -#endif // CLANG_INTERPRETER_WIN_EXCEPTIONS - -} // namespace interpreter Index: examples/clang-interpreter/main.cpp =================================================================== --- examples/clang-interpreter/main.cpp +++ examples/clang-interpreter/main.cpp @@ -7,11 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "Invoke.h" -#include "Manager.h" - -#include "clang/CodeGen/CodeGenAction.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/CodeGen/CodeGenAction.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" @@ -21,7 +18,12 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/SmallString.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -29,29 +31,11 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" using namespace clang; using namespace clang::driver; -namespace interpreter { - -static llvm::ExecutionEngine * -createExecutionEngine(std::unique_ptr M, std::string *ErrorStr) { - llvm::EngineBuilder EB(std::move(M)); - EB.setErrorStr(ErrorStr); - EB.setMemoryManager(llvm::make_unique()); - llvm::ExecutionEngine *EE = EB.create(); - EE->finalizeObject(); - return EE; -} - -// Invoked from a try/catch block in invoke.cpp. -// -static int Invoke(llvm::ExecutionEngine *EE, llvm::Function *EntryFn, - const std::vector &Args, char *const *EnvP) { - return EE->runFunctionAsMain(EntryFn, Args, EnvP); -} - // This function isn't referenced outside its translation unit, but it // can't use the "static" keyword because its address is used for // GetMainExecutable (since some platforms don't support taking the @@ -61,13 +45,75 @@ return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } -} // namespace interpreter +namespace llvm { +namespace orc { + +class SimpleJIT { +private: + ExecutionSession ES; + std::shared_ptr Resolver; + std::unique_ptr TM; + const DataLayout DL; + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + +public: + SimpleJIT() + : Resolver(createLegacyLookupResolver( + [this](const std::string &Name) -> JITSymbol { + if (auto Sym = CompileLayer.findSymbol(Name, false)) + return Sym; + else if (auto Err = Sym.takeError()) + return std::move(Err); + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return JITSymbol(SymAddr, JITSymbolFlags::Exported); + return nullptr; + }, + [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), + TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + ObjectLayer(ES, + [this](VModuleKey) { + return RTDyldObjectLinkingLayer::Resources{ + std::make_shared(), Resolver}; + }), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + const TargetMachine &getTargetMachine() const { return *TM; } -int main(int argc, const char **argv, char * const *envp) { + VModuleKey addModule(std::unique_ptr M) { + // Add the module to the JIT with a new VModuleKey. + auto K = ES.allocateVModule(); + cantFail(CompileLayer.addModule(K, std::move(M))); + return K; + } + + JITSymbol findSymbol(const StringRef &Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return CompileLayer.findSymbol(MangledNameStream.str(), true); + } + + JITTargetAddress getSymbolAddress(const StringRef &Name) { + return cantFail(findSymbol(Name).getAddress()); + } + + void removeModule(VModuleKey K) { + cantFail(CompileLayer.removeModule(K)); + } +}; + +} // end namespace orc +} // end namespace llvm + +int main(int argc, const char **argv) { // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. - void *MainAddr = (void*) (intptr_t) interpreter::GetExecutablePath; - std::string Path = interpreter::GetExecutablePath(argv[0], MainAddr); + void *MainAddr = (void*) (intptr_t) GetExecutablePath; + std::string Path = GetExecutablePath(argv[0], MainAddr); IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); @@ -83,7 +129,7 @@ if (T.isOSBinFormatCOFF()) T.setObjectFormat(llvm::Triple::ELF); #endif - + Driver TheDriver(Path, T.str(), Diags); TheDriver.setTitle("clang interpreter"); TheDriver.setCheckInputsExist(false); @@ -158,29 +204,14 @@ llvm::InitializeNativeTargetAsmPrinter(); int Res = 255; - if (std::unique_ptr Module = Act->takeModule()) { - llvm::Function *EntryFn = Module->getFunction("main"); - if (!EntryFn) { - llvm::errs() << "'main' function not found in module.\n"; - return Res; - } - - std::string Error; - std::unique_ptr EE( - interpreter::createExecutionEngine(std::move(Module), &Error)); - if (!EE) { - llvm::errs() << "unable to make execution engine: " << Error << "\n"; - return Res; - } - - interpreter::InvokeArgs Args; - for (int I = 1; I < argc; ++I) - Args.push_back(argv[I]); - - if (Clang.getLangOpts().CPlusPlus) - Res = interpreter::TryIt(EE.get(), EntryFn, Args, envp, interpreter::Invoke); - else - Res = interpreter::Invoke(EE.get(), EntryFn, Args, envp); + std::unique_ptr Module = Act->takeModule(); + + if (Module) { + llvm::orc::SimpleJIT J; + auto H = J.addModule(std::move(Module)); + auto Main = (int(*)(...))J.getSymbolAddress("main"); + Res = Main(); + J.removeModule(H); } // Shutdown.