xref: /netbsd-src/external/apache2/llvm/dist/llvm/examples/ExceptionDemo/ExceptionDemo.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Demo program which implements an example LLVM exception implementation, and
107330f729Sjoerg // shows several test cases including the handling of foreign exceptions.
117330f729Sjoerg // It is run with type info types arguments to throw. A test will
127330f729Sjoerg // be run for each given type info type. While type info types with the value
137330f729Sjoerg // of -1 will trigger a foreign C++ exception to be thrown; type info types
147330f729Sjoerg // <= 6 and >= 1 will cause the associated generated exceptions to be thrown
157330f729Sjoerg // and caught by generated test functions; and type info types > 6
167330f729Sjoerg // will result in exceptions which pass through to the test harness. All other
177330f729Sjoerg // type info types are not supported and could cause a crash. In all cases,
187330f729Sjoerg // the "finally" blocks of every generated test functions will executed
197330f729Sjoerg // regardless of whether or not that test function ignores or catches the
207330f729Sjoerg // thrown exception.
217330f729Sjoerg //
227330f729Sjoerg // examples:
237330f729Sjoerg //
247330f729Sjoerg // ExceptionDemo
257330f729Sjoerg //
267330f729Sjoerg //     causes a usage to be printed to stderr
277330f729Sjoerg //
287330f729Sjoerg // ExceptionDemo 2 3 7 -1
297330f729Sjoerg //
307330f729Sjoerg //     results in the following cases:
317330f729Sjoerg //         - Value 2 causes an exception with a type info type of 2 to be
327330f729Sjoerg //           thrown and caught by an inner generated test function.
337330f729Sjoerg //         - Value 3 causes an exception with a type info type of 3 to be
347330f729Sjoerg //           thrown and caught by an outer generated test function.
357330f729Sjoerg //         - Value 7 causes an exception with a type info type of 7 to be
367330f729Sjoerg //           thrown and NOT be caught by any generated function.
377330f729Sjoerg //         - Value -1 causes a foreign C++ exception to be thrown and not be
387330f729Sjoerg //           caught by any generated function
397330f729Sjoerg //
407330f729Sjoerg //     Cases -1 and 7 are caught by a C++ test harness where the validity of
417330f729Sjoerg //         of a C++ catch(...) clause catching a generated exception with a
427330f729Sjoerg //         type info type of 7 is explained by: example in rules 1.6.4 in
437330f729Sjoerg //         http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22)
447330f729Sjoerg //
457330f729Sjoerg // This code uses code from the llvm compiler-rt project and the llvm
467330f729Sjoerg // Kaleidoscope project.
477330f729Sjoerg //
487330f729Sjoerg //===----------------------------------------------------------------------===//
497330f729Sjoerg 
507330f729Sjoerg #include "llvm/ADT/STLExtras.h"
517330f729Sjoerg #include "llvm/BinaryFormat/Dwarf.h"
527330f729Sjoerg #include "llvm/ExecutionEngine/MCJIT.h"
537330f729Sjoerg #include "llvm/ExecutionEngine/SectionMemoryManager.h"
547330f729Sjoerg #include "llvm/IR/DataLayout.h"
557330f729Sjoerg #include "llvm/IR/DerivedTypes.h"
567330f729Sjoerg #include "llvm/IR/IRBuilder.h"
577330f729Sjoerg #include "llvm/IR/Intrinsics.h"
587330f729Sjoerg #include "llvm/IR/LLVMContext.h"
597330f729Sjoerg #include "llvm/IR/LegacyPassManager.h"
607330f729Sjoerg #include "llvm/IR/Module.h"
617330f729Sjoerg #include "llvm/IR/Verifier.h"
627330f729Sjoerg #include "llvm/Support/TargetSelect.h"
637330f729Sjoerg #include "llvm/Target/TargetOptions.h"
647330f729Sjoerg #include "llvm/Transforms/Scalar.h"
657330f729Sjoerg 
667330f729Sjoerg // FIXME: Although all systems tested with (Linux, OS X), do not need this
677330f729Sjoerg //        header file included. A user on ubuntu reported, undefined symbols
687330f729Sjoerg //        for stderr, and fprintf, and the addition of this include fixed the
697330f729Sjoerg //        issue for them. Given that LLVM's best practices include the goal
707330f729Sjoerg //        of reducing the number of redundant header files included, the
717330f729Sjoerg //        correct solution would be to find out why these symbols are not
727330f729Sjoerg //        defined for the system in question, and fix the issue by finding out
737330f729Sjoerg //        which LLVM header file, if any, would include these symbols.
747330f729Sjoerg #include <cstdio>
757330f729Sjoerg 
767330f729Sjoerg #include <sstream>
777330f729Sjoerg #include <stdexcept>
787330f729Sjoerg 
797330f729Sjoerg #include <inttypes.h>
807330f729Sjoerg 
817330f729Sjoerg #include <unwind.h>
827330f729Sjoerg 
837330f729Sjoerg #ifndef USE_GLOBAL_STR_CONSTS
847330f729Sjoerg #define USE_GLOBAL_STR_CONSTS true
857330f729Sjoerg #endif
867330f729Sjoerg 
877330f729Sjoerg //
887330f729Sjoerg // Example types
897330f729Sjoerg //
907330f729Sjoerg 
917330f729Sjoerg /// This is our simplistic type info
927330f729Sjoerg struct OurExceptionType_t {
937330f729Sjoerg   /// type info type
947330f729Sjoerg   int type;
957330f729Sjoerg };
967330f729Sjoerg 
977330f729Sjoerg 
987330f729Sjoerg /// This is our Exception class which relies on a negative offset to calculate
997330f729Sjoerg /// pointers to its instances from pointers to its unwindException member.
1007330f729Sjoerg ///
1017330f729Sjoerg /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
1027330f729Sjoerg ///       on a double word boundary. This is necessary to match the standard:
1037330f729Sjoerg ///       http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
1047330f729Sjoerg struct OurBaseException_t {
1057330f729Sjoerg   struct OurExceptionType_t type;
1067330f729Sjoerg 
1077330f729Sjoerg   // Note: This is properly aligned in unwind.h
1087330f729Sjoerg   struct _Unwind_Exception unwindException;
1097330f729Sjoerg };
1107330f729Sjoerg 
1117330f729Sjoerg 
1127330f729Sjoerg // Note: Not needed since we are C++
1137330f729Sjoerg typedef struct OurBaseException_t OurException;
1147330f729Sjoerg typedef struct _Unwind_Exception OurUnwindException;
1157330f729Sjoerg 
1167330f729Sjoerg //
1177330f729Sjoerg // Various globals used to support typeinfo and generatted exceptions in
1187330f729Sjoerg // general
1197330f729Sjoerg //
1207330f729Sjoerg 
1217330f729Sjoerg static std::map<std::string, llvm::Value*> namedValues;
1227330f729Sjoerg 
1237330f729Sjoerg int64_t ourBaseFromUnwindOffset;
1247330f729Sjoerg 
1257330f729Sjoerg const unsigned char ourBaseExcpClassChars[] =
1267330f729Sjoerg {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
1277330f729Sjoerg 
1287330f729Sjoerg 
1297330f729Sjoerg static uint64_t ourBaseExceptionClass = 0;
1307330f729Sjoerg 
1317330f729Sjoerg static std::vector<std::string> ourTypeInfoNames;
1327330f729Sjoerg static std::map<int, std::string> ourTypeInfoNamesIndex;
1337330f729Sjoerg 
1347330f729Sjoerg static llvm::StructType *ourTypeInfoType;
1357330f729Sjoerg static llvm::StructType *ourCaughtResultType;
1367330f729Sjoerg static llvm::StructType *ourExceptionType;
1377330f729Sjoerg static llvm::StructType *ourUnwindExceptionType;
1387330f729Sjoerg 
1397330f729Sjoerg static llvm::ConstantInt *ourExceptionNotThrownState;
1407330f729Sjoerg static llvm::ConstantInt *ourExceptionThrownState;
1417330f729Sjoerg static llvm::ConstantInt *ourExceptionCaughtState;
1427330f729Sjoerg 
1437330f729Sjoerg typedef std::vector<std::string> ArgNames;
1447330f729Sjoerg typedef std::vector<llvm::Type*> ArgTypes;
1457330f729Sjoerg 
1467330f729Sjoerg //
1477330f729Sjoerg // Code Generation Utilities
1487330f729Sjoerg //
1497330f729Sjoerg 
1507330f729Sjoerg /// Utility used to create a function, both declarations and definitions
1517330f729Sjoerg /// @param module for module instance
1527330f729Sjoerg /// @param retType function return type
1537330f729Sjoerg /// @param theArgTypes function's ordered argument types
1547330f729Sjoerg /// @param theArgNames function's ordered arguments needed if use of this
1557330f729Sjoerg ///        function corresponds to a function definition. Use empty
1567330f729Sjoerg ///        aggregate for function declarations.
1577330f729Sjoerg /// @param functName function name
1587330f729Sjoerg /// @param linkage function linkage
1597330f729Sjoerg /// @param declarationOnly for function declarations
1607330f729Sjoerg /// @param isVarArg function uses vararg arguments
1617330f729Sjoerg /// @returns function instance
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)1627330f729Sjoerg llvm::Function *createFunction(llvm::Module &module,
1637330f729Sjoerg                                llvm::Type *retType,
1647330f729Sjoerg                                const ArgTypes &theArgTypes,
1657330f729Sjoerg                                const ArgNames &theArgNames,
1667330f729Sjoerg                                const std::string &functName,
1677330f729Sjoerg                                llvm::GlobalValue::LinkageTypes linkage,
1687330f729Sjoerg                                bool declarationOnly,
1697330f729Sjoerg                                bool isVarArg) {
1707330f729Sjoerg   llvm::FunctionType *functType =
1717330f729Sjoerg     llvm::FunctionType::get(retType, theArgTypes, isVarArg);
1727330f729Sjoerg   llvm::Function *ret =
1737330f729Sjoerg     llvm::Function::Create(functType, linkage, functName, &module);
1747330f729Sjoerg   if (!ret || declarationOnly)
1757330f729Sjoerg     return(ret);
1767330f729Sjoerg 
1777330f729Sjoerg   namedValues.clear();
1787330f729Sjoerg   unsigned i = 0;
1797330f729Sjoerg   for (llvm::Function::arg_iterator argIndex = ret->arg_begin();
1807330f729Sjoerg        i != theArgNames.size();
1817330f729Sjoerg        ++argIndex, ++i) {
1827330f729Sjoerg 
1837330f729Sjoerg     argIndex->setName(theArgNames[i]);
1847330f729Sjoerg     namedValues[theArgNames[i]] = argIndex;
1857330f729Sjoerg   }
1867330f729Sjoerg 
1877330f729Sjoerg   return(ret);
1887330f729Sjoerg }
1897330f729Sjoerg 
1907330f729Sjoerg 
1917330f729Sjoerg /// Create an alloca instruction in the entry block of
1927330f729Sjoerg /// the parent function.  This is used for mutable variables etc.
1937330f729Sjoerg /// @param function parent instance
1947330f729Sjoerg /// @param varName stack variable name
1957330f729Sjoerg /// @param type stack variable type
1967330f729Sjoerg /// @param initWith optional constant initialization value
1977330f729Sjoerg /// @returns AllocaInst instance
createEntryBlockAlloca(llvm::Function & function,const std::string & varName,llvm::Type * type,llvm::Constant * initWith=0)1987330f729Sjoerg static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function,
1997330f729Sjoerg                                                 const std::string &varName,
2007330f729Sjoerg                                                 llvm::Type *type,
2017330f729Sjoerg                                                 llvm::Constant *initWith = 0) {
2027330f729Sjoerg   llvm::BasicBlock &block = function.getEntryBlock();
2037330f729Sjoerg   llvm::IRBuilder<> tmp(&block, block.begin());
2047330f729Sjoerg   llvm::AllocaInst *ret = tmp.CreateAlloca(type, 0, varName);
2057330f729Sjoerg 
2067330f729Sjoerg   if (initWith)
2077330f729Sjoerg     tmp.CreateStore(initWith, ret);
2087330f729Sjoerg 
2097330f729Sjoerg   return(ret);
2107330f729Sjoerg }
2117330f729Sjoerg 
2127330f729Sjoerg 
2137330f729Sjoerg //
2147330f729Sjoerg // Code Generation Utilities End
2157330f729Sjoerg //
2167330f729Sjoerg 
2177330f729Sjoerg //
2187330f729Sjoerg // Runtime C Library functions
2197330f729Sjoerg //
2207330f729Sjoerg 
2217330f729Sjoerg namespace {
2227330f729Sjoerg template <typename Type_>
ReadType(const uint8_t * & p)2237330f729Sjoerg uintptr_t ReadType(const uint8_t *&p) {
2247330f729Sjoerg   Type_ value;
2257330f729Sjoerg   memcpy(&value, p, sizeof(Type_));
2267330f729Sjoerg   p += sizeof(Type_);
2277330f729Sjoerg   return static_cast<uintptr_t>(value);
2287330f729Sjoerg }
2297330f729Sjoerg }
2307330f729Sjoerg 
2317330f729Sjoerg // Note: using an extern "C" block so that static functions can be used
2327330f729Sjoerg extern "C" {
2337330f729Sjoerg 
2347330f729Sjoerg // Note: Better ways to decide on bit width
2357330f729Sjoerg //
2367330f729Sjoerg /// Prints a 32 bit number, according to the format, to stderr.
2377330f729Sjoerg /// @param intToPrint integer to print
2387330f729Sjoerg /// @param format printf like format to use when printing
print32Int(int intToPrint,const char * format)2397330f729Sjoerg void print32Int(int intToPrint, const char *format) {
2407330f729Sjoerg   if (format) {
2417330f729Sjoerg     // Note: No NULL check
2427330f729Sjoerg     fprintf(stderr, format, intToPrint);
2437330f729Sjoerg   }
2447330f729Sjoerg   else {
2457330f729Sjoerg     // Note: No NULL check
2467330f729Sjoerg     fprintf(stderr, "::print32Int(...):NULL arg.\n");
2477330f729Sjoerg   }
2487330f729Sjoerg }
2497330f729Sjoerg 
2507330f729Sjoerg 
2517330f729Sjoerg // Note: Better ways to decide on bit width
2527330f729Sjoerg //
2537330f729Sjoerg /// Prints a 64 bit number, according to the format, to stderr.
2547330f729Sjoerg /// @param intToPrint integer to print
2557330f729Sjoerg /// @param format printf like format to use when printing
print64Int(long int intToPrint,const char * format)2567330f729Sjoerg void print64Int(long int intToPrint, const char *format) {
2577330f729Sjoerg   if (format) {
2587330f729Sjoerg     // Note: No NULL check
2597330f729Sjoerg     fprintf(stderr, format, intToPrint);
2607330f729Sjoerg   }
2617330f729Sjoerg   else {
2627330f729Sjoerg     // Note: No NULL check
2637330f729Sjoerg     fprintf(stderr, "::print64Int(...):NULL arg.\n");
2647330f729Sjoerg   }
2657330f729Sjoerg }
2667330f729Sjoerg 
2677330f729Sjoerg 
2687330f729Sjoerg /// Prints a C string to stderr
2697330f729Sjoerg /// @param toPrint string to print
printStr(char * toPrint)2707330f729Sjoerg void printStr(char *toPrint) {
2717330f729Sjoerg   if (toPrint) {
2727330f729Sjoerg     fprintf(stderr, "%s", toPrint);
2737330f729Sjoerg   }
2747330f729Sjoerg   else {
2757330f729Sjoerg     fprintf(stderr, "::printStr(...):NULL arg.\n");
2767330f729Sjoerg   }
2777330f729Sjoerg }
2787330f729Sjoerg 
2797330f729Sjoerg 
2807330f729Sjoerg /// Deletes the true previously allocated exception whose address
2817330f729Sjoerg /// is calculated from the supplied OurBaseException_t::unwindException
2827330f729Sjoerg /// member address. Handles (ignores), NULL pointers.
2837330f729Sjoerg /// @param expToDelete exception to delete
deleteOurException(OurUnwindException * expToDelete)2847330f729Sjoerg void deleteOurException(OurUnwindException *expToDelete) {
2857330f729Sjoerg #ifdef DEBUG
2867330f729Sjoerg   fprintf(stderr,
2877330f729Sjoerg           "deleteOurException(...).\n");
2887330f729Sjoerg #endif
2897330f729Sjoerg 
2907330f729Sjoerg   if (expToDelete &&
2917330f729Sjoerg       (expToDelete->exception_class == ourBaseExceptionClass)) {
2927330f729Sjoerg 
2937330f729Sjoerg     free(((char*) expToDelete) + ourBaseFromUnwindOffset);
2947330f729Sjoerg   }
2957330f729Sjoerg }
2967330f729Sjoerg 
2977330f729Sjoerg 
2987330f729Sjoerg /// This function is the struct _Unwind_Exception API mandated delete function
2997330f729Sjoerg /// used by foreign exception handlers when deleting our exception
3007330f729Sjoerg /// (OurException), instances.
3017330f729Sjoerg /// @param reason See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
3027330f729Sjoerg /// @unlink
3037330f729Sjoerg /// @param expToDelete exception instance to delete
deleteFromUnwindOurException(_Unwind_Reason_Code reason,OurUnwindException * expToDelete)3047330f729Sjoerg void deleteFromUnwindOurException(_Unwind_Reason_Code reason,
3057330f729Sjoerg                                   OurUnwindException *expToDelete) {
3067330f729Sjoerg #ifdef DEBUG
3077330f729Sjoerg   fprintf(stderr,
3087330f729Sjoerg           "deleteFromUnwindOurException(...).\n");
3097330f729Sjoerg #endif
3107330f729Sjoerg 
3117330f729Sjoerg   deleteOurException(expToDelete);
3127330f729Sjoerg }
3137330f729Sjoerg 
3147330f729Sjoerg 
3157330f729Sjoerg /// Creates (allocates on the heap), an exception (OurException instance),
3167330f729Sjoerg /// of the supplied type info type.
3177330f729Sjoerg /// @param type type info type
createOurException(int type)3187330f729Sjoerg OurUnwindException *createOurException(int type) {
3197330f729Sjoerg   size_t size = sizeof(OurException);
3207330f729Sjoerg   OurException *ret = (OurException*) memset(malloc(size), 0, size);
3217330f729Sjoerg   (ret->type).type = type;
3227330f729Sjoerg   (ret->unwindException).exception_class = ourBaseExceptionClass;
3237330f729Sjoerg   (ret->unwindException).exception_cleanup = deleteFromUnwindOurException;
3247330f729Sjoerg 
3257330f729Sjoerg   return(&(ret->unwindException));
3267330f729Sjoerg }
3277330f729Sjoerg 
3287330f729Sjoerg 
3297330f729Sjoerg /// Read a uleb128 encoded value and advance pointer
3307330f729Sjoerg /// See Variable Length Data in:
3317330f729Sjoerg /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
3327330f729Sjoerg /// @param data reference variable holding memory pointer to decode from
3337330f729Sjoerg /// @returns decoded value
readULEB128(const uint8_t ** data)3347330f729Sjoerg static uintptr_t readULEB128(const uint8_t **data) {
3357330f729Sjoerg   uintptr_t result = 0;
3367330f729Sjoerg   uintptr_t shift = 0;
3377330f729Sjoerg   unsigned char byte;
3387330f729Sjoerg   const uint8_t *p = *data;
3397330f729Sjoerg 
3407330f729Sjoerg   do {
3417330f729Sjoerg     byte = *p++;
3427330f729Sjoerg     result |= (byte & 0x7f) << shift;
3437330f729Sjoerg     shift += 7;
3447330f729Sjoerg   }
3457330f729Sjoerg   while (byte & 0x80);
3467330f729Sjoerg 
3477330f729Sjoerg   *data = p;
3487330f729Sjoerg 
3497330f729Sjoerg   return result;
3507330f729Sjoerg }
3517330f729Sjoerg 
3527330f729Sjoerg 
3537330f729Sjoerg /// Read a sleb128 encoded value and advance pointer
3547330f729Sjoerg /// See Variable Length Data in:
3557330f729Sjoerg /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
3567330f729Sjoerg /// @param data reference variable holding memory pointer to decode from
3577330f729Sjoerg /// @returns decoded value
readSLEB128(const uint8_t ** data)3587330f729Sjoerg static uintptr_t readSLEB128(const uint8_t **data) {
3597330f729Sjoerg   uintptr_t result = 0;
3607330f729Sjoerg   uintptr_t shift = 0;
3617330f729Sjoerg   unsigned char byte;
3627330f729Sjoerg   const uint8_t *p = *data;
3637330f729Sjoerg 
3647330f729Sjoerg   do {
3657330f729Sjoerg     byte = *p++;
3667330f729Sjoerg     result |= (byte & 0x7f) << shift;
3677330f729Sjoerg     shift += 7;
3687330f729Sjoerg   }
3697330f729Sjoerg   while (byte & 0x80);
3707330f729Sjoerg 
3717330f729Sjoerg   *data = p;
3727330f729Sjoerg 
3737330f729Sjoerg   if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
3747330f729Sjoerg     result |= (~0 << shift);
3757330f729Sjoerg   }
3767330f729Sjoerg 
3777330f729Sjoerg   return result;
3787330f729Sjoerg }
3797330f729Sjoerg 
getEncodingSize(uint8_t Encoding)3807330f729Sjoerg unsigned getEncodingSize(uint8_t Encoding) {
3817330f729Sjoerg   if (Encoding == llvm::dwarf::DW_EH_PE_omit)
3827330f729Sjoerg     return 0;
3837330f729Sjoerg 
3847330f729Sjoerg   switch (Encoding & 0x0F) {
3857330f729Sjoerg   case llvm::dwarf::DW_EH_PE_absptr:
3867330f729Sjoerg     return sizeof(uintptr_t);
3877330f729Sjoerg   case llvm::dwarf::DW_EH_PE_udata2:
3887330f729Sjoerg     return sizeof(uint16_t);
3897330f729Sjoerg   case llvm::dwarf::DW_EH_PE_udata4:
3907330f729Sjoerg     return sizeof(uint32_t);
3917330f729Sjoerg   case llvm::dwarf::DW_EH_PE_udata8:
3927330f729Sjoerg     return sizeof(uint64_t);
3937330f729Sjoerg   case llvm::dwarf::DW_EH_PE_sdata2:
3947330f729Sjoerg     return sizeof(int16_t);
3957330f729Sjoerg   case llvm::dwarf::DW_EH_PE_sdata4:
3967330f729Sjoerg     return sizeof(int32_t);
3977330f729Sjoerg   case llvm::dwarf::DW_EH_PE_sdata8:
3987330f729Sjoerg     return sizeof(int64_t);
3997330f729Sjoerg   default:
4007330f729Sjoerg     // not supported
4017330f729Sjoerg     abort();
4027330f729Sjoerg   }
4037330f729Sjoerg }
4047330f729Sjoerg 
4057330f729Sjoerg /// Read a pointer encoded value and advance pointer
4067330f729Sjoerg /// See Variable Length Data in:
4077330f729Sjoerg /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
4087330f729Sjoerg /// @param data reference variable holding memory pointer to decode from
4097330f729Sjoerg /// @param encoding dwarf encoding type
4107330f729Sjoerg /// @returns decoded value
readEncodedPointer(const uint8_t ** data,uint8_t encoding)4117330f729Sjoerg static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
4127330f729Sjoerg   uintptr_t result = 0;
4137330f729Sjoerg   const uint8_t *p = *data;
4147330f729Sjoerg 
4157330f729Sjoerg   if (encoding == llvm::dwarf::DW_EH_PE_omit)
4167330f729Sjoerg     return(result);
4177330f729Sjoerg 
4187330f729Sjoerg   // first get value
4197330f729Sjoerg   switch (encoding & 0x0F) {
4207330f729Sjoerg     case llvm::dwarf::DW_EH_PE_absptr:
4217330f729Sjoerg       result = ReadType<uintptr_t>(p);
4227330f729Sjoerg       break;
4237330f729Sjoerg     case llvm::dwarf::DW_EH_PE_uleb128:
4247330f729Sjoerg       result = readULEB128(&p);
4257330f729Sjoerg       break;
4267330f729Sjoerg       // Note: This case has not been tested
4277330f729Sjoerg     case llvm::dwarf::DW_EH_PE_sleb128:
4287330f729Sjoerg       result = readSLEB128(&p);
4297330f729Sjoerg       break;
4307330f729Sjoerg     case llvm::dwarf::DW_EH_PE_udata2:
4317330f729Sjoerg       result = ReadType<uint16_t>(p);
4327330f729Sjoerg       break;
4337330f729Sjoerg     case llvm::dwarf::DW_EH_PE_udata4:
4347330f729Sjoerg       result = ReadType<uint32_t>(p);
4357330f729Sjoerg       break;
4367330f729Sjoerg     case llvm::dwarf::DW_EH_PE_udata8:
4377330f729Sjoerg       result = ReadType<uint64_t>(p);
4387330f729Sjoerg       break;
4397330f729Sjoerg     case llvm::dwarf::DW_EH_PE_sdata2:
4407330f729Sjoerg       result = ReadType<int16_t>(p);
4417330f729Sjoerg       break;
4427330f729Sjoerg     case llvm::dwarf::DW_EH_PE_sdata4:
4437330f729Sjoerg       result = ReadType<int32_t>(p);
4447330f729Sjoerg       break;
4457330f729Sjoerg     case llvm::dwarf::DW_EH_PE_sdata8:
4467330f729Sjoerg       result = ReadType<int64_t>(p);
4477330f729Sjoerg       break;
4487330f729Sjoerg     default:
4497330f729Sjoerg       // not supported
4507330f729Sjoerg       abort();
4517330f729Sjoerg       break;
4527330f729Sjoerg   }
4537330f729Sjoerg 
4547330f729Sjoerg   // then add relative offset
4557330f729Sjoerg   switch (encoding & 0x70) {
4567330f729Sjoerg     case llvm::dwarf::DW_EH_PE_absptr:
4577330f729Sjoerg       // do nothing
4587330f729Sjoerg       break;
4597330f729Sjoerg     case llvm::dwarf::DW_EH_PE_pcrel:
4607330f729Sjoerg       result += (uintptr_t)(*data);
4617330f729Sjoerg       break;
4627330f729Sjoerg     case llvm::dwarf::DW_EH_PE_textrel:
4637330f729Sjoerg     case llvm::dwarf::DW_EH_PE_datarel:
4647330f729Sjoerg     case llvm::dwarf::DW_EH_PE_funcrel:
4657330f729Sjoerg     case llvm::dwarf::DW_EH_PE_aligned:
4667330f729Sjoerg     default:
4677330f729Sjoerg       // not supported
4687330f729Sjoerg       abort();
4697330f729Sjoerg       break;
4707330f729Sjoerg   }
4717330f729Sjoerg 
4727330f729Sjoerg   // then apply indirection
4737330f729Sjoerg   if (encoding & llvm::dwarf::DW_EH_PE_indirect) {
4747330f729Sjoerg     result = *((uintptr_t*)result);
4757330f729Sjoerg   }
4767330f729Sjoerg 
4777330f729Sjoerg   *data = p;
4787330f729Sjoerg 
4797330f729Sjoerg   return result;
4807330f729Sjoerg }
4817330f729Sjoerg 
4827330f729Sjoerg 
4837330f729Sjoerg /// Deals with Dwarf actions matching our type infos
4847330f729Sjoerg /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
4857330f729Sjoerg /// action matches the supplied exception type. If such a match succeeds,
4867330f729Sjoerg /// the resultAction argument will be set with > 0 index value. Only
4877330f729Sjoerg /// corresponding llvm.eh.selector type info arguments, cleanup arguments
4887330f729Sjoerg /// are supported. Filters are not supported.
4897330f729Sjoerg /// See Variable Length Data in:
4907330f729Sjoerg /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
4917330f729Sjoerg /// Also see @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
4927330f729Sjoerg /// @param resultAction reference variable which will be set with result
4937330f729Sjoerg /// @param classInfo our array of type info pointers (to globals)
4947330f729Sjoerg /// @param actionEntry index into above type info array or 0 (clean up).
4957330f729Sjoerg ///        We do not support filters.
4967330f729Sjoerg /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
4977330f729Sjoerg ///        of thrown exception.
4987330f729Sjoerg /// @param exceptionObject thrown _Unwind_Exception instance.
4997330f729Sjoerg /// @returns whether or not a type info was found. False is returned if only
5007330f729Sjoerg ///          a cleanup was found
handleActionValue(int64_t * resultAction,uint8_t TTypeEncoding,const uint8_t * ClassInfo,uintptr_t actionEntry,uint64_t exceptionClass,struct _Unwind_Exception * exceptionObject)5017330f729Sjoerg static bool handleActionValue(int64_t *resultAction,
5027330f729Sjoerg                               uint8_t TTypeEncoding,
5037330f729Sjoerg                               const uint8_t *ClassInfo,
5047330f729Sjoerg                               uintptr_t actionEntry,
5057330f729Sjoerg                               uint64_t exceptionClass,
5067330f729Sjoerg                               struct _Unwind_Exception *exceptionObject) {
5077330f729Sjoerg   bool ret = false;
5087330f729Sjoerg 
5097330f729Sjoerg   if (!resultAction ||
5107330f729Sjoerg       !exceptionObject ||
5117330f729Sjoerg       (exceptionClass != ourBaseExceptionClass))
5127330f729Sjoerg     return(ret);
5137330f729Sjoerg 
5147330f729Sjoerg   struct OurBaseException_t *excp = (struct OurBaseException_t*)
5157330f729Sjoerg   (((char*) exceptionObject) + ourBaseFromUnwindOffset);
5167330f729Sjoerg   struct OurExceptionType_t *excpType = &(excp->type);
5177330f729Sjoerg   int type = excpType->type;
5187330f729Sjoerg 
5197330f729Sjoerg #ifdef DEBUG
5207330f729Sjoerg   fprintf(stderr,
5217330f729Sjoerg           "handleActionValue(...): exceptionObject = <%p>, "
5227330f729Sjoerg           "excp = <%p>.\n",
5237330f729Sjoerg           (void*)exceptionObject,
5247330f729Sjoerg           (void*)excp);
5257330f729Sjoerg #endif
5267330f729Sjoerg 
5277330f729Sjoerg   const uint8_t *actionPos = (uint8_t*) actionEntry,
5287330f729Sjoerg   *tempActionPos;
5297330f729Sjoerg   int64_t typeOffset = 0,
5307330f729Sjoerg   actionOffset;
5317330f729Sjoerg 
5327330f729Sjoerg   for (int i = 0; true; ++i) {
5337330f729Sjoerg     // Each emitted dwarf action corresponds to a 2 tuple of
5347330f729Sjoerg     // type info address offset, and action offset to the next
5357330f729Sjoerg     // emitted action.
5367330f729Sjoerg     typeOffset = readSLEB128(&actionPos);
5377330f729Sjoerg     tempActionPos = actionPos;
5387330f729Sjoerg     actionOffset = readSLEB128(&tempActionPos);
5397330f729Sjoerg 
5407330f729Sjoerg #ifdef DEBUG
5417330f729Sjoerg     fprintf(stderr,
5427330f729Sjoerg             "handleActionValue(...):typeOffset: <%" PRIi64 ">, "
5437330f729Sjoerg             "actionOffset: <%" PRIi64 ">.\n",
5447330f729Sjoerg             typeOffset,
5457330f729Sjoerg             actionOffset);
5467330f729Sjoerg #endif
5477330f729Sjoerg     assert((typeOffset >= 0) &&
5487330f729Sjoerg            "handleActionValue(...):filters are not supported.");
5497330f729Sjoerg 
5507330f729Sjoerg     // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
5517330f729Sjoerg     //       argument has been matched.
5527330f729Sjoerg     if (typeOffset > 0) {
5537330f729Sjoerg #ifdef DEBUG
5547330f729Sjoerg       fprintf(stderr,
5557330f729Sjoerg               "handleActionValue(...):actionValue <%d> found.\n",
5567330f729Sjoerg               i);
5577330f729Sjoerg #endif
5587330f729Sjoerg       unsigned EncSize = getEncodingSize(TTypeEncoding);
5597330f729Sjoerg       const uint8_t *EntryP = ClassInfo - typeOffset * EncSize;
5607330f729Sjoerg       uintptr_t P = readEncodedPointer(&EntryP, TTypeEncoding);
5617330f729Sjoerg       struct OurExceptionType_t *ThisClassInfo =
5627330f729Sjoerg         reinterpret_cast<struct OurExceptionType_t *>(P);
5637330f729Sjoerg       if (ThisClassInfo->type == type) {
5647330f729Sjoerg         *resultAction = i + 1;
5657330f729Sjoerg         ret = true;
5667330f729Sjoerg         break;
5677330f729Sjoerg       }
5687330f729Sjoerg     }
5697330f729Sjoerg 
5707330f729Sjoerg #ifdef DEBUG
5717330f729Sjoerg     fprintf(stderr,
5727330f729Sjoerg             "handleActionValue(...):actionValue not found.\n");
5737330f729Sjoerg #endif
5747330f729Sjoerg     if (!actionOffset)
5757330f729Sjoerg       break;
5767330f729Sjoerg 
5777330f729Sjoerg     actionPos += actionOffset;
5787330f729Sjoerg   }
5797330f729Sjoerg 
5807330f729Sjoerg   return(ret);
5817330f729Sjoerg }
5827330f729Sjoerg 
5837330f729Sjoerg 
5847330f729Sjoerg /// Deals with the Language specific data portion of the emitted dwarf code.
5857330f729Sjoerg /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
5867330f729Sjoerg /// @param version unsupported (ignored), unwind version
5877330f729Sjoerg /// @param lsda language specific data area
5887330f729Sjoerg /// @param _Unwind_Action actions minimally supported unwind stage
5897330f729Sjoerg ///        (forced specifically not supported)
5907330f729Sjoerg /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
5917330f729Sjoerg ///        of thrown exception.
5927330f729Sjoerg /// @param exceptionObject thrown _Unwind_Exception instance.
5937330f729Sjoerg /// @param context unwind system context
5947330f729Sjoerg /// @returns minimally supported unwinding control indicator
handleLsda(int version,const uint8_t * lsda,_Unwind_Action actions,_Unwind_Exception_Class exceptionClass,struct _Unwind_Exception * exceptionObject,struct _Unwind_Context * context)5957330f729Sjoerg static _Unwind_Reason_Code handleLsda(int version, const uint8_t *lsda,
5967330f729Sjoerg                                       _Unwind_Action actions,
5977330f729Sjoerg                                       _Unwind_Exception_Class exceptionClass,
5987330f729Sjoerg                                       struct _Unwind_Exception *exceptionObject,
5997330f729Sjoerg                                       struct _Unwind_Context *context) {
6007330f729Sjoerg   _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND;
6017330f729Sjoerg 
6027330f729Sjoerg   if (!lsda)
6037330f729Sjoerg     return(ret);
6047330f729Sjoerg 
6057330f729Sjoerg #ifdef DEBUG
6067330f729Sjoerg   fprintf(stderr,
6077330f729Sjoerg           "handleLsda(...):lsda is non-zero.\n");
6087330f729Sjoerg #endif
6097330f729Sjoerg 
6107330f729Sjoerg   // Get the current instruction pointer and offset it before next
6117330f729Sjoerg   // instruction in the current frame which threw the exception.
6127330f729Sjoerg   uintptr_t pc = _Unwind_GetIP(context)-1;
6137330f729Sjoerg 
6147330f729Sjoerg   // Get beginning current frame's code (as defined by the
6157330f729Sjoerg   // emitted dwarf code)
6167330f729Sjoerg   uintptr_t funcStart = _Unwind_GetRegionStart(context);
6177330f729Sjoerg   uintptr_t pcOffset = pc - funcStart;
6187330f729Sjoerg   const uint8_t *ClassInfo = NULL;
6197330f729Sjoerg 
6207330f729Sjoerg   // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
6217330f729Sjoerg   //       dwarf emission
6227330f729Sjoerg 
6237330f729Sjoerg   // Parse LSDA header.
6247330f729Sjoerg   uint8_t lpStartEncoding = *lsda++;
6257330f729Sjoerg 
6267330f729Sjoerg   if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) {
6277330f729Sjoerg     readEncodedPointer(&lsda, lpStartEncoding);
6287330f729Sjoerg   }
6297330f729Sjoerg 
6307330f729Sjoerg   uint8_t ttypeEncoding = *lsda++;
6317330f729Sjoerg   uintptr_t classInfoOffset;
6327330f729Sjoerg 
6337330f729Sjoerg   if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) {
6347330f729Sjoerg     // Calculate type info locations in emitted dwarf code which
6357330f729Sjoerg     // were flagged by type info arguments to llvm.eh.selector
6367330f729Sjoerg     // intrinsic
6377330f729Sjoerg     classInfoOffset = readULEB128(&lsda);
6387330f729Sjoerg     ClassInfo = lsda + classInfoOffset;
6397330f729Sjoerg   }
6407330f729Sjoerg 
6417330f729Sjoerg   // Walk call-site table looking for range that
6427330f729Sjoerg   // includes current PC.
6437330f729Sjoerg 
6447330f729Sjoerg   uint8_t         callSiteEncoding = *lsda++;
6457330f729Sjoerg   uint32_t        callSiteTableLength = readULEB128(&lsda);
6467330f729Sjoerg   const uint8_t   *callSiteTableStart = lsda;
6477330f729Sjoerg   const uint8_t   *callSiteTableEnd = callSiteTableStart +
6487330f729Sjoerg   callSiteTableLength;
6497330f729Sjoerg   const uint8_t   *actionTableStart = callSiteTableEnd;
6507330f729Sjoerg   const uint8_t   *callSitePtr = callSiteTableStart;
6517330f729Sjoerg 
6527330f729Sjoerg   while (callSitePtr < callSiteTableEnd) {
6537330f729Sjoerg     uintptr_t start = readEncodedPointer(&callSitePtr,
6547330f729Sjoerg                                          callSiteEncoding);
6557330f729Sjoerg     uintptr_t length = readEncodedPointer(&callSitePtr,
6567330f729Sjoerg                                           callSiteEncoding);
6577330f729Sjoerg     uintptr_t landingPad = readEncodedPointer(&callSitePtr,
6587330f729Sjoerg                                               callSiteEncoding);
6597330f729Sjoerg 
6607330f729Sjoerg     // Note: Action value
6617330f729Sjoerg     uintptr_t actionEntry = readULEB128(&callSitePtr);
6627330f729Sjoerg 
6637330f729Sjoerg     if (exceptionClass != ourBaseExceptionClass) {
6647330f729Sjoerg       // We have been notified of a foreign exception being thrown,
6657330f729Sjoerg       // and we therefore need to execute cleanup landing pads
6667330f729Sjoerg       actionEntry = 0;
6677330f729Sjoerg     }
6687330f729Sjoerg 
6697330f729Sjoerg     if (landingPad == 0) {
6707330f729Sjoerg #ifdef DEBUG
6717330f729Sjoerg       fprintf(stderr,
6727330f729Sjoerg               "handleLsda(...): No landing pad found.\n");
6737330f729Sjoerg #endif
6747330f729Sjoerg 
6757330f729Sjoerg       continue; // no landing pad for this entry
6767330f729Sjoerg     }
6777330f729Sjoerg 
6787330f729Sjoerg     if (actionEntry) {
6797330f729Sjoerg       actionEntry += ((uintptr_t) actionTableStart) - 1;
6807330f729Sjoerg     }
6817330f729Sjoerg     else {
6827330f729Sjoerg #ifdef DEBUG
6837330f729Sjoerg       fprintf(stderr,
6847330f729Sjoerg               "handleLsda(...):No action table found.\n");
6857330f729Sjoerg #endif
6867330f729Sjoerg     }
6877330f729Sjoerg 
6887330f729Sjoerg     bool exceptionMatched = false;
6897330f729Sjoerg 
6907330f729Sjoerg     if ((start <= pcOffset) && (pcOffset < (start + length))) {
6917330f729Sjoerg #ifdef DEBUG
6927330f729Sjoerg       fprintf(stderr,
6937330f729Sjoerg               "handleLsda(...): Landing pad found.\n");
6947330f729Sjoerg #endif
6957330f729Sjoerg       int64_t actionValue = 0;
6967330f729Sjoerg 
6977330f729Sjoerg       if (actionEntry) {
6987330f729Sjoerg         exceptionMatched = handleActionValue(&actionValue,
6997330f729Sjoerg                                              ttypeEncoding,
7007330f729Sjoerg                                              ClassInfo,
7017330f729Sjoerg                                              actionEntry,
7027330f729Sjoerg                                              exceptionClass,
7037330f729Sjoerg                                              exceptionObject);
7047330f729Sjoerg       }
7057330f729Sjoerg 
7067330f729Sjoerg       if (!(actions & _UA_SEARCH_PHASE)) {
7077330f729Sjoerg #ifdef DEBUG
7087330f729Sjoerg         fprintf(stderr,
7097330f729Sjoerg                 "handleLsda(...): installed landing pad "
7107330f729Sjoerg                 "context.\n");
7117330f729Sjoerg #endif
7127330f729Sjoerg 
7137330f729Sjoerg         // Found landing pad for the PC.
7147330f729Sjoerg         // Set Instruction Pointer to so we re-enter function
7157330f729Sjoerg         // at landing pad. The landing pad is created by the
7167330f729Sjoerg         // compiler to take two parameters in registers.
7177330f729Sjoerg         _Unwind_SetGR(context,
7187330f729Sjoerg                       __builtin_eh_return_data_regno(0),
7197330f729Sjoerg                       (uintptr_t)exceptionObject);
7207330f729Sjoerg 
7217330f729Sjoerg         // Note: this virtual register directly corresponds
7227330f729Sjoerg         //       to the return of the llvm.eh.selector intrinsic
7237330f729Sjoerg         if (!actionEntry || !exceptionMatched) {
7247330f729Sjoerg           // We indicate cleanup only
7257330f729Sjoerg           _Unwind_SetGR(context,
7267330f729Sjoerg                         __builtin_eh_return_data_regno(1),
7277330f729Sjoerg                         0);
7287330f729Sjoerg         }
7297330f729Sjoerg         else {
7307330f729Sjoerg           // Matched type info index of llvm.eh.selector intrinsic
7317330f729Sjoerg           // passed here.
7327330f729Sjoerg           _Unwind_SetGR(context,
7337330f729Sjoerg                         __builtin_eh_return_data_regno(1),
7347330f729Sjoerg                         actionValue);
7357330f729Sjoerg         }
7367330f729Sjoerg 
7377330f729Sjoerg         // To execute landing pad set here
7387330f729Sjoerg         _Unwind_SetIP(context, funcStart + landingPad);
7397330f729Sjoerg         ret = _URC_INSTALL_CONTEXT;
7407330f729Sjoerg       }
7417330f729Sjoerg       else if (exceptionMatched) {
7427330f729Sjoerg #ifdef DEBUG
7437330f729Sjoerg         fprintf(stderr,
7447330f729Sjoerg                 "handleLsda(...): setting handler found.\n");
7457330f729Sjoerg #endif
7467330f729Sjoerg         ret = _URC_HANDLER_FOUND;
7477330f729Sjoerg       }
7487330f729Sjoerg       else {
7497330f729Sjoerg         // Note: Only non-clean up handlers are marked as
7507330f729Sjoerg         //       found. Otherwise the clean up handlers will be
7517330f729Sjoerg         //       re-found and executed during the clean up
7527330f729Sjoerg         //       phase.
7537330f729Sjoerg #ifdef DEBUG
7547330f729Sjoerg         fprintf(stderr,
7557330f729Sjoerg                 "handleLsda(...): cleanup handler found.\n");
7567330f729Sjoerg #endif
7577330f729Sjoerg       }
7587330f729Sjoerg 
7597330f729Sjoerg       break;
7607330f729Sjoerg     }
7617330f729Sjoerg   }
7627330f729Sjoerg 
7637330f729Sjoerg   return(ret);
7647330f729Sjoerg }
7657330f729Sjoerg 
7667330f729Sjoerg 
7677330f729Sjoerg /// This is the personality function which is embedded (dwarf emitted), in the
7687330f729Sjoerg /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
7697330f729Sjoerg /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
7707330f729Sjoerg /// @param version unsupported (ignored), unwind version
7717330f729Sjoerg /// @param _Unwind_Action actions minimally supported unwind stage
7727330f729Sjoerg ///        (forced specifically not supported)
7737330f729Sjoerg /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
7747330f729Sjoerg ///        of thrown exception.
7757330f729Sjoerg /// @param exceptionObject thrown _Unwind_Exception instance.
7767330f729Sjoerg /// @param context unwind system context
7777330f729Sjoerg /// @returns minimally supported unwinding control indicator
ourPersonality(int version,_Unwind_Action actions,_Unwind_Exception_Class exceptionClass,struct _Unwind_Exception * exceptionObject,struct _Unwind_Context * context)7787330f729Sjoerg _Unwind_Reason_Code ourPersonality(int version, _Unwind_Action actions,
7797330f729Sjoerg                                    _Unwind_Exception_Class exceptionClass,
7807330f729Sjoerg                                    struct _Unwind_Exception *exceptionObject,
7817330f729Sjoerg                                    struct _Unwind_Context *context) {
7827330f729Sjoerg #ifdef DEBUG
7837330f729Sjoerg   fprintf(stderr,
7847330f729Sjoerg           "We are in ourPersonality(...):actions is <%d>.\n",
7857330f729Sjoerg           actions);
7867330f729Sjoerg 
7877330f729Sjoerg   if (actions & _UA_SEARCH_PHASE) {
7887330f729Sjoerg     fprintf(stderr, "ourPersonality(...):In search phase.\n");
7897330f729Sjoerg   }
7907330f729Sjoerg   else {
7917330f729Sjoerg     fprintf(stderr, "ourPersonality(...):In non-search phase.\n");
7927330f729Sjoerg   }
7937330f729Sjoerg #endif
7947330f729Sjoerg 
795*82d56013Sjoerg   const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);
7967330f729Sjoerg 
7977330f729Sjoerg #ifdef DEBUG
7987330f729Sjoerg   fprintf(stderr,
7997330f729Sjoerg           "ourPersonality(...):lsda = <%p>.\n",
8007330f729Sjoerg           (void*)lsda);
8017330f729Sjoerg #endif
8027330f729Sjoerg 
8037330f729Sjoerg   // The real work of the personality function is captured here
8047330f729Sjoerg   return(handleLsda(version,
8057330f729Sjoerg                     lsda,
8067330f729Sjoerg                     actions,
8077330f729Sjoerg                     exceptionClass,
8087330f729Sjoerg                     exceptionObject,
8097330f729Sjoerg                     context));
8107330f729Sjoerg }
8117330f729Sjoerg 
8127330f729Sjoerg 
8137330f729Sjoerg /// Generates our _Unwind_Exception class from a given character array.
8147330f729Sjoerg /// thereby handling arbitrary lengths (not in standard), and handling
8157330f729Sjoerg /// embedded \0s.
8167330f729Sjoerg /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
8177330f729Sjoerg /// @param classChars char array to encode. NULL values not checkedf
8187330f729Sjoerg /// @param classCharsSize number of chars in classChars. Value is not checked.
8197330f729Sjoerg /// @returns class value
genClass(const unsigned char classChars[],size_t classCharsSize)8207330f729Sjoerg uint64_t genClass(const unsigned char classChars[], size_t classCharsSize)
8217330f729Sjoerg {
8227330f729Sjoerg   uint64_t ret = classChars[0];
8237330f729Sjoerg 
8247330f729Sjoerg   for (unsigned i = 1; i < classCharsSize; ++i) {
8257330f729Sjoerg     ret <<= 8;
8267330f729Sjoerg     ret += classChars[i];
8277330f729Sjoerg   }
8287330f729Sjoerg 
8297330f729Sjoerg   return(ret);
8307330f729Sjoerg }
8317330f729Sjoerg 
8327330f729Sjoerg } // extern "C"
8337330f729Sjoerg 
8347330f729Sjoerg //
8357330f729Sjoerg // Runtime C Library functions End
8367330f729Sjoerg //
8377330f729Sjoerg 
8387330f729Sjoerg //
8397330f729Sjoerg // Code generation functions
8407330f729Sjoerg //
8417330f729Sjoerg 
8427330f729Sjoerg /// Generates code to print given constant string
8437330f729Sjoerg /// @param context llvm context
8447330f729Sjoerg /// @param module code for module instance
8457330f729Sjoerg /// @param builder builder instance
8467330f729Sjoerg /// @param toPrint string to print
8477330f729Sjoerg /// @param useGlobal A value of true (default) indicates a GlobalValue is
8487330f729Sjoerg ///        generated, and is used to hold the constant string. A value of
8497330f729Sjoerg ///        false indicates that the constant string will be stored on the
8507330f729Sjoerg ///        stack.
generateStringPrint(llvm::LLVMContext & context,llvm::Module & module,llvm::IRBuilder<> & builder,std::string toPrint,bool useGlobal=true)8517330f729Sjoerg void generateStringPrint(llvm::LLVMContext &context,
8527330f729Sjoerg                          llvm::Module &module,
8537330f729Sjoerg                          llvm::IRBuilder<> &builder,
8547330f729Sjoerg                          std::string toPrint,
8557330f729Sjoerg                          bool useGlobal = true) {
8567330f729Sjoerg   llvm::Function *printFunct = module.getFunction("printStr");
8577330f729Sjoerg 
8587330f729Sjoerg   llvm::Value *stringVar;
8597330f729Sjoerg   llvm::Constant *stringConstant =
8607330f729Sjoerg   llvm::ConstantDataArray::getString(context, toPrint);
8617330f729Sjoerg 
8627330f729Sjoerg   if (useGlobal) {
8637330f729Sjoerg     // Note: Does not work without allocation
8647330f729Sjoerg     stringVar =
8657330f729Sjoerg     new llvm::GlobalVariable(module,
8667330f729Sjoerg                              stringConstant->getType(),
8677330f729Sjoerg                              true,
8687330f729Sjoerg                              llvm::GlobalValue::PrivateLinkage,
8697330f729Sjoerg                              stringConstant,
8707330f729Sjoerg                              "");
8717330f729Sjoerg   }
8727330f729Sjoerg   else {
8737330f729Sjoerg     stringVar = builder.CreateAlloca(stringConstant->getType());
8747330f729Sjoerg     builder.CreateStore(stringConstant, stringVar);
8757330f729Sjoerg   }
8767330f729Sjoerg 
8777330f729Sjoerg   llvm::Value *cast = builder.CreatePointerCast(stringVar,
8787330f729Sjoerg                                                 builder.getInt8PtrTy());
8797330f729Sjoerg   builder.CreateCall(printFunct, cast);
8807330f729Sjoerg }
8817330f729Sjoerg 
8827330f729Sjoerg 
8837330f729Sjoerg /// Generates code to print given runtime integer according to constant
8847330f729Sjoerg /// string format, and a given print function.
8857330f729Sjoerg /// @param context llvm context
8867330f729Sjoerg /// @param module code for module instance
8877330f729Sjoerg /// @param builder builder instance
8887330f729Sjoerg /// @param printFunct function used to "print" integer
8897330f729Sjoerg /// @param toPrint string to print
8907330f729Sjoerg /// @param format printf like formating string for print
8917330f729Sjoerg /// @param useGlobal A value of true (default) indicates a GlobalValue is
8927330f729Sjoerg ///        generated, and is used to hold the constant string. A value of
8937330f729Sjoerg ///        false indicates that the constant string will be stored on the
8947330f729Sjoerg ///        stack.
generateIntegerPrint(llvm::LLVMContext & context,llvm::Module & module,llvm::IRBuilder<> & builder,llvm::Function & printFunct,llvm::Value & toPrint,std::string format,bool useGlobal=true)8957330f729Sjoerg void generateIntegerPrint(llvm::LLVMContext &context,
8967330f729Sjoerg                           llvm::Module &module,
8977330f729Sjoerg                           llvm::IRBuilder<> &builder,
8987330f729Sjoerg                           llvm::Function &printFunct,
8997330f729Sjoerg                           llvm::Value &toPrint,
9007330f729Sjoerg                           std::string format,
9017330f729Sjoerg                           bool useGlobal = true) {
9027330f729Sjoerg   llvm::Constant *stringConstant =
9037330f729Sjoerg     llvm::ConstantDataArray::getString(context, format);
9047330f729Sjoerg   llvm::Value *stringVar;
9057330f729Sjoerg 
9067330f729Sjoerg   if (useGlobal) {
9077330f729Sjoerg     // Note: Does not seem to work without allocation
9087330f729Sjoerg     stringVar =
9097330f729Sjoerg     new llvm::GlobalVariable(module,
9107330f729Sjoerg                              stringConstant->getType(),
9117330f729Sjoerg                              true,
9127330f729Sjoerg                              llvm::GlobalValue::PrivateLinkage,
9137330f729Sjoerg                              stringConstant,
9147330f729Sjoerg                              "");
9157330f729Sjoerg   }
9167330f729Sjoerg   else {
9177330f729Sjoerg     stringVar = builder.CreateAlloca(stringConstant->getType());
9187330f729Sjoerg     builder.CreateStore(stringConstant, stringVar);
9197330f729Sjoerg   }
9207330f729Sjoerg 
9217330f729Sjoerg   llvm::Value *cast = builder.CreateBitCast(stringVar,
9227330f729Sjoerg                                             builder.getInt8PtrTy());
9237330f729Sjoerg   builder.CreateCall(&printFunct, {&toPrint, cast});
9247330f729Sjoerg }
9257330f729Sjoerg 
9267330f729Sjoerg 
9277330f729Sjoerg /// Generates code to handle finally block type semantics: always runs
9287330f729Sjoerg /// regardless of whether a thrown exception is passing through or the
9297330f729Sjoerg /// parent function is simply exiting. In addition to printing some state
9307330f729Sjoerg /// to stderr, this code will resume the exception handling--runs the
9317330f729Sjoerg /// unwind resume block, if the exception has not been previously caught
9327330f729Sjoerg /// by a catch clause, and will otherwise execute the end block (terminator
9337330f729Sjoerg /// block). In addition this function creates the corresponding function's
9347330f729Sjoerg /// stack storage for the exception pointer and catch flag status.
9357330f729Sjoerg /// @param context llvm context
9367330f729Sjoerg /// @param module code for module instance
9377330f729Sjoerg /// @param builder builder instance
9387330f729Sjoerg /// @param toAddTo parent function to add block to
9397330f729Sjoerg /// @param blockName block name of new "finally" block.
9407330f729Sjoerg /// @param functionId output id used for printing
9417330f729Sjoerg /// @param terminatorBlock terminator "end" block
9427330f729Sjoerg /// @param unwindResumeBlock unwind resume block
9437330f729Sjoerg /// @param exceptionCaughtFlag reference exception caught/thrown status storage
9447330f729Sjoerg /// @param exceptionStorage reference to exception pointer storage
9457330f729Sjoerg /// @param caughtResultStorage reference to landingpad result storage
9467330f729Sjoerg /// @returns newly created block
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)9477330f729Sjoerg static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
9487330f729Sjoerg                                             llvm::Module &module,
9497330f729Sjoerg                                             llvm::IRBuilder<> &builder,
9507330f729Sjoerg                                             llvm::Function &toAddTo,
9517330f729Sjoerg                                             std::string &blockName,
9527330f729Sjoerg                                             std::string &functionId,
9537330f729Sjoerg                                             llvm::BasicBlock &terminatorBlock,
9547330f729Sjoerg                                             llvm::BasicBlock &unwindResumeBlock,
9557330f729Sjoerg                                             llvm::Value **exceptionCaughtFlag,
9567330f729Sjoerg                                             llvm::Value **exceptionStorage,
9577330f729Sjoerg                                             llvm::Value **caughtResultStorage) {
9587330f729Sjoerg   assert(exceptionCaughtFlag &&
9597330f729Sjoerg          "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
9607330f729Sjoerg          "is NULL");
9617330f729Sjoerg   assert(exceptionStorage &&
9627330f729Sjoerg          "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
9637330f729Sjoerg          "is NULL");
9647330f729Sjoerg   assert(caughtResultStorage &&
9657330f729Sjoerg          "ExceptionDemo::createFinallyBlock(...):caughtResultStorage "
9667330f729Sjoerg          "is NULL");
9677330f729Sjoerg 
9687330f729Sjoerg   *exceptionCaughtFlag = createEntryBlockAlloca(toAddTo,
9697330f729Sjoerg                                          "exceptionCaught",
9707330f729Sjoerg                                          ourExceptionNotThrownState->getType(),
9717330f729Sjoerg                                          ourExceptionNotThrownState);
9727330f729Sjoerg 
9737330f729Sjoerg   llvm::PointerType *exceptionStorageType = builder.getInt8PtrTy();
9747330f729Sjoerg   *exceptionStorage = createEntryBlockAlloca(toAddTo,
9757330f729Sjoerg                                              "exceptionStorage",
9767330f729Sjoerg                                              exceptionStorageType,
9777330f729Sjoerg                                              llvm::ConstantPointerNull::get(
9787330f729Sjoerg                                                exceptionStorageType));
9797330f729Sjoerg   *caughtResultStorage = createEntryBlockAlloca(toAddTo,
9807330f729Sjoerg                                               "caughtResultStorage",
9817330f729Sjoerg                                               ourCaughtResultType,
9827330f729Sjoerg                                               llvm::ConstantAggregateZero::get(
9837330f729Sjoerg                                                 ourCaughtResultType));
9847330f729Sjoerg 
9857330f729Sjoerg   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
9867330f729Sjoerg                                                    blockName,
9877330f729Sjoerg                                                    &toAddTo);
9887330f729Sjoerg 
9897330f729Sjoerg   builder.SetInsertPoint(ret);
9907330f729Sjoerg 
9917330f729Sjoerg   std::ostringstream bufferToPrint;
9927330f729Sjoerg   bufferToPrint << "Gen: Executing finally block "
9937330f729Sjoerg     << blockName << " in " << functionId << "\n";
9947330f729Sjoerg   generateStringPrint(context,
9957330f729Sjoerg                       module,
9967330f729Sjoerg                       builder,
9977330f729Sjoerg                       bufferToPrint.str(),
9987330f729Sjoerg                       USE_GLOBAL_STR_CONSTS);
9997330f729Sjoerg 
10007330f729Sjoerg   llvm::SwitchInst *theSwitch = builder.CreateSwitch(builder.CreateLoad(
10017330f729Sjoerg                                                        *exceptionCaughtFlag),
10027330f729Sjoerg                                                      &terminatorBlock,
10037330f729Sjoerg                                                      2);
10047330f729Sjoerg   theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
10057330f729Sjoerg   theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
10067330f729Sjoerg 
10077330f729Sjoerg   return(ret);
10087330f729Sjoerg }
10097330f729Sjoerg 
10107330f729Sjoerg 
10117330f729Sjoerg /// Generates catch block semantics which print a string to indicate type of
10127330f729Sjoerg /// catch executed, sets an exception caught flag, and executes passed in
10137330f729Sjoerg /// end block (terminator block).
10147330f729Sjoerg /// @param context llvm context
10157330f729Sjoerg /// @param module code for module instance
10167330f729Sjoerg /// @param builder builder instance
10177330f729Sjoerg /// @param toAddTo parent function to add block to
10187330f729Sjoerg /// @param blockName block name of new "catch" block.
10197330f729Sjoerg /// @param functionId output id used for printing
10207330f729Sjoerg /// @param terminatorBlock terminator "end" block
10217330f729Sjoerg /// @param exceptionCaughtFlag exception caught/thrown status
10227330f729Sjoerg /// @returns newly created block
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)10237330f729Sjoerg static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context,
10247330f729Sjoerg                                           llvm::Module &module,
10257330f729Sjoerg                                           llvm::IRBuilder<> &builder,
10267330f729Sjoerg                                           llvm::Function &toAddTo,
10277330f729Sjoerg                                           std::string &blockName,
10287330f729Sjoerg                                           std::string &functionId,
10297330f729Sjoerg                                           llvm::BasicBlock &terminatorBlock,
10307330f729Sjoerg                                           llvm::Value &exceptionCaughtFlag) {
10317330f729Sjoerg 
10327330f729Sjoerg   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
10337330f729Sjoerg                                                    blockName,
10347330f729Sjoerg                                                    &toAddTo);
10357330f729Sjoerg 
10367330f729Sjoerg   builder.SetInsertPoint(ret);
10377330f729Sjoerg 
10387330f729Sjoerg   std::ostringstream bufferToPrint;
10397330f729Sjoerg   bufferToPrint << "Gen: Executing catch block "
10407330f729Sjoerg   << blockName
10417330f729Sjoerg   << " in "
10427330f729Sjoerg   << functionId
10437330f729Sjoerg   << std::endl;
10447330f729Sjoerg   generateStringPrint(context,
10457330f729Sjoerg                       module,
10467330f729Sjoerg                       builder,
10477330f729Sjoerg                       bufferToPrint.str(),
10487330f729Sjoerg                       USE_GLOBAL_STR_CONSTS);
10497330f729Sjoerg   builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
10507330f729Sjoerg   builder.CreateBr(&terminatorBlock);
10517330f729Sjoerg 
10527330f729Sjoerg   return(ret);
10537330f729Sjoerg }
10547330f729Sjoerg 
10557330f729Sjoerg 
10567330f729Sjoerg /// Generates a function which invokes a function (toInvoke) and, whose
10577330f729Sjoerg /// unwind block will "catch" the type info types correspondingly held in the
10587330f729Sjoerg /// exceptionTypesToCatch argument. If the toInvoke function throws an
10597330f729Sjoerg /// exception which does not match any type info types contained in
10607330f729Sjoerg /// exceptionTypesToCatch, the generated code will call _Unwind_Resume
10617330f729Sjoerg /// with the raised exception. On the other hand the generated code will
10627330f729Sjoerg /// normally exit if the toInvoke function does not throw an exception.
10637330f729Sjoerg /// The generated "finally" block is always run regardless of the cause of
10647330f729Sjoerg /// the generated function exit.
10657330f729Sjoerg /// The generated function is returned after being verified.
10667330f729Sjoerg /// @param module code for module instance
10677330f729Sjoerg /// @param builder builder instance
10687330f729Sjoerg /// @param fpm a function pass manager holding optional IR to IR
10697330f729Sjoerg ///        transformations
10707330f729Sjoerg /// @param toInvoke inner function to invoke
10717330f729Sjoerg /// @param ourId id used to printing purposes
10727330f729Sjoerg /// @param numExceptionsToCatch length of exceptionTypesToCatch array
10737330f729Sjoerg /// @param exceptionTypesToCatch array of type info types to "catch"
10747330f729Sjoerg /// @returns generated function
createCatchWrappedInvokeFunction(llvm::Module & module,llvm::IRBuilder<> & builder,llvm::legacy::FunctionPassManager & fpm,llvm::Function & toInvoke,std::string ourId,unsigned numExceptionsToCatch,unsigned exceptionTypesToCatch[])10757330f729Sjoerg static llvm::Function *createCatchWrappedInvokeFunction(
10767330f729Sjoerg     llvm::Module &module, llvm::IRBuilder<> &builder,
10777330f729Sjoerg     llvm::legacy::FunctionPassManager &fpm, llvm::Function &toInvoke,
10787330f729Sjoerg     std::string ourId, unsigned numExceptionsToCatch,
10797330f729Sjoerg     unsigned exceptionTypesToCatch[]) {
10807330f729Sjoerg 
10817330f729Sjoerg   llvm::LLVMContext &context = module.getContext();
10827330f729Sjoerg   llvm::Function *toPrint32Int = module.getFunction("print32Int");
10837330f729Sjoerg 
10847330f729Sjoerg   ArgTypes argTypes;
10857330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
10867330f729Sjoerg 
10877330f729Sjoerg   ArgNames argNames;
10887330f729Sjoerg   argNames.push_back("exceptTypeToThrow");
10897330f729Sjoerg 
10907330f729Sjoerg   llvm::Function *ret = createFunction(module,
10917330f729Sjoerg                                        builder.getVoidTy(),
10927330f729Sjoerg                                        argTypes,
10937330f729Sjoerg                                        argNames,
10947330f729Sjoerg                                        ourId,
10957330f729Sjoerg                                        llvm::Function::ExternalLinkage,
10967330f729Sjoerg                                        false,
10977330f729Sjoerg                                        false);
10987330f729Sjoerg 
10997330f729Sjoerg   // Block which calls invoke
11007330f729Sjoerg   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
11017330f729Sjoerg                                                           "entry",
11027330f729Sjoerg                                                           ret);
11037330f729Sjoerg   // Normal block for invoke
11047330f729Sjoerg   llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
11057330f729Sjoerg                                                            "normal",
11067330f729Sjoerg                                                            ret);
11077330f729Sjoerg   // Unwind block for invoke
11087330f729Sjoerg   llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context,
11097330f729Sjoerg                                                               "exception",
11107330f729Sjoerg                                                               ret);
11117330f729Sjoerg 
11127330f729Sjoerg   // Block which routes exception to correct catch handler block
11137330f729Sjoerg   llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context,
11147330f729Sjoerg                                                              "exceptionRoute",
11157330f729Sjoerg                                                              ret);
11167330f729Sjoerg 
11177330f729Sjoerg   // Foreign exception handler
11187330f729Sjoerg   llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context,
11197330f729Sjoerg                                                           "externalException",
11207330f729Sjoerg                                                           ret);
11217330f729Sjoerg 
11227330f729Sjoerg   // Block which calls _Unwind_Resume
11237330f729Sjoerg   llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context,
11247330f729Sjoerg                                                                "unwindResume",
11257330f729Sjoerg                                                                ret);
11267330f729Sjoerg 
11277330f729Sjoerg   // Clean up block which delete exception if needed
11287330f729Sjoerg   llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret);
11297330f729Sjoerg 
11307330f729Sjoerg   std::string nextName;
11317330f729Sjoerg   std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
11327330f729Sjoerg   llvm::Value *exceptionCaughtFlag = NULL;
11337330f729Sjoerg   llvm::Value *exceptionStorage = NULL;
11347330f729Sjoerg   llvm::Value *caughtResultStorage = NULL;
11357330f729Sjoerg 
11367330f729Sjoerg   // Finally block which will branch to unwindResumeBlock if
11377330f729Sjoerg   // exception is not caught. Initializes/allocates stack locations.
11387330f729Sjoerg   llvm::BasicBlock *finallyBlock = createFinallyBlock(context,
11397330f729Sjoerg                                                       module,
11407330f729Sjoerg                                                       builder,
11417330f729Sjoerg                                                       *ret,
11427330f729Sjoerg                                                       nextName = "finally",
11437330f729Sjoerg                                                       ourId,
11447330f729Sjoerg                                                       *endBlock,
11457330f729Sjoerg                                                       *unwindResumeBlock,
11467330f729Sjoerg                                                       &exceptionCaughtFlag,
11477330f729Sjoerg                                                       &exceptionStorage,
11487330f729Sjoerg                                                       &caughtResultStorage
11497330f729Sjoerg                                                       );
11507330f729Sjoerg 
11517330f729Sjoerg   for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
11527330f729Sjoerg     nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
11537330f729Sjoerg 
11547330f729Sjoerg     // One catch block per type info to be caught
11557330f729Sjoerg     catchBlocks[i] = createCatchBlock(context,
11567330f729Sjoerg                                       module,
11577330f729Sjoerg                                       builder,
11587330f729Sjoerg                                       *ret,
11597330f729Sjoerg                                       nextName,
11607330f729Sjoerg                                       ourId,
11617330f729Sjoerg                                       *finallyBlock,
11627330f729Sjoerg                                       *exceptionCaughtFlag);
11637330f729Sjoerg   }
11647330f729Sjoerg 
11657330f729Sjoerg   // Entry Block
11667330f729Sjoerg 
11677330f729Sjoerg   builder.SetInsertPoint(entryBlock);
11687330f729Sjoerg 
11697330f729Sjoerg   std::vector<llvm::Value*> args;
11707330f729Sjoerg   args.push_back(namedValues["exceptTypeToThrow"]);
11717330f729Sjoerg   builder.CreateInvoke(&toInvoke,
11727330f729Sjoerg                        normalBlock,
11737330f729Sjoerg                        exceptionBlock,
11747330f729Sjoerg                        args);
11757330f729Sjoerg 
11767330f729Sjoerg   // End Block
11777330f729Sjoerg 
11787330f729Sjoerg   builder.SetInsertPoint(endBlock);
11797330f729Sjoerg 
11807330f729Sjoerg   generateStringPrint(context,
11817330f729Sjoerg                       module,
11827330f729Sjoerg                       builder,
11837330f729Sjoerg                       "Gen: In end block: exiting in " + ourId + ".\n",
11847330f729Sjoerg                       USE_GLOBAL_STR_CONSTS);
11857330f729Sjoerg   llvm::Function *deleteOurException = module.getFunction("deleteOurException");
11867330f729Sjoerg 
11877330f729Sjoerg   // Note: function handles NULL exceptions
11887330f729Sjoerg   builder.CreateCall(deleteOurException,
11897330f729Sjoerg                      builder.CreateLoad(exceptionStorage));
11907330f729Sjoerg   builder.CreateRetVoid();
11917330f729Sjoerg 
11927330f729Sjoerg   // Normal Block
11937330f729Sjoerg 
11947330f729Sjoerg   builder.SetInsertPoint(normalBlock);
11957330f729Sjoerg 
11967330f729Sjoerg   generateStringPrint(context,
11977330f729Sjoerg                       module,
11987330f729Sjoerg                       builder,
11997330f729Sjoerg                       "Gen: No exception in " + ourId + "!\n",
12007330f729Sjoerg                       USE_GLOBAL_STR_CONSTS);
12017330f729Sjoerg 
12027330f729Sjoerg   // Finally block is always called
12037330f729Sjoerg   builder.CreateBr(finallyBlock);
12047330f729Sjoerg 
12057330f729Sjoerg   // Unwind Resume Block
12067330f729Sjoerg 
12077330f729Sjoerg   builder.SetInsertPoint(unwindResumeBlock);
12087330f729Sjoerg 
12097330f729Sjoerg   builder.CreateResume(builder.CreateLoad(caughtResultStorage));
12107330f729Sjoerg 
12117330f729Sjoerg   // Exception Block
12127330f729Sjoerg 
12137330f729Sjoerg   builder.SetInsertPoint(exceptionBlock);
12147330f729Sjoerg 
12157330f729Sjoerg   llvm::Function *personality = module.getFunction("ourPersonality");
12167330f729Sjoerg   ret->setPersonalityFn(personality);
12177330f729Sjoerg 
12187330f729Sjoerg   llvm::LandingPadInst *caughtResult =
12197330f729Sjoerg     builder.CreateLandingPad(ourCaughtResultType,
12207330f729Sjoerg                              numExceptionsToCatch,
12217330f729Sjoerg                              "landingPad");
12227330f729Sjoerg 
12237330f729Sjoerg   caughtResult->setCleanup(true);
12247330f729Sjoerg 
12257330f729Sjoerg   for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
12267330f729Sjoerg     // Set up type infos to be caught
12277330f729Sjoerg     caughtResult->addClause(module.getGlobalVariable(
12287330f729Sjoerg                              ourTypeInfoNames[exceptionTypesToCatch[i]]));
12297330f729Sjoerg   }
12307330f729Sjoerg 
12317330f729Sjoerg   llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0);
12327330f729Sjoerg   llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1);
12337330f729Sjoerg 
12347330f729Sjoerg   // FIXME: Redundant storage which, beyond utilizing value of
12357330f729Sjoerg   //        caughtResultStore for unwindException storage, may be alleviated
12367330f729Sjoerg   //        altogether with a block rearrangement
12377330f729Sjoerg   builder.CreateStore(caughtResult, caughtResultStorage);
12387330f729Sjoerg   builder.CreateStore(unwindException, exceptionStorage);
12397330f729Sjoerg   builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag);
12407330f729Sjoerg 
12417330f729Sjoerg   // Retrieve exception_class member from thrown exception
12427330f729Sjoerg   // (_Unwind_Exception instance). This member tells us whether or not
12437330f729Sjoerg   // the exception is foreign.
12447330f729Sjoerg   llvm::Value *unwindExceptionClass =
12457330f729Sjoerg       builder.CreateLoad(builder.CreateStructGEP(
12467330f729Sjoerg           ourUnwindExceptionType,
12477330f729Sjoerg           builder.CreatePointerCast(unwindException,
12487330f729Sjoerg                                     ourUnwindExceptionType->getPointerTo()),
12497330f729Sjoerg           0));
12507330f729Sjoerg 
12517330f729Sjoerg   // Branch to the externalExceptionBlock if the exception is foreign or
12527330f729Sjoerg   // to a catch router if not. Either way the finally block will be run.
12537330f729Sjoerg   builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass,
12547330f729Sjoerg                             llvm::ConstantInt::get(builder.getInt64Ty(),
12557330f729Sjoerg                                                    ourBaseExceptionClass)),
12567330f729Sjoerg                        exceptionRouteBlock,
12577330f729Sjoerg                        externalExceptionBlock);
12587330f729Sjoerg 
12597330f729Sjoerg   // External Exception Block
12607330f729Sjoerg 
12617330f729Sjoerg   builder.SetInsertPoint(externalExceptionBlock);
12627330f729Sjoerg 
12637330f729Sjoerg   generateStringPrint(context,
12647330f729Sjoerg                       module,
12657330f729Sjoerg                       builder,
12667330f729Sjoerg                       "Gen: Foreign exception received.\n",
12677330f729Sjoerg                       USE_GLOBAL_STR_CONSTS);
12687330f729Sjoerg 
12697330f729Sjoerg   // Branch to the finally block
12707330f729Sjoerg   builder.CreateBr(finallyBlock);
12717330f729Sjoerg 
12727330f729Sjoerg   // Exception Route Block
12737330f729Sjoerg 
12747330f729Sjoerg   builder.SetInsertPoint(exceptionRouteBlock);
12757330f729Sjoerg 
12767330f729Sjoerg   // Casts exception pointer (_Unwind_Exception instance) to parent
12777330f729Sjoerg   // (OurException instance).
12787330f729Sjoerg   //
12797330f729Sjoerg   // Note: ourBaseFromUnwindOffset is usually negative
12807330f729Sjoerg   llvm::Value *typeInfoThrown = builder.CreatePointerCast(
12817330f729Sjoerg                                   builder.CreateConstGEP1_64(unwindException,
12827330f729Sjoerg                                                        ourBaseFromUnwindOffset),
12837330f729Sjoerg                                   ourExceptionType->getPointerTo());
12847330f729Sjoerg 
12857330f729Sjoerg   // Retrieve thrown exception type info type
12867330f729Sjoerg   //
12877330f729Sjoerg   // Note: Index is not relative to pointer but instead to structure
12887330f729Sjoerg   //       unlike a true getelementptr (GEP) instruction
12897330f729Sjoerg   typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0);
12907330f729Sjoerg 
12917330f729Sjoerg   llvm::Value *typeInfoThrownType =
12927330f729Sjoerg       builder.CreateStructGEP(builder.getInt8PtrTy(), typeInfoThrown, 0);
12937330f729Sjoerg 
12947330f729Sjoerg   generateIntegerPrint(context,
12957330f729Sjoerg                        module,
12967330f729Sjoerg                        builder,
12977330f729Sjoerg                        *toPrint32Int,
12987330f729Sjoerg                        *(builder.CreateLoad(typeInfoThrownType)),
12997330f729Sjoerg                        "Gen: Exception type <%d> received (stack unwound) "
13007330f729Sjoerg                        " in " +
13017330f729Sjoerg                        ourId +
13027330f729Sjoerg                        ".\n",
13037330f729Sjoerg                        USE_GLOBAL_STR_CONSTS);
13047330f729Sjoerg 
13057330f729Sjoerg   // Route to matched type info catch block or run cleanup finally block
13067330f729Sjoerg   llvm::SwitchInst *switchToCatchBlock = builder.CreateSwitch(retTypeInfoIndex,
13077330f729Sjoerg                                                           finallyBlock,
13087330f729Sjoerg                                                           numExceptionsToCatch);
13097330f729Sjoerg 
13107330f729Sjoerg   unsigned nextTypeToCatch;
13117330f729Sjoerg 
13127330f729Sjoerg   for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
13137330f729Sjoerg     nextTypeToCatch = i - 1;
13147330f729Sjoerg     switchToCatchBlock->addCase(llvm::ConstantInt::get(
13157330f729Sjoerg                                    llvm::Type::getInt32Ty(context), i),
13167330f729Sjoerg                                 catchBlocks[nextTypeToCatch]);
13177330f729Sjoerg   }
13187330f729Sjoerg 
13197330f729Sjoerg   llvm::verifyFunction(*ret);
13207330f729Sjoerg   fpm.run(*ret);
13217330f729Sjoerg 
13227330f729Sjoerg   return(ret);
13237330f729Sjoerg }
13247330f729Sjoerg 
13257330f729Sjoerg 
13267330f729Sjoerg /// Generates function which throws either an exception matched to a runtime
13277330f729Sjoerg /// determined type info type (argument to generated function), or if this
13287330f729Sjoerg /// runtime value matches nativeThrowType, throws a foreign exception by
13297330f729Sjoerg /// calling nativeThrowFunct.
13307330f729Sjoerg /// @param module code for module instance
13317330f729Sjoerg /// @param builder builder instance
13327330f729Sjoerg /// @param fpm a function pass manager holding optional IR to IR
13337330f729Sjoerg ///        transformations
13347330f729Sjoerg /// @param ourId id used to printing purposes
13357330f729Sjoerg /// @param nativeThrowType a runtime argument of this value results in
13367330f729Sjoerg ///        nativeThrowFunct being called to generate/throw exception.
13377330f729Sjoerg /// @param nativeThrowFunct function which will throw a foreign exception
13387330f729Sjoerg ///        if the above nativeThrowType matches generated function's arg.
13397330f729Sjoerg /// @returns generated function
13407330f729Sjoerg static llvm::Function *
createThrowExceptionFunction(llvm::Module & module,llvm::IRBuilder<> & builder,llvm::legacy::FunctionPassManager & fpm,std::string ourId,int32_t nativeThrowType,llvm::Function & nativeThrowFunct)13417330f729Sjoerg createThrowExceptionFunction(llvm::Module &module, llvm::IRBuilder<> &builder,
13427330f729Sjoerg                              llvm::legacy::FunctionPassManager &fpm,
13437330f729Sjoerg                              std::string ourId, int32_t nativeThrowType,
13447330f729Sjoerg                              llvm::Function &nativeThrowFunct) {
13457330f729Sjoerg   llvm::LLVMContext &context = module.getContext();
13467330f729Sjoerg   namedValues.clear();
13477330f729Sjoerg   ArgTypes unwindArgTypes;
13487330f729Sjoerg   unwindArgTypes.push_back(builder.getInt32Ty());
13497330f729Sjoerg   ArgNames unwindArgNames;
13507330f729Sjoerg   unwindArgNames.push_back("exceptTypeToThrow");
13517330f729Sjoerg 
13527330f729Sjoerg   llvm::Function *ret = createFunction(module,
13537330f729Sjoerg                                        builder.getVoidTy(),
13547330f729Sjoerg                                        unwindArgTypes,
13557330f729Sjoerg                                        unwindArgNames,
13567330f729Sjoerg                                        ourId,
13577330f729Sjoerg                                        llvm::Function::ExternalLinkage,
13587330f729Sjoerg                                        false,
13597330f729Sjoerg                                        false);
13607330f729Sjoerg 
13617330f729Sjoerg   // Throws either one of our exception or a native C++ exception depending
13627330f729Sjoerg   // on a runtime argument value containing a type info type.
13637330f729Sjoerg   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
13647330f729Sjoerg                                                           "entry",
13657330f729Sjoerg                                                           ret);
13667330f729Sjoerg   // Throws a foreign exception
13677330f729Sjoerg   llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context,
13687330f729Sjoerg                                                                 "nativeThrow",
13697330f729Sjoerg                                                                 ret);
13707330f729Sjoerg   // Throws one of our Exceptions
13717330f729Sjoerg   llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context,
13727330f729Sjoerg                                                              "generatedThrow",
13737330f729Sjoerg                                                              ret);
13747330f729Sjoerg   // Retrieved runtime type info type to throw
13757330f729Sjoerg   llvm::Value *exceptionType = namedValues["exceptTypeToThrow"];
13767330f729Sjoerg 
13777330f729Sjoerg   // nativeThrowBlock block
13787330f729Sjoerg 
13797330f729Sjoerg   builder.SetInsertPoint(nativeThrowBlock);
13807330f729Sjoerg 
13817330f729Sjoerg   // Throws foreign exception
13827330f729Sjoerg   builder.CreateCall(&nativeThrowFunct, exceptionType);
13837330f729Sjoerg   builder.CreateUnreachable();
13847330f729Sjoerg 
13857330f729Sjoerg   // entry block
13867330f729Sjoerg 
13877330f729Sjoerg   builder.SetInsertPoint(entryBlock);
13887330f729Sjoerg 
13897330f729Sjoerg   llvm::Function *toPrint32Int = module.getFunction("print32Int");
13907330f729Sjoerg   generateIntegerPrint(context,
13917330f729Sjoerg                        module,
13927330f729Sjoerg                        builder,
13937330f729Sjoerg                        *toPrint32Int,
13947330f729Sjoerg                        *exceptionType,
13957330f729Sjoerg                        "\nGen: About to throw exception type <%d> in " +
13967330f729Sjoerg                        ourId +
13977330f729Sjoerg                        ".\n",
13987330f729Sjoerg                        USE_GLOBAL_STR_CONSTS);
13997330f729Sjoerg 
14007330f729Sjoerg   // Switches on runtime type info type value to determine whether or not
14017330f729Sjoerg   // a foreign exception is thrown. Defaults to throwing one of our
14027330f729Sjoerg   // generated exceptions.
14037330f729Sjoerg   llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType,
14047330f729Sjoerg                                                      generatedThrowBlock,
14057330f729Sjoerg                                                      1);
14067330f729Sjoerg 
14077330f729Sjoerg   theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
14087330f729Sjoerg                                             nativeThrowType),
14097330f729Sjoerg                      nativeThrowBlock);
14107330f729Sjoerg 
14117330f729Sjoerg   // generatedThrow block
14127330f729Sjoerg 
14137330f729Sjoerg   builder.SetInsertPoint(generatedThrowBlock);
14147330f729Sjoerg 
14157330f729Sjoerg   llvm::Function *createOurException = module.getFunction("createOurException");
14167330f729Sjoerg   llvm::Function *raiseOurException = module.getFunction(
14177330f729Sjoerg                                         "_Unwind_RaiseException");
14187330f729Sjoerg 
14197330f729Sjoerg   // Creates exception to throw with runtime type info type.
14207330f729Sjoerg   llvm::Value *exception = builder.CreateCall(createOurException,
14217330f729Sjoerg                                               namedValues["exceptTypeToThrow"]);
14227330f729Sjoerg 
14237330f729Sjoerg   // Throw generated Exception
14247330f729Sjoerg   builder.CreateCall(raiseOurException, exception);
14257330f729Sjoerg   builder.CreateUnreachable();
14267330f729Sjoerg 
14277330f729Sjoerg   llvm::verifyFunction(*ret);
14287330f729Sjoerg   fpm.run(*ret);
14297330f729Sjoerg 
14307330f729Sjoerg   return(ret);
14317330f729Sjoerg }
14327330f729Sjoerg 
14337330f729Sjoerg static void createStandardUtilityFunctions(unsigned numTypeInfos,
14347330f729Sjoerg                                            llvm::Module &module,
14357330f729Sjoerg                                            llvm::IRBuilder<> &builder);
14367330f729Sjoerg 
14377330f729Sjoerg /// Creates test code by generating and organizing these functions into the
14387330f729Sjoerg /// test case. The test case consists of an outer function setup to invoke
14397330f729Sjoerg /// an inner function within an environment having multiple catch and single
14407330f729Sjoerg /// finally blocks. This inner function is also setup to invoke a throw
14417330f729Sjoerg /// function within an evironment similar in nature to the outer function's
14427330f729Sjoerg /// catch and finally blocks. Each of these two functions catch mutually
14437330f729Sjoerg /// exclusive subsets (even or odd) of the type info types configured
14447330f729Sjoerg /// for this this. All generated functions have a runtime argument which
14457330f729Sjoerg /// holds a type info type to throw that each function takes and passes it
14467330f729Sjoerg /// to the inner one if such a inner function exists. This type info type is
14477330f729Sjoerg /// looked at by the generated throw function to see whether or not it should
14487330f729Sjoerg /// throw a generated exception with the same type info type, or instead call
14497330f729Sjoerg /// a supplied a function which in turn will throw a foreign exception.
14507330f729Sjoerg /// @param module code for module instance
14517330f729Sjoerg /// @param builder builder instance
14527330f729Sjoerg /// @param fpm a function pass manager holding optional IR to IR
14537330f729Sjoerg ///        transformations
14547330f729Sjoerg /// @param nativeThrowFunctName name of external function which will throw
14557330f729Sjoerg ///        a foreign exception
14567330f729Sjoerg /// @returns outermost generated test function.
14577330f729Sjoerg llvm::Function *
createUnwindExceptionTest(llvm::Module & module,llvm::IRBuilder<> & builder,llvm::legacy::FunctionPassManager & fpm,std::string nativeThrowFunctName)14587330f729Sjoerg createUnwindExceptionTest(llvm::Module &module, llvm::IRBuilder<> &builder,
14597330f729Sjoerg                           llvm::legacy::FunctionPassManager &fpm,
14607330f729Sjoerg                           std::string nativeThrowFunctName) {
14617330f729Sjoerg   // Number of type infos to generate
14627330f729Sjoerg   unsigned numTypeInfos = 6;
14637330f729Sjoerg 
14647330f729Sjoerg   // Initialze intrisics and external functions to use along with exception
14657330f729Sjoerg   // and type info globals.
14667330f729Sjoerg   createStandardUtilityFunctions(numTypeInfos,
14677330f729Sjoerg                                  module,
14687330f729Sjoerg                                  builder);
14697330f729Sjoerg   llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName);
14707330f729Sjoerg 
14717330f729Sjoerg   // Create exception throw function using the value ~0 to cause
14727330f729Sjoerg   // foreign exceptions to be thrown.
14737330f729Sjoerg   llvm::Function *throwFunct = createThrowExceptionFunction(module,
14747330f729Sjoerg                                                             builder,
14757330f729Sjoerg                                                             fpm,
14767330f729Sjoerg                                                             "throwFunct",
14777330f729Sjoerg                                                             ~0,
14787330f729Sjoerg                                                             *nativeThrowFunct);
14797330f729Sjoerg   // Inner function will catch even type infos
14807330f729Sjoerg   unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
14817330f729Sjoerg   size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
14827330f729Sjoerg                                     sizeof(unsigned);
14837330f729Sjoerg 
14847330f729Sjoerg   // Generate inner function.
14857330f729Sjoerg   llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module,
14867330f729Sjoerg                                                     builder,
14877330f729Sjoerg                                                     fpm,
14887330f729Sjoerg                                                     *throwFunct,
14897330f729Sjoerg                                                     "innerCatchFunct",
14907330f729Sjoerg                                                     numExceptionTypesToCatch,
14917330f729Sjoerg                                                     innerExceptionTypesToCatch);
14927330f729Sjoerg 
14937330f729Sjoerg   // Outer function will catch odd type infos
14947330f729Sjoerg   unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
14957330f729Sjoerg   numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
14967330f729Sjoerg   sizeof(unsigned);
14977330f729Sjoerg 
14987330f729Sjoerg   // Generate outer function
14997330f729Sjoerg   llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module,
15007330f729Sjoerg                                                     builder,
15017330f729Sjoerg                                                     fpm,
15027330f729Sjoerg                                                     *innerCatchFunct,
15037330f729Sjoerg                                                     "outerCatchFunct",
15047330f729Sjoerg                                                     numExceptionTypesToCatch,
15057330f729Sjoerg                                                     outerExceptionTypesToCatch);
15067330f729Sjoerg 
15077330f729Sjoerg   // Return outer function to run
15087330f729Sjoerg   return(outerCatchFunct);
15097330f729Sjoerg }
15107330f729Sjoerg 
15117330f729Sjoerg namespace {
15127330f729Sjoerg /// Represents our foreign exceptions
15137330f729Sjoerg class OurCppRunException : public std::runtime_error {
15147330f729Sjoerg public:
OurCppRunException(const std::string reason)15157330f729Sjoerg   OurCppRunException(const std::string reason) :
15167330f729Sjoerg   std::runtime_error(reason) {}
15177330f729Sjoerg 
OurCppRunException(const OurCppRunException & toCopy)15187330f729Sjoerg   OurCppRunException (const OurCppRunException &toCopy) :
15197330f729Sjoerg   std::runtime_error(toCopy) {}
15207330f729Sjoerg 
operator =(const OurCppRunException & toCopy)15217330f729Sjoerg   OurCppRunException &operator = (const OurCppRunException &toCopy) {
15227330f729Sjoerg     return(reinterpret_cast<OurCppRunException&>(
15237330f729Sjoerg                                  std::runtime_error::operator=(toCopy)));
15247330f729Sjoerg   }
15257330f729Sjoerg 
~OurCppRunException(void)15267330f729Sjoerg   ~OurCppRunException(void) throw() override {}
15277330f729Sjoerg };
15287330f729Sjoerg } // end anonymous namespace
15297330f729Sjoerg 
15307330f729Sjoerg /// Throws foreign C++ exception.
15317330f729Sjoerg /// @param ignoreIt unused parameter that allows function to match implied
15327330f729Sjoerg ///        generated function contract.
15337330f729Sjoerg extern "C"
throwCppException(int32_t ignoreIt)15347330f729Sjoerg void throwCppException (int32_t ignoreIt) {
15357330f729Sjoerg   throw(OurCppRunException("thrown by throwCppException(...)"));
15367330f729Sjoerg }
15377330f729Sjoerg 
15387330f729Sjoerg typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
15397330f729Sjoerg 
15407330f729Sjoerg /// This is a test harness which runs test by executing generated
15417330f729Sjoerg /// function with a type info type to throw. Harness wraps the execution
15427330f729Sjoerg /// of generated function in a C++ try catch clause.
15437330f729Sjoerg /// @param engine execution engine to use for executing generated function.
15447330f729Sjoerg ///        This demo program expects this to be a JIT instance for demo
15457330f729Sjoerg ///        purposes.
15467330f729Sjoerg /// @param function generated test function to run
15477330f729Sjoerg /// @param typeToThrow type info type of generated exception to throw, or
15487330f729Sjoerg ///        indicator to cause foreign exception to be thrown.
15497330f729Sjoerg static
runExceptionThrow(llvm::ExecutionEngine * engine,llvm::Function * function,int32_t typeToThrow)15507330f729Sjoerg void runExceptionThrow(llvm::ExecutionEngine *engine,
15517330f729Sjoerg                        llvm::Function *function,
15527330f729Sjoerg                        int32_t typeToThrow) {
15537330f729Sjoerg 
15547330f729Sjoerg   // Find test's function pointer
15557330f729Sjoerg   OurExceptionThrowFunctType functPtr =
15567330f729Sjoerg     reinterpret_cast<OurExceptionThrowFunctType>(
15577330f729Sjoerg        reinterpret_cast<intptr_t>(engine->getPointerToFunction(function)));
15587330f729Sjoerg 
15597330f729Sjoerg   try {
15607330f729Sjoerg     // Run test
15617330f729Sjoerg     (*functPtr)(typeToThrow);
15627330f729Sjoerg   }
15637330f729Sjoerg   catch (OurCppRunException exc) {
15647330f729Sjoerg     // Catch foreign C++ exception
15657330f729Sjoerg     fprintf(stderr,
15667330f729Sjoerg             "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
15677330f729Sjoerg             "with reason: %s.\n",
15687330f729Sjoerg             exc.what());
15697330f729Sjoerg   }
15707330f729Sjoerg   catch (...) {
15717330f729Sjoerg     // Catch all exceptions including our generated ones. This latter
15727330f729Sjoerg     // functionality works according to the example in rules 1.6.4 of
15737330f729Sjoerg     // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22),
15747330f729Sjoerg     // given that these will be exceptions foreign to C++
15757330f729Sjoerg     // (the _Unwind_Exception::exception_class should be different from
15767330f729Sjoerg     // the one used by C++).
15777330f729Sjoerg     fprintf(stderr,
15787330f729Sjoerg             "\nrunExceptionThrow(...):In C++ catch all.\n");
15797330f729Sjoerg   }
15807330f729Sjoerg }
15817330f729Sjoerg 
15827330f729Sjoerg //
15837330f729Sjoerg // End test functions
15847330f729Sjoerg //
15857330f729Sjoerg 
15867330f729Sjoerg typedef llvm::ArrayRef<llvm::Type*> TypeArray;
15877330f729Sjoerg 
15887330f729Sjoerg /// This initialization routine creates type info globals and
15897330f729Sjoerg /// adds external function declarations to module.
15907330f729Sjoerg /// @param numTypeInfos number of linear type info associated type info types
15917330f729Sjoerg ///        to create as GlobalVariable instances, starting with the value 1.
15927330f729Sjoerg /// @param module code for module instance
15937330f729Sjoerg /// @param builder builder instance
createStandardUtilityFunctions(unsigned numTypeInfos,llvm::Module & module,llvm::IRBuilder<> & builder)15947330f729Sjoerg static void createStandardUtilityFunctions(unsigned numTypeInfos,
15957330f729Sjoerg                                            llvm::Module &module,
15967330f729Sjoerg                                            llvm::IRBuilder<> &builder) {
15977330f729Sjoerg 
15987330f729Sjoerg   llvm::LLVMContext &context = module.getContext();
15997330f729Sjoerg 
16007330f729Sjoerg   // Exception initializations
16017330f729Sjoerg 
16027330f729Sjoerg   // Setup exception catch state
16037330f729Sjoerg   ourExceptionNotThrownState =
16047330f729Sjoerg     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
16057330f729Sjoerg   ourExceptionThrownState =
16067330f729Sjoerg     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
16077330f729Sjoerg   ourExceptionCaughtState =
16087330f729Sjoerg     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
16097330f729Sjoerg 
16107330f729Sjoerg 
16117330f729Sjoerg 
16127330f729Sjoerg   // Create our type info type
16137330f729Sjoerg   ourTypeInfoType = llvm::StructType::get(context,
16147330f729Sjoerg                                           TypeArray(builder.getInt32Ty()));
16157330f729Sjoerg 
16167330f729Sjoerg   llvm::Type *caughtResultFieldTypes[] = {
16177330f729Sjoerg     builder.getInt8PtrTy(),
16187330f729Sjoerg     builder.getInt32Ty()
16197330f729Sjoerg   };
16207330f729Sjoerg 
16217330f729Sjoerg   // Create our landingpad result type
16227330f729Sjoerg   ourCaughtResultType = llvm::StructType::get(context,
16237330f729Sjoerg                                             TypeArray(caughtResultFieldTypes));
16247330f729Sjoerg 
16257330f729Sjoerg   // Create OurException type
16267330f729Sjoerg   ourExceptionType = llvm::StructType::get(context,
16277330f729Sjoerg                                            TypeArray(ourTypeInfoType));
16287330f729Sjoerg 
16297330f729Sjoerg   // Create portion of _Unwind_Exception type
16307330f729Sjoerg   //
16317330f729Sjoerg   // Note: Declaring only a portion of the _Unwind_Exception struct.
16327330f729Sjoerg   //       Does this cause problems?
16337330f729Sjoerg   ourUnwindExceptionType =
16347330f729Sjoerg     llvm::StructType::get(context,
16357330f729Sjoerg                     TypeArray(builder.getInt64Ty()));
16367330f729Sjoerg 
16377330f729Sjoerg   struct OurBaseException_t dummyException;
16387330f729Sjoerg 
16397330f729Sjoerg   // Calculate offset of OurException::unwindException member.
16407330f729Sjoerg   ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
16417330f729Sjoerg                             ((uintptr_t) &(dummyException.unwindException));
16427330f729Sjoerg 
16437330f729Sjoerg #ifdef DEBUG
16447330f729Sjoerg   fprintf(stderr,
16457330f729Sjoerg           "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
16467330f729Sjoerg           "= %" PRIi64 ", sizeof(struct OurBaseException_t) - "
16477330f729Sjoerg           "sizeof(struct _Unwind_Exception) = %lu.\n",
16487330f729Sjoerg           ourBaseFromUnwindOffset,
16497330f729Sjoerg           sizeof(struct OurBaseException_t) -
16507330f729Sjoerg           sizeof(struct _Unwind_Exception));
16517330f729Sjoerg #endif
16527330f729Sjoerg 
16537330f729Sjoerg   size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
16547330f729Sjoerg 
16557330f729Sjoerg   // Create our _Unwind_Exception::exception_class value
16567330f729Sjoerg   ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
16577330f729Sjoerg 
16587330f729Sjoerg   // Type infos
16597330f729Sjoerg 
16607330f729Sjoerg   std::string baseStr = "typeInfo", typeInfoName;
16617330f729Sjoerg   std::ostringstream typeInfoNameBuilder;
16627330f729Sjoerg   std::vector<llvm::Constant*> structVals;
16637330f729Sjoerg 
16647330f729Sjoerg   llvm::Constant *nextStruct;
16657330f729Sjoerg 
16667330f729Sjoerg   // Generate each type info
16677330f729Sjoerg   //
16687330f729Sjoerg   // Note: First type info is not used.
16697330f729Sjoerg   for (unsigned i = 0; i <= numTypeInfos; ++i) {
16707330f729Sjoerg     structVals.clear();
16717330f729Sjoerg     structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
16727330f729Sjoerg     nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
16737330f729Sjoerg 
16747330f729Sjoerg     typeInfoNameBuilder.str("");
16757330f729Sjoerg     typeInfoNameBuilder << baseStr << i;
16767330f729Sjoerg     typeInfoName = typeInfoNameBuilder.str();
16777330f729Sjoerg 
16787330f729Sjoerg     // Note: Does not seem to work without allocation
16797330f729Sjoerg     new llvm::GlobalVariable(module,
16807330f729Sjoerg                              ourTypeInfoType,
16817330f729Sjoerg                              true,
16827330f729Sjoerg                              llvm::GlobalValue::ExternalLinkage,
16837330f729Sjoerg                              nextStruct,
16847330f729Sjoerg                              typeInfoName);
16857330f729Sjoerg 
16867330f729Sjoerg     ourTypeInfoNames.push_back(typeInfoName);
16877330f729Sjoerg     ourTypeInfoNamesIndex[i] = typeInfoName;
16887330f729Sjoerg   }
16897330f729Sjoerg 
16907330f729Sjoerg   ArgNames argNames;
16917330f729Sjoerg   ArgTypes argTypes;
16927330f729Sjoerg   llvm::Function *funct = NULL;
16937330f729Sjoerg 
16947330f729Sjoerg   // print32Int
16957330f729Sjoerg 
16967330f729Sjoerg   llvm::Type *retType = builder.getVoidTy();
16977330f729Sjoerg 
16987330f729Sjoerg   argTypes.clear();
16997330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
17007330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
17017330f729Sjoerg 
17027330f729Sjoerg   argNames.clear();
17037330f729Sjoerg 
17047330f729Sjoerg   createFunction(module,
17057330f729Sjoerg                  retType,
17067330f729Sjoerg                  argTypes,
17077330f729Sjoerg                  argNames,
17087330f729Sjoerg                  "print32Int",
17097330f729Sjoerg                  llvm::Function::ExternalLinkage,
17107330f729Sjoerg                  true,
17117330f729Sjoerg                  false);
17127330f729Sjoerg 
17137330f729Sjoerg   // print64Int
17147330f729Sjoerg 
17157330f729Sjoerg   retType = builder.getVoidTy();
17167330f729Sjoerg 
17177330f729Sjoerg   argTypes.clear();
17187330f729Sjoerg   argTypes.push_back(builder.getInt64Ty());
17197330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
17207330f729Sjoerg 
17217330f729Sjoerg   argNames.clear();
17227330f729Sjoerg 
17237330f729Sjoerg   createFunction(module,
17247330f729Sjoerg                  retType,
17257330f729Sjoerg                  argTypes,
17267330f729Sjoerg                  argNames,
17277330f729Sjoerg                  "print64Int",
17287330f729Sjoerg                  llvm::Function::ExternalLinkage,
17297330f729Sjoerg                  true,
17307330f729Sjoerg                  false);
17317330f729Sjoerg 
17327330f729Sjoerg   // printStr
17337330f729Sjoerg 
17347330f729Sjoerg   retType = builder.getVoidTy();
17357330f729Sjoerg 
17367330f729Sjoerg   argTypes.clear();
17377330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
17387330f729Sjoerg 
17397330f729Sjoerg   argNames.clear();
17407330f729Sjoerg 
17417330f729Sjoerg   createFunction(module,
17427330f729Sjoerg                  retType,
17437330f729Sjoerg                  argTypes,
17447330f729Sjoerg                  argNames,
17457330f729Sjoerg                  "printStr",
17467330f729Sjoerg                  llvm::Function::ExternalLinkage,
17477330f729Sjoerg                  true,
17487330f729Sjoerg                  false);
17497330f729Sjoerg 
17507330f729Sjoerg   // throwCppException
17517330f729Sjoerg 
17527330f729Sjoerg   retType = builder.getVoidTy();
17537330f729Sjoerg 
17547330f729Sjoerg   argTypes.clear();
17557330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
17567330f729Sjoerg 
17577330f729Sjoerg   argNames.clear();
17587330f729Sjoerg 
17597330f729Sjoerg   createFunction(module,
17607330f729Sjoerg                  retType,
17617330f729Sjoerg                  argTypes,
17627330f729Sjoerg                  argNames,
17637330f729Sjoerg                  "throwCppException",
17647330f729Sjoerg                  llvm::Function::ExternalLinkage,
17657330f729Sjoerg                  true,
17667330f729Sjoerg                  false);
17677330f729Sjoerg 
17687330f729Sjoerg   // deleteOurException
17697330f729Sjoerg 
17707330f729Sjoerg   retType = builder.getVoidTy();
17717330f729Sjoerg 
17727330f729Sjoerg   argTypes.clear();
17737330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
17747330f729Sjoerg 
17757330f729Sjoerg   argNames.clear();
17767330f729Sjoerg 
17777330f729Sjoerg   createFunction(module,
17787330f729Sjoerg                  retType,
17797330f729Sjoerg                  argTypes,
17807330f729Sjoerg                  argNames,
17817330f729Sjoerg                  "deleteOurException",
17827330f729Sjoerg                  llvm::Function::ExternalLinkage,
17837330f729Sjoerg                  true,
17847330f729Sjoerg                  false);
17857330f729Sjoerg 
17867330f729Sjoerg   // createOurException
17877330f729Sjoerg 
17887330f729Sjoerg   retType = builder.getInt8PtrTy();
17897330f729Sjoerg 
17907330f729Sjoerg   argTypes.clear();
17917330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
17927330f729Sjoerg 
17937330f729Sjoerg   argNames.clear();
17947330f729Sjoerg 
17957330f729Sjoerg   createFunction(module,
17967330f729Sjoerg                  retType,
17977330f729Sjoerg                  argTypes,
17987330f729Sjoerg                  argNames,
17997330f729Sjoerg                  "createOurException",
18007330f729Sjoerg                  llvm::Function::ExternalLinkage,
18017330f729Sjoerg                  true,
18027330f729Sjoerg                  false);
18037330f729Sjoerg 
18047330f729Sjoerg   // _Unwind_RaiseException
18057330f729Sjoerg 
18067330f729Sjoerg   retType = builder.getInt32Ty();
18077330f729Sjoerg 
18087330f729Sjoerg   argTypes.clear();
18097330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
18107330f729Sjoerg 
18117330f729Sjoerg   argNames.clear();
18127330f729Sjoerg 
18137330f729Sjoerg   funct = createFunction(module,
18147330f729Sjoerg                          retType,
18157330f729Sjoerg                          argTypes,
18167330f729Sjoerg                          argNames,
18177330f729Sjoerg                          "_Unwind_RaiseException",
18187330f729Sjoerg                          llvm::Function::ExternalLinkage,
18197330f729Sjoerg                          true,
18207330f729Sjoerg                          false);
18217330f729Sjoerg 
18227330f729Sjoerg   funct->setDoesNotReturn();
18237330f729Sjoerg 
18247330f729Sjoerg   // _Unwind_Resume
18257330f729Sjoerg 
18267330f729Sjoerg   retType = builder.getInt32Ty();
18277330f729Sjoerg 
18287330f729Sjoerg   argTypes.clear();
18297330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
18307330f729Sjoerg 
18317330f729Sjoerg   argNames.clear();
18327330f729Sjoerg 
18337330f729Sjoerg   funct = createFunction(module,
18347330f729Sjoerg                          retType,
18357330f729Sjoerg                          argTypes,
18367330f729Sjoerg                          argNames,
18377330f729Sjoerg                          "_Unwind_Resume",
18387330f729Sjoerg                          llvm::Function::ExternalLinkage,
18397330f729Sjoerg                          true,
18407330f729Sjoerg                          false);
18417330f729Sjoerg 
18427330f729Sjoerg   funct->setDoesNotReturn();
18437330f729Sjoerg 
18447330f729Sjoerg   // ourPersonality
18457330f729Sjoerg 
18467330f729Sjoerg   retType = builder.getInt32Ty();
18477330f729Sjoerg 
18487330f729Sjoerg   argTypes.clear();
18497330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
18507330f729Sjoerg   argTypes.push_back(builder.getInt32Ty());
18517330f729Sjoerg   argTypes.push_back(builder.getInt64Ty());
18527330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
18537330f729Sjoerg   argTypes.push_back(builder.getInt8PtrTy());
18547330f729Sjoerg 
18557330f729Sjoerg   argNames.clear();
18567330f729Sjoerg 
18577330f729Sjoerg   createFunction(module,
18587330f729Sjoerg                  retType,
18597330f729Sjoerg                  argTypes,
18607330f729Sjoerg                  argNames,
18617330f729Sjoerg                  "ourPersonality",
18627330f729Sjoerg                  llvm::Function::ExternalLinkage,
18637330f729Sjoerg                  true,
18647330f729Sjoerg                  false);
18657330f729Sjoerg 
18667330f729Sjoerg   // llvm.eh.typeid.for intrinsic
18677330f729Sjoerg 
18687330f729Sjoerg   getDeclaration(&module, llvm::Intrinsic::eh_typeid_for);
18697330f729Sjoerg }
18707330f729Sjoerg 
18717330f729Sjoerg 
18727330f729Sjoerg //===----------------------------------------------------------------------===//
18737330f729Sjoerg // Main test driver code.
18747330f729Sjoerg //===----------------------------------------------------------------------===//
18757330f729Sjoerg 
18767330f729Sjoerg /// Demo main routine which takes the type info types to throw. A test will
18777330f729Sjoerg /// be run for each given type info type. While type info types with the value
18787330f729Sjoerg /// of -1 will trigger a foreign C++ exception to be thrown; type info types
18797330f729Sjoerg /// <= 6 and >= 1 will be caught by test functions; and type info types > 6
18807330f729Sjoerg /// will result in exceptions which pass through to the test harness. All other
18817330f729Sjoerg /// type info types are not supported and could cause a crash.
main(int argc,char * argv[])18827330f729Sjoerg int main(int argc, char *argv[]) {
18837330f729Sjoerg   if (argc == 1) {
18847330f729Sjoerg     fprintf(stderr,
18857330f729Sjoerg             "\nUsage: ExceptionDemo <exception type to throw> "
18867330f729Sjoerg             "[<type 2>...<type n>].\n"
18877330f729Sjoerg             "   Each type must have the value of 1 - 6 for "
18887330f729Sjoerg             "generated exceptions to be caught;\n"
18897330f729Sjoerg             "   the value -1 for foreign C++ exceptions to be "
18907330f729Sjoerg             "generated and thrown;\n"
18917330f729Sjoerg             "   or the values > 6 for exceptions to be ignored.\n"
18927330f729Sjoerg             "\nTry: ExceptionDemo 2 3 7 -1\n"
18937330f729Sjoerg             "   for a full test.\n\n");
18947330f729Sjoerg     return(0);
18957330f729Sjoerg   }
18967330f729Sjoerg 
18977330f729Sjoerg   // If not set, exception handling will not be turned on
18987330f729Sjoerg   llvm::TargetOptions Opts;
18997330f729Sjoerg 
19007330f729Sjoerg   llvm::InitializeNativeTarget();
19017330f729Sjoerg   llvm::InitializeNativeTargetAsmPrinter();
19027330f729Sjoerg   llvm::LLVMContext Context;
19037330f729Sjoerg   llvm::IRBuilder<> theBuilder(Context);
19047330f729Sjoerg 
19057330f729Sjoerg   // Make the module, which holds all the code.
19067330f729Sjoerg   std::unique_ptr<llvm::Module> Owner =
19077330f729Sjoerg       std::make_unique<llvm::Module>("my cool jit", Context);
19087330f729Sjoerg   llvm::Module *module = Owner.get();
19097330f729Sjoerg 
19107330f729Sjoerg   std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager());
19117330f729Sjoerg 
19127330f729Sjoerg   // Build engine with JIT
19137330f729Sjoerg   llvm::EngineBuilder factory(std::move(Owner));
19147330f729Sjoerg   factory.setEngineKind(llvm::EngineKind::JIT);
19157330f729Sjoerg   factory.setTargetOptions(Opts);
19167330f729Sjoerg   factory.setMCJITMemoryManager(std::move(MemMgr));
19177330f729Sjoerg   llvm::ExecutionEngine *executionEngine = factory.create();
19187330f729Sjoerg 
19197330f729Sjoerg   {
19207330f729Sjoerg     llvm::legacy::FunctionPassManager fpm(module);
19217330f729Sjoerg 
19227330f729Sjoerg     // Set up the optimizer pipeline.
19237330f729Sjoerg     // Start with registering info about how the
19247330f729Sjoerg     // target lays out data structures.
19257330f729Sjoerg     module->setDataLayout(executionEngine->getDataLayout());
19267330f729Sjoerg 
19277330f729Sjoerg     // Optimizations turned on
19287330f729Sjoerg #ifdef ADD_OPT_PASSES
19297330f729Sjoerg 
19307330f729Sjoerg     // Basic AliasAnslysis support for GVN.
19317330f729Sjoerg     fpm.add(llvm::createBasicAliasAnalysisPass());
19327330f729Sjoerg 
19337330f729Sjoerg     // Promote allocas to registers.
19347330f729Sjoerg     fpm.add(llvm::createPromoteMemoryToRegisterPass());
19357330f729Sjoerg 
19367330f729Sjoerg     // Do simple "peephole" optimizations and bit-twiddling optzns.
19377330f729Sjoerg     fpm.add(llvm::createInstructionCombiningPass());
19387330f729Sjoerg 
19397330f729Sjoerg     // Reassociate expressions.
19407330f729Sjoerg     fpm.add(llvm::createReassociatePass());
19417330f729Sjoerg 
19427330f729Sjoerg     // Eliminate Common SubExpressions.
19437330f729Sjoerg     fpm.add(llvm::createGVNPass());
19447330f729Sjoerg 
19457330f729Sjoerg     // Simplify the control flow graph (deleting unreachable
19467330f729Sjoerg     // blocks, etc).
19477330f729Sjoerg     fpm.add(llvm::createCFGSimplificationPass());
19487330f729Sjoerg #endif  // ADD_OPT_PASSES
19497330f729Sjoerg 
19507330f729Sjoerg     fpm.doInitialization();
19517330f729Sjoerg 
19527330f729Sjoerg     // Generate test code using function throwCppException(...) as
19537330f729Sjoerg     // the function which throws foreign exceptions.
19547330f729Sjoerg     llvm::Function *toRun =
19557330f729Sjoerg     createUnwindExceptionTest(*module,
19567330f729Sjoerg                               theBuilder,
19577330f729Sjoerg                               fpm,
19587330f729Sjoerg                               "throwCppException");
19597330f729Sjoerg 
19607330f729Sjoerg     executionEngine->finalizeObject();
19617330f729Sjoerg 
1962*82d56013Sjoerg #ifndef NDEBUG
19637330f729Sjoerg     fprintf(stderr, "\nBegin module dump:\n\n");
19647330f729Sjoerg 
19657330f729Sjoerg     module->dump();
19667330f729Sjoerg 
19677330f729Sjoerg     fprintf(stderr, "\nEnd module dump:\n");
1968*82d56013Sjoerg #endif
19697330f729Sjoerg 
19707330f729Sjoerg     fprintf(stderr, "\n\nBegin Test:\n");
19717330f729Sjoerg 
19727330f729Sjoerg     for (int i = 1; i < argc; ++i) {
19737330f729Sjoerg       // Run test for each argument whose value is the exception
19747330f729Sjoerg       // type to throw.
19757330f729Sjoerg       runExceptionThrow(executionEngine,
19767330f729Sjoerg                         toRun,
19777330f729Sjoerg                         (unsigned) strtoul(argv[i], NULL, 10));
19787330f729Sjoerg     }
19797330f729Sjoerg 
19807330f729Sjoerg     fprintf(stderr, "\nEnd Test:\n\n");
19817330f729Sjoerg   }
19827330f729Sjoerg 
19837330f729Sjoerg   delete executionEngine;
19847330f729Sjoerg 
19857330f729Sjoerg   return 0;
19867330f729Sjoerg }
1987