1 //===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Demo program which implements an example LLVM exception implementation, and
11 // shows several test cases including the handling of foreign exceptions.
12 // It is run with type info types arguments to throw. A test will
13 // be run for each given type info type. While type info types with the value
14 // of -1 will trigger a foreign C++ exception to be thrown; type info types
15 // <= 6 and >= 1 will cause the associated generated exceptions to be thrown
16 // and caught by generated test functions; and type info types > 6
17 // will result in exceptions which pass through to the test harness. All other
18 // type info types are not supported and could cause a crash. In all cases,
19 // the "finally" blocks of every generated test functions will executed
20 // regardless of whether or not that test function ignores or catches the
27 // causes a usage to be printed to stderr
29 // ExceptionDemo 2 3 7 -1
31 // results in the following cases:
32 // - Value 2 causes an exception with a type info type of 2 to be
33 // thrown and caught by an inner generated test function.
34 // - Value 3 causes an exception with a type info type of 3 to be
35 // thrown and caught by an outer generated test function.
36 // - Value 7 causes an exception with a type info type of 7 to be
37 // thrown and NOT be caught by any generated function.
38 // - Value -1 causes a foreign C++ exception to be thrown and not be
39 // caught by any generated function
41 // Cases -1 and 7 are caught by a C++ test harness where the validity of
42 // of a C++ catch(...) clause catching a generated exception with a
43 // type info type of 7 is questionable.
45 // This code uses code from the llvm compiler-rt project and the llvm
46 // Kaleidoscope project.
48 //===----------------------------------------------------------------------===//
50 #include "llvm/LLVMContext.h"
51 #include "llvm/DerivedTypes.h"
52 #include "llvm/ExecutionEngine/ExecutionEngine.h"
53 #include "llvm/ExecutionEngine/JIT.h"
54 #include "llvm/Module.h"
55 #include "llvm/PassManager.h"
56 #include "llvm/Intrinsics.h"
57 #include "llvm/Analysis/Verifier.h"
58 #include "llvm/Target/TargetData.h"
59 #include "llvm/Target/TargetOptions.h"
60 #include "llvm/Transforms/Scalar.h"
61 #include "llvm/Support/IRBuilder.h"
62 #include "llvm/Support/Dwarf.h"
63 #include "llvm/Support/TargetSelect.h"
65 // FIXME: See use of UpgradeExceptionHandling(...) below
66 #include "llvm/AutoUpgrade.h"
68 // FIXME: Although all systems tested with (Linux, OS X), do not need this
69 // header file included. A user on ubuntu reported, undefined symbols
70 // for stderr, and fprintf, and the addition of this include fixed the
71 // issue for them. Given that LLVM's best practices include the goal
72 // of reducing the number of redundant header files included, the
73 // correct solution would be to find out why these symbols are not
74 // defined for the system in question, and fix the issue by finding out
75 // which LLVM header file, if any, would include these symbols.
82 #ifndef USE_GLOBAL_STR_CONSTS
83 #define USE_GLOBAL_STR_CONSTS true
86 // System C++ ABI unwind types from:
87 // http://refspecs.freestandards.org/abi-eh-1.21.html
93 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
94 _URC_FATAL_PHASE2_ERROR = 2,
95 _URC_FATAL_PHASE1_ERROR = 3,
97 _URC_END_OF_STACK = 5,
98 _URC_HANDLER_FOUND = 6,
99 _URC_INSTALL_CONTEXT = 7,
100 _URC_CONTINUE_UNWIND = 8
101 } _Unwind_Reason_Code;
104 _UA_SEARCH_PHASE = 1,
105 _UA_CLEANUP_PHASE = 2,
106 _UA_HANDLER_FRAME = 4,
107 _UA_FORCE_UNWIND = 8,
108 _UA_END_OF_STACK = 16
111 struct _Unwind_Exception;
113 typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
114 struct _Unwind_Exception *);
116 struct _Unwind_Exception {
117 uint64_t exception_class;
118 _Unwind_Exception_Cleanup_Fn exception_cleanup;
123 // @@@ The IA-64 ABI says that this structure must be double-word aligned.
124 // Taking that literally does not make much sense generically. Instead
125 // we provide the maximum alignment required by any type for the machine.
126 } __attribute__((__aligned__));
128 struct _Unwind_Context;
129 typedef struct _Unwind_Context *_Unwind_Context_t;
131 extern const uint8_t *_Unwind_GetLanguageSpecificData (_Unwind_Context_t c);
132 extern uintptr_t _Unwind_GetGR (_Unwind_Context_t c, int i);
133 extern void _Unwind_SetGR (_Unwind_Context_t c, int i, uintptr_t n);
134 extern void _Unwind_SetIP (_Unwind_Context_t, uintptr_t new_value);
135 extern uintptr_t _Unwind_GetIP (_Unwind_Context_t context);
136 extern uintptr_t _Unwind_GetRegionStart (_Unwind_Context_t context);
144 /// This is our simplistic type info
145 struct OurExceptionType_t {
151 /// This is our Exception class which relies on a negative offset to calculate
152 /// pointers to its instances from pointers to its unwindException member.
154 /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
155 /// on a double word boundary. This is necessary to match the standard:
156 /// http://refspecs.freestandards.org/abi-eh-1.21.html
157 struct OurBaseException_t {
158 struct OurExceptionType_t type;
160 // Note: This is properly aligned in unwind.h
161 struct _Unwind_Exception unwindException;
165 // Note: Not needed since we are C++
166 typedef struct OurBaseException_t OurException;
167 typedef struct _Unwind_Exception OurUnwindException;
170 // Various globals used to support typeinfo and generatted exceptions in
174 static std::map<std::string, llvm::Value*> namedValues;
176 int64_t ourBaseFromUnwindOffset;
178 const unsigned char ourBaseExcpClassChars[] =
179 {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
182 static uint64_t ourBaseExceptionClass = 0;
184 static std::vector<std::string> ourTypeInfoNames;
185 static std::map<int, std::string> ourTypeInfoNamesIndex;
187 static llvm::StructType *ourTypeInfoType;
188 static llvm::StructType *ourExceptionType;
189 static llvm::StructType *ourUnwindExceptionType;
191 static llvm::ConstantInt *ourExceptionNotThrownState;
192 static llvm::ConstantInt *ourExceptionThrownState;
193 static llvm::ConstantInt *ourExceptionCaughtState;
195 typedef std::vector<std::string> ArgNames;
196 typedef std::vector<llvm::Type*> ArgTypes;
199 // Code Generation Utilities
202 /// Utility used to create a function, both declarations and definitions
203 /// @param module for module instance
204 /// @param retType function return type
205 /// @param theArgTypes function's ordered argument types
206 /// @param theArgNames function's ordered arguments needed if use of this
207 /// function corresponds to a function definition. Use empty
208 /// aggregate for function declarations.
209 /// @param functName function name
210 /// @param linkage function linkage
211 /// @param declarationOnly for function declarations
212 /// @param isVarArg function uses vararg arguments
213 /// @returns function instance
214 llvm::Function *createFunction(llvm::Module &module,
216 const ArgTypes &theArgTypes,
217 const ArgNames &theArgNames,
218 const std::string &functName,
219 llvm::GlobalValue::LinkageTypes linkage,
220 bool declarationOnly,
222 llvm::FunctionType *functType =
223 llvm::FunctionType::get(retType, theArgTypes, isVarArg);
224 llvm::Function *ret =
225 llvm::Function::Create(functType, linkage, functName, &module);
226 if (!ret || declarationOnly)
231 for (llvm::Function::arg_iterator argIndex = ret->arg_begin();
232 i != theArgNames.size();
235 argIndex->setName(theArgNames[i]);
236 namedValues[theArgNames[i]] = argIndex;
243 /// Create an alloca instruction in the entry block of
244 /// the parent function. This is used for mutable variables etc.
245 /// @param function parent instance
246 /// @param varName stack variable name
247 /// @param type stack variable type
248 /// @param initWith optional constant initialization value
249 /// @returns AllocaInst instance
250 static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function,
251 const std::string &varName,
253 llvm::Constant *initWith = 0) {
254 llvm::BasicBlock &block = function.getEntryBlock();
255 llvm::IRBuilder<> tmp(&block, block.begin());
256 llvm::AllocaInst *ret = tmp.CreateAlloca(type, 0, varName.c_str());
259 tmp.CreateStore(initWith, ret);
266 // Code Generation Utilities End
270 // Runtime C Library functions
273 // Note: using an extern "C" block so that static functions can be used
276 // Note: Better ways to decide on bit width
278 /// Prints a 32 bit number, according to the format, to stderr.
279 /// @param intToPrint integer to print
280 /// @param format printf like format to use when printing
281 void print32Int(int intToPrint, const char *format) {
283 // Note: No NULL check
284 fprintf(stderr, format, intToPrint);
287 // Note: No NULL check
288 fprintf(stderr, "::print32Int(...):NULL arg.\n");
293 // Note: Better ways to decide on bit width
295 /// Prints a 64 bit number, according to the format, to stderr.
296 /// @param intToPrint integer to print
297 /// @param format printf like format to use when printing
298 void print64Int(long int intToPrint, const char *format) {
300 // Note: No NULL check
301 fprintf(stderr, format, intToPrint);
304 // Note: No NULL check
305 fprintf(stderr, "::print64Int(...):NULL arg.\n");
310 /// Prints a C string to stderr
311 /// @param toPrint string to print
312 void printStr(char *toPrint) {
314 fprintf(stderr, "%s", toPrint);
317 fprintf(stderr, "::printStr(...):NULL arg.\n");
322 /// Deletes the true previosly allocated exception whose address
323 /// is calculated from the supplied OurBaseException_t::unwindException
324 /// member address. Handles (ignores), NULL pointers.
325 /// @param expToDelete exception to delete
326 void deleteOurException(OurUnwindException *expToDelete) {
329 "deleteOurException(...).\n");
333 (expToDelete->exception_class == ourBaseExceptionClass)) {
335 free(((char*) expToDelete) + ourBaseFromUnwindOffset);
340 /// This function is the struct _Unwind_Exception API mandated delete function
341 /// used by foreign exception handlers when deleting our exception
342 /// (OurException), instances.
343 /// @param reason @link http://refspecs.freestandards.org/abi-eh-1.21.html
345 /// @param expToDelete exception instance to delete
346 void deleteFromUnwindOurException(_Unwind_Reason_Code reason,
347 OurUnwindException *expToDelete) {
350 "deleteFromUnwindOurException(...).\n");
353 deleteOurException(expToDelete);
357 /// Creates (allocates on the heap), an exception (OurException instance),
358 /// of the supplied type info type.
359 /// @param type type info type
360 OurUnwindException *createOurException(int type) {
361 size_t size = sizeof(OurException);
362 OurException *ret = (OurException*) memset(malloc(size), 0, size);
363 (ret->type).type = type;
364 (ret->unwindException).exception_class = ourBaseExceptionClass;
365 (ret->unwindException).exception_cleanup = deleteFromUnwindOurException;
367 return(&(ret->unwindException));
371 /// Read a uleb128 encoded value and advance pointer
372 /// See Variable Length Data in:
373 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
374 /// @param data reference variable holding memory pointer to decode from
375 /// @returns decoded value
376 static uintptr_t readULEB128(const uint8_t **data) {
377 uintptr_t result = 0;
380 const uint8_t *p = *data;
384 result |= (byte & 0x7f) << shift;
395 /// Read a sleb128 encoded value and advance pointer
396 /// See Variable Length Data in:
397 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
398 /// @param data reference variable holding memory pointer to decode from
399 /// @returns decoded value
400 static uintptr_t readSLEB128(const uint8_t **data) {
401 uintptr_t result = 0;
404 const uint8_t *p = *data;
408 result |= (byte & 0x7f) << shift;
415 if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
416 result |= (~0 << shift);
423 /// Read a pointer encoded value and advance pointer
424 /// See Variable Length Data in:
425 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
426 /// @param data reference variable holding memory pointer to decode from
427 /// @param encoding dwarf encoding type
428 /// @returns decoded value
429 static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
430 uintptr_t result = 0;
431 const uint8_t *p = *data;
433 if (encoding == llvm::dwarf::DW_EH_PE_omit)
437 switch (encoding & 0x0F) {
438 case llvm::dwarf::DW_EH_PE_absptr:
439 result = *((uintptr_t*)p);
440 p += sizeof(uintptr_t);
442 case llvm::dwarf::DW_EH_PE_uleb128:
443 result = readULEB128(&p);
445 // Note: This case has not been tested
446 case llvm::dwarf::DW_EH_PE_sleb128:
447 result = readSLEB128(&p);
449 case llvm::dwarf::DW_EH_PE_udata2:
450 result = *((uint16_t*)p);
451 p += sizeof(uint16_t);
453 case llvm::dwarf::DW_EH_PE_udata4:
454 result = *((uint32_t*)p);
455 p += sizeof(uint32_t);
457 case llvm::dwarf::DW_EH_PE_udata8:
458 result = *((uint64_t*)p);
459 p += sizeof(uint64_t);
461 case llvm::dwarf::DW_EH_PE_sdata2:
462 result = *((int16_t*)p);
463 p += sizeof(int16_t);
465 case llvm::dwarf::DW_EH_PE_sdata4:
466 result = *((int32_t*)p);
467 p += sizeof(int32_t);
469 case llvm::dwarf::DW_EH_PE_sdata8:
470 result = *((int64_t*)p);
471 p += sizeof(int64_t);
479 // then add relative offset
480 switch (encoding & 0x70) {
481 case llvm::dwarf::DW_EH_PE_absptr:
484 case llvm::dwarf::DW_EH_PE_pcrel:
485 result += (uintptr_t)(*data);
487 case llvm::dwarf::DW_EH_PE_textrel:
488 case llvm::dwarf::DW_EH_PE_datarel:
489 case llvm::dwarf::DW_EH_PE_funcrel:
490 case llvm::dwarf::DW_EH_PE_aligned:
497 // then apply indirection
498 if (encoding & llvm::dwarf::DW_EH_PE_indirect) {
499 result = *((uintptr_t*)result);
508 /// Deals with Dwarf actions matching our type infos
509 /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
510 /// action matches the supplied exception type. If such a match succeeds,
511 /// the resultAction argument will be set with > 0 index value. Only
512 /// corresponding llvm.eh.selector type info arguments, cleanup arguments
513 /// are supported. Filters are not supported.
514 /// See Variable Length Data in:
515 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
516 /// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
517 /// @param resultAction reference variable which will be set with result
518 /// @param classInfo our array of type info pointers (to globals)
519 /// @param actionEntry index into above type info array or 0 (clean up).
520 /// We do not support filters.
521 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
522 /// of thrown exception.
523 /// @param exceptionObject thrown _Unwind_Exception instance.
524 /// @returns whether or not a type info was found. False is returned if only
525 /// a cleanup was found
526 static bool handleActionValue(int64_t *resultAction,
527 struct OurExceptionType_t **classInfo,
528 uintptr_t actionEntry,
529 uint64_t exceptionClass,
530 struct _Unwind_Exception *exceptionObject) {
535 (exceptionClass != ourBaseExceptionClass))
538 struct OurBaseException_t *excp = (struct OurBaseException_t*)
539 (((char*) exceptionObject) + ourBaseFromUnwindOffset);
540 struct OurExceptionType_t *excpType = &(excp->type);
541 int type = excpType->type;
545 "handleActionValue(...): exceptionObject = <%p>, "
551 const uint8_t *actionPos = (uint8_t*) actionEntry,
553 int64_t typeOffset = 0,
556 for (int i = 0; true; ++i) {
557 // Each emitted dwarf action corresponds to a 2 tuple of
558 // type info address offset, and action offset to the next
560 typeOffset = readSLEB128(&actionPos);
561 tempActionPos = actionPos;
562 actionOffset = readSLEB128(&tempActionPos);
566 "handleActionValue(...):typeOffset: <%lld>, "
567 "actionOffset: <%lld>.\n",
571 assert((typeOffset >= 0) &&
572 "handleActionValue(...):filters are not supported.");
574 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
575 // argument has been matched.
576 if ((typeOffset > 0) &&
577 (type == (classInfo[-typeOffset])->type)) {
580 "handleActionValue(...):actionValue <%d> found.\n",
583 *resultAction = i + 1;
590 "handleActionValue(...):actionValue not found.\n");
595 actionPos += actionOffset;
602 /// Deals with the Language specific data portion of the emitted dwarf code.
603 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
604 /// @param version unsupported (ignored), unwind version
605 /// @param lsda language specific data area
606 /// @param _Unwind_Action actions minimally supported unwind stage
607 /// (forced specifically not supported)
608 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
609 /// of thrown exception.
610 /// @param exceptionObject thrown _Unwind_Exception instance.
611 /// @param context unwind system context
612 /// @returns minimally supported unwinding control indicator
613 static _Unwind_Reason_Code handleLsda(int version,
615 _Unwind_Action actions,
616 uint64_t exceptionClass,
617 struct _Unwind_Exception *exceptionObject,
618 _Unwind_Context_t context) {
619 _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND;
626 "handleLsda(...):lsda is non-zero.\n");
629 // Get the current instruction pointer and offset it before next
630 // instruction in the current frame which threw the exception.
631 uintptr_t pc = _Unwind_GetIP(context)-1;
633 // Get beginning current frame's code (as defined by the
634 // emitted dwarf code)
635 uintptr_t funcStart = _Unwind_GetRegionStart(context);
636 uintptr_t pcOffset = pc - funcStart;
637 struct OurExceptionType_t **classInfo = NULL;
639 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
642 // Parse LSDA header.
643 uint8_t lpStartEncoding = *lsda++;
645 if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) {
646 readEncodedPointer(&lsda, lpStartEncoding);
649 uint8_t ttypeEncoding = *lsda++;
650 uintptr_t classInfoOffset;
652 if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) {
653 // Calculate type info locations in emitted dwarf code which
654 // were flagged by type info arguments to llvm.eh.selector
656 classInfoOffset = readULEB128(&lsda);
657 classInfo = (struct OurExceptionType_t**) (lsda + classInfoOffset);
660 // Walk call-site table looking for range that
661 // includes current PC.
663 uint8_t callSiteEncoding = *lsda++;
664 uint32_t callSiteTableLength = readULEB128(&lsda);
665 const uint8_t *callSiteTableStart = lsda;
666 const uint8_t *callSiteTableEnd = callSiteTableStart +
668 const uint8_t *actionTableStart = callSiteTableEnd;
669 const uint8_t *callSitePtr = callSiteTableStart;
671 bool foreignException = false;
673 while (callSitePtr < callSiteTableEnd) {
674 uintptr_t start = readEncodedPointer(&callSitePtr,
676 uintptr_t length = readEncodedPointer(&callSitePtr,
678 uintptr_t landingPad = readEncodedPointer(&callSitePtr,
681 // Note: Action value
682 uintptr_t actionEntry = readULEB128(&callSitePtr);
684 if (exceptionClass != ourBaseExceptionClass) {
685 // We have been notified of a foreign exception being thrown,
686 // and we therefore need to execute cleanup landing pads
688 foreignException = true;
691 if (landingPad == 0) {
694 "handleLsda(...): No landing pad found.\n");
697 continue; // no landing pad for this entry
701 actionEntry += ((uintptr_t) actionTableStart) - 1;
706 "handleLsda(...):No action table found.\n");
710 bool exceptionMatched = false;
712 if ((start <= pcOffset) && (pcOffset < (start + length))) {
715 "handleLsda(...): Landing pad found.\n");
717 int64_t actionValue = 0;
720 exceptionMatched = handleActionValue(&actionValue,
727 if (!(actions & _UA_SEARCH_PHASE)) {
730 "handleLsda(...): installed landing pad "
734 // Found landing pad for the PC.
735 // Set Instruction Pointer to so we re-enter function
736 // at landing pad. The landing pad is created by the
737 // compiler to take two parameters in registers.
738 _Unwind_SetGR(context,
739 __builtin_eh_return_data_regno(0),
740 (uintptr_t)exceptionObject);
742 // Note: this virtual register directly corresponds
743 // to the return of the llvm.eh.selector intrinsic
744 if (!actionEntry || !exceptionMatched) {
745 // We indicate cleanup only
746 _Unwind_SetGR(context,
747 __builtin_eh_return_data_regno(1),
751 // Matched type info index of llvm.eh.selector intrinsic
753 _Unwind_SetGR(context,
754 __builtin_eh_return_data_regno(1),
758 // To execute landing pad set here
759 _Unwind_SetIP(context, funcStart + landingPad);
760 ret = _URC_INSTALL_CONTEXT;
762 else if (exceptionMatched) {
765 "handleLsda(...): setting handler found.\n");
767 ret = _URC_HANDLER_FOUND;
770 // Note: Only non-clean up handlers are marked as
771 // found. Otherwise the clean up handlers will be
772 // re-found and executed during the clean up
776 "handleLsda(...): cleanup handler found.\n");
788 /// This is the personality function which is embedded (dwarf emitted), in the
789 /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
790 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
791 /// @param version unsupported (ignored), unwind version
792 /// @param _Unwind_Action actions minimally supported unwind stage
793 /// (forced specifically not supported)
794 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
795 /// of thrown exception.
796 /// @param exceptionObject thrown _Unwind_Exception instance.
797 /// @param context unwind system context
798 /// @returns minimally supported unwinding control indicator
799 _Unwind_Reason_Code ourPersonality(int version,
800 _Unwind_Action actions,
801 uint64_t exceptionClass,
802 struct _Unwind_Exception *exceptionObject,
803 _Unwind_Context_t context) {
806 "We are in ourPersonality(...):actions is <%d>.\n",
809 if (actions & _UA_SEARCH_PHASE) {
810 fprintf(stderr, "ourPersonality(...):In search phase.\n");
813 fprintf(stderr, "ourPersonality(...):In non-search phase.\n");
817 const uint8_t *lsda = _Unwind_GetLanguageSpecificData(context);
821 "ourPersonality(...):lsda = <%p>.\n",
825 // The real work of the personality function is captured here
826 return(handleLsda(version,
835 /// Generates our _Unwind_Exception class from a given character array.
836 /// thereby handling arbitrary lengths (not in standard), and handling
838 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
839 /// @param classChars char array to encode. NULL values not checkedf
840 /// @param classCharsSize number of chars in classChars. Value is not checked.
841 /// @returns class value
842 uint64_t genClass(const unsigned char classChars[], size_t classCharsSize)
844 uint64_t ret = classChars[0];
846 for (unsigned i = 1; i < classCharsSize; ++i) {
848 ret += classChars[i];
857 // Runtime C Library functions End
861 // Code generation functions
864 /// Generates code to print given constant string
865 /// @param context llvm context
866 /// @param module code for module instance
867 /// @param builder builder instance
868 /// @param toPrint string to print
869 /// @param useGlobal A value of true (default) indicates a GlobalValue is
870 /// generated, and is used to hold the constant string. A value of
871 /// false indicates that the constant string will be stored on the
873 void generateStringPrint(llvm::LLVMContext &context,
874 llvm::Module &module,
875 llvm::IRBuilder<> &builder,
877 bool useGlobal = true) {
878 llvm::Function *printFunct = module.getFunction("printStr");
880 llvm::Value *stringVar;
881 llvm::Constant *stringConstant =
882 llvm::ConstantArray::get(context, toPrint);
885 // Note: Does not work without allocation
887 new llvm::GlobalVariable(module,
888 stringConstant->getType(),
890 llvm::GlobalValue::LinkerPrivateLinkage,
895 stringVar = builder.CreateAlloca(stringConstant->getType());
896 builder.CreateStore(stringConstant, stringVar);
900 builder.CreatePointerCast(stringVar,
901 builder.getInt8PtrTy());
902 builder.CreateCall(printFunct, cast);
906 /// Generates code to print given runtime integer according to constant
907 /// string format, and a given print function.
908 /// @param context llvm context
909 /// @param module code for module instance
910 /// @param builder builder instance
911 /// @param printFunct function used to "print" integer
912 /// @param toPrint string to print
913 /// @param format printf like formating string for print
914 /// @param useGlobal A value of true (default) indicates a GlobalValue is
915 /// generated, and is used to hold the constant string. A value of
916 /// false indicates that the constant string will be stored on the
918 void generateIntegerPrint(llvm::LLVMContext &context,
919 llvm::Module &module,
920 llvm::IRBuilder<> &builder,
921 llvm::Function &printFunct,
922 llvm::Value &toPrint,
924 bool useGlobal = true) {
925 llvm::Constant *stringConstant = llvm::ConstantArray::get(context, format);
926 llvm::Value *stringVar;
929 // Note: Does not seem to work without allocation
931 new llvm::GlobalVariable(module,
932 stringConstant->getType(),
934 llvm::GlobalValue::LinkerPrivateLinkage,
939 stringVar = builder.CreateAlloca(stringConstant->getType());
940 builder.CreateStore(stringConstant, stringVar);
944 builder.CreateBitCast(stringVar,
945 builder.getInt8PtrTy());
946 builder.CreateCall2(&printFunct, &toPrint, cast);
950 /// Generates code to handle finally block type semantics: always runs
951 /// regardless of whether a thrown exception is passing through or the
952 /// parent function is simply exiting. In addition to printing some state
953 /// to stderr, this code will resume the exception handling--runs the
954 /// unwind resume block, if the exception has not been previously caught
955 /// by a catch clause, and will otherwise execute the end block (terminator
956 /// block). In addition this function creates the corresponding function's
957 /// stack storage for the exception pointer and catch flag status.
958 /// @param context llvm context
959 /// @param module code for module instance
960 /// @param builder builder instance
961 /// @param toAddTo parent function to add block to
962 /// @param blockName block name of new "finally" block.
963 /// @param functionId output id used for printing
964 /// @param terminatorBlock terminator "end" block
965 /// @param unwindResumeBlock unwind resume block
966 /// @param exceptionCaughtFlag reference exception caught/thrown status storage
967 /// @param exceptionStorage reference to exception pointer storage
968 /// @returns newly created block
969 static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
970 llvm::Module &module,
971 llvm::IRBuilder<> &builder,
972 llvm::Function &toAddTo,
973 std::string &blockName,
974 std::string &functionId,
975 llvm::BasicBlock &terminatorBlock,
976 llvm::BasicBlock &unwindResumeBlock,
977 llvm::Value **exceptionCaughtFlag,
978 llvm::Value **exceptionStorage) {
979 assert(exceptionCaughtFlag &&
980 "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
982 assert(exceptionStorage &&
983 "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
986 *exceptionCaughtFlag =
987 createEntryBlockAlloca(toAddTo,
989 ourExceptionNotThrownState->getType(),
990 ourExceptionNotThrownState);
992 llvm::PointerType *exceptionStorageType = builder.getInt8PtrTy();
994 createEntryBlockAlloca(toAddTo,
996 exceptionStorageType,
997 llvm::ConstantPointerNull::get(
998 exceptionStorageType));
1000 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1004 builder.SetInsertPoint(ret);
1006 std::ostringstream bufferToPrint;
1007 bufferToPrint << "Gen: Executing finally block "
1008 << blockName << " in " << functionId << "\n";
1009 generateStringPrint(context,
1012 bufferToPrint.str(),
1013 USE_GLOBAL_STR_CONSTS);
1015 llvm::SwitchInst *theSwitch =
1016 builder.CreateSwitch(builder.CreateLoad(*exceptionCaughtFlag),
1019 theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
1020 theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
1026 /// Generates catch block semantics which print a string to indicate type of
1027 /// catch executed, sets an exception caught flag, and executes passed in
1028 /// end block (terminator block).
1029 /// @param context llvm context
1030 /// @param module code for module instance
1031 /// @param builder builder instance
1032 /// @param toAddTo parent function to add block to
1033 /// @param blockName block name of new "catch" block.
1034 /// @param functionId output id used for printing
1035 /// @param terminatorBlock terminator "end" block
1036 /// @param exceptionCaughtFlag exception caught/thrown status
1037 /// @returns newly created block
1038 static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context,
1039 llvm::Module &module,
1040 llvm::IRBuilder<> &builder,
1041 llvm::Function &toAddTo,
1042 std::string &blockName,
1043 std::string &functionId,
1044 llvm::BasicBlock &terminatorBlock,
1045 llvm::Value &exceptionCaughtFlag) {
1047 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1051 builder.SetInsertPoint(ret);
1053 std::ostringstream bufferToPrint;
1054 bufferToPrint << "Gen: Executing catch block "
1059 generateStringPrint(context,
1062 bufferToPrint.str(),
1063 USE_GLOBAL_STR_CONSTS);
1064 builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
1065 builder.CreateBr(&terminatorBlock);
1071 /// Generates a function which invokes a function (toInvoke) and, whose
1072 /// unwind block will "catch" the type info types correspondingly held in the
1073 /// exceptionTypesToCatch argument. If the toInvoke function throws an
1074 /// exception which does not match any type info types contained in
1075 /// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1076 /// with the raised exception. On the other hand the generated code will
1077 /// normally exit if the toInvoke function does not throw an exception.
1078 /// The generated "finally" block is always run regardless of the cause of
1079 /// the generated function exit.
1080 /// The generated function is returned after being verified.
1081 /// @param module code for module instance
1082 /// @param builder builder instance
1083 /// @param fpm a function pass manager holding optional IR to IR
1085 /// @param toInvoke inner function to invoke
1086 /// @param ourId id used to printing purposes
1087 /// @param numExceptionsToCatch length of exceptionTypesToCatch array
1088 /// @param exceptionTypesToCatch array of type info types to "catch"
1089 /// @returns generated function
1091 llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module,
1092 llvm::IRBuilder<> &builder,
1093 llvm::FunctionPassManager &fpm,
1094 llvm::Function &toInvoke,
1096 unsigned numExceptionsToCatch,
1097 unsigned exceptionTypesToCatch[]) {
1099 llvm::LLVMContext &context = module.getContext();
1100 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1103 argTypes.push_back(builder.getInt32Ty());
1106 argNames.push_back("exceptTypeToThrow");
1108 llvm::Function *ret = createFunction(module,
1109 builder.getVoidTy(),
1113 llvm::Function::ExternalLinkage,
1117 // Block which calls invoke
1118 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1121 // Normal block for invoke
1122 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
1125 // Unwind block for invoke
1126 llvm::BasicBlock *exceptionBlock =
1127 llvm::BasicBlock::Create(context, "exception", ret);
1129 // Block which routes exception to correct catch handler block
1130 llvm::BasicBlock *exceptionRouteBlock =
1131 llvm::BasicBlock::Create(context, "exceptionRoute", ret);
1133 // Foreign exception handler
1134 llvm::BasicBlock *externalExceptionBlock =
1135 llvm::BasicBlock::Create(context, "externalException", ret);
1137 // Block which calls _Unwind_Resume
1138 llvm::BasicBlock *unwindResumeBlock =
1139 llvm::BasicBlock::Create(context, "unwindResume", ret);
1141 // Clean up block which delete exception if needed
1142 llvm::BasicBlock *endBlock =
1143 llvm::BasicBlock::Create(context, "end", ret);
1145 std::string nextName;
1146 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
1147 llvm::Value *exceptionCaughtFlag = NULL;
1148 llvm::Value *exceptionStorage = NULL;
1150 // Finally block which will branch to unwindResumeBlock if
1151 // exception is not caught. Initializes/allocates stack locations.
1152 llvm::BasicBlock *finallyBlock = createFinallyBlock(context,
1156 nextName = "finally",
1160 &exceptionCaughtFlag,
1163 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1164 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
1166 // One catch block per type info to be caught
1167 catchBlocks[i] = createCatchBlock(context,
1174 *exceptionCaughtFlag);
1179 builder.SetInsertPoint(entryBlock);
1181 std::vector<llvm::Value*> args;
1182 args.push_back(namedValues["exceptTypeToThrow"]);
1183 builder.CreateInvoke(&toInvoke,
1190 builder.SetInsertPoint(endBlock);
1192 generateStringPrint(context,
1195 "Gen: In end block: exiting in " + ourId + ".\n",
1196 USE_GLOBAL_STR_CONSTS);
1197 llvm::Function *deleteOurException =
1198 module.getFunction("deleteOurException");
1200 // Note: function handles NULL exceptions
1201 builder.CreateCall(deleteOurException,
1202 builder.CreateLoad(exceptionStorage));
1203 builder.CreateRetVoid();
1207 builder.SetInsertPoint(normalBlock);
1209 generateStringPrint(context,
1212 "Gen: No exception in " + ourId + "!\n",
1213 USE_GLOBAL_STR_CONSTS);
1215 // Finally block is always called
1216 builder.CreateBr(finallyBlock);
1218 // Unwind Resume Block
1220 builder.SetInsertPoint(unwindResumeBlock);
1222 llvm::Function *resumeOurException =
1223 module.getFunction("_Unwind_Resume");
1224 builder.CreateCall(resumeOurException,
1225 builder.CreateLoad(exceptionStorage));
1226 builder.CreateUnreachable();
1230 builder.SetInsertPoint(exceptionBlock);
1232 llvm::Function *ehException = module.getFunction("llvm.eh.exception");
1234 // Retrieve thrown exception
1235 llvm::Value *unwindException = builder.CreateCall(ehException);
1237 // Store exception and flag
1238 builder.CreateStore(unwindException, exceptionStorage);
1239 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag);
1240 llvm::Function *personality = module.getFunction("ourPersonality");
1241 llvm::Value *functPtr =
1242 builder.CreatePointerCast(personality,
1243 builder.getInt8PtrTy());
1246 args.push_back(unwindException);
1247 args.push_back(functPtr);
1249 // Note: Skipping index 0
1250 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1251 // Set up type infos to be caught
1252 args.push_back(module.getGlobalVariable(
1253 ourTypeInfoNames[exceptionTypesToCatch[i]]));
1256 args.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), 0));
1258 llvm::Function *ehSelector = module.getFunction("llvm.eh.selector");
1260 // Set up this exeption block as the landing pad which will handle
1261 // given type infos. See case Intrinsic::eh_selector in
1262 // SelectionDAGBuilder::visitIntrinsicCall(...) and AddCatchInfo(...)
1263 // implemented in FunctionLoweringInfo.cpp to see how the implementation
1264 // handles this call. This landing pad (this exception block), will be
1265 // called either because it nees to cleanup (call finally) or a type
1266 // info was found which matched the thrown exception.
1267 llvm::Value *retTypeInfoIndex = builder.CreateCall(ehSelector, args);
1269 // Retrieve exception_class member from thrown exception
1270 // (_Unwind_Exception instance). This member tells us whether or not
1271 // the exception is foreign.
1272 llvm::Value *unwindExceptionClass =
1273 builder.CreateLoad(builder.CreateStructGEP(
1274 builder.CreatePointerCast(unwindException,
1275 ourUnwindExceptionType->getPointerTo()),
1278 // Branch to the externalExceptionBlock if the exception is foreign or
1279 // to a catch router if not. Either way the finally block will be run.
1280 builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass,
1281 llvm::ConstantInt::get(builder.getInt64Ty(),
1282 ourBaseExceptionClass)),
1283 exceptionRouteBlock,
1284 externalExceptionBlock);
1286 // External Exception Block
1288 builder.SetInsertPoint(externalExceptionBlock);
1290 generateStringPrint(context,
1293 "Gen: Foreign exception received.\n",
1294 USE_GLOBAL_STR_CONSTS);
1296 // Branch to the finally block
1297 builder.CreateBr(finallyBlock);
1299 // Exception Route Block
1301 builder.SetInsertPoint(exceptionRouteBlock);
1303 // Casts exception pointer (_Unwind_Exception instance) to parent
1304 // (OurException instance).
1306 // Note: ourBaseFromUnwindOffset is usually negative
1307 llvm::Value *typeInfoThrown =
1308 builder.CreatePointerCast(builder.CreateConstGEP1_64(unwindException,
1309 ourBaseFromUnwindOffset),
1310 ourExceptionType->getPointerTo());
1312 // Retrieve thrown exception type info type
1314 // Note: Index is not relative to pointer but instead to structure
1315 // unlike a true getelementptr (GEP) instruction
1316 typeInfoThrown = builder.CreateStructGEP(typeInfoThrown, 0);
1318 llvm::Value *typeInfoThrownType =
1319 builder.CreateStructGEP(typeInfoThrown, 0);
1321 generateIntegerPrint(context,
1325 *(builder.CreateLoad(typeInfoThrownType)),
1326 "Gen: Exception type <%d> received (stack unwound) "
1330 USE_GLOBAL_STR_CONSTS);
1332 // Route to matched type info catch block or run cleanup finally block
1333 llvm::SwitchInst *switchToCatchBlock =
1334 builder.CreateSwitch(retTypeInfoIndex,
1336 numExceptionsToCatch);
1338 unsigned nextTypeToCatch;
1340 for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
1341 nextTypeToCatch = i - 1;
1342 switchToCatchBlock->addCase(llvm::ConstantInt::get(
1343 llvm::Type::getInt32Ty(context), i),
1344 catchBlocks[nextTypeToCatch]);
1347 // FIXME: This is a hack to get the demo working with the new 3.0 exception
1348 // infrastructure. As this makes the demo no longer a demo, and
1349 // especially not a demo on how to use the llvm exception mechanism,
1350 // this hack will shortly be changed to use the new 3.0 exception
1351 // infrastructure. However for the time being this demo is an
1352 // example on how to use the AutoUpgrade UpgradeExceptionHandling(...)
1353 // function on < 3.0 exception handling code.
1355 // Must be run before verifier
1356 UpgradeExceptionHandling(&module);
1358 llvm::verifyFunction(*ret);
1365 /// Generates function which throws either an exception matched to a runtime
1366 /// determined type info type (argument to generated function), or if this
1367 /// runtime value matches nativeThrowType, throws a foreign exception by
1368 /// calling nativeThrowFunct.
1369 /// @param module code for module instance
1370 /// @param builder builder instance
1371 /// @param fpm a function pass manager holding optional IR to IR
1373 /// @param ourId id used to printing purposes
1374 /// @param nativeThrowType a runtime argument of this value results in
1375 /// nativeThrowFunct being called to generate/throw exception.
1376 /// @param nativeThrowFunct function which will throw a foreign exception
1377 /// if the above nativeThrowType matches generated function's arg.
1378 /// @returns generated function
1380 llvm::Function *createThrowExceptionFunction(llvm::Module &module,
1381 llvm::IRBuilder<> &builder,
1382 llvm::FunctionPassManager &fpm,
1384 int32_t nativeThrowType,
1385 llvm::Function &nativeThrowFunct) {
1386 llvm::LLVMContext &context = module.getContext();
1387 namedValues.clear();
1388 ArgTypes unwindArgTypes;
1389 unwindArgTypes.push_back(builder.getInt32Ty());
1390 ArgNames unwindArgNames;
1391 unwindArgNames.push_back("exceptTypeToThrow");
1393 llvm::Function *ret = createFunction(module,
1394 builder.getVoidTy(),
1398 llvm::Function::ExternalLinkage,
1402 // Throws either one of our exception or a native C++ exception depending
1403 // on a runtime argument value containing a type info type.
1404 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1407 // Throws a foreign exception
1408 llvm::BasicBlock *nativeThrowBlock =
1409 llvm::BasicBlock::Create(context,
1412 // Throws one of our Exceptions
1413 llvm::BasicBlock *generatedThrowBlock =
1414 llvm::BasicBlock::Create(context,
1417 // Retrieved runtime type info type to throw
1418 llvm::Value *exceptionType = namedValues["exceptTypeToThrow"];
1420 // nativeThrowBlock block
1422 builder.SetInsertPoint(nativeThrowBlock);
1424 // Throws foreign exception
1425 builder.CreateCall(&nativeThrowFunct, exceptionType);
1426 builder.CreateUnreachable();
1430 builder.SetInsertPoint(entryBlock);
1432 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1433 generateIntegerPrint(context,
1438 "\nGen: About to throw exception type <%d> in " +
1441 USE_GLOBAL_STR_CONSTS);
1443 // Switches on runtime type info type value to determine whether or not
1444 // a foreign exception is thrown. Defaults to throwing one of our
1445 // generated exceptions.
1446 llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType,
1447 generatedThrowBlock,
1450 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
1454 // generatedThrow block
1456 builder.SetInsertPoint(generatedThrowBlock);
1458 llvm::Function *createOurException =
1459 module.getFunction("createOurException");
1460 llvm::Function *raiseOurException =
1461 module.getFunction("_Unwind_RaiseException");
1463 // Creates exception to throw with runtime type info type.
1464 llvm::Value *exception =
1465 builder.CreateCall(createOurException,
1466 namedValues["exceptTypeToThrow"]);
1468 // Throw generated Exception
1469 builder.CreateCall(raiseOurException, exception);
1470 builder.CreateUnreachable();
1472 llvm::verifyFunction(*ret);
1478 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1479 llvm::Module &module,
1480 llvm::IRBuilder<> &builder);
1482 /// Creates test code by generating and organizing these functions into the
1483 /// test case. The test case consists of an outer function setup to invoke
1484 /// an inner function within an environment having multiple catch and single
1485 /// finally blocks. This inner function is also setup to invoke a throw
1486 /// function within an evironment similar in nature to the outer function's
1487 /// catch and finally blocks. Each of these two functions catch mutually
1488 /// exclusive subsets (even or odd) of the type info types configured
1489 /// for this this. All generated functions have a runtime argument which
1490 /// holds a type info type to throw that each function takes and passes it
1491 /// to the inner one if such a inner function exists. This type info type is
1492 /// looked at by the generated throw function to see whether or not it should
1493 /// throw a generated exception with the same type info type, or instead call
1494 /// a supplied a function which in turn will throw a foreign exception.
1495 /// @param module code for module instance
1496 /// @param builder builder instance
1497 /// @param fpm a function pass manager holding optional IR to IR
1499 /// @param nativeThrowFunctName name of external function which will throw
1500 /// a foreign exception
1501 /// @returns outermost generated test function.
1502 llvm::Function *createUnwindExceptionTest(llvm::Module &module,
1503 llvm::IRBuilder<> &builder,
1504 llvm::FunctionPassManager &fpm,
1505 std::string nativeThrowFunctName) {
1506 // Number of type infos to generate
1507 unsigned numTypeInfos = 6;
1509 // Initialze intrisics and external functions to use along with exception
1510 // and type info globals.
1511 createStandardUtilityFunctions(numTypeInfos,
1514 llvm::Function *nativeThrowFunct =
1515 module.getFunction(nativeThrowFunctName);
1517 // Create exception throw function using the value ~0 to cause
1518 // foreign exceptions to be thrown.
1519 llvm::Function *throwFunct =
1520 createThrowExceptionFunction(module,
1526 // Inner function will catch even type infos
1527 unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
1528 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
1531 // Generate inner function.
1532 llvm::Function *innerCatchFunct =
1533 createCatchWrappedInvokeFunction(module,
1538 numExceptionTypesToCatch,
1539 innerExceptionTypesToCatch);
1541 // Outer function will catch odd type infos
1542 unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
1543 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
1546 // Generate outer function
1547 llvm::Function *outerCatchFunct =
1548 createCatchWrappedInvokeFunction(module,
1553 numExceptionTypesToCatch,
1554 outerExceptionTypesToCatch);
1556 // Return outer function to run
1557 return(outerCatchFunct);
1561 /// Represents our foreign exceptions
1562 class OurCppRunException : public std::runtime_error {
1564 OurCppRunException(const std::string reason) :
1565 std::runtime_error(reason) {}
1567 OurCppRunException (const OurCppRunException &toCopy) :
1568 std::runtime_error(toCopy) {}
1570 OurCppRunException &operator = (const OurCppRunException &toCopy) {
1571 return(reinterpret_cast<OurCppRunException&>(
1572 std::runtime_error::operator=(toCopy)));
1575 ~OurCppRunException (void) throw () {}
1579 /// Throws foreign C++ exception.
1580 /// @param ignoreIt unused parameter that allows function to match implied
1581 /// generated function contract.
1583 void throwCppException (int32_t ignoreIt) {
1584 throw(OurCppRunException("thrown by throwCppException(...)"));
1587 typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
1589 /// This is a test harness which runs test by executing generated
1590 /// function with a type info type to throw. Harness wraps the execution
1591 /// of generated function in a C++ try catch clause.
1592 /// @param engine execution engine to use for executing generated function.
1593 /// This demo program expects this to be a JIT instance for demo
1595 /// @param function generated test function to run
1596 /// @param typeToThrow type info type of generated exception to throw, or
1597 /// indicator to cause foreign exception to be thrown.
1599 void runExceptionThrow(llvm::ExecutionEngine *engine,
1600 llvm::Function *function,
1601 int32_t typeToThrow) {
1603 // Find test's function pointer
1604 OurExceptionThrowFunctType functPtr =
1605 reinterpret_cast<OurExceptionThrowFunctType>(
1606 reinterpret_cast<intptr_t>(engine->getPointerToFunction(function)));
1610 (*functPtr)(typeToThrow);
1612 catch (OurCppRunException exc) {
1613 // Catch foreign C++ exception
1615 "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1616 "with reason: %s.\n",
1620 // Catch all exceptions including our generated ones. I'm not sure
1621 // why this latter functionality should work, as it seems that
1622 // our exceptions should be foreign to C++ (the _Unwind_Exception::
1623 // exception_class should be different from the one used by C++), and
1624 // therefore C++ should ignore the generated exceptions.
1627 "\nrunExceptionThrow(...):In C++ catch all.\n");
1632 // End test functions
1635 typedef llvm::ArrayRef<llvm::Type*> TypeArray;
1637 /// This initialization routine creates type info globals and
1638 /// adds external function declarations to module.
1639 /// @param numTypeInfos number of linear type info associated type info types
1640 /// to create as GlobalVariable instances, starting with the value 1.
1641 /// @param module code for module instance
1642 /// @param builder builder instance
1643 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1644 llvm::Module &module,
1645 llvm::IRBuilder<> &builder) {
1647 llvm::LLVMContext &context = module.getContext();
1649 // Exception initializations
1651 // Setup exception catch state
1652 ourExceptionNotThrownState =
1653 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
1654 ourExceptionThrownState =
1655 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
1656 ourExceptionCaughtState =
1657 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
1661 // Create our type info type
1662 ourTypeInfoType = llvm::StructType::get(context,
1663 TypeArray(builder.getInt32Ty()));
1664 // Create OurException type
1665 ourExceptionType = llvm::StructType::get(context,
1666 TypeArray(ourTypeInfoType));
1668 // Create portion of _Unwind_Exception type
1670 // Note: Declaring only a portion of the _Unwind_Exception struct.
1671 // Does this cause problems?
1672 ourUnwindExceptionType =
1673 llvm::StructType::get(context,
1674 TypeArray(builder.getInt64Ty()));
1676 struct OurBaseException_t dummyException;
1678 // Calculate offset of OurException::unwindException member.
1679 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
1680 ((uintptr_t) &(dummyException.unwindException));
1684 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1685 "= %lld, sizeof(struct OurBaseException_t) - "
1686 "sizeof(struct _Unwind_Exception) = %lu.\n",
1687 ourBaseFromUnwindOffset,
1688 sizeof(struct OurBaseException_t) -
1689 sizeof(struct _Unwind_Exception));
1692 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
1694 // Create our _Unwind_Exception::exception_class value
1695 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
1699 std::string baseStr = "typeInfo", typeInfoName;
1700 std::ostringstream typeInfoNameBuilder;
1701 std::vector<llvm::Constant*> structVals;
1703 llvm::Constant *nextStruct;
1704 llvm::GlobalVariable *nextGlobal = NULL;
1706 // Generate each type info
1708 // Note: First type info is not used.
1709 for (unsigned i = 0; i <= numTypeInfos; ++i) {
1711 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
1712 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
1714 typeInfoNameBuilder.str("");
1715 typeInfoNameBuilder << baseStr << i;
1716 typeInfoName = typeInfoNameBuilder.str();
1718 // Note: Does not seem to work without allocation
1720 new llvm::GlobalVariable(module,
1723 llvm::GlobalValue::ExternalLinkage,
1727 ourTypeInfoNames.push_back(typeInfoName);
1728 ourTypeInfoNamesIndex[i] = typeInfoName;
1733 llvm::Function *funct = NULL;
1737 llvm::Type *retType = builder.getVoidTy();
1740 argTypes.push_back(builder.getInt32Ty());
1741 argTypes.push_back(builder.getInt8PtrTy());
1745 createFunction(module,
1750 llvm::Function::ExternalLinkage,
1756 retType = builder.getVoidTy();
1759 argTypes.push_back(builder.getInt64Ty());
1760 argTypes.push_back(builder.getInt8PtrTy());
1764 createFunction(module,
1769 llvm::Function::ExternalLinkage,
1775 retType = builder.getVoidTy();
1778 argTypes.push_back(builder.getInt8PtrTy());
1782 createFunction(module,
1787 llvm::Function::ExternalLinkage,
1791 // throwCppException
1793 retType = builder.getVoidTy();
1796 argTypes.push_back(builder.getInt32Ty());
1800 createFunction(module,
1804 "throwCppException",
1805 llvm::Function::ExternalLinkage,
1809 // deleteOurException
1811 retType = builder.getVoidTy();
1814 argTypes.push_back(builder.getInt8PtrTy());
1818 createFunction(module,
1822 "deleteOurException",
1823 llvm::Function::ExternalLinkage,
1827 // createOurException
1829 retType = builder.getInt8PtrTy();
1832 argTypes.push_back(builder.getInt32Ty());
1836 createFunction(module,
1840 "createOurException",
1841 llvm::Function::ExternalLinkage,
1845 // _Unwind_RaiseException
1847 retType = builder.getInt32Ty();
1850 argTypes.push_back(builder.getInt8PtrTy());
1854 funct = createFunction(module,
1858 "_Unwind_RaiseException",
1859 llvm::Function::ExternalLinkage,
1863 funct->addFnAttr(llvm::Attribute::NoReturn);
1867 retType = builder.getInt32Ty();
1870 argTypes.push_back(builder.getInt8PtrTy());
1874 funct = createFunction(module,
1879 llvm::Function::ExternalLinkage,
1883 funct->addFnAttr(llvm::Attribute::NoReturn);
1887 retType = builder.getInt32Ty();
1890 argTypes.push_back(builder.getInt32Ty());
1891 argTypes.push_back(builder.getInt32Ty());
1892 argTypes.push_back(builder.getInt64Ty());
1893 argTypes.push_back(builder.getInt8PtrTy());
1894 argTypes.push_back(builder.getInt8PtrTy());
1898 createFunction(module,
1903 llvm::Function::ExternalLinkage,
1907 // llvm.eh.selector intrinsic
1909 getDeclaration(&module, llvm::Intrinsic::eh_selector);
1911 // llvm.eh.exception intrinsic
1913 getDeclaration(&module, llvm::Intrinsic::eh_exception);
1915 // llvm.eh.typeid.for intrinsic
1917 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for);
1921 //===----------------------------------------------------------------------===//
1922 // Main test driver code.
1923 //===----------------------------------------------------------------------===//
1925 /// Demo main routine which takes the type info types to throw. A test will
1926 /// be run for each given type info type. While type info types with the value
1927 /// of -1 will trigger a foreign C++ exception to be thrown; type info types
1928 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1929 /// will result in exceptions which pass through to the test harness. All other
1930 /// type info types are not supported and could cause a crash.
1931 int main(int argc, char *argv[]) {
1934 "\nUsage: ExceptionDemo <exception type to throw> "
1935 "[<type 2>...<type n>].\n"
1936 " Each type must have the value of 1 - 6 for "
1937 "generated exceptions to be caught;\n"
1938 " the value -1 for foreign C++ exceptions to be "
1939 "generated and thrown;\n"
1940 " or the values > 6 for exceptions to be ignored.\n"
1941 "\nTry: ExceptionDemo 2 3 7 -1\n"
1942 " for a full test.\n\n");
1946 // If not set, exception handling will not be turned on
1947 llvm::JITExceptionHandling = true;
1949 llvm::InitializeNativeTarget();
1950 llvm::LLVMContext &context = llvm::getGlobalContext();
1951 llvm::IRBuilder<> theBuilder(context);
1953 // Make the module, which holds all the code.
1954 llvm::Module *module = new llvm::Module("my cool jit", context);
1956 // Build engine with JIT
1957 llvm::EngineBuilder factory(module);
1958 factory.setEngineKind(llvm::EngineKind::JIT);
1959 factory.setAllocateGVsWithCode(false);
1960 llvm::ExecutionEngine *executionEngine = factory.create();
1963 llvm::FunctionPassManager fpm(module);
1965 // Set up the optimizer pipeline.
1966 // Start with registering info about how the
1967 // target lays out data structures.
1968 fpm.add(new llvm::TargetData(*executionEngine->getTargetData()));
1970 // Optimizations turned on
1971 #ifdef ADD_OPT_PASSES
1973 // Basic AliasAnslysis support for GVN.
1974 fpm.add(llvm::createBasicAliasAnalysisPass());
1976 // Promote allocas to registers.
1977 fpm.add(llvm::createPromoteMemoryToRegisterPass());
1979 // Do simple "peephole" optimizations and bit-twiddling optzns.
1980 fpm.add(llvm::createInstructionCombiningPass());
1982 // Reassociate expressions.
1983 fpm.add(llvm::createReassociatePass());
1985 // Eliminate Common SubExpressions.
1986 fpm.add(llvm::createGVNPass());
1988 // Simplify the control flow graph (deleting unreachable
1990 fpm.add(llvm::createCFGSimplificationPass());
1991 #endif // ADD_OPT_PASSES
1993 fpm.doInitialization();
1995 // Generate test code using function throwCppException(...) as
1996 // the function which throws foreign exceptions.
1997 llvm::Function *toRun =
1998 createUnwindExceptionTest(*module,
2001 "throwCppException");
2003 fprintf(stderr, "\nBegin module dump:\n\n");
2007 fprintf(stderr, "\nEnd module dump:\n");
2009 fprintf(stderr, "\n\nBegin Test:\n");
2011 for (int i = 1; i < argc; ++i) {
2012 // Run test for each argument whose value is the exception
2014 runExceptionThrow(executionEngine,
2016 (unsigned) strtoul(argv[i], NULL, 10));
2019 fprintf(stderr, "\nEnd Test:\n\n");
2022 delete executionEngine;