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 <memory>
+
 using namespace clang;
 using namespace clang::driver;
 
+namespace interpreter {
+
+static llvm::ExecutionEngine *
+createExecutionEngine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr) {
+  llvm::EngineBuilder EB(std::move(M));
+  EB.setErrorStr(ErrorStr);
+  EB.setMemoryManager(llvm::make_unique<SingleSectionMemoryManager>());
+  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<std::string> &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
 // 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();
-}
-
-static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp) {
-  llvm::InitializeNativeTarget();
-  llvm::InitializeNativeTargetAsmPrinter();
-
-  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;
-  }
-
-  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<std::string> 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<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticPrinter *DiagClient =
     new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
 
   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");
   TheDriver.setCheckInputsExist(false);
@@ -163,12 +154,36 @@
   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);
+  if (std::unique_ptr<llvm::Module> 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<llvm::ExecutionEngine> 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);
+  }
 
   // Shutdown.
-
   llvm::llvm_shutdown();
 
   return Res;
Index: examples/clang-interpreter/Test.cxx
===================================================================
--- /dev/null
+++ 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;
+}
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.h
===================================================================
--- /dev/null
+++ examples/clang-interpreter/Manager.h
@@ -0,0 +1,56 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#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
+};
+
+}
Index: examples/clang-interpreter/Manager.cpp
===================================================================
--- /dev/null
+++ 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 <windows.h>
+#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<std::pair<DWORD, DWORD>> ImageRanges;
+  typedef std::map<uintptr_t, ImageRanges> 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<DWORD>::max(),
+                        std::numeric_limits<DWORD>::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<PRUNTIME_FUNCTION>(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<PRUNTIME_FUNCTION>(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<ULONG_PTR **>(CxxExcept);
+    EPtr--;
+
+    WINRTEXCEPTIONINFO **ppWei = reinterpret_cast<WINRTEXCEPTIONINFO **>(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/Invoke.h
===================================================================
--- /dev/null
+++ examples/clang-interpreter/Invoke.h
@@ -0,0 +1,31 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+namespace llvm {
+  class ExecutionEngine;
+  class Function;
+}
+
+#include <string>
+#include <vector>
+
+namespace interpreter {
+
+typedef std::vector<std::string> 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
Index: examples/clang-interpreter/Invoke.cpp
===================================================================
--- /dev/null
+++ 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 <iostream>
+#include <stdexcept>
+
+namespace interpreter {
+
+int TryIt(llvm::ExecutionEngine *EE, llvm::Function *EntryFn,
+          const std::vector<std::string> &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/CMakeLists.txt
===================================================================
--- examples/clang-interpreter/CMakeLists.txt
+++ examples/clang-interpreter/CMakeLists.txt
@@ -3,13 +3,17 @@
   ExecutionEngine
   MC
   MCJIT
+  OrcJit
   Option
+  RuntimeDyld
   Support
   native
   )
 
 add_clang_executable(clang-interpreter
   main.cpp
+  Invoke.cpp
+  Manager.cpp
   )
 
 add_dependencies(clang-interpreter
@@ -22,3 +26,69 @@
   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 rom 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})
+    #message("COMPILE_FLAGS: '${addedFlags}' '${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})
+    #message("COMPILE_DEFINITIONS: '${addedFlags}' '${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)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to