[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
This revision was automatically updated to reflect the committed changes. Closed by commit rC327528: Expand clang-interpreter with example of throwing in and from the JIT for… (authored by marsupial, committed by ). Repository: rC Clang https://reviews.llvm.org/D35103 Files: examples/clang-interpreter/CMakeLists.txt examples/clang-interpreter/Invoke.cpp examples/clang-interpreter/Invoke.h examples/clang-interpreter/Manager.cpp examples/clang-interpreter/Manager.h examples/clang-interpreter/README.txt examples/clang-interpreter/Test.cxx examples/clang-interpreter/main.cpp Index: examples/clang-interpreter/Invoke.cpp === --- examples/clang-interpreter/Invoke.cpp +++ examples/clang-interpreter/Invoke.cpp @@ -0,0 +1,31 @@ +//==-- 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 , char *const *EnvP, + Invoker Invoke) { + int Res = -1; + try { +Res = Invoke(EE, EntryFn, Args, EnvP); + } catch (const std::exception ) { +std::cout << "Caught '" << E.what() << "'\n"; + } catch (...) { +std::cout << "Unknown exception\n"; + } + return Res; +} + +} Index: examples/clang-interpreter/README.txt === --- examples/clang-interpreter/README.txt +++ 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 @@ 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. Index: examples/clang-interpreter/Manager.cpp === --- examples/clang-interpreter/Manager.cpp +++ examples/clang-interpreter/Manager.cpp @@ -0,0 +1,328 @@ +//==-- 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
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
martell added a comment. Herald added a subscriber: mgrang. ping @marsupial https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial marked 3 inline comments as done. marsupial added a comment. Done, thanks. Would it be possible to look at https://reviews.llvm.org/D30709 as this depends on that. (ELF does not like Windows exceptions). https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial updated this revision to Diff 108676. marsupial added a comment. Use include guards, not pragma once and remove commented CMake debug lines. https://reviews.llvm.org/D35103 Files: examples/clang-interpreter/CMakeLists.txt examples/clang-interpreter/Invoke.cpp examples/clang-interpreter/Invoke.h examples/clang-interpreter/Manager.cpp examples/clang-interpreter/Manager.h examples/clang-interpreter/README.txt examples/clang-interpreter/Test.cxx examples/clang-interpreter/main.cpp Index: examples/clang-interpreter/main.cpp === --- examples/clang-interpreter/main.cpp +++ examples/clang-interpreter/main.cpp @@ -7,6 +7,9 @@ // //===--===// +#include "Invoke.h" +#include "Manager.h" + #include "clang/CodeGen/CodeGenAction.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" @@ -26,73 +29,61 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include + 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 , 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 // 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 M, std::string *ErrorStr) { - return llvm::EngineBuilder(std::move(M)) - .setEngineKind(llvm::EngineKind::Either) - .setErrorStr(ErrorStr) - .create(); -} - -static int Execute(std::unique_ptr Mod, char *const *envp) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::Module = *Mod; - std::string Error; - std::unique_ptr EE( - createExecutionEngine(std::move(Mod), )); - if (!EE) { -llvm::errs() << "unable to make execution engine: " << Error << "\n"; -return 255; - } - - llvm::Function *EntryFn = M.getFunction("main"); - if (!EntryFn) { -llvm::errs() << "'main' function not found in module.\n"; -return 255; - } - - // FIXME: Support passing arguments. - std::vector Args; - Args.push_back(M.getModuleIdentifier()); - - EE->finalizeObject(); - return EE->runFunctionAsMain(EntryFn, Args, envp); -} +} // namespace interpreter int main(int argc, const char **argv, char * const *envp) { - void *MainAddr = (void*) (intptr_t) GetExecutablePath; - std::string Path = GetExecutablePath(argv[0]); + // 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); IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); IntrusiveRefCntPtr 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"); TheDriver.setCheckInputsExist(false); @@ -163,12 +154,36 @@ if (!Clang.ExecuteAction(*Act)) return 1; + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + int Res = 255; - if (std::unique_ptr Module = Act->takeModule()) -Res = Execute(std::move(Module), envp); + if (std::unique_ptr Module = Act->takeModule()) { +llvm::Function
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
lhames accepted this revision. lhames added a comment. This revision is now accepted and ready to land. Otherwise this looks good to me. Comment at: examples/clang-interpreter/CMakeLists.txt:73 +set_property(TARGET ${TARGET} PROPERTY COMPILE_FLAGS ${editedFlags}) +#message("COMPILE_FLAGS: '${addedFlags}' '${editedFlags}'") + These debugging messages (this and the one below) should probably be stripped. Comment at: examples/clang-interpreter/Invoke.h:10 + +#pragma once + I believe you should use include guards in LLVM headers. Pragma once should work, but I don't think it's standard (and it doesn't seem to be used anywhere else in the codebase). Comment at: examples/clang-interpreter/Manager.h:10 + +#pragma once + Ditto here. https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial added a comment. Ping. https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial marked 3 inline comments as done. marsupial added a comment. Done, and changed to 'windows.h', but blocked mingw from even attempting SEH for now. https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial updated this revision to Diff 106548. marsupial added a comment. Blocked Win64 SEH for MingW entirely. Theoretically it should be possible to throw a SEH from within mingw, but but I'm thinking clang may be generating exception handlers for the gcc runtime in that case. I'll leave it up to someone with interest in such a mixture to figure that tout. https://reviews.llvm.org/D35103 Files: examples/clang-interpreter/CMakeLists.txt examples/clang-interpreter/Invoke.cpp examples/clang-interpreter/Invoke.h examples/clang-interpreter/Manager.cpp examples/clang-interpreter/Manager.h examples/clang-interpreter/README.txt examples/clang-interpreter/Test.cxx examples/clang-interpreter/main.cpp Index: examples/clang-interpreter/main.cpp === --- examples/clang-interpreter/main.cpp +++ examples/clang-interpreter/main.cpp @@ -7,6 +7,9 @@ // //===--===// +#include "Invoke.h" +#include "Manager.h" + #include "clang/CodeGen/CodeGenAction.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" @@ -26,73 +29,61 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include + 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 , 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 // 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 M, std::string *ErrorStr) { - return llvm::EngineBuilder(std::move(M)) - .setEngineKind(llvm::EngineKind::Either) - .setErrorStr(ErrorStr) - .create(); -} - -static int Execute(std::unique_ptr Mod, char *const *envp) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::Module = *Mod; - std::string Error; - std::unique_ptr EE( - createExecutionEngine(std::move(Mod), )); - if (!EE) { -llvm::errs() << "unable to make execution engine: " << Error << "\n"; -return 255; - } - - llvm::Function *EntryFn = M.getFunction("main"); - if (!EntryFn) { -llvm::errs() << "'main' function not found in module.\n"; -return 255; - } - - // FIXME: Support passing arguments. - std::vector Args; - Args.push_back(M.getModuleIdentifier()); - - EE->finalizeObject(); - return EE->runFunctionAsMain(EntryFn, Args, envp); -} +} // namespace interpreter int main(int argc, const char **argv, char * const *envp) { - void *MainAddr = (void*) (intptr_t) GetExecutablePath; - std::string Path = GetExecutablePath(argv[0]); + // 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); IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); IntrusiveRefCntPtr 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"); TheDriver.setCheckInputsExist(false); @@ -163,12 +154,36 @@ if (!Clang.ExecuteAction(*Act)) return 1; + llvm::InitializeNativeTarget(); +
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
martell added inline comments. Comment at: examples/clang-interpreter/Manager.cpp:18 +#define NOMINMAX +#include +#endif windows.h with lower case `w` to not break mingw https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
martell added a comment. Just 2 small nits. Comment at: examples/clang-interpreter/main.cpp:165 + llvm::errs() << "'main' function not found in module.\n"; + return 255; +} 255 -> Res ? Comment at: examples/clang-interpreter/main.cpp:173 + llvm::errs() << "unable to make execution engine: " << Error << "\n"; + return 255; +} 255 -> Res https://reviews.llvm.org/D35103 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35103: Expand clang-interpreter with example of throwing in and from the JIT for Windows64.
marsupial created this revision. Herald added a subscriber: mgorny. Getting this to work is not particularly obvious, and having it as an example should be helpful. Portions of this could be placed into LLVM, but as a whole it seems necessary to do this a higher level. https://reviews.llvm.org/D35103 Files: examples/clang-interpreter/CMakeLists.txt examples/clang-interpreter/Invoke.cpp examples/clang-interpreter/Invoke.h examples/clang-interpreter/Manager.cpp examples/clang-interpreter/Manager.h examples/clang-interpreter/README.txt examples/clang-interpreter/Test.cxx examples/clang-interpreter/main.cpp Index: examples/clang-interpreter/main.cpp === --- examples/clang-interpreter/main.cpp +++ examples/clang-interpreter/main.cpp @@ -7,6 +7,9 @@ // //===--===// +#include "Invoke.h" +#include "Manager.h" + #include "clang/CodeGen/CodeGenAction.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" @@ -26,73 +29,61 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include + 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 , 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 // 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 M, std::string *ErrorStr) { - return llvm::EngineBuilder(std::move(M)) - .setEngineKind(llvm::EngineKind::Either) - .setErrorStr(ErrorStr) - .create(); -} - -static int Execute(std::unique_ptr Mod, char *const *envp) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::Module = *Mod; - std::string Error; - std::unique_ptr EE( - createExecutionEngine(std::move(Mod), )); - if (!EE) { -llvm::errs() << "unable to make execution engine: " << Error << "\n"; -return 255; - } - - llvm::Function *EntryFn = M.getFunction("main"); - if (!EntryFn) { -llvm::errs() << "'main' function not found in module.\n"; -return 255; - } - - // FIXME: Support passing arguments. - std::vector Args; - Args.push_back(M.getModuleIdentifier()); - - EE->finalizeObject(); - return EE->runFunctionAsMain(EntryFn, Args, envp); -} +} // namespace interpreter int main(int argc, const char **argv, char * const *envp) { - void *MainAddr = (void*) (intptr_t) GetExecutablePath; - std::string Path = GetExecutablePath(argv[0]); + // 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); IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); IntrusiveRefCntPtr 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 for now. +#if defined(_WIN32) && !defined(_WIN64) if (T.isOSBinFormatCOFF()) T.setObjectFormat(llvm::Triple::ELF); - +#endif + Driver TheDriver(Path, T.str(), Diags); TheDriver.setTitle("clang interpreter"); TheDriver.setCheckInputsExist(false); @@ -163,12 +154,36 @@ if (!Clang.ExecuteAction(*Act)) return 1; + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + int Res = 255; - if (std::unique_ptr Module = Act->takeModule()) -Res =