diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /examples | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) |
Notes
Diffstat (limited to 'examples')
-rw-r--r-- | examples/PrintFunctionNames/CMakeLists.txt | 2 | ||||
-rw-r--r-- | examples/analyzer-plugin/MainCallChecker.cpp | 4 | ||||
-rw-r--r-- | examples/clang-interpreter/CMakeLists.txt | 67 | ||||
-rw-r--r-- | examples/clang-interpreter/README.txt | 7 | ||||
-rw-r--r-- | examples/clang-interpreter/Test.cxx | 34 | ||||
-rw-r--r-- | examples/clang-interpreter/main.cpp | 129 |
6 files changed, 196 insertions, 47 deletions
diff --git a/examples/PrintFunctionNames/CMakeLists.txt b/examples/PrintFunctionNames/CMakeLists.txt index f5f818866ca60..e582b2c45a861 100644 --- a/examples/PrintFunctionNames/CMakeLists.txt +++ b/examples/PrintFunctionNames/CMakeLists.txt @@ -1,7 +1,7 @@ # If we don't need RTTI or EH, there's no reason to export anything # from the plugin. if( NOT MSVC ) # MSVC mangles symbols differently, and - # PrintFunctionNames.export contains C++ symbols. + # PrintFunctionNames.export contains C++ symbols. if( NOT LLVM_REQUIRES_RTTI ) if( NOT LLVM_REQUIRES_EH ) set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/PrintFunctionNames.exports) diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp index 7f08760e3d4ce..74fe663e981f5 100644 --- a/examples/analyzer-plugin/MainCallChecker.cpp +++ b/examples/analyzer-plugin/MainCallChecker.cpp @@ -16,10 +16,8 @@ public: } // end anonymous namespace void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { - const ProgramStateRef state = C.getState(); - const LocationContext *LC = C.getLocationContext(); const Expr *Callee = CE->getCallee(); - const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl(); + const FunctionDecl *FD = C.getSVal(Callee).getAsFunctionDecl(); if (!FD) return; diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt index 3084238844802..7b9657ec1abf5 100644 --- a/examples/clang-interpreter/CMakeLists.txt +++ b/examples/clang-interpreter/CMakeLists.txt @@ -3,7 +3,10 @@ set(LLVM_LINK_COMPONENTS ExecutionEngine MC MCJIT + Object + OrcJit Option + RuntimeDyld Support native ) @@ -23,3 +26,67 @@ target_link_libraries(clang-interpreter clangDriver clangFrontend ) + +export_executable_symbols(clang-interpreter) + +if (MSVC) + # Is this a CMake bug that even with export_executable_symbols, Windows + # needs to explictly export the type_info vtable + set_property(TARGET clang-interpreter + APPEND_STRING PROPERTY LINK_FLAGS " /EXPORT:??_7type_info@@6B@") +endif() + +function(clang_enable_exceptions TARGET) + # Really have to jump through hoops to enable exception handling independent + # of how LLVM is being built. + if (NOT LLVM_REQUIRES_EH AND NOT LLVM_REQUIRES_RTTI) + if (MSVC) + # /EHs to allow throwing from extern "C" + set(excptnExceptions_ON "/D _HAS_EXCEPTIONS=1 /EHs /wd4714") + set(excptnExceptions_OFF "/D _HAS_EXCEPTIONS=0 /EHs-c-") + set(excptnRTTI_ON "/GR") + set(excptnRTTI_OFF "/GR-") + set(excptnEHRTTIRegEx "(/EHs(-c-?)|_HAS_EXCEPTIONS=(0|1))") + else() + set(excptnExceptions_ON "-fexceptions") + set(excptnExceptions_OFF "-fno-exceptions") + set(excptnRTTI_ON "-frtti") + set(excptnRTTI_OFF "-fno-rtti") + set(excptnEHRTTIRegEx "-f(exceptions|no-exceptions)") + endif() + if (LLVM_REQUIRES_EH) + set(excptnExceptions_DFLT ${excptnExceptions_ON}) + else() + set(excptnExceptions_DFLT ${excptnExceptions_OFF}) + endif() + if (LLVM_REQUIRES_RTTI) + set(excptnRTTI_DFLT ${excptnRTTI_ON}) + else() + set(excptnRTTI_DFLT ${excptnRTTI_OFF}) + endif() + + # Strip the exception & rtti flags from the target + get_property(addedFlags TARGET ${TARGET} PROPERTY COMPILE_FLAGS) + string(REGEX REPLACE ${excptnEHRTTIRegEx} "" editedFlags "${addedFlags}") + string(REPLACE ${excptnRTTI_OFF} "" editedFlags "${editedFlags}") + set_property(TARGET ${TARGET} PROPERTY COMPILE_FLAGS "${editedFlags}") + + get_property(addedFlags TARGET ${TARGET} PROPERTY COMPILE_DEFINITIONS) + string(REGEX REPLACE ${excptnEHRTTIRegEx} "" editedFlags "${addedFlags}") + string(REPLACE ${excptnRTTI_OFF} "" editedFlags "${editedFlags}") + set_property(TARGET ${TARGET} PROPERTY COMPILE_DEFINITIONS "${editedFlags}") + + # Re-add the exception & rtti flags from LLVM + set_property(SOURCE main.cpp APPEND_STRING PROPERTY COMPILE_FLAGS + " ${excptnExceptions_DFLT} ${excptnRTTI_DFLT} ") + set_property(SOURCE Manager.cpp APPEND_STRING PROPERTY COMPILE_FLAGS + " ${excptnExceptions_DFLT} ${excptnRTTI_DFLT} ") + + # Invoke with exceptions & rtti + set_property(SOURCE Invoke.cpp APPEND_STRING PROPERTY COMPILE_FLAGS + " ${excptnExceptions_ON} ${excptnRTTI_ON} ") + + endif() +endfunction(clang_enable_exceptions) + +clang_enable_exceptions(clang-interpreter) diff --git a/examples/clang-interpreter/README.txt b/examples/clang-interpreter/README.txt index 7dd45fad50483..b4f8a935cef83 100644 --- a/examples/clang-interpreter/README.txt +++ b/examples/clang-interpreter/README.txt @@ -1,4 +1,4 @@ -This is an example of Clang based interpreter, for executing standalone C +This is an example of Clang based interpreter, for executing standalone C/C++ programs. It demonstrates the following features: @@ -12,6 +12,9 @@ It demonstrates the following features: 4. Use the LLVM JIT functionality to execute the final module. + 5. Intercepting a Win64 library call to allow throwing and catching exceptions + in and from the JIT. + The implementation has many limitations and is not designed to be a full fledged -C interpreter. It is designed to demonstrate a simple but functional use of the +interpreter. It is designed to demonstrate a simple but functional use of the Clang compiler libraries. diff --git a/examples/clang-interpreter/Test.cxx b/examples/clang-interpreter/Test.cxx new file mode 100644 index 0000000000000..d2cbb0baac5c2 --- /dev/null +++ b/examples/clang-interpreter/Test.cxx @@ -0,0 +1,34 @@ +//===-- examples/clang-interpreter/Test.cxx - 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. +// +//===----------------------------------------------------------------------===// + +// Example throwing in and from the JIT (particularly on Win64). +// +// ./bin/clang-interpreter <src>/tools/clang/examples/clang-interpreter/Test.cxx + +#include <stdexcept> +#include <stdio.h> + +static void ThrowerAnError(const char* Name) { + throw std::runtime_error(Name); +} + +int main(int argc, const char** argv) { + for (int I = 0; I < argc; ++I) + printf("arg[%d]='%s'\n", I, argv[I]); + + try { + ThrowerAnError("In JIT"); + } catch (const std::exception& E) { + printf("Caught: '%s'\n", E.what()); + } catch (...) { + printf("Unknown exception\n"); + } + ThrowerAnError("From JIT"); + return 0; +} diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp index f7832291f2b62..3f87be29a9794 100644 --- a/examples/clang-interpreter/main.cpp +++ b/examples/clang-interpreter/main.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#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" @@ -18,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" @@ -26,7 +31,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include <memory> +#include "llvm/Target/TargetMachine.h" + using namespace clang; using namespace clang::driver; @@ -35,51 +41,80 @@ using namespace clang::driver; // GetMainExecutable (since some platforms don't support taking the // address of main, and some platforms can't implement GetMainExecutable // without being given the address of a function in the main executable). -std::string GetExecutablePath(const char *Argv0) { - // 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) GetExecutablePath; +std::string GetExecutablePath(const char *Argv0, void *MainAddr) { return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } -static llvm::ExecutionEngine * -createExecutionEngine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr) { - return llvm::EngineBuilder(std::move(M)) - .setEngineKind(llvm::EngineKind::Either) - .setErrorStr(ErrorStr) - .create(); -} +namespace llvm { +namespace orc { + +class SimpleJIT { +private: + ExecutionSession ES; + std::shared_ptr<SymbolResolver> Resolver; + std::unique_ptr<TargetMachine> TM; + const DataLayout DL; + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer; + +public: + SimpleJIT() + : Resolver(createLegacyLookupResolver( + ES, + [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<SectionMemoryManager>(), Resolver}; + }), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } -static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); + const TargetMachine &getTargetMachine() const { return *TM; } + + VModuleKey addModule(std::unique_ptr<Module> M) { + // Add the module to the JIT with a new VModuleKey. + auto K = ES.allocateVModule(); + cantFail(CompileLayer.addModule(K, std::move(M))); + return K; + } - llvm::Module &M = *Mod; - std::string Error; - std::unique_ptr<llvm::ExecutionEngine> EE( - createExecutionEngine(std::move(Mod), &Error)); - if (!EE) { - llvm::errs() << "unable to make execution engine: " << Error << "\n"; - return 255; + JITSymbol findSymbol(const StringRef &Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return CompileLayer.findSymbol(MangledNameStream.str(), true); } - llvm::Function *EntryFn = M.getFunction("main"); - if (!EntryFn) { - llvm::errs() << "'main' function not found in module.\n"; - return 255; + JITTargetAddress getSymbolAddress(const StringRef &Name) { + return cantFail(findSymbol(Name).getAddress()); } - // FIXME: Support passing arguments. - std::vector<std::string> Args; - Args.push_back(M.getModuleIdentifier()); + void removeModule(VModuleKey K) { + cantFail(CompileLayer.removeModule(K)); + } +}; - EE->finalizeObject(); - return EE->runFunctionAsMain(EntryFn, Args, envp); -} +} // end namespace orc +} // end namespace llvm -int main(int argc, const char **argv, char * const *envp) { +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) GetExecutablePath; - std::string Path = GetExecutablePath(argv[0]); + std::string Path = GetExecutablePath(argv[0], MainAddr); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); @@ -87,11 +122,14 @@ int main(int argc, const char **argv, char * const *envp) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); - // Use ELF on windows for now. - std::string TripleStr = llvm::sys::getProcessTriple(); + const std::string TripleStr = llvm::sys::getProcessTriple(); llvm::Triple T(TripleStr); + + // Use ELF on Windows-32 and MingW for now. +#ifndef CLANG_INTERPRETER_COFF_FORMAT if (T.isOSBinFormatCOFF()) T.setObjectFormat(llvm::Triple::ELF); +#endif Driver TheDriver(Path, T.str(), Diags); TheDriver.setTitle("clang interpreter"); @@ -163,12 +201,21 @@ int main(int argc, const char **argv, char * const *envp) { if (!Clang.ExecuteAction(*Act)) return 1; + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + int Res = 255; - if (std::unique_ptr<llvm::Module> Module = Act->takeModule()) - Res = Execute(std::move(Module), envp); + std::unique_ptr<llvm::Module> 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. - llvm::llvm_shutdown(); return Res; |