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