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