| //===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // Demo program which implements an example LLVM exception implementation, and | 
 | // shows several test cases including the handling of foreign exceptions. | 
 | // It is run with type info types arguments to throw. A test will | 
 | // be run for each given type info type. While type info types with the value | 
 | // of -1 will trigger a foreign C++ exception to be thrown; type info types | 
 | // <= 6 and >= 1 will cause the associated generated exceptions to be thrown | 
 | // and caught by generated test functions; and type info types > 6 | 
 | // will result in exceptions which pass through to the test harness. All other | 
 | // type info types are not supported and could cause a crash. In all cases, | 
 | // the "finally" blocks of every generated test functions will executed | 
 | // regardless of whether or not that test function ignores or catches the | 
 | // thrown exception. | 
 | // | 
 | // examples: | 
 | // | 
 | // ExceptionDemo | 
 | // | 
 | //     causes a usage to be printed to stderr | 
 | // | 
 | // ExceptionDemo 2 3 7 -1 | 
 | // | 
 | //     results in the following cases: | 
 | //         - Value 2 causes an exception with a type info type of 2 to be | 
 | //           thrown and caught by an inner generated test function. | 
 | //         - Value 3 causes an exception with a type info type of 3 to be | 
 | //           thrown and caught by an outer generated test function. | 
 | //         - Value 7 causes an exception with a type info type of 7 to be | 
 | //           thrown and NOT be caught by any generated function. | 
 | //         - Value -1 causes a foreign C++ exception to be thrown and not be | 
 | //           caught by any generated function | 
 | // | 
 | //     Cases -1 and 7 are caught by a C++ test harness where the validity of | 
 | //         of a C++ catch(...) clause catching a generated exception with a | 
 | //         type info type of 7 is explained by: example in rules 1.6.4 in | 
 | //         http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22) | 
 | // | 
 | // This code uses code from the llvm compiler-rt project and the llvm | 
 | // Kaleidoscope project. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/BinaryFormat/Dwarf.h" | 
 | #include "llvm/ExecutionEngine/MCJIT.h" | 
 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" | 
 | #include "llvm/IR/DataLayout.h" | 
 | #include "llvm/IR/DerivedTypes.h" | 
 | #include "llvm/IR/IRBuilder.h" | 
 | #include "llvm/IR/Intrinsics.h" | 
 | #include "llvm/IR/LLVMContext.h" | 
 | #include "llvm/IR/LegacyPassManager.h" | 
 | #include "llvm/IR/Module.h" | 
 | #include "llvm/IR/Verifier.h" | 
 | #include "llvm/Support/TargetSelect.h" | 
 | #include "llvm/Target/TargetOptions.h" | 
 | #include "llvm/Transforms/Scalar.h" | 
 |  | 
 | // FIXME: Although all systems tested with (Linux, OS X), do not need this | 
 | //        header file included. A user on ubuntu reported, undefined symbols | 
 | //        for stderr, and fprintf, and the addition of this include fixed the | 
 | //        issue for them. Given that LLVM's best practices include the goal | 
 | //        of reducing the number of redundant header files included, the | 
 | //        correct solution would be to find out why these symbols are not | 
 | //        defined for the system in question, and fix the issue by finding out | 
 | //        which LLVM header file, if any, would include these symbols. | 
 | #include <cstdio> | 
 |  | 
 | #include <sstream> | 
 | #include <stdexcept> | 
 |  | 
 | #include <inttypes.h> | 
 |  | 
 | #include <unwind.h> | 
 |  | 
 | #ifndef USE_GLOBAL_STR_CONSTS | 
 | #define USE_GLOBAL_STR_CONSTS true | 
 | #endif | 
 |  | 
 | // | 
 | // Example types | 
 | // | 
 |  | 
 | /// This is our simplistic type info | 
 | struct OurExceptionType_t { | 
 |   /// type info type | 
 |   int type; | 
 | }; | 
 |  | 
 |  | 
 | /// This is our Exception class which relies on a negative offset to calculate | 
 | /// pointers to its instances from pointers to its unwindException member. | 
 | /// | 
 | /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned | 
 | ///       on a double word boundary. This is necessary to match the standard: | 
 | ///       http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html | 
 | struct OurBaseException_t { | 
 |   struct OurExceptionType_t type; | 
 |  | 
 |   // Note: This is properly aligned in unwind.h | 
 |   struct _Unwind_Exception unwindException; | 
 | }; | 
 |  | 
 |  | 
 | // Note: Not needed since we are C++ | 
 | typedef struct OurBaseException_t OurException; | 
 | typedef struct _Unwind_Exception OurUnwindException; | 
 |  | 
 | // | 
 | // Various globals used to support typeinfo and generatted exceptions in | 
 | // general | 
 | // | 
 |  | 
 | static std::map<std::string, llvm::Value*> namedValues; | 
 |  | 
 | int64_t ourBaseFromUnwindOffset; | 
 |  | 
 | const unsigned char ourBaseExcpClassChars[] = | 
 | {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'}; | 
 |  | 
 |  | 
 | static uint64_t ourBaseExceptionClass = 0; | 
 |  | 
 | static std::vector<std::string> ourTypeInfoNames; | 
 | static std::map<int, std::string> ourTypeInfoNamesIndex; | 
 |  | 
 | static llvm::StructType *ourTypeInfoType; | 
 | static llvm::StructType *ourCaughtResultType; | 
 | static llvm::StructType *ourExceptionType; | 
 | static llvm::StructType *ourUnwindExceptionType; | 
 |  | 
 | static llvm::ConstantInt *ourExceptionNotThrownState; | 
 | static llvm::ConstantInt *ourExceptionThrownState; | 
 | static llvm::ConstantInt *ourExceptionCaughtState; | 
 |  | 
 | typedef std::vector<std::string> ArgNames; | 
 | typedef std::vector<llvm::Type*> ArgTypes; | 
 |  | 
 | // | 
 | // Code Generation Utilities | 
 | // | 
 |  | 
 | /// Utility used to create a function, both declarations and definitions | 
 | /// @param module for module instance | 
 | /// @param retType function return type | 
 | /// @param theArgTypes function's ordered argument types | 
 | /// @param theArgNames function's ordered arguments needed if use of this | 
 | ///        function corresponds to a function definition. Use empty | 
 | ///        aggregate for function declarations. | 
 | /// @param functName function name | 
 | /// @param linkage function linkage | 
 | /// @param declarationOnly for function declarations | 
 | /// @param isVarArg function uses vararg arguments | 
 | /// @returns function instance | 
 | llvm::Function *createFunction(llvm::Module &module, | 
 |                                llvm::Type *retType, | 
 |                                const ArgTypes &theArgTypes, | 
 |                                const ArgNames &theArgNames, | 
 |                                const std::string &functName, | 
 |                                llvm::GlobalValue::LinkageTypes linkage, | 
 |                                bool declarationOnly, | 
 |                                bool isVarArg) { | 
 |   llvm::FunctionType *functType = | 
 |     llvm::FunctionType::get(retType, theArgTypes, isVarArg); | 
 |   llvm::Function *ret = | 
 |     llvm::Function::Create(functType, linkage, functName, &module); | 
 |   if (!ret || declarationOnly) | 
 |     return(ret); | 
 |  | 
 |   namedValues.clear(); | 
 |   unsigned i = 0; | 
 |   for (llvm::Function::arg_iterator argIndex = ret->arg_begin(); | 
 |        i != theArgNames.size(); | 
 |        ++argIndex, ++i) { | 
 |  | 
 |     argIndex->setName(theArgNames[i]); | 
 |     namedValues[theArgNames[i]] = argIndex; | 
 |   } | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// Create an alloca instruction in the entry block of | 
 | /// the parent function.  This is used for mutable variables etc. | 
 | /// @param function parent instance | 
 | /// @param varName stack variable name | 
 | /// @param type stack variable type | 
 | /// @param initWith optional constant initialization value | 
 | /// @returns AllocaInst instance | 
 | static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function, | 
 |                                                 const std::string &varName, | 
 |                                                 llvm::Type *type, | 
 |                                                 llvm::Constant *initWith = 0) { | 
 |   llvm::BasicBlock &block = function.getEntryBlock(); | 
 |   llvm::IRBuilder<> tmp(&block, block.begin()); | 
 |   llvm::AllocaInst *ret = tmp.CreateAlloca(type, 0, varName); | 
 |  | 
 |   if (initWith) | 
 |     tmp.CreateStore(initWith, ret); | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | // | 
 | // Code Generation Utilities End | 
 | // | 
 |  | 
 | // | 
 | // Runtime C Library functions | 
 | // | 
 |  | 
 | namespace { | 
 | template <typename Type_> | 
 | uintptr_t ReadType(const uint8_t *&p) { | 
 |   Type_ value; | 
 |   memcpy(&value, p, sizeof(Type_)); | 
 |   p += sizeof(Type_); | 
 |   return static_cast<uintptr_t>(value); | 
 | } | 
 | } | 
 |  | 
 | // Note: using an extern "C" block so that static functions can be used | 
 | extern "C" { | 
 |  | 
 | // Note: Better ways to decide on bit width | 
 | // | 
 | /// Prints a 32 bit number, according to the format, to stderr. | 
 | /// @param intToPrint integer to print | 
 | /// @param format printf like format to use when printing | 
 | void print32Int(int intToPrint, const char *format) { | 
 |   if (format) { | 
 |     // Note: No NULL check | 
 |     fprintf(stderr, format, intToPrint); | 
 |   } | 
 |   else { | 
 |     // Note: No NULL check | 
 |     fprintf(stderr, "::print32Int(...):NULL arg.\n"); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | // Note: Better ways to decide on bit width | 
 | // | 
 | /// Prints a 64 bit number, according to the format, to stderr. | 
 | /// @param intToPrint integer to print | 
 | /// @param format printf like format to use when printing | 
 | void print64Int(long int intToPrint, const char *format) { | 
 |   if (format) { | 
 |     // Note: No NULL check | 
 |     fprintf(stderr, format, intToPrint); | 
 |   } | 
 |   else { | 
 |     // Note: No NULL check | 
 |     fprintf(stderr, "::print64Int(...):NULL arg.\n"); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /// Prints a C string to stderr | 
 | /// @param toPrint string to print | 
 | void printStr(char *toPrint) { | 
 |   if (toPrint) { | 
 |     fprintf(stderr, "%s", toPrint); | 
 |   } | 
 |   else { | 
 |     fprintf(stderr, "::printStr(...):NULL arg.\n"); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /// Deletes the true previously allocated exception whose address | 
 | /// is calculated from the supplied OurBaseException_t::unwindException | 
 | /// member address. Handles (ignores), NULL pointers. | 
 | /// @param expToDelete exception to delete | 
 | void deleteOurException(OurUnwindException *expToDelete) { | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "deleteOurException(...).\n"); | 
 | #endif | 
 |  | 
 |   if (expToDelete && | 
 |       (expToDelete->exception_class == ourBaseExceptionClass)) { | 
 |  | 
 |     free(((char*) expToDelete) + ourBaseFromUnwindOffset); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /// This function is the struct _Unwind_Exception API mandated delete function | 
 | /// used by foreign exception handlers when deleting our exception | 
 | /// (OurException), instances. | 
 | /// @param reason See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html | 
 | /// @unlink | 
 | /// @param expToDelete exception instance to delete | 
 | void deleteFromUnwindOurException(_Unwind_Reason_Code reason, | 
 |                                   OurUnwindException *expToDelete) { | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "deleteFromUnwindOurException(...).\n"); | 
 | #endif | 
 |  | 
 |   deleteOurException(expToDelete); | 
 | } | 
 |  | 
 |  | 
 | /// Creates (allocates on the heap), an exception (OurException instance), | 
 | /// of the supplied type info type. | 
 | /// @param type type info type | 
 | OurUnwindException *createOurException(int type) { | 
 |   size_t size = sizeof(OurException); | 
 |   OurException *ret = (OurException*) memset(malloc(size), 0, size); | 
 |   (ret->type).type = type; | 
 |   (ret->unwindException).exception_class = ourBaseExceptionClass; | 
 |   (ret->unwindException).exception_cleanup = deleteFromUnwindOurException; | 
 |  | 
 |   return(&(ret->unwindException)); | 
 | } | 
 |  | 
 |  | 
 | /// Read a uleb128 encoded value and advance pointer | 
 | /// See Variable Length Data in: | 
 | /// @link http://dwarfstd.org/Dwarf3.pdf @unlink | 
 | /// @param data reference variable holding memory pointer to decode from | 
 | /// @returns decoded value | 
 | static uintptr_t readULEB128(const uint8_t **data) { | 
 |   uintptr_t result = 0; | 
 |   uintptr_t shift = 0; | 
 |   unsigned char byte; | 
 |   const uint8_t *p = *data; | 
 |  | 
 |   do { | 
 |     byte = *p++; | 
 |     result |= (byte & 0x7f) << shift; | 
 |     shift += 7; | 
 |   } | 
 |   while (byte & 0x80); | 
 |  | 
 |   *data = p; | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | /// Read a sleb128 encoded value and advance pointer | 
 | /// See Variable Length Data in: | 
 | /// @link http://dwarfstd.org/Dwarf3.pdf @unlink | 
 | /// @param data reference variable holding memory pointer to decode from | 
 | /// @returns decoded value | 
 | static uintptr_t readSLEB128(const uint8_t **data) { | 
 |   uintptr_t result = 0; | 
 |   uintptr_t shift = 0; | 
 |   unsigned char byte; | 
 |   const uint8_t *p = *data; | 
 |  | 
 |   do { | 
 |     byte = *p++; | 
 |     result |= (byte & 0x7f) << shift; | 
 |     shift += 7; | 
 |   } | 
 |   while (byte & 0x80); | 
 |  | 
 |   *data = p; | 
 |  | 
 |   if ((byte & 0x40) && (shift < (sizeof(result) << 3))) { | 
 |     result |= (~0 << shift); | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | unsigned getEncodingSize(uint8_t Encoding) { | 
 |   if (Encoding == llvm::dwarf::DW_EH_PE_omit) | 
 |     return 0; | 
 |  | 
 |   switch (Encoding & 0x0F) { | 
 |   case llvm::dwarf::DW_EH_PE_absptr: | 
 |     return sizeof(uintptr_t); | 
 |   case llvm::dwarf::DW_EH_PE_udata2: | 
 |     return sizeof(uint16_t); | 
 |   case llvm::dwarf::DW_EH_PE_udata4: | 
 |     return sizeof(uint32_t); | 
 |   case llvm::dwarf::DW_EH_PE_udata8: | 
 |     return sizeof(uint64_t); | 
 |   case llvm::dwarf::DW_EH_PE_sdata2: | 
 |     return sizeof(int16_t); | 
 |   case llvm::dwarf::DW_EH_PE_sdata4: | 
 |     return sizeof(int32_t); | 
 |   case llvm::dwarf::DW_EH_PE_sdata8: | 
 |     return sizeof(int64_t); | 
 |   default: | 
 |     // not supported | 
 |     abort(); | 
 |   } | 
 | } | 
 |  | 
 | /// Read a pointer encoded value and advance pointer | 
 | /// See Variable Length Data in: | 
 | /// @link http://dwarfstd.org/Dwarf3.pdf @unlink | 
 | /// @param data reference variable holding memory pointer to decode from | 
 | /// @param encoding dwarf encoding type | 
 | /// @returns decoded value | 
 | static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) { | 
 |   uintptr_t result = 0; | 
 |   const uint8_t *p = *data; | 
 |  | 
 |   if (encoding == llvm::dwarf::DW_EH_PE_omit) | 
 |     return(result); | 
 |  | 
 |   // first get value | 
 |   switch (encoding & 0x0F) { | 
 |     case llvm::dwarf::DW_EH_PE_absptr: | 
 |       result = ReadType<uintptr_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_uleb128: | 
 |       result = readULEB128(&p); | 
 |       break; | 
 |       // Note: This case has not been tested | 
 |     case llvm::dwarf::DW_EH_PE_sleb128: | 
 |       result = readSLEB128(&p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_udata2: | 
 |       result = ReadType<uint16_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_udata4: | 
 |       result = ReadType<uint32_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_udata8: | 
 |       result = ReadType<uint64_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_sdata2: | 
 |       result = ReadType<int16_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_sdata4: | 
 |       result = ReadType<int32_t>(p); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_sdata8: | 
 |       result = ReadType<int64_t>(p); | 
 |       break; | 
 |     default: | 
 |       // not supported | 
 |       abort(); | 
 |       break; | 
 |   } | 
 |  | 
 |   // then add relative offset | 
 |   switch (encoding & 0x70) { | 
 |     case llvm::dwarf::DW_EH_PE_absptr: | 
 |       // do nothing | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_pcrel: | 
 |       result += (uintptr_t)(*data); | 
 |       break; | 
 |     case llvm::dwarf::DW_EH_PE_textrel: | 
 |     case llvm::dwarf::DW_EH_PE_datarel: | 
 |     case llvm::dwarf::DW_EH_PE_funcrel: | 
 |     case llvm::dwarf::DW_EH_PE_aligned: | 
 |     default: | 
 |       // not supported | 
 |       abort(); | 
 |       break; | 
 |   } | 
 |  | 
 |   // then apply indirection | 
 |   if (encoding & llvm::dwarf::DW_EH_PE_indirect) { | 
 |     result = *((uintptr_t*)result); | 
 |   } | 
 |  | 
 |   *data = p; | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | /// Deals with Dwarf actions matching our type infos | 
 | /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted | 
 | /// action matches the supplied exception type. If such a match succeeds, | 
 | /// the resultAction argument will be set with > 0 index value. Only | 
 | /// corresponding llvm.eh.selector type info arguments, cleanup arguments | 
 | /// are supported. Filters are not supported. | 
 | /// See Variable Length Data in: | 
 | /// @link http://dwarfstd.org/Dwarf3.pdf @unlink | 
 | /// Also see @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink | 
 | /// @param resultAction reference variable which will be set with result | 
 | /// @param classInfo our array of type info pointers (to globals) | 
 | /// @param actionEntry index into above type info array or 0 (clean up). | 
 | ///        We do not support filters. | 
 | /// @param exceptionClass exception class (_Unwind_Exception::exception_class) | 
 | ///        of thrown exception. | 
 | /// @param exceptionObject thrown _Unwind_Exception instance. | 
 | /// @returns whether or not a type info was found. False is returned if only | 
 | ///          a cleanup was found | 
 | static bool handleActionValue(int64_t *resultAction, | 
 |                               uint8_t TTypeEncoding, | 
 |                               const uint8_t *ClassInfo, | 
 |                               uintptr_t actionEntry, | 
 |                               uint64_t exceptionClass, | 
 |                               struct _Unwind_Exception *exceptionObject) { | 
 |   bool ret = false; | 
 |  | 
 |   if (!resultAction || | 
 |       !exceptionObject || | 
 |       (exceptionClass != ourBaseExceptionClass)) | 
 |     return(ret); | 
 |  | 
 |   struct OurBaseException_t *excp = (struct OurBaseException_t*) | 
 |   (((char*) exceptionObject) + ourBaseFromUnwindOffset); | 
 |   struct OurExceptionType_t *excpType = &(excp->type); | 
 |   int type = excpType->type; | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "handleActionValue(...): exceptionObject = <%p>, " | 
 |           "excp = <%p>.\n", | 
 |           (void*)exceptionObject, | 
 |           (void*)excp); | 
 | #endif | 
 |  | 
 |   const uint8_t *actionPos = (uint8_t*) actionEntry, | 
 |   *tempActionPos; | 
 |   int64_t typeOffset = 0, | 
 |   actionOffset; | 
 |  | 
 |   for (int i = 0; true; ++i) { | 
 |     // Each emitted dwarf action corresponds to a 2 tuple of | 
 |     // type info address offset, and action offset to the next | 
 |     // emitted action. | 
 |     typeOffset = readSLEB128(&actionPos); | 
 |     tempActionPos = actionPos; | 
 |     actionOffset = readSLEB128(&tempActionPos); | 
 |  | 
 | #ifdef DEBUG | 
 |     fprintf(stderr, | 
 |             "handleActionValue(...):typeOffset: <%" PRIi64 ">, " | 
 |             "actionOffset: <%" PRIi64 ">.\n", | 
 |             typeOffset, | 
 |             actionOffset); | 
 | #endif | 
 |     assert((typeOffset >= 0) && | 
 |            "handleActionValue(...):filters are not supported."); | 
 |  | 
 |     // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector | 
 |     //       argument has been matched. | 
 |     if (typeOffset > 0) { | 
 | #ifdef DEBUG | 
 |       fprintf(stderr, | 
 |               "handleActionValue(...):actionValue <%d> found.\n", | 
 |               i); | 
 | #endif | 
 |       unsigned EncSize = getEncodingSize(TTypeEncoding); | 
 |       const uint8_t *EntryP = ClassInfo - typeOffset * EncSize; | 
 |       uintptr_t P = readEncodedPointer(&EntryP, TTypeEncoding); | 
 |       struct OurExceptionType_t *ThisClassInfo = | 
 |         reinterpret_cast<struct OurExceptionType_t *>(P); | 
 |       if (ThisClassInfo->type == type) { | 
 |         *resultAction = i + 1; | 
 |         ret = true; | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 | #ifdef DEBUG | 
 |     fprintf(stderr, | 
 |             "handleActionValue(...):actionValue not found.\n"); | 
 | #endif | 
 |     if (!actionOffset) | 
 |       break; | 
 |  | 
 |     actionPos += actionOffset; | 
 |   } | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// Deals with the Language specific data portion of the emitted dwarf code. | 
 | /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink | 
 | /// @param version unsupported (ignored), unwind version | 
 | /// @param lsda language specific data area | 
 | /// @param _Unwind_Action actions minimally supported unwind stage | 
 | ///        (forced specifically not supported) | 
 | /// @param exceptionClass exception class (_Unwind_Exception::exception_class) | 
 | ///        of thrown exception. | 
 | /// @param exceptionObject thrown _Unwind_Exception instance. | 
 | /// @param context unwind system context | 
 | /// @returns minimally supported unwinding control indicator | 
 | static _Unwind_Reason_Code handleLsda(int version, const uint8_t *lsda, | 
 |                                       _Unwind_Action actions, | 
 |                                       _Unwind_Exception_Class exceptionClass, | 
 |                                       struct _Unwind_Exception *exceptionObject, | 
 |                                       struct _Unwind_Context *context) { | 
 |   _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND; | 
 |  | 
 |   if (!lsda) | 
 |     return(ret); | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "handleLsda(...):lsda is non-zero.\n"); | 
 | #endif | 
 |  | 
 |   // Get the current instruction pointer and offset it before next | 
 |   // instruction in the current frame which threw the exception. | 
 |   uintptr_t pc = _Unwind_GetIP(context)-1; | 
 |  | 
 |   // Get beginning current frame's code (as defined by the | 
 |   // emitted dwarf code) | 
 |   uintptr_t funcStart = _Unwind_GetRegionStart(context); | 
 |   uintptr_t pcOffset = pc - funcStart; | 
 |   const uint8_t *ClassInfo = NULL; | 
 |  | 
 |   // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding | 
 |   //       dwarf emission | 
 |  | 
 |   // Parse LSDA header. | 
 |   uint8_t lpStartEncoding = *lsda++; | 
 |  | 
 |   if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) { | 
 |     readEncodedPointer(&lsda, lpStartEncoding); | 
 |   } | 
 |  | 
 |   uint8_t ttypeEncoding = *lsda++; | 
 |   uintptr_t classInfoOffset; | 
 |  | 
 |   if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) { | 
 |     // Calculate type info locations in emitted dwarf code which | 
 |     // were flagged by type info arguments to llvm.eh.selector | 
 |     // intrinsic | 
 |     classInfoOffset = readULEB128(&lsda); | 
 |     ClassInfo = lsda + classInfoOffset; | 
 |   } | 
 |  | 
 |   // Walk call-site table looking for range that | 
 |   // includes current PC. | 
 |  | 
 |   uint8_t         callSiteEncoding = *lsda++; | 
 |   uint32_t        callSiteTableLength = readULEB128(&lsda); | 
 |   const uint8_t   *callSiteTableStart = lsda; | 
 |   const uint8_t   *callSiteTableEnd = callSiteTableStart + | 
 |   callSiteTableLength; | 
 |   const uint8_t   *actionTableStart = callSiteTableEnd; | 
 |   const uint8_t   *callSitePtr = callSiteTableStart; | 
 |  | 
 |   while (callSitePtr < callSiteTableEnd) { | 
 |     uintptr_t start = readEncodedPointer(&callSitePtr, | 
 |                                          callSiteEncoding); | 
 |     uintptr_t length = readEncodedPointer(&callSitePtr, | 
 |                                           callSiteEncoding); | 
 |     uintptr_t landingPad = readEncodedPointer(&callSitePtr, | 
 |                                               callSiteEncoding); | 
 |  | 
 |     // Note: Action value | 
 |     uintptr_t actionEntry = readULEB128(&callSitePtr); | 
 |  | 
 |     if (exceptionClass != ourBaseExceptionClass) { | 
 |       // We have been notified of a foreign exception being thrown, | 
 |       // and we therefore need to execute cleanup landing pads | 
 |       actionEntry = 0; | 
 |     } | 
 |  | 
 |     if (landingPad == 0) { | 
 | #ifdef DEBUG | 
 |       fprintf(stderr, | 
 |               "handleLsda(...): No landing pad found.\n"); | 
 | #endif | 
 |  | 
 |       continue; // no landing pad for this entry | 
 |     } | 
 |  | 
 |     if (actionEntry) { | 
 |       actionEntry += ((uintptr_t) actionTableStart) - 1; | 
 |     } | 
 |     else { | 
 | #ifdef DEBUG | 
 |       fprintf(stderr, | 
 |               "handleLsda(...):No action table found.\n"); | 
 | #endif | 
 |     } | 
 |  | 
 |     bool exceptionMatched = false; | 
 |  | 
 |     if ((start <= pcOffset) && (pcOffset < (start + length))) { | 
 | #ifdef DEBUG | 
 |       fprintf(stderr, | 
 |               "handleLsda(...): Landing pad found.\n"); | 
 | #endif | 
 |       int64_t actionValue = 0; | 
 |  | 
 |       if (actionEntry) { | 
 |         exceptionMatched = handleActionValue(&actionValue, | 
 |                                              ttypeEncoding, | 
 |                                              ClassInfo, | 
 |                                              actionEntry, | 
 |                                              exceptionClass, | 
 |                                              exceptionObject); | 
 |       } | 
 |  | 
 |       if (!(actions & _UA_SEARCH_PHASE)) { | 
 | #ifdef DEBUG | 
 |         fprintf(stderr, | 
 |                 "handleLsda(...): installed landing pad " | 
 |                 "context.\n"); | 
 | #endif | 
 |  | 
 |         // Found landing pad for the PC. | 
 |         // Set Instruction Pointer to so we re-enter function | 
 |         // at landing pad. The landing pad is created by the | 
 |         // compiler to take two parameters in registers. | 
 |         _Unwind_SetGR(context, | 
 |                       __builtin_eh_return_data_regno(0), | 
 |                       (uintptr_t)exceptionObject); | 
 |  | 
 |         // Note: this virtual register directly corresponds | 
 |         //       to the return of the llvm.eh.selector intrinsic | 
 |         if (!actionEntry || !exceptionMatched) { | 
 |           // We indicate cleanup only | 
 |           _Unwind_SetGR(context, | 
 |                         __builtin_eh_return_data_regno(1), | 
 |                         0); | 
 |         } | 
 |         else { | 
 |           // Matched type info index of llvm.eh.selector intrinsic | 
 |           // passed here. | 
 |           _Unwind_SetGR(context, | 
 |                         __builtin_eh_return_data_regno(1), | 
 |                         actionValue); | 
 |         } | 
 |  | 
 |         // To execute landing pad set here | 
 |         _Unwind_SetIP(context, funcStart + landingPad); | 
 |         ret = _URC_INSTALL_CONTEXT; | 
 |       } | 
 |       else if (exceptionMatched) { | 
 | #ifdef DEBUG | 
 |         fprintf(stderr, | 
 |                 "handleLsda(...): setting handler found.\n"); | 
 | #endif | 
 |         ret = _URC_HANDLER_FOUND; | 
 |       } | 
 |       else { | 
 |         // Note: Only non-clean up handlers are marked as | 
 |         //       found. Otherwise the clean up handlers will be | 
 |         //       re-found and executed during the clean up | 
 |         //       phase. | 
 | #ifdef DEBUG | 
 |         fprintf(stderr, | 
 |                 "handleLsda(...): cleanup handler found.\n"); | 
 | #endif | 
 |       } | 
 |  | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// This is the personality function which is embedded (dwarf emitted), in the | 
 | /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp. | 
 | /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink | 
 | /// @param version unsupported (ignored), unwind version | 
 | /// @param _Unwind_Action actions minimally supported unwind stage | 
 | ///        (forced specifically not supported) | 
 | /// @param exceptionClass exception class (_Unwind_Exception::exception_class) | 
 | ///        of thrown exception. | 
 | /// @param exceptionObject thrown _Unwind_Exception instance. | 
 | /// @param context unwind system context | 
 | /// @returns minimally supported unwinding control indicator | 
 | _Unwind_Reason_Code ourPersonality(int version, _Unwind_Action actions, | 
 |                                    _Unwind_Exception_Class exceptionClass, | 
 |                                    struct _Unwind_Exception *exceptionObject, | 
 |                                    struct _Unwind_Context *context) { | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "We are in ourPersonality(...):actions is <%d>.\n", | 
 |           actions); | 
 |  | 
 |   if (actions & _UA_SEARCH_PHASE) { | 
 |     fprintf(stderr, "ourPersonality(...):In search phase.\n"); | 
 |   } | 
 |   else { | 
 |     fprintf(stderr, "ourPersonality(...):In non-search phase.\n"); | 
 |   } | 
 | #endif | 
 |  | 
 |   const uint8_t *lsda = _Unwind_GetLanguageSpecificData(context); | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "ourPersonality(...):lsda = <%p>.\n", | 
 |           (void*)lsda); | 
 | #endif | 
 |  | 
 |   // The real work of the personality function is captured here | 
 |   return(handleLsda(version, | 
 |                     lsda, | 
 |                     actions, | 
 |                     exceptionClass, | 
 |                     exceptionObject, | 
 |                     context)); | 
 | } | 
 |  | 
 |  | 
 | /// Generates our _Unwind_Exception class from a given character array. | 
 | /// thereby handling arbitrary lengths (not in standard), and handling | 
 | /// embedded \0s. | 
 | /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink | 
 | /// @param classChars char array to encode. NULL values not checkedf | 
 | /// @param classCharsSize number of chars in classChars. Value is not checked. | 
 | /// @returns class value | 
 | uint64_t genClass(const unsigned char classChars[], size_t classCharsSize) | 
 | { | 
 |   uint64_t ret = classChars[0]; | 
 |  | 
 |   for (unsigned i = 1; i < classCharsSize; ++i) { | 
 |     ret <<= 8; | 
 |     ret += classChars[i]; | 
 |   } | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 | } // extern "C" | 
 |  | 
 | // | 
 | // Runtime C Library functions End | 
 | // | 
 |  | 
 | // | 
 | // Code generation functions | 
 | // | 
 |  | 
 | /// Generates code to print given constant string | 
 | /// @param context llvm context | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param toPrint string to print | 
 | /// @param useGlobal A value of true (default) indicates a GlobalValue is | 
 | ///        generated, and is used to hold the constant string. A value of | 
 | ///        false indicates that the constant string will be stored on the | 
 | ///        stack. | 
 | void generateStringPrint(llvm::LLVMContext &context, | 
 |                          llvm::Module &module, | 
 |                          llvm::IRBuilder<> &builder, | 
 |                          std::string toPrint, | 
 |                          bool useGlobal = true) { | 
 |   llvm::Function *printFunct = module.getFunction("printStr"); | 
 |  | 
 |   llvm::Value *stringVar; | 
 |   llvm::Constant *stringConstant = | 
 |   llvm::ConstantDataArray::getString(context, toPrint); | 
 |  | 
 |   if (useGlobal) { | 
 |     // Note: Does not work without allocation | 
 |     stringVar = | 
 |     new llvm::GlobalVariable(module, | 
 |                              stringConstant->getType(), | 
 |                              true, | 
 |                              llvm::GlobalValue::PrivateLinkage, | 
 |                              stringConstant, | 
 |                              ""); | 
 |   } | 
 |   else { | 
 |     stringVar = builder.CreateAlloca(stringConstant->getType()); | 
 |     builder.CreateStore(stringConstant, stringVar); | 
 |   } | 
 |  | 
 |   llvm::Value *cast = builder.CreatePointerCast(stringVar, | 
 |                                                 builder.getInt8PtrTy()); | 
 |   builder.CreateCall(printFunct, cast); | 
 | } | 
 |  | 
 |  | 
 | /// Generates code to print given runtime integer according to constant | 
 | /// string format, and a given print function. | 
 | /// @param context llvm context | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param printFunct function used to "print" integer | 
 | /// @param toPrint string to print | 
 | /// @param format printf like formating string for print | 
 | /// @param useGlobal A value of true (default) indicates a GlobalValue is | 
 | ///        generated, and is used to hold the constant string. A value of | 
 | ///        false indicates that the constant string will be stored on the | 
 | ///        stack. | 
 | void generateIntegerPrint(llvm::LLVMContext &context, | 
 |                           llvm::Module &module, | 
 |                           llvm::IRBuilder<> &builder, | 
 |                           llvm::Function &printFunct, | 
 |                           llvm::Value &toPrint, | 
 |                           std::string format, | 
 |                           bool useGlobal = true) { | 
 |   llvm::Constant *stringConstant = | 
 |     llvm::ConstantDataArray::getString(context, format); | 
 |   llvm::Value *stringVar; | 
 |  | 
 |   if (useGlobal) { | 
 |     // Note: Does not seem to work without allocation | 
 |     stringVar = | 
 |     new llvm::GlobalVariable(module, | 
 |                              stringConstant->getType(), | 
 |                              true, | 
 |                              llvm::GlobalValue::PrivateLinkage, | 
 |                              stringConstant, | 
 |                              ""); | 
 |   } | 
 |   else { | 
 |     stringVar = builder.CreateAlloca(stringConstant->getType()); | 
 |     builder.CreateStore(stringConstant, stringVar); | 
 |   } | 
 |  | 
 |   llvm::Value *cast = builder.CreateBitCast(stringVar, | 
 |                                             builder.getInt8PtrTy()); | 
 |   builder.CreateCall(&printFunct, {&toPrint, cast}); | 
 | } | 
 |  | 
 |  | 
 | /// Generates code to handle finally block type semantics: always runs | 
 | /// regardless of whether a thrown exception is passing through or the | 
 | /// parent function is simply exiting. In addition to printing some state | 
 | /// to stderr, this code will resume the exception handling--runs the | 
 | /// unwind resume block, if the exception has not been previously caught | 
 | /// by a catch clause, and will otherwise execute the end block (terminator | 
 | /// block). In addition this function creates the corresponding function's | 
 | /// stack storage for the exception pointer and catch flag status. | 
 | /// @param context llvm context | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param toAddTo parent function to add block to | 
 | /// @param blockName block name of new "finally" block. | 
 | /// @param functionId output id used for printing | 
 | /// @param terminatorBlock terminator "end" block | 
 | /// @param unwindResumeBlock unwind resume block | 
 | /// @param exceptionCaughtFlag reference exception caught/thrown status storage | 
 | /// @param exceptionStorage reference to exception pointer storage | 
 | /// @param caughtResultStorage reference to landingpad result storage | 
 | /// @returns newly created block | 
 | static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context, | 
 |                                             llvm::Module &module, | 
 |                                             llvm::IRBuilder<> &builder, | 
 |                                             llvm::Function &toAddTo, | 
 |                                             std::string &blockName, | 
 |                                             std::string &functionId, | 
 |                                             llvm::BasicBlock &terminatorBlock, | 
 |                                             llvm::BasicBlock &unwindResumeBlock, | 
 |                                             llvm::Value **exceptionCaughtFlag, | 
 |                                             llvm::Value **exceptionStorage, | 
 |                                             llvm::Value **caughtResultStorage) { | 
 |   assert(exceptionCaughtFlag && | 
 |          "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag " | 
 |          "is NULL"); | 
 |   assert(exceptionStorage && | 
 |          "ExceptionDemo::createFinallyBlock(...):exceptionStorage " | 
 |          "is NULL"); | 
 |   assert(caughtResultStorage && | 
 |          "ExceptionDemo::createFinallyBlock(...):caughtResultStorage " | 
 |          "is NULL"); | 
 |  | 
 |   *exceptionCaughtFlag = createEntryBlockAlloca(toAddTo, | 
 |                                          "exceptionCaught", | 
 |                                          ourExceptionNotThrownState->getType(), | 
 |                                          ourExceptionNotThrownState); | 
 |  | 
 |   llvm::PointerType *exceptionStorageType = builder.getInt8PtrTy(); | 
 |   *exceptionStorage = createEntryBlockAlloca(toAddTo, | 
 |                                              "exceptionStorage", | 
 |                                              exceptionStorageType, | 
 |                                              llvm::ConstantPointerNull::get( | 
 |                                                exceptionStorageType)); | 
 |   *caughtResultStorage = createEntryBlockAlloca(toAddTo, | 
 |                                               "caughtResultStorage", | 
 |                                               ourCaughtResultType, | 
 |                                               llvm::ConstantAggregateZero::get( | 
 |                                                 ourCaughtResultType)); | 
 |  | 
 |   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context, | 
 |                                                    blockName, | 
 |                                                    &toAddTo); | 
 |  | 
 |   builder.SetInsertPoint(ret); | 
 |  | 
 |   std::ostringstream bufferToPrint; | 
 |   bufferToPrint << "Gen: Executing finally block " | 
 |     << blockName << " in " << functionId << "\n"; | 
 |   generateStringPrint(context, | 
 |                       module, | 
 |                       builder, | 
 |                       bufferToPrint.str(), | 
 |                       USE_GLOBAL_STR_CONSTS); | 
 |  | 
 |   llvm::SwitchInst *theSwitch = builder.CreateSwitch(builder.CreateLoad( | 
 |                                                        *exceptionCaughtFlag), | 
 |                                                      &terminatorBlock, | 
 |                                                      2); | 
 |   theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock); | 
 |   theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock); | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// Generates catch block semantics which print a string to indicate type of | 
 | /// catch executed, sets an exception caught flag, and executes passed in | 
 | /// end block (terminator block). | 
 | /// @param context llvm context | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param toAddTo parent function to add block to | 
 | /// @param blockName block name of new "catch" block. | 
 | /// @param functionId output id used for printing | 
 | /// @param terminatorBlock terminator "end" block | 
 | /// @param exceptionCaughtFlag exception caught/thrown status | 
 | /// @returns newly created block | 
 | static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context, | 
 |                                           llvm::Module &module, | 
 |                                           llvm::IRBuilder<> &builder, | 
 |                                           llvm::Function &toAddTo, | 
 |                                           std::string &blockName, | 
 |                                           std::string &functionId, | 
 |                                           llvm::BasicBlock &terminatorBlock, | 
 |                                           llvm::Value &exceptionCaughtFlag) { | 
 |  | 
 |   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context, | 
 |                                                    blockName, | 
 |                                                    &toAddTo); | 
 |  | 
 |   builder.SetInsertPoint(ret); | 
 |  | 
 |   std::ostringstream bufferToPrint; | 
 |   bufferToPrint << "Gen: Executing catch block " | 
 |   << blockName | 
 |   << " in " | 
 |   << functionId | 
 |   << std::endl; | 
 |   generateStringPrint(context, | 
 |                       module, | 
 |                       builder, | 
 |                       bufferToPrint.str(), | 
 |                       USE_GLOBAL_STR_CONSTS); | 
 |   builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag); | 
 |   builder.CreateBr(&terminatorBlock); | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// Generates a function which invokes a function (toInvoke) and, whose | 
 | /// unwind block will "catch" the type info types correspondingly held in the | 
 | /// exceptionTypesToCatch argument. If the toInvoke function throws an | 
 | /// exception which does not match any type info types contained in | 
 | /// exceptionTypesToCatch, the generated code will call _Unwind_Resume | 
 | /// with the raised exception. On the other hand the generated code will | 
 | /// normally exit if the toInvoke function does not throw an exception. | 
 | /// The generated "finally" block is always run regardless of the cause of | 
 | /// the generated function exit. | 
 | /// The generated function is returned after being verified. | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param fpm a function pass manager holding optional IR to IR | 
 | ///        transformations | 
 | /// @param toInvoke inner function to invoke | 
 | /// @param ourId id used to printing purposes | 
 | /// @param numExceptionsToCatch length of exceptionTypesToCatch array | 
 | /// @param exceptionTypesToCatch array of type info types to "catch" | 
 | /// @returns generated function | 
 | static llvm::Function *createCatchWrappedInvokeFunction( | 
 |     llvm::Module &module, llvm::IRBuilder<> &builder, | 
 |     llvm::legacy::FunctionPassManager &fpm, llvm::Function &toInvoke, | 
 |     std::string ourId, unsigned numExceptionsToCatch, | 
 |     unsigned exceptionTypesToCatch[]) { | 
 |  | 
 |   llvm::LLVMContext &context = module.getContext(); | 
 |   llvm::Function *toPrint32Int = module.getFunction("print32Int"); | 
 |  | 
 |   ArgTypes argTypes; | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |  | 
 |   ArgNames argNames; | 
 |   argNames.push_back("exceptTypeToThrow"); | 
 |  | 
 |   llvm::Function *ret = createFunction(module, | 
 |                                        builder.getVoidTy(), | 
 |                                        argTypes, | 
 |                                        argNames, | 
 |                                        ourId, | 
 |                                        llvm::Function::ExternalLinkage, | 
 |                                        false, | 
 |                                        false); | 
 |  | 
 |   // Block which calls invoke | 
 |   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, | 
 |                                                           "entry", | 
 |                                                           ret); | 
 |   // Normal block for invoke | 
 |   llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context, | 
 |                                                            "normal", | 
 |                                                            ret); | 
 |   // Unwind block for invoke | 
 |   llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context, | 
 |                                                               "exception", | 
 |                                                               ret); | 
 |  | 
 |   // Block which routes exception to correct catch handler block | 
 |   llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context, | 
 |                                                              "exceptionRoute", | 
 |                                                              ret); | 
 |  | 
 |   // Foreign exception handler | 
 |   llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context, | 
 |                                                           "externalException", | 
 |                                                           ret); | 
 |  | 
 |   // Block which calls _Unwind_Resume | 
 |   llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context, | 
 |                                                                "unwindResume", | 
 |                                                                ret); | 
 |  | 
 |   // Clean up block which delete exception if needed | 
 |   llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret); | 
 |  | 
 |   std::string nextName; | 
 |   std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch); | 
 |   llvm::Value *exceptionCaughtFlag = NULL; | 
 |   llvm::Value *exceptionStorage = NULL; | 
 |   llvm::Value *caughtResultStorage = NULL; | 
 |  | 
 |   // Finally block which will branch to unwindResumeBlock if | 
 |   // exception is not caught. Initializes/allocates stack locations. | 
 |   llvm::BasicBlock *finallyBlock = createFinallyBlock(context, | 
 |                                                       module, | 
 |                                                       builder, | 
 |                                                       *ret, | 
 |                                                       nextName = "finally", | 
 |                                                       ourId, | 
 |                                                       *endBlock, | 
 |                                                       *unwindResumeBlock, | 
 |                                                       &exceptionCaughtFlag, | 
 |                                                       &exceptionStorage, | 
 |                                                       &caughtResultStorage | 
 |                                                       ); | 
 |  | 
 |   for (unsigned i = 0; i < numExceptionsToCatch; ++i) { | 
 |     nextName = ourTypeInfoNames[exceptionTypesToCatch[i]]; | 
 |  | 
 |     // One catch block per type info to be caught | 
 |     catchBlocks[i] = createCatchBlock(context, | 
 |                                       module, | 
 |                                       builder, | 
 |                                       *ret, | 
 |                                       nextName, | 
 |                                       ourId, | 
 |                                       *finallyBlock, | 
 |                                       *exceptionCaughtFlag); | 
 |   } | 
 |  | 
 |   // Entry Block | 
 |  | 
 |   builder.SetInsertPoint(entryBlock); | 
 |  | 
 |   std::vector<llvm::Value*> args; | 
 |   args.push_back(namedValues["exceptTypeToThrow"]); | 
 |   builder.CreateInvoke(&toInvoke, | 
 |                        normalBlock, | 
 |                        exceptionBlock, | 
 |                        args); | 
 |  | 
 |   // End Block | 
 |  | 
 |   builder.SetInsertPoint(endBlock); | 
 |  | 
 |   generateStringPrint(context, | 
 |                       module, | 
 |                       builder, | 
 |                       "Gen: In end block: exiting in " + ourId + ".\n", | 
 |                       USE_GLOBAL_STR_CONSTS); | 
 |   llvm::Function *deleteOurException = module.getFunction("deleteOurException"); | 
 |  | 
 |   // Note: function handles NULL exceptions | 
 |   builder.CreateCall(deleteOurException, | 
 |                      builder.CreateLoad(exceptionStorage)); | 
 |   builder.CreateRetVoid(); | 
 |  | 
 |   // Normal Block | 
 |  | 
 |   builder.SetInsertPoint(normalBlock); | 
 |  | 
 |   generateStringPrint(context, | 
 |                       module, | 
 |                       builder, | 
 |                       "Gen: No exception in " + ourId + "!\n", | 
 |                       USE_GLOBAL_STR_CONSTS); | 
 |  | 
 |   // Finally block is always called | 
 |   builder.CreateBr(finallyBlock); | 
 |  | 
 |   // Unwind Resume Block | 
 |  | 
 |   builder.SetInsertPoint(unwindResumeBlock); | 
 |  | 
 |   builder.CreateResume(builder.CreateLoad(caughtResultStorage)); | 
 |  | 
 |   // Exception Block | 
 |  | 
 |   builder.SetInsertPoint(exceptionBlock); | 
 |  | 
 |   llvm::Function *personality = module.getFunction("ourPersonality"); | 
 |   ret->setPersonalityFn(personality); | 
 |  | 
 |   llvm::LandingPadInst *caughtResult = | 
 |     builder.CreateLandingPad(ourCaughtResultType, | 
 |                              numExceptionsToCatch, | 
 |                              "landingPad"); | 
 |  | 
 |   caughtResult->setCleanup(true); | 
 |  | 
 |   for (unsigned i = 0; i < numExceptionsToCatch; ++i) { | 
 |     // Set up type infos to be caught | 
 |     caughtResult->addClause(module.getGlobalVariable( | 
 |                              ourTypeInfoNames[exceptionTypesToCatch[i]])); | 
 |   } | 
 |  | 
 |   llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0); | 
 |   llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1); | 
 |  | 
 |   // FIXME: Redundant storage which, beyond utilizing value of | 
 |   //        caughtResultStore for unwindException storage, may be alleviated | 
 |   //        altogether with a block rearrangement | 
 |   builder.CreateStore(caughtResult, caughtResultStorage); | 
 |   builder.CreateStore(unwindException, exceptionStorage); | 
 |   builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag); | 
 |  | 
 |   // Retrieve exception_class member from thrown exception | 
 |   // (_Unwind_Exception instance). This member tells us whether or not | 
 |   // the exception is foreign. | 
 |   llvm::Value *unwindExceptionClass = | 
 |       builder.CreateLoad(builder.CreateStructGEP( | 
 |           ourUnwindExceptionType, | 
 |           builder.CreatePointerCast(unwindException, | 
 |                                     ourUnwindExceptionType->getPointerTo()), | 
 |           0)); | 
 |  | 
 |   // Branch to the externalExceptionBlock if the exception is foreign or | 
 |   // to a catch router if not. Either way the finally block will be run. | 
 |   builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass, | 
 |                             llvm::ConstantInt::get(builder.getInt64Ty(), | 
 |                                                    ourBaseExceptionClass)), | 
 |                        exceptionRouteBlock, | 
 |                        externalExceptionBlock); | 
 |  | 
 |   // External Exception Block | 
 |  | 
 |   builder.SetInsertPoint(externalExceptionBlock); | 
 |  | 
 |   generateStringPrint(context, | 
 |                       module, | 
 |                       builder, | 
 |                       "Gen: Foreign exception received.\n", | 
 |                       USE_GLOBAL_STR_CONSTS); | 
 |  | 
 |   // Branch to the finally block | 
 |   builder.CreateBr(finallyBlock); | 
 |  | 
 |   // Exception Route Block | 
 |  | 
 |   builder.SetInsertPoint(exceptionRouteBlock); | 
 |  | 
 |   // Casts exception pointer (_Unwind_Exception instance) to parent | 
 |   // (OurException instance). | 
 |   // | 
 |   // Note: ourBaseFromUnwindOffset is usually negative | 
 |   llvm::Value *typeInfoThrown = builder.CreatePointerCast( | 
 |                                   builder.CreateConstGEP1_64(unwindException, | 
 |                                                        ourBaseFromUnwindOffset), | 
 |                                   ourExceptionType->getPointerTo()); | 
 |  | 
 |   // Retrieve thrown exception type info type | 
 |   // | 
 |   // Note: Index is not relative to pointer but instead to structure | 
 |   //       unlike a true getelementptr (GEP) instruction | 
 |   typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0); | 
 |  | 
 |   llvm::Value *typeInfoThrownType = | 
 |       builder.CreateStructGEP(builder.getInt8PtrTy(), typeInfoThrown, 0); | 
 |  | 
 |   generateIntegerPrint(context, | 
 |                        module, | 
 |                        builder, | 
 |                        *toPrint32Int, | 
 |                        *(builder.CreateLoad(typeInfoThrownType)), | 
 |                        "Gen: Exception type <%d> received (stack unwound) " | 
 |                        " in " + | 
 |                        ourId + | 
 |                        ".\n", | 
 |                        USE_GLOBAL_STR_CONSTS); | 
 |  | 
 |   // Route to matched type info catch block or run cleanup finally block | 
 |   llvm::SwitchInst *switchToCatchBlock = builder.CreateSwitch(retTypeInfoIndex, | 
 |                                                           finallyBlock, | 
 |                                                           numExceptionsToCatch); | 
 |  | 
 |   unsigned nextTypeToCatch; | 
 |  | 
 |   for (unsigned i = 1; i <= numExceptionsToCatch; ++i) { | 
 |     nextTypeToCatch = i - 1; | 
 |     switchToCatchBlock->addCase(llvm::ConstantInt::get( | 
 |                                    llvm::Type::getInt32Ty(context), i), | 
 |                                 catchBlocks[nextTypeToCatch]); | 
 |   } | 
 |  | 
 |   llvm::verifyFunction(*ret); | 
 |   fpm.run(*ret); | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 |  | 
 | /// Generates function which throws either an exception matched to a runtime | 
 | /// determined type info type (argument to generated function), or if this | 
 | /// runtime value matches nativeThrowType, throws a foreign exception by | 
 | /// calling nativeThrowFunct. | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param fpm a function pass manager holding optional IR to IR | 
 | ///        transformations | 
 | /// @param ourId id used to printing purposes | 
 | /// @param nativeThrowType a runtime argument of this value results in | 
 | ///        nativeThrowFunct being called to generate/throw exception. | 
 | /// @param nativeThrowFunct function which will throw a foreign exception | 
 | ///        if the above nativeThrowType matches generated function's arg. | 
 | /// @returns generated function | 
 | static llvm::Function * | 
 | createThrowExceptionFunction(llvm::Module &module, llvm::IRBuilder<> &builder, | 
 |                              llvm::legacy::FunctionPassManager &fpm, | 
 |                              std::string ourId, int32_t nativeThrowType, | 
 |                              llvm::Function &nativeThrowFunct) { | 
 |   llvm::LLVMContext &context = module.getContext(); | 
 |   namedValues.clear(); | 
 |   ArgTypes unwindArgTypes; | 
 |   unwindArgTypes.push_back(builder.getInt32Ty()); | 
 |   ArgNames unwindArgNames; | 
 |   unwindArgNames.push_back("exceptTypeToThrow"); | 
 |  | 
 |   llvm::Function *ret = createFunction(module, | 
 |                                        builder.getVoidTy(), | 
 |                                        unwindArgTypes, | 
 |                                        unwindArgNames, | 
 |                                        ourId, | 
 |                                        llvm::Function::ExternalLinkage, | 
 |                                        false, | 
 |                                        false); | 
 |  | 
 |   // Throws either one of our exception or a native C++ exception depending | 
 |   // on a runtime argument value containing a type info type. | 
 |   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, | 
 |                                                           "entry", | 
 |                                                           ret); | 
 |   // Throws a foreign exception | 
 |   llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context, | 
 |                                                                 "nativeThrow", | 
 |                                                                 ret); | 
 |   // Throws one of our Exceptions | 
 |   llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context, | 
 |                                                              "generatedThrow", | 
 |                                                              ret); | 
 |   // Retrieved runtime type info type to throw | 
 |   llvm::Value *exceptionType = namedValues["exceptTypeToThrow"]; | 
 |  | 
 |   // nativeThrowBlock block | 
 |  | 
 |   builder.SetInsertPoint(nativeThrowBlock); | 
 |  | 
 |   // Throws foreign exception | 
 |   builder.CreateCall(&nativeThrowFunct, exceptionType); | 
 |   builder.CreateUnreachable(); | 
 |  | 
 |   // entry block | 
 |  | 
 |   builder.SetInsertPoint(entryBlock); | 
 |  | 
 |   llvm::Function *toPrint32Int = module.getFunction("print32Int"); | 
 |   generateIntegerPrint(context, | 
 |                        module, | 
 |                        builder, | 
 |                        *toPrint32Int, | 
 |                        *exceptionType, | 
 |                        "\nGen: About to throw exception type <%d> in " + | 
 |                        ourId + | 
 |                        ".\n", | 
 |                        USE_GLOBAL_STR_CONSTS); | 
 |  | 
 |   // Switches on runtime type info type value to determine whether or not | 
 |   // a foreign exception is thrown. Defaults to throwing one of our | 
 |   // generated exceptions. | 
 |   llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType, | 
 |                                                      generatedThrowBlock, | 
 |                                                      1); | 
 |  | 
 |   theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), | 
 |                                             nativeThrowType), | 
 |                      nativeThrowBlock); | 
 |  | 
 |   // generatedThrow block | 
 |  | 
 |   builder.SetInsertPoint(generatedThrowBlock); | 
 |  | 
 |   llvm::Function *createOurException = module.getFunction("createOurException"); | 
 |   llvm::Function *raiseOurException = module.getFunction( | 
 |                                         "_Unwind_RaiseException"); | 
 |  | 
 |   // Creates exception to throw with runtime type info type. | 
 |   llvm::Value *exception = builder.CreateCall(createOurException, | 
 |                                               namedValues["exceptTypeToThrow"]); | 
 |  | 
 |   // Throw generated Exception | 
 |   builder.CreateCall(raiseOurException, exception); | 
 |   builder.CreateUnreachable(); | 
 |  | 
 |   llvm::verifyFunction(*ret); | 
 |   fpm.run(*ret); | 
 |  | 
 |   return(ret); | 
 | } | 
 |  | 
 | static void createStandardUtilityFunctions(unsigned numTypeInfos, | 
 |                                            llvm::Module &module, | 
 |                                            llvm::IRBuilder<> &builder); | 
 |  | 
 | /// Creates test code by generating and organizing these functions into the | 
 | /// test case. The test case consists of an outer function setup to invoke | 
 | /// an inner function within an environment having multiple catch and single | 
 | /// finally blocks. This inner function is also setup to invoke a throw | 
 | /// function within an evironment similar in nature to the outer function's | 
 | /// catch and finally blocks. Each of these two functions catch mutually | 
 | /// exclusive subsets (even or odd) of the type info types configured | 
 | /// for this this. All generated functions have a runtime argument which | 
 | /// holds a type info type to throw that each function takes and passes it | 
 | /// to the inner one if such a inner function exists. This type info type is | 
 | /// looked at by the generated throw function to see whether or not it should | 
 | /// throw a generated exception with the same type info type, or instead call | 
 | /// a supplied a function which in turn will throw a foreign exception. | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | /// @param fpm a function pass manager holding optional IR to IR | 
 | ///        transformations | 
 | /// @param nativeThrowFunctName name of external function which will throw | 
 | ///        a foreign exception | 
 | /// @returns outermost generated test function. | 
 | llvm::Function * | 
 | createUnwindExceptionTest(llvm::Module &module, llvm::IRBuilder<> &builder, | 
 |                           llvm::legacy::FunctionPassManager &fpm, | 
 |                           std::string nativeThrowFunctName) { | 
 |   // Number of type infos to generate | 
 |   unsigned numTypeInfos = 6; | 
 |  | 
 |   // Initialze intrisics and external functions to use along with exception | 
 |   // and type info globals. | 
 |   createStandardUtilityFunctions(numTypeInfos, | 
 |                                  module, | 
 |                                  builder); | 
 |   llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName); | 
 |  | 
 |   // Create exception throw function using the value ~0 to cause | 
 |   // foreign exceptions to be thrown. | 
 |   llvm::Function *throwFunct = createThrowExceptionFunction(module, | 
 |                                                             builder, | 
 |                                                             fpm, | 
 |                                                             "throwFunct", | 
 |                                                             ~0, | 
 |                                                             *nativeThrowFunct); | 
 |   // Inner function will catch even type infos | 
 |   unsigned innerExceptionTypesToCatch[] = {6, 2, 4}; | 
 |   size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) / | 
 |                                     sizeof(unsigned); | 
 |  | 
 |   // Generate inner function. | 
 |   llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module, | 
 |                                                     builder, | 
 |                                                     fpm, | 
 |                                                     *throwFunct, | 
 |                                                     "innerCatchFunct", | 
 |                                                     numExceptionTypesToCatch, | 
 |                                                     innerExceptionTypesToCatch); | 
 |  | 
 |   // Outer function will catch odd type infos | 
 |   unsigned outerExceptionTypesToCatch[] = {3, 1, 5}; | 
 |   numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) / | 
 |   sizeof(unsigned); | 
 |  | 
 |   // Generate outer function | 
 |   llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module, | 
 |                                                     builder, | 
 |                                                     fpm, | 
 |                                                     *innerCatchFunct, | 
 |                                                     "outerCatchFunct", | 
 |                                                     numExceptionTypesToCatch, | 
 |                                                     outerExceptionTypesToCatch); | 
 |  | 
 |   // Return outer function to run | 
 |   return(outerCatchFunct); | 
 | } | 
 |  | 
 | namespace { | 
 | /// Represents our foreign exceptions | 
 | class OurCppRunException : public std::runtime_error { | 
 | public: | 
 |   OurCppRunException(const std::string reason) : | 
 |   std::runtime_error(reason) {} | 
 |  | 
 |   OurCppRunException (const OurCppRunException &toCopy) : | 
 |   std::runtime_error(toCopy) {} | 
 |  | 
 |   OurCppRunException &operator = (const OurCppRunException &toCopy) { | 
 |     return(reinterpret_cast<OurCppRunException&>( | 
 |                                  std::runtime_error::operator=(toCopy))); | 
 |   } | 
 |  | 
 |   ~OurCppRunException(void) throw() override {} | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 | /// Throws foreign C++ exception. | 
 | /// @param ignoreIt unused parameter that allows function to match implied | 
 | ///        generated function contract. | 
 | extern "C" | 
 | void throwCppException (int32_t ignoreIt) { | 
 |   throw(OurCppRunException("thrown by throwCppException(...)")); | 
 | } | 
 |  | 
 | typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow); | 
 |  | 
 | /// This is a test harness which runs test by executing generated | 
 | /// function with a type info type to throw. Harness wraps the execution | 
 | /// of generated function in a C++ try catch clause. | 
 | /// @param engine execution engine to use for executing generated function. | 
 | ///        This demo program expects this to be a JIT instance for demo | 
 | ///        purposes. | 
 | /// @param function generated test function to run | 
 | /// @param typeToThrow type info type of generated exception to throw, or | 
 | ///        indicator to cause foreign exception to be thrown. | 
 | static | 
 | void runExceptionThrow(llvm::ExecutionEngine *engine, | 
 |                        llvm::Function *function, | 
 |                        int32_t typeToThrow) { | 
 |  | 
 |   // Find test's function pointer | 
 |   OurExceptionThrowFunctType functPtr = | 
 |     reinterpret_cast<OurExceptionThrowFunctType>( | 
 |        reinterpret_cast<intptr_t>(engine->getPointerToFunction(function))); | 
 |  | 
 |   try { | 
 |     // Run test | 
 |     (*functPtr)(typeToThrow); | 
 |   } | 
 |   catch (OurCppRunException exc) { | 
 |     // Catch foreign C++ exception | 
 |     fprintf(stderr, | 
 |             "\nrunExceptionThrow(...):In C++ catch OurCppRunException " | 
 |             "with reason: %s.\n", | 
 |             exc.what()); | 
 |   } | 
 |   catch (...) { | 
 |     // Catch all exceptions including our generated ones. This latter | 
 |     // functionality works according to the example in rules 1.6.4 of | 
 |     // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22), | 
 |     // given that these will be exceptions foreign to C++ | 
 |     // (the _Unwind_Exception::exception_class should be different from | 
 |     // the one used by C++). | 
 |     fprintf(stderr, | 
 |             "\nrunExceptionThrow(...):In C++ catch all.\n"); | 
 |   } | 
 | } | 
 |  | 
 | // | 
 | // End test functions | 
 | // | 
 |  | 
 | typedef llvm::ArrayRef<llvm::Type*> TypeArray; | 
 |  | 
 | /// This initialization routine creates type info globals and | 
 | /// adds external function declarations to module. | 
 | /// @param numTypeInfos number of linear type info associated type info types | 
 | ///        to create as GlobalVariable instances, starting with the value 1. | 
 | /// @param module code for module instance | 
 | /// @param builder builder instance | 
 | static void createStandardUtilityFunctions(unsigned numTypeInfos, | 
 |                                            llvm::Module &module, | 
 |                                            llvm::IRBuilder<> &builder) { | 
 |  | 
 |   llvm::LLVMContext &context = module.getContext(); | 
 |  | 
 |   // Exception initializations | 
 |  | 
 |   // Setup exception catch state | 
 |   ourExceptionNotThrownState = | 
 |     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), | 
 |   ourExceptionThrownState = | 
 |     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), | 
 |   ourExceptionCaughtState = | 
 |     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), | 
 |  | 
 |  | 
 |  | 
 |   // Create our type info type | 
 |   ourTypeInfoType = llvm::StructType::get(context, | 
 |                                           TypeArray(builder.getInt32Ty())); | 
 |  | 
 |   llvm::Type *caughtResultFieldTypes[] = { | 
 |     builder.getInt8PtrTy(), | 
 |     builder.getInt32Ty() | 
 |   }; | 
 |  | 
 |   // Create our landingpad result type | 
 |   ourCaughtResultType = llvm::StructType::get(context, | 
 |                                             TypeArray(caughtResultFieldTypes)); | 
 |  | 
 |   // Create OurException type | 
 |   ourExceptionType = llvm::StructType::get(context, | 
 |                                            TypeArray(ourTypeInfoType)); | 
 |  | 
 |   // Create portion of _Unwind_Exception type | 
 |   // | 
 |   // Note: Declaring only a portion of the _Unwind_Exception struct. | 
 |   //       Does this cause problems? | 
 |   ourUnwindExceptionType = | 
 |     llvm::StructType::get(context, | 
 |                     TypeArray(builder.getInt64Ty())); | 
 |  | 
 |   struct OurBaseException_t dummyException; | 
 |  | 
 |   // Calculate offset of OurException::unwindException member. | 
 |   ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) - | 
 |                             ((uintptr_t) &(dummyException.unwindException)); | 
 |  | 
 | #ifdef DEBUG | 
 |   fprintf(stderr, | 
 |           "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset " | 
 |           "= %" PRIi64 ", sizeof(struct OurBaseException_t) - " | 
 |           "sizeof(struct _Unwind_Exception) = %lu.\n", | 
 |           ourBaseFromUnwindOffset, | 
 |           sizeof(struct OurBaseException_t) - | 
 |           sizeof(struct _Unwind_Exception)); | 
 | #endif | 
 |  | 
 |   size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char); | 
 |  | 
 |   // Create our _Unwind_Exception::exception_class value | 
 |   ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars); | 
 |  | 
 |   // Type infos | 
 |  | 
 |   std::string baseStr = "typeInfo", typeInfoName; | 
 |   std::ostringstream typeInfoNameBuilder; | 
 |   std::vector<llvm::Constant*> structVals; | 
 |  | 
 |   llvm::Constant *nextStruct; | 
 |  | 
 |   // Generate each type info | 
 |   // | 
 |   // Note: First type info is not used. | 
 |   for (unsigned i = 0; i <= numTypeInfos; ++i) { | 
 |     structVals.clear(); | 
 |     structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i)); | 
 |     nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals); | 
 |  | 
 |     typeInfoNameBuilder.str(""); | 
 |     typeInfoNameBuilder << baseStr << i; | 
 |     typeInfoName = typeInfoNameBuilder.str(); | 
 |  | 
 |     // Note: Does not seem to work without allocation | 
 |     new llvm::GlobalVariable(module, | 
 |                              ourTypeInfoType, | 
 |                              true, | 
 |                              llvm::GlobalValue::ExternalLinkage, | 
 |                              nextStruct, | 
 |                              typeInfoName); | 
 |  | 
 |     ourTypeInfoNames.push_back(typeInfoName); | 
 |     ourTypeInfoNamesIndex[i] = typeInfoName; | 
 |   } | 
 |  | 
 |   ArgNames argNames; | 
 |   ArgTypes argTypes; | 
 |   llvm::Function *funct = NULL; | 
 |  | 
 |   // print32Int | 
 |  | 
 |   llvm::Type *retType = builder.getVoidTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "print32Int", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // print64Int | 
 |  | 
 |   retType = builder.getVoidTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt64Ty()); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "print64Int", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // printStr | 
 |  | 
 |   retType = builder.getVoidTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "printStr", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // throwCppException | 
 |  | 
 |   retType = builder.getVoidTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "throwCppException", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // deleteOurException | 
 |  | 
 |   retType = builder.getVoidTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "deleteOurException", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // createOurException | 
 |  | 
 |   retType = builder.getInt8PtrTy(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "createOurException", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // _Unwind_RaiseException | 
 |  | 
 |   retType = builder.getInt32Ty(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   funct = createFunction(module, | 
 |                          retType, | 
 |                          argTypes, | 
 |                          argNames, | 
 |                          "_Unwind_RaiseException", | 
 |                          llvm::Function::ExternalLinkage, | 
 |                          true, | 
 |                          false); | 
 |  | 
 |   funct->setDoesNotReturn(); | 
 |  | 
 |   // _Unwind_Resume | 
 |  | 
 |   retType = builder.getInt32Ty(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   funct = createFunction(module, | 
 |                          retType, | 
 |                          argTypes, | 
 |                          argNames, | 
 |                          "_Unwind_Resume", | 
 |                          llvm::Function::ExternalLinkage, | 
 |                          true, | 
 |                          false); | 
 |  | 
 |   funct->setDoesNotReturn(); | 
 |  | 
 |   // ourPersonality | 
 |  | 
 |   retType = builder.getInt32Ty(); | 
 |  | 
 |   argTypes.clear(); | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |   argTypes.push_back(builder.getInt32Ty()); | 
 |   argTypes.push_back(builder.getInt64Ty()); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |   argTypes.push_back(builder.getInt8PtrTy()); | 
 |  | 
 |   argNames.clear(); | 
 |  | 
 |   createFunction(module, | 
 |                  retType, | 
 |                  argTypes, | 
 |                  argNames, | 
 |                  "ourPersonality", | 
 |                  llvm::Function::ExternalLinkage, | 
 |                  true, | 
 |                  false); | 
 |  | 
 |   // llvm.eh.typeid.for intrinsic | 
 |  | 
 |   getDeclaration(&module, llvm::Intrinsic::eh_typeid_for); | 
 | } | 
 |  | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Main test driver code. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | /// Demo main routine which takes the type info types to throw. A test will | 
 | /// be run for each given type info type. While type info types with the value | 
 | /// of -1 will trigger a foreign C++ exception to be thrown; type info types | 
 | /// <= 6 and >= 1 will be caught by test functions; and type info types > 6 | 
 | /// will result in exceptions which pass through to the test harness. All other | 
 | /// type info types are not supported and could cause a crash. | 
 | int main(int argc, char *argv[]) { | 
 |   if (argc == 1) { | 
 |     fprintf(stderr, | 
 |             "\nUsage: ExceptionDemo <exception type to throw> " | 
 |             "[<type 2>...<type n>].\n" | 
 |             "   Each type must have the value of 1 - 6 for " | 
 |             "generated exceptions to be caught;\n" | 
 |             "   the value -1 for foreign C++ exceptions to be " | 
 |             "generated and thrown;\n" | 
 |             "   or the values > 6 for exceptions to be ignored.\n" | 
 |             "\nTry: ExceptionDemo 2 3 7 -1\n" | 
 |             "   for a full test.\n\n"); | 
 |     return(0); | 
 |   } | 
 |  | 
 |   // If not set, exception handling will not be turned on | 
 |   llvm::TargetOptions Opts; | 
 |  | 
 |   llvm::InitializeNativeTarget(); | 
 |   llvm::InitializeNativeTargetAsmPrinter(); | 
 |   llvm::LLVMContext Context; | 
 |   llvm::IRBuilder<> theBuilder(Context); | 
 |  | 
 |   // Make the module, which holds all the code. | 
 |   std::unique_ptr<llvm::Module> Owner = | 
 |       llvm::make_unique<llvm::Module>("my cool jit", Context); | 
 |   llvm::Module *module = Owner.get(); | 
 |  | 
 |   std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager()); | 
 |  | 
 |   // Build engine with JIT | 
 |   llvm::EngineBuilder factory(std::move(Owner)); | 
 |   factory.setEngineKind(llvm::EngineKind::JIT); | 
 |   factory.setTargetOptions(Opts); | 
 |   factory.setMCJITMemoryManager(std::move(MemMgr)); | 
 |   llvm::ExecutionEngine *executionEngine = factory.create(); | 
 |  | 
 |   { | 
 |     llvm::legacy::FunctionPassManager fpm(module); | 
 |  | 
 |     // Set up the optimizer pipeline. | 
 |     // Start with registering info about how the | 
 |     // target lays out data structures. | 
 |     module->setDataLayout(executionEngine->getDataLayout()); | 
 |  | 
 |     // Optimizations turned on | 
 | #ifdef ADD_OPT_PASSES | 
 |  | 
 |     // Basic AliasAnslysis support for GVN. | 
 |     fpm.add(llvm::createBasicAliasAnalysisPass()); | 
 |  | 
 |     // Promote allocas to registers. | 
 |     fpm.add(llvm::createPromoteMemoryToRegisterPass()); | 
 |  | 
 |     // Do simple "peephole" optimizations and bit-twiddling optzns. | 
 |     fpm.add(llvm::createInstructionCombiningPass()); | 
 |  | 
 |     // Reassociate expressions. | 
 |     fpm.add(llvm::createReassociatePass()); | 
 |  | 
 |     // Eliminate Common SubExpressions. | 
 |     fpm.add(llvm::createGVNPass()); | 
 |  | 
 |     // Simplify the control flow graph (deleting unreachable | 
 |     // blocks, etc). | 
 |     fpm.add(llvm::createCFGSimplificationPass()); | 
 | #endif  // ADD_OPT_PASSES | 
 |  | 
 |     fpm.doInitialization(); | 
 |  | 
 |     // Generate test code using function throwCppException(...) as | 
 |     // the function which throws foreign exceptions. | 
 |     llvm::Function *toRun = | 
 |     createUnwindExceptionTest(*module, | 
 |                               theBuilder, | 
 |                               fpm, | 
 |                               "throwCppException"); | 
 |  | 
 |     executionEngine->finalizeObject(); | 
 |  | 
 |     fprintf(stderr, "\nBegin module dump:\n\n"); | 
 |  | 
 |     module->dump(); | 
 |  | 
 |     fprintf(stderr, "\nEnd module dump:\n"); | 
 |  | 
 |     fprintf(stderr, "\n\nBegin Test:\n"); | 
 |  | 
 |     for (int i = 1; i < argc; ++i) { | 
 |       // Run test for each argument whose value is the exception | 
 |       // type to throw. | 
 |       runExceptionThrow(executionEngine, | 
 |                         toRun, | 
 |                         (unsigned) strtoul(argv[i], NULL, 10)); | 
 |     } | 
 |  | 
 |     fprintf(stderr, "\nEnd Test:\n\n"); | 
 |   } | 
 |  | 
 |   delete executionEngine; | 
 |  | 
 |   return 0; | 
 | } |