1 //===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Demo program which implements an example LLVM exception implementation, and
10 // shows several test cases including the handling of foreign exceptions.
11 // It is run with type info types arguments to throw. A test will
12 // be run for each given type info type. While type info types with the value
13 // of -1 will trigger a foreign C++ exception to be thrown; type info types
14 // <= 6 and >= 1 will cause the associated generated exceptions to be thrown
15 // and caught by generated test functions; and type info types > 6
16 // will result in exceptions which pass through to the test harness. All other
17 // type info types are not supported and could cause a crash. In all cases,
18 // the "finally" blocks of every generated test functions will executed
19 // regardless of whether or not that test function ignores or catches the
26 // causes a usage to be printed to stderr
28 // ExceptionDemo 2 3 7 -1
30 // results in the following cases:
31 // - Value 2 causes an exception with a type info type of 2 to be
32 // thrown and caught by an inner generated test function.
33 // - Value 3 causes an exception with a type info type of 3 to be
34 // thrown and caught by an outer generated test function.
35 // - Value 7 causes an exception with a type info type of 7 to be
36 // thrown and NOT be caught by any generated function.
37 // - Value -1 causes a foreign C++ exception to be thrown and not be
38 // caught by any generated function
40 // Cases -1 and 7 are caught by a C++ test harness where the validity of
41 // of a C++ catch(...) clause catching a generated exception with a
42 // type info type of 7 is explained by: example in rules 1.6.4 in
43 // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22)
45 // This code uses code from the llvm compiler-rt project and the llvm
46 // Kaleidoscope project.
48 //===----------------------------------------------------------------------===//
50 #include "llvm/ADT/STLExtras.h"
51 #include "llvm/BinaryFormat/Dwarf.h"
52 #include "llvm/ExecutionEngine/MCJIT.h"
53 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
54 #include "llvm/IR/DataLayout.h"
55 #include "llvm/IR/DerivedTypes.h"
56 #include "llvm/IR/IRBuilder.h"
57 #include "llvm/IR/Intrinsics.h"
58 #include "llvm/IR/LLVMContext.h"
59 #include "llvm/IR/LegacyPassManager.h"
60 #include "llvm/IR/Module.h"
61 #include "llvm/IR/Verifier.h"
62 #include "llvm/Support/TargetSelect.h"
63 #include "llvm/Target/TargetOptions.h"
64 #include "llvm/Transforms/Scalar.h"
66 // FIXME: Although all systems tested with (Linux, OS X), do not need this
67 // header file included. A user on ubuntu reported, undefined symbols
68 // for stderr, and fprintf, and the addition of this include fixed the
69 // issue for them. Given that LLVM's best practices include the goal
70 // of reducing the number of redundant header files included, the
71 // correct solution would be to find out why these symbols are not
72 // defined for the system in question, and fix the issue by finding out
73 // which LLVM header file, if any, would include these symbols.
83 #ifndef USE_GLOBAL_STR_CONSTS
84 #define USE_GLOBAL_STR_CONSTS true
91 /// This is our simplistic type info
92 struct OurExceptionType_t
{
98 /// This is our Exception class which relies on a negative offset to calculate
99 /// pointers to its instances from pointers to its unwindException member.
101 /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
102 /// on a double word boundary. This is necessary to match the standard:
103 /// http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
104 struct OurBaseException_t
{
105 struct OurExceptionType_t type
;
107 // Note: This is properly aligned in unwind.h
108 struct _Unwind_Exception unwindException
;
112 // Note: Not needed since we are C++
113 typedef struct OurBaseException_t OurException
;
114 typedef struct _Unwind_Exception OurUnwindException
;
117 // Various globals used to support typeinfo and generatted exceptions in
121 static std::map
<std::string
, llvm::Value
*> namedValues
;
123 int64_t ourBaseFromUnwindOffset
;
125 const unsigned char ourBaseExcpClassChars
[] =
126 {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
129 static uint64_t ourBaseExceptionClass
= 0;
131 static std::vector
<std::string
> ourTypeInfoNames
;
132 static std::map
<int, std::string
> ourTypeInfoNamesIndex
;
134 static llvm::StructType
*ourTypeInfoType
;
135 static llvm::StructType
*ourCaughtResultType
;
136 static llvm::StructType
*ourExceptionType
;
137 static llvm::StructType
*ourUnwindExceptionType
;
139 static llvm::ConstantInt
*ourExceptionNotThrownState
;
140 static llvm::ConstantInt
*ourExceptionThrownState
;
141 static llvm::ConstantInt
*ourExceptionCaughtState
;
143 typedef std::vector
<std::string
> ArgNames
;
144 typedef std::vector
<llvm::Type
*> ArgTypes
;
147 // Code Generation Utilities
150 /// Utility used to create a function, both declarations and definitions
151 /// @param module for module instance
152 /// @param retType function return type
153 /// @param theArgTypes function's ordered argument types
154 /// @param theArgNames function's ordered arguments needed if use of this
155 /// function corresponds to a function definition. Use empty
156 /// aggregate for function declarations.
157 /// @param functName function name
158 /// @param linkage function linkage
159 /// @param declarationOnly for function declarations
160 /// @param isVarArg function uses vararg arguments
161 /// @returns function instance
162 llvm::Function
*createFunction(llvm::Module
&module
,
164 const ArgTypes
&theArgTypes
,
165 const ArgNames
&theArgNames
,
166 const std::string
&functName
,
167 llvm::GlobalValue::LinkageTypes linkage
,
168 bool declarationOnly
,
170 llvm::FunctionType
*functType
=
171 llvm::FunctionType::get(retType
, theArgTypes
, isVarArg
);
172 llvm::Function
*ret
=
173 llvm::Function::Create(functType
, linkage
, functName
, &module
);
174 if (!ret
|| declarationOnly
)
179 for (llvm::Function::arg_iterator argIndex
= ret
->arg_begin();
180 i
!= theArgNames
.size();
183 argIndex
->setName(theArgNames
[i
]);
184 namedValues
[theArgNames
[i
]] = argIndex
;
191 /// Create an alloca instruction in the entry block of
192 /// the parent function. This is used for mutable variables etc.
193 /// @param function parent instance
194 /// @param varName stack variable name
195 /// @param type stack variable type
196 /// @param initWith optional constant initialization value
197 /// @returns AllocaInst instance
198 static llvm::AllocaInst
*createEntryBlockAlloca(llvm::Function
&function
,
199 const std::string
&varName
,
201 llvm::Constant
*initWith
= 0) {
202 llvm::BasicBlock
&block
= function
.getEntryBlock();
203 llvm::IRBuilder
<> tmp(&block
, block
.begin());
204 llvm::AllocaInst
*ret
= tmp
.CreateAlloca(type
, 0, varName
);
207 tmp
.CreateStore(initWith
, ret
);
214 // Code Generation Utilities End
218 // Runtime C Library functions
222 template <typename Type_
>
223 uintptr_t ReadType(const uint8_t *&p
) {
225 memcpy(&value
, p
, sizeof(Type_
));
227 return static_cast<uintptr_t>(value
);
231 // Note: using an extern "C" block so that static functions can be used
234 // Note: Better ways to decide on bit width
236 /// Prints a 32 bit number, according to the format, to stderr.
237 /// @param intToPrint integer to print
238 /// @param format printf like format to use when printing
239 void print32Int(int intToPrint
, const char *format
) {
241 // Note: No NULL check
242 fprintf(stderr
, format
, intToPrint
);
245 // Note: No NULL check
246 fprintf(stderr
, "::print32Int(...):NULL arg.\n");
251 // Note: Better ways to decide on bit width
253 /// Prints a 64 bit number, according to the format, to stderr.
254 /// @param intToPrint integer to print
255 /// @param format printf like format to use when printing
256 void print64Int(long int intToPrint
, const char *format
) {
258 // Note: No NULL check
259 fprintf(stderr
, format
, intToPrint
);
262 // Note: No NULL check
263 fprintf(stderr
, "::print64Int(...):NULL arg.\n");
268 /// Prints a C string to stderr
269 /// @param toPrint string to print
270 void printStr(char *toPrint
) {
272 fprintf(stderr
, "%s", toPrint
);
275 fprintf(stderr
, "::printStr(...):NULL arg.\n");
280 /// Deletes the true previously allocated exception whose address
281 /// is calculated from the supplied OurBaseException_t::unwindException
282 /// member address. Handles (ignores), NULL pointers.
283 /// @param expToDelete exception to delete
284 void deleteOurException(OurUnwindException
*expToDelete
) {
287 "deleteOurException(...).\n");
291 (expToDelete
->exception_class
== ourBaseExceptionClass
)) {
293 free(((char*) expToDelete
) + ourBaseFromUnwindOffset
);
298 /// This function is the struct _Unwind_Exception API mandated delete function
299 /// used by foreign exception handlers when deleting our exception
300 /// (OurException), instances.
301 /// @param reason See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
303 /// @param expToDelete exception instance to delete
304 void deleteFromUnwindOurException(_Unwind_Reason_Code reason
,
305 OurUnwindException
*expToDelete
) {
308 "deleteFromUnwindOurException(...).\n");
311 deleteOurException(expToDelete
);
315 /// Creates (allocates on the heap), an exception (OurException instance),
316 /// of the supplied type info type.
317 /// @param type type info type
318 OurUnwindException
*createOurException(int type
) {
319 size_t size
= sizeof(OurException
);
320 OurException
*ret
= (OurException
*) memset(malloc(size
), 0, size
);
321 (ret
->type
).type
= type
;
322 (ret
->unwindException
).exception_class
= ourBaseExceptionClass
;
323 (ret
->unwindException
).exception_cleanup
= deleteFromUnwindOurException
;
325 return(&(ret
->unwindException
));
329 /// Read a uleb128 encoded value and advance pointer
330 /// See Variable Length Data in:
331 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
332 /// @param data reference variable holding memory pointer to decode from
333 /// @returns decoded value
334 static uintptr_t readULEB128(const uint8_t **data
) {
335 uintptr_t result
= 0;
338 const uint8_t *p
= *data
;
342 result
|= (byte
& 0x7f) << shift
;
353 /// Read a sleb128 encoded value and advance pointer
354 /// See Variable Length Data in:
355 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
356 /// @param data reference variable holding memory pointer to decode from
357 /// @returns decoded value
358 static uintptr_t readSLEB128(const uint8_t **data
) {
359 uintptr_t result
= 0;
362 const uint8_t *p
= *data
;
366 result
|= (byte
& 0x7f) << shift
;
373 if ((byte
& 0x40) && (shift
< (sizeof(result
) << 3))) {
374 result
|= (~0 << shift
);
380 unsigned getEncodingSize(uint8_t Encoding
) {
381 if (Encoding
== llvm::dwarf::DW_EH_PE_omit
)
384 switch (Encoding
& 0x0F) {
385 case llvm::dwarf::DW_EH_PE_absptr
:
386 return sizeof(uintptr_t);
387 case llvm::dwarf::DW_EH_PE_udata2
:
388 return sizeof(uint16_t);
389 case llvm::dwarf::DW_EH_PE_udata4
:
390 return sizeof(uint32_t);
391 case llvm::dwarf::DW_EH_PE_udata8
:
392 return sizeof(uint64_t);
393 case llvm::dwarf::DW_EH_PE_sdata2
:
394 return sizeof(int16_t);
395 case llvm::dwarf::DW_EH_PE_sdata4
:
396 return sizeof(int32_t);
397 case llvm::dwarf::DW_EH_PE_sdata8
:
398 return sizeof(int64_t);
405 /// Read a pointer encoded value and advance pointer
406 /// See Variable Length Data in:
407 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
408 /// @param data reference variable holding memory pointer to decode from
409 /// @param encoding dwarf encoding type
410 /// @returns decoded value
411 static uintptr_t readEncodedPointer(const uint8_t **data
, uint8_t encoding
) {
412 uintptr_t result
= 0;
413 const uint8_t *p
= *data
;
415 if (encoding
== llvm::dwarf::DW_EH_PE_omit
)
419 switch (encoding
& 0x0F) {
420 case llvm::dwarf::DW_EH_PE_absptr
:
421 result
= ReadType
<uintptr_t>(p
);
423 case llvm::dwarf::DW_EH_PE_uleb128
:
424 result
= readULEB128(&p
);
426 // Note: This case has not been tested
427 case llvm::dwarf::DW_EH_PE_sleb128
:
428 result
= readSLEB128(&p
);
430 case llvm::dwarf::DW_EH_PE_udata2
:
431 result
= ReadType
<uint16_t>(p
);
433 case llvm::dwarf::DW_EH_PE_udata4
:
434 result
= ReadType
<uint32_t>(p
);
436 case llvm::dwarf::DW_EH_PE_udata8
:
437 result
= ReadType
<uint64_t>(p
);
439 case llvm::dwarf::DW_EH_PE_sdata2
:
440 result
= ReadType
<int16_t>(p
);
442 case llvm::dwarf::DW_EH_PE_sdata4
:
443 result
= ReadType
<int32_t>(p
);
445 case llvm::dwarf::DW_EH_PE_sdata8
:
446 result
= ReadType
<int64_t>(p
);
454 // then add relative offset
455 switch (encoding
& 0x70) {
456 case llvm::dwarf::DW_EH_PE_absptr
:
459 case llvm::dwarf::DW_EH_PE_pcrel
:
460 result
+= (uintptr_t)(*data
);
462 case llvm::dwarf::DW_EH_PE_textrel
:
463 case llvm::dwarf::DW_EH_PE_datarel
:
464 case llvm::dwarf::DW_EH_PE_funcrel
:
465 case llvm::dwarf::DW_EH_PE_aligned
:
472 // then apply indirection
473 if (encoding
& llvm::dwarf::DW_EH_PE_indirect
) {
474 result
= *((uintptr_t*)result
);
483 /// Deals with Dwarf actions matching our type infos
484 /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
485 /// action matches the supplied exception type. If such a match succeeds,
486 /// the resultAction argument will be set with > 0 index value. Only
487 /// corresponding llvm.eh.selector type info arguments, cleanup arguments
488 /// are supported. Filters are not supported.
489 /// See Variable Length Data in:
490 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
491 /// Also see @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
492 /// @param resultAction reference variable which will be set with result
493 /// @param classInfo our array of type info pointers (to globals)
494 /// @param actionEntry index into above type info array or 0 (clean up).
495 /// We do not support filters.
496 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
497 /// of thrown exception.
498 /// @param exceptionObject thrown _Unwind_Exception instance.
499 /// @returns whether or not a type info was found. False is returned if only
500 /// a cleanup was found
501 static bool handleActionValue(int64_t *resultAction
,
502 uint8_t TTypeEncoding
,
503 const uint8_t *ClassInfo
,
504 uintptr_t actionEntry
,
505 uint64_t exceptionClass
,
506 struct _Unwind_Exception
*exceptionObject
) {
511 (exceptionClass
!= ourBaseExceptionClass
))
514 struct OurBaseException_t
*excp
= (struct OurBaseException_t
*)
515 (((char*) exceptionObject
) + ourBaseFromUnwindOffset
);
516 struct OurExceptionType_t
*excpType
= &(excp
->type
);
517 int type
= excpType
->type
;
521 "handleActionValue(...): exceptionObject = <%p>, "
523 (void*)exceptionObject
,
527 const uint8_t *actionPos
= (uint8_t*) actionEntry
,
529 int64_t typeOffset
= 0,
532 for (int i
= 0; true; ++i
) {
533 // Each emitted dwarf action corresponds to a 2 tuple of
534 // type info address offset, and action offset to the next
536 typeOffset
= readSLEB128(&actionPos
);
537 tempActionPos
= actionPos
;
538 actionOffset
= readSLEB128(&tempActionPos
);
542 "handleActionValue(...):typeOffset: <%" PRIi64
">, "
543 "actionOffset: <%" PRIi64
">.\n",
547 assert((typeOffset
>= 0) &&
548 "handleActionValue(...):filters are not supported.");
550 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
551 // argument has been matched.
552 if (typeOffset
> 0) {
555 "handleActionValue(...):actionValue <%d> found.\n",
558 unsigned EncSize
= getEncodingSize(TTypeEncoding
);
559 const uint8_t *EntryP
= ClassInfo
- typeOffset
* EncSize
;
560 uintptr_t P
= readEncodedPointer(&EntryP
, TTypeEncoding
);
561 struct OurExceptionType_t
*ThisClassInfo
=
562 reinterpret_cast<struct OurExceptionType_t
*>(P
);
563 if (ThisClassInfo
->type
== type
) {
564 *resultAction
= i
+ 1;
572 "handleActionValue(...):actionValue not found.\n");
577 actionPos
+= actionOffset
;
584 /// Deals with the Language specific data portion of the emitted dwarf code.
585 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
586 /// @param version unsupported (ignored), unwind version
587 /// @param lsda language specific data area
588 /// @param _Unwind_Action actions minimally supported unwind stage
589 /// (forced specifically not supported)
590 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
591 /// of thrown exception.
592 /// @param exceptionObject thrown _Unwind_Exception instance.
593 /// @param context unwind system context
594 /// @returns minimally supported unwinding control indicator
595 static _Unwind_Reason_Code
handleLsda(int version
, const uint8_t *lsda
,
596 _Unwind_Action actions
,
597 _Unwind_Exception_Class exceptionClass
,
598 struct _Unwind_Exception
*exceptionObject
,
599 struct _Unwind_Context
*context
) {
600 _Unwind_Reason_Code ret
= _URC_CONTINUE_UNWIND
;
607 "handleLsda(...):lsda is non-zero.\n");
610 // Get the current instruction pointer and offset it before next
611 // instruction in the current frame which threw the exception.
612 uintptr_t pc
= _Unwind_GetIP(context
)-1;
614 // Get beginning current frame's code (as defined by the
615 // emitted dwarf code)
616 uintptr_t funcStart
= _Unwind_GetRegionStart(context
);
617 uintptr_t pcOffset
= pc
- funcStart
;
618 const uint8_t *ClassInfo
= NULL
;
620 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
623 // Parse LSDA header.
624 uint8_t lpStartEncoding
= *lsda
++;
626 if (lpStartEncoding
!= llvm::dwarf::DW_EH_PE_omit
) {
627 readEncodedPointer(&lsda
, lpStartEncoding
);
630 uint8_t ttypeEncoding
= *lsda
++;
631 uintptr_t classInfoOffset
;
633 if (ttypeEncoding
!= llvm::dwarf::DW_EH_PE_omit
) {
634 // Calculate type info locations in emitted dwarf code which
635 // were flagged by type info arguments to llvm.eh.selector
637 classInfoOffset
= readULEB128(&lsda
);
638 ClassInfo
= lsda
+ classInfoOffset
;
641 // Walk call-site table looking for range that
642 // includes current PC.
644 uint8_t callSiteEncoding
= *lsda
++;
645 uint32_t callSiteTableLength
= readULEB128(&lsda
);
646 const uint8_t *callSiteTableStart
= lsda
;
647 const uint8_t *callSiteTableEnd
= callSiteTableStart
+
649 const uint8_t *actionTableStart
= callSiteTableEnd
;
650 const uint8_t *callSitePtr
= callSiteTableStart
;
652 while (callSitePtr
< callSiteTableEnd
) {
653 uintptr_t start
= readEncodedPointer(&callSitePtr
,
655 uintptr_t length
= readEncodedPointer(&callSitePtr
,
657 uintptr_t landingPad
= readEncodedPointer(&callSitePtr
,
660 // Note: Action value
661 uintptr_t actionEntry
= readULEB128(&callSitePtr
);
663 if (exceptionClass
!= ourBaseExceptionClass
) {
664 // We have been notified of a foreign exception being thrown,
665 // and we therefore need to execute cleanup landing pads
669 if (landingPad
== 0) {
672 "handleLsda(...): No landing pad found.\n");
675 continue; // no landing pad for this entry
679 actionEntry
+= ((uintptr_t) actionTableStart
) - 1;
684 "handleLsda(...):No action table found.\n");
688 bool exceptionMatched
= false;
690 if ((start
<= pcOffset
) && (pcOffset
< (start
+ length
))) {
693 "handleLsda(...): Landing pad found.\n");
695 int64_t actionValue
= 0;
698 exceptionMatched
= handleActionValue(&actionValue
,
706 if (!(actions
& _UA_SEARCH_PHASE
)) {
709 "handleLsda(...): installed landing pad "
713 // Found landing pad for the PC.
714 // Set Instruction Pointer to so we re-enter function
715 // at landing pad. The landing pad is created by the
716 // compiler to take two parameters in registers.
717 _Unwind_SetGR(context
,
718 __builtin_eh_return_data_regno(0),
719 (uintptr_t)exceptionObject
);
721 // Note: this virtual register directly corresponds
722 // to the return of the llvm.eh.selector intrinsic
723 if (!actionEntry
|| !exceptionMatched
) {
724 // We indicate cleanup only
725 _Unwind_SetGR(context
,
726 __builtin_eh_return_data_regno(1),
730 // Matched type info index of llvm.eh.selector intrinsic
732 _Unwind_SetGR(context
,
733 __builtin_eh_return_data_regno(1),
737 // To execute landing pad set here
738 _Unwind_SetIP(context
, funcStart
+ landingPad
);
739 ret
= _URC_INSTALL_CONTEXT
;
741 else if (exceptionMatched
) {
744 "handleLsda(...): setting handler found.\n");
746 ret
= _URC_HANDLER_FOUND
;
749 // Note: Only non-clean up handlers are marked as
750 // found. Otherwise the clean up handlers will be
751 // re-found and executed during the clean up
755 "handleLsda(...): cleanup handler found.\n");
767 /// This is the personality function which is embedded (dwarf emitted), in the
768 /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
769 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
770 /// @param version unsupported (ignored), unwind version
771 /// @param _Unwind_Action actions minimally supported unwind stage
772 /// (forced specifically not supported)
773 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
774 /// of thrown exception.
775 /// @param exceptionObject thrown _Unwind_Exception instance.
776 /// @param context unwind system context
777 /// @returns minimally supported unwinding control indicator
778 _Unwind_Reason_Code
ourPersonality(int version
, _Unwind_Action actions
,
779 _Unwind_Exception_Class exceptionClass
,
780 struct _Unwind_Exception
*exceptionObject
,
781 struct _Unwind_Context
*context
) {
784 "We are in ourPersonality(...):actions is <%d>.\n",
787 if (actions
& _UA_SEARCH_PHASE
) {
788 fprintf(stderr
, "ourPersonality(...):In search phase.\n");
791 fprintf(stderr
, "ourPersonality(...):In non-search phase.\n");
795 const uint8_t *lsda
= _Unwind_GetLanguageSpecificData(context
);
799 "ourPersonality(...):lsda = <%p>.\n",
803 // The real work of the personality function is captured here
804 return(handleLsda(version
,
813 /// Generates our _Unwind_Exception class from a given character array.
814 /// thereby handling arbitrary lengths (not in standard), and handling
816 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
817 /// @param classChars char array to encode. NULL values not checkedf
818 /// @param classCharsSize number of chars in classChars. Value is not checked.
819 /// @returns class value
820 uint64_t genClass(const unsigned char classChars
[], size_t classCharsSize
)
822 uint64_t ret
= classChars
[0];
824 for (unsigned i
= 1; i
< classCharsSize
; ++i
) {
826 ret
+= classChars
[i
];
835 // Runtime C Library functions End
839 // Code generation functions
842 /// Generates code to print given constant string
843 /// @param context llvm context
844 /// @param module code for module instance
845 /// @param builder builder instance
846 /// @param toPrint string to print
847 /// @param useGlobal A value of true (default) indicates a GlobalValue is
848 /// generated, and is used to hold the constant string. A value of
849 /// false indicates that the constant string will be stored on the
851 void generateStringPrint(llvm::LLVMContext
&context
,
852 llvm::Module
&module
,
853 llvm::IRBuilder
<> &builder
,
855 bool useGlobal
= true) {
856 llvm::Function
*printFunct
= module
.getFunction("printStr");
858 llvm::Value
*stringVar
;
859 llvm::Constant
*stringConstant
=
860 llvm::ConstantDataArray::getString(context
, toPrint
);
863 // Note: Does not work without allocation
865 new llvm::GlobalVariable(module
,
866 stringConstant
->getType(),
868 llvm::GlobalValue::PrivateLinkage
,
873 stringVar
= builder
.CreateAlloca(stringConstant
->getType());
874 builder
.CreateStore(stringConstant
, stringVar
);
877 llvm::Value
*cast
= builder
.CreatePointerCast(stringVar
,
878 builder
.getInt8PtrTy());
879 builder
.CreateCall(printFunct
, cast
);
883 /// Generates code to print given runtime integer according to constant
884 /// string format, and a given print function.
885 /// @param context llvm context
886 /// @param module code for module instance
887 /// @param builder builder instance
888 /// @param printFunct function used to "print" integer
889 /// @param toPrint string to print
890 /// @param format printf like formating string for print
891 /// @param useGlobal A value of true (default) indicates a GlobalValue is
892 /// generated, and is used to hold the constant string. A value of
893 /// false indicates that the constant string will be stored on the
895 void generateIntegerPrint(llvm::LLVMContext
&context
,
896 llvm::Module
&module
,
897 llvm::IRBuilder
<> &builder
,
898 llvm::Function
&printFunct
,
899 llvm::Value
&toPrint
,
901 bool useGlobal
= true) {
902 llvm::Constant
*stringConstant
=
903 llvm::ConstantDataArray::getString(context
, format
);
904 llvm::Value
*stringVar
;
907 // Note: Does not seem to work without allocation
909 new llvm::GlobalVariable(module
,
910 stringConstant
->getType(),
912 llvm::GlobalValue::PrivateLinkage
,
917 stringVar
= builder
.CreateAlloca(stringConstant
->getType());
918 builder
.CreateStore(stringConstant
, stringVar
);
921 llvm::Value
*cast
= builder
.CreateBitCast(stringVar
,
922 builder
.getInt8PtrTy());
923 builder
.CreateCall(&printFunct
, {&toPrint
, cast
});
927 /// Generates code to handle finally block type semantics: always runs
928 /// regardless of whether a thrown exception is passing through or the
929 /// parent function is simply exiting. In addition to printing some state
930 /// to stderr, this code will resume the exception handling--runs the
931 /// unwind resume block, if the exception has not been previously caught
932 /// by a catch clause, and will otherwise execute the end block (terminator
933 /// block). In addition this function creates the corresponding function's
934 /// stack storage for the exception pointer and catch flag status.
935 /// @param context llvm context
936 /// @param module code for module instance
937 /// @param builder builder instance
938 /// @param toAddTo parent function to add block to
939 /// @param blockName block name of new "finally" block.
940 /// @param functionId output id used for printing
941 /// @param terminatorBlock terminator "end" block
942 /// @param unwindResumeBlock unwind resume block
943 /// @param exceptionCaughtFlag reference exception caught/thrown status storage
944 /// @param exceptionStorage reference to exception pointer storage
945 /// @param caughtResultStorage reference to landingpad result storage
946 /// @returns newly created block
947 static llvm::BasicBlock
*createFinallyBlock(llvm::LLVMContext
&context
,
948 llvm::Module
&module
,
949 llvm::IRBuilder
<> &builder
,
950 llvm::Function
&toAddTo
,
951 std::string
&blockName
,
952 std::string
&functionId
,
953 llvm::BasicBlock
&terminatorBlock
,
954 llvm::BasicBlock
&unwindResumeBlock
,
955 llvm::Value
**exceptionCaughtFlag
,
956 llvm::Value
**exceptionStorage
,
957 llvm::Value
**caughtResultStorage
) {
958 assert(exceptionCaughtFlag
&&
959 "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
961 assert(exceptionStorage
&&
962 "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
964 assert(caughtResultStorage
&&
965 "ExceptionDemo::createFinallyBlock(...):caughtResultStorage "
968 *exceptionCaughtFlag
= createEntryBlockAlloca(toAddTo
,
970 ourExceptionNotThrownState
->getType(),
971 ourExceptionNotThrownState
);
973 llvm::PointerType
*exceptionStorageType
= builder
.getInt8PtrTy();
974 *exceptionStorage
= createEntryBlockAlloca(toAddTo
,
976 exceptionStorageType
,
977 llvm::ConstantPointerNull::get(
978 exceptionStorageType
));
979 *caughtResultStorage
= createEntryBlockAlloca(toAddTo
,
980 "caughtResultStorage",
982 llvm::ConstantAggregateZero::get(
983 ourCaughtResultType
));
985 llvm::BasicBlock
*ret
= llvm::BasicBlock::Create(context
,
989 builder
.SetInsertPoint(ret
);
991 std::ostringstream bufferToPrint
;
992 bufferToPrint
<< "Gen: Executing finally block "
993 << blockName
<< " in " << functionId
<< "\n";
994 generateStringPrint(context
,
998 USE_GLOBAL_STR_CONSTS
);
1000 llvm::SwitchInst
*theSwitch
= builder
.CreateSwitch(builder
.CreateLoad(
1001 *exceptionCaughtFlag
),
1004 theSwitch
->addCase(ourExceptionCaughtState
, &terminatorBlock
);
1005 theSwitch
->addCase(ourExceptionThrownState
, &unwindResumeBlock
);
1011 /// Generates catch block semantics which print a string to indicate type of
1012 /// catch executed, sets an exception caught flag, and executes passed in
1013 /// end block (terminator block).
1014 /// @param context llvm context
1015 /// @param module code for module instance
1016 /// @param builder builder instance
1017 /// @param toAddTo parent function to add block to
1018 /// @param blockName block name of new "catch" block.
1019 /// @param functionId output id used for printing
1020 /// @param terminatorBlock terminator "end" block
1021 /// @param exceptionCaughtFlag exception caught/thrown status
1022 /// @returns newly created block
1023 static llvm::BasicBlock
*createCatchBlock(llvm::LLVMContext
&context
,
1024 llvm::Module
&module
,
1025 llvm::IRBuilder
<> &builder
,
1026 llvm::Function
&toAddTo
,
1027 std::string
&blockName
,
1028 std::string
&functionId
,
1029 llvm::BasicBlock
&terminatorBlock
,
1030 llvm::Value
&exceptionCaughtFlag
) {
1032 llvm::BasicBlock
*ret
= llvm::BasicBlock::Create(context
,
1036 builder
.SetInsertPoint(ret
);
1038 std::ostringstream bufferToPrint
;
1039 bufferToPrint
<< "Gen: Executing catch block "
1044 generateStringPrint(context
,
1047 bufferToPrint
.str(),
1048 USE_GLOBAL_STR_CONSTS
);
1049 builder
.CreateStore(ourExceptionCaughtState
, &exceptionCaughtFlag
);
1050 builder
.CreateBr(&terminatorBlock
);
1056 /// Generates a function which invokes a function (toInvoke) and, whose
1057 /// unwind block will "catch" the type info types correspondingly held in the
1058 /// exceptionTypesToCatch argument. If the toInvoke function throws an
1059 /// exception which does not match any type info types contained in
1060 /// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1061 /// with the raised exception. On the other hand the generated code will
1062 /// normally exit if the toInvoke function does not throw an exception.
1063 /// The generated "finally" block is always run regardless of the cause of
1064 /// the generated function exit.
1065 /// The generated function is returned after being verified.
1066 /// @param module code for module instance
1067 /// @param builder builder instance
1068 /// @param fpm a function pass manager holding optional IR to IR
1070 /// @param toInvoke inner function to invoke
1071 /// @param ourId id used to printing purposes
1072 /// @param numExceptionsToCatch length of exceptionTypesToCatch array
1073 /// @param exceptionTypesToCatch array of type info types to "catch"
1074 /// @returns generated function
1075 static llvm::Function
*createCatchWrappedInvokeFunction(
1076 llvm::Module
&module
, llvm::IRBuilder
<> &builder
,
1077 llvm::legacy::FunctionPassManager
&fpm
, llvm::Function
&toInvoke
,
1078 std::string ourId
, unsigned numExceptionsToCatch
,
1079 unsigned exceptionTypesToCatch
[]) {
1081 llvm::LLVMContext
&context
= module
.getContext();
1082 llvm::Function
*toPrint32Int
= module
.getFunction("print32Int");
1085 argTypes
.push_back(builder
.getInt32Ty());
1088 argNames
.push_back("exceptTypeToThrow");
1090 llvm::Function
*ret
= createFunction(module
,
1091 builder
.getVoidTy(),
1095 llvm::Function::ExternalLinkage
,
1099 // Block which calls invoke
1100 llvm::BasicBlock
*entryBlock
= llvm::BasicBlock::Create(context
,
1103 // Normal block for invoke
1104 llvm::BasicBlock
*normalBlock
= llvm::BasicBlock::Create(context
,
1107 // Unwind block for invoke
1108 llvm::BasicBlock
*exceptionBlock
= llvm::BasicBlock::Create(context
,
1112 // Block which routes exception to correct catch handler block
1113 llvm::BasicBlock
*exceptionRouteBlock
= llvm::BasicBlock::Create(context
,
1117 // Foreign exception handler
1118 llvm::BasicBlock
*externalExceptionBlock
= llvm::BasicBlock::Create(context
,
1119 "externalException",
1122 // Block which calls _Unwind_Resume
1123 llvm::BasicBlock
*unwindResumeBlock
= llvm::BasicBlock::Create(context
,
1127 // Clean up block which delete exception if needed
1128 llvm::BasicBlock
*endBlock
= llvm::BasicBlock::Create(context
, "end", ret
);
1130 std::string nextName
;
1131 std::vector
<llvm::BasicBlock
*> catchBlocks(numExceptionsToCatch
);
1132 llvm::Value
*exceptionCaughtFlag
= NULL
;
1133 llvm::Value
*exceptionStorage
= NULL
;
1134 llvm::Value
*caughtResultStorage
= NULL
;
1136 // Finally block which will branch to unwindResumeBlock if
1137 // exception is not caught. Initializes/allocates stack locations.
1138 llvm::BasicBlock
*finallyBlock
= createFinallyBlock(context
,
1142 nextName
= "finally",
1146 &exceptionCaughtFlag
,
1148 &caughtResultStorage
1151 for (unsigned i
= 0; i
< numExceptionsToCatch
; ++i
) {
1152 nextName
= ourTypeInfoNames
[exceptionTypesToCatch
[i
]];
1154 // One catch block per type info to be caught
1155 catchBlocks
[i
] = createCatchBlock(context
,
1162 *exceptionCaughtFlag
);
1167 builder
.SetInsertPoint(entryBlock
);
1169 std::vector
<llvm::Value
*> args
;
1170 args
.push_back(namedValues
["exceptTypeToThrow"]);
1171 builder
.CreateInvoke(&toInvoke
,
1178 builder
.SetInsertPoint(endBlock
);
1180 generateStringPrint(context
,
1183 "Gen: In end block: exiting in " + ourId
+ ".\n",
1184 USE_GLOBAL_STR_CONSTS
);
1185 llvm::Function
*deleteOurException
= module
.getFunction("deleteOurException");
1187 // Note: function handles NULL exceptions
1188 builder
.CreateCall(deleteOurException
,
1189 builder
.CreateLoad(exceptionStorage
));
1190 builder
.CreateRetVoid();
1194 builder
.SetInsertPoint(normalBlock
);
1196 generateStringPrint(context
,
1199 "Gen: No exception in " + ourId
+ "!\n",
1200 USE_GLOBAL_STR_CONSTS
);
1202 // Finally block is always called
1203 builder
.CreateBr(finallyBlock
);
1205 // Unwind Resume Block
1207 builder
.SetInsertPoint(unwindResumeBlock
);
1209 builder
.CreateResume(builder
.CreateLoad(caughtResultStorage
));
1213 builder
.SetInsertPoint(exceptionBlock
);
1215 llvm::Function
*personality
= module
.getFunction("ourPersonality");
1216 ret
->setPersonalityFn(personality
);
1218 llvm::LandingPadInst
*caughtResult
=
1219 builder
.CreateLandingPad(ourCaughtResultType
,
1220 numExceptionsToCatch
,
1223 caughtResult
->setCleanup(true);
1225 for (unsigned i
= 0; i
< numExceptionsToCatch
; ++i
) {
1226 // Set up type infos to be caught
1227 caughtResult
->addClause(module
.getGlobalVariable(
1228 ourTypeInfoNames
[exceptionTypesToCatch
[i
]]));
1231 llvm::Value
*unwindException
= builder
.CreateExtractValue(caughtResult
, 0);
1232 llvm::Value
*retTypeInfoIndex
= builder
.CreateExtractValue(caughtResult
, 1);
1234 // FIXME: Redundant storage which, beyond utilizing value of
1235 // caughtResultStore for unwindException storage, may be alleviated
1236 // altogether with a block rearrangement
1237 builder
.CreateStore(caughtResult
, caughtResultStorage
);
1238 builder
.CreateStore(unwindException
, exceptionStorage
);
1239 builder
.CreateStore(ourExceptionThrownState
, exceptionCaughtFlag
);
1241 // Retrieve exception_class member from thrown exception
1242 // (_Unwind_Exception instance). This member tells us whether or not
1243 // the exception is foreign.
1244 llvm::Value
*unwindExceptionClass
=
1245 builder
.CreateLoad(builder
.CreateStructGEP(
1246 ourUnwindExceptionType
,
1247 builder
.CreatePointerCast(unwindException
,
1248 ourUnwindExceptionType
->getPointerTo()),
1251 // Branch to the externalExceptionBlock if the exception is foreign or
1252 // to a catch router if not. Either way the finally block will be run.
1253 builder
.CreateCondBr(builder
.CreateICmpEQ(unwindExceptionClass
,
1254 llvm::ConstantInt::get(builder
.getInt64Ty(),
1255 ourBaseExceptionClass
)),
1256 exceptionRouteBlock
,
1257 externalExceptionBlock
);
1259 // External Exception Block
1261 builder
.SetInsertPoint(externalExceptionBlock
);
1263 generateStringPrint(context
,
1266 "Gen: Foreign exception received.\n",
1267 USE_GLOBAL_STR_CONSTS
);
1269 // Branch to the finally block
1270 builder
.CreateBr(finallyBlock
);
1272 // Exception Route Block
1274 builder
.SetInsertPoint(exceptionRouteBlock
);
1276 // Casts exception pointer (_Unwind_Exception instance) to parent
1277 // (OurException instance).
1279 // Note: ourBaseFromUnwindOffset is usually negative
1280 llvm::Value
*typeInfoThrown
= builder
.CreatePointerCast(
1281 builder
.CreateConstGEP1_64(unwindException
,
1282 ourBaseFromUnwindOffset
),
1283 ourExceptionType
->getPointerTo());
1285 // Retrieve thrown exception type info type
1287 // Note: Index is not relative to pointer but instead to structure
1288 // unlike a true getelementptr (GEP) instruction
1289 typeInfoThrown
= builder
.CreateStructGEP(ourExceptionType
, typeInfoThrown
, 0);
1291 llvm::Value
*typeInfoThrownType
=
1292 builder
.CreateStructGEP(builder
.getInt8PtrTy(), typeInfoThrown
, 0);
1294 generateIntegerPrint(context
,
1298 *(builder
.CreateLoad(typeInfoThrownType
)),
1299 "Gen: Exception type <%d> received (stack unwound) "
1303 USE_GLOBAL_STR_CONSTS
);
1305 // Route to matched type info catch block or run cleanup finally block
1306 llvm::SwitchInst
*switchToCatchBlock
= builder
.CreateSwitch(retTypeInfoIndex
,
1308 numExceptionsToCatch
);
1310 unsigned nextTypeToCatch
;
1312 for (unsigned i
= 1; i
<= numExceptionsToCatch
; ++i
) {
1313 nextTypeToCatch
= i
- 1;
1314 switchToCatchBlock
->addCase(llvm::ConstantInt::get(
1315 llvm::Type::getInt32Ty(context
), i
),
1316 catchBlocks
[nextTypeToCatch
]);
1319 llvm::verifyFunction(*ret
);
1326 /// Generates function which throws either an exception matched to a runtime
1327 /// determined type info type (argument to generated function), or if this
1328 /// runtime value matches nativeThrowType, throws a foreign exception by
1329 /// calling nativeThrowFunct.
1330 /// @param module code for module instance
1331 /// @param builder builder instance
1332 /// @param fpm a function pass manager holding optional IR to IR
1334 /// @param ourId id used to printing purposes
1335 /// @param nativeThrowType a runtime argument of this value results in
1336 /// nativeThrowFunct being called to generate/throw exception.
1337 /// @param nativeThrowFunct function which will throw a foreign exception
1338 /// if the above nativeThrowType matches generated function's arg.
1339 /// @returns generated function
1340 static llvm::Function
*
1341 createThrowExceptionFunction(llvm::Module
&module
, llvm::IRBuilder
<> &builder
,
1342 llvm::legacy::FunctionPassManager
&fpm
,
1343 std::string ourId
, int32_t nativeThrowType
,
1344 llvm::Function
&nativeThrowFunct
) {
1345 llvm::LLVMContext
&context
= module
.getContext();
1346 namedValues
.clear();
1347 ArgTypes unwindArgTypes
;
1348 unwindArgTypes
.push_back(builder
.getInt32Ty());
1349 ArgNames unwindArgNames
;
1350 unwindArgNames
.push_back("exceptTypeToThrow");
1352 llvm::Function
*ret
= createFunction(module
,
1353 builder
.getVoidTy(),
1357 llvm::Function::ExternalLinkage
,
1361 // Throws either one of our exception or a native C++ exception depending
1362 // on a runtime argument value containing a type info type.
1363 llvm::BasicBlock
*entryBlock
= llvm::BasicBlock::Create(context
,
1366 // Throws a foreign exception
1367 llvm::BasicBlock
*nativeThrowBlock
= llvm::BasicBlock::Create(context
,
1370 // Throws one of our Exceptions
1371 llvm::BasicBlock
*generatedThrowBlock
= llvm::BasicBlock::Create(context
,
1374 // Retrieved runtime type info type to throw
1375 llvm::Value
*exceptionType
= namedValues
["exceptTypeToThrow"];
1377 // nativeThrowBlock block
1379 builder
.SetInsertPoint(nativeThrowBlock
);
1381 // Throws foreign exception
1382 builder
.CreateCall(&nativeThrowFunct
, exceptionType
);
1383 builder
.CreateUnreachable();
1387 builder
.SetInsertPoint(entryBlock
);
1389 llvm::Function
*toPrint32Int
= module
.getFunction("print32Int");
1390 generateIntegerPrint(context
,
1395 "\nGen: About to throw exception type <%d> in " +
1398 USE_GLOBAL_STR_CONSTS
);
1400 // Switches on runtime type info type value to determine whether or not
1401 // a foreign exception is thrown. Defaults to throwing one of our
1402 // generated exceptions.
1403 llvm::SwitchInst
*theSwitch
= builder
.CreateSwitch(exceptionType
,
1404 generatedThrowBlock
,
1407 theSwitch
->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context
),
1411 // generatedThrow block
1413 builder
.SetInsertPoint(generatedThrowBlock
);
1415 llvm::Function
*createOurException
= module
.getFunction("createOurException");
1416 llvm::Function
*raiseOurException
= module
.getFunction(
1417 "_Unwind_RaiseException");
1419 // Creates exception to throw with runtime type info type.
1420 llvm::Value
*exception
= builder
.CreateCall(createOurException
,
1421 namedValues
["exceptTypeToThrow"]);
1423 // Throw generated Exception
1424 builder
.CreateCall(raiseOurException
, exception
);
1425 builder
.CreateUnreachable();
1427 llvm::verifyFunction(*ret
);
1433 static void createStandardUtilityFunctions(unsigned numTypeInfos
,
1434 llvm::Module
&module
,
1435 llvm::IRBuilder
<> &builder
);
1437 /// Creates test code by generating and organizing these functions into the
1438 /// test case. The test case consists of an outer function setup to invoke
1439 /// an inner function within an environment having multiple catch and single
1440 /// finally blocks. This inner function is also setup to invoke a throw
1441 /// function within an evironment similar in nature to the outer function's
1442 /// catch and finally blocks. Each of these two functions catch mutually
1443 /// exclusive subsets (even or odd) of the type info types configured
1444 /// for this this. All generated functions have a runtime argument which
1445 /// holds a type info type to throw that each function takes and passes it
1446 /// to the inner one if such a inner function exists. This type info type is
1447 /// looked at by the generated throw function to see whether or not it should
1448 /// throw a generated exception with the same type info type, or instead call
1449 /// a supplied a function which in turn will throw a foreign exception.
1450 /// @param module code for module instance
1451 /// @param builder builder instance
1452 /// @param fpm a function pass manager holding optional IR to IR
1454 /// @param nativeThrowFunctName name of external function which will throw
1455 /// a foreign exception
1456 /// @returns outermost generated test function.
1458 createUnwindExceptionTest(llvm::Module
&module
, llvm::IRBuilder
<> &builder
,
1459 llvm::legacy::FunctionPassManager
&fpm
,
1460 std::string nativeThrowFunctName
) {
1461 // Number of type infos to generate
1462 unsigned numTypeInfos
= 6;
1464 // Initialze intrisics and external functions to use along with exception
1465 // and type info globals.
1466 createStandardUtilityFunctions(numTypeInfos
,
1469 llvm::Function
*nativeThrowFunct
= module
.getFunction(nativeThrowFunctName
);
1471 // Create exception throw function using the value ~0 to cause
1472 // foreign exceptions to be thrown.
1473 llvm::Function
*throwFunct
= createThrowExceptionFunction(module
,
1479 // Inner function will catch even type infos
1480 unsigned innerExceptionTypesToCatch
[] = {6, 2, 4};
1481 size_t numExceptionTypesToCatch
= sizeof(innerExceptionTypesToCatch
) /
1484 // Generate inner function.
1485 llvm::Function
*innerCatchFunct
= createCatchWrappedInvokeFunction(module
,
1490 numExceptionTypesToCatch
,
1491 innerExceptionTypesToCatch
);
1493 // Outer function will catch odd type infos
1494 unsigned outerExceptionTypesToCatch
[] = {3, 1, 5};
1495 numExceptionTypesToCatch
= sizeof(outerExceptionTypesToCatch
) /
1498 // Generate outer function
1499 llvm::Function
*outerCatchFunct
= createCatchWrappedInvokeFunction(module
,
1504 numExceptionTypesToCatch
,
1505 outerExceptionTypesToCatch
);
1507 // Return outer function to run
1508 return(outerCatchFunct
);
1512 /// Represents our foreign exceptions
1513 class OurCppRunException
: public std::runtime_error
{
1515 OurCppRunException(const std::string reason
) :
1516 std::runtime_error(reason
) {}
1518 OurCppRunException (const OurCppRunException
&toCopy
) :
1519 std::runtime_error(toCopy
) {}
1521 OurCppRunException
&operator = (const OurCppRunException
&toCopy
) {
1522 return(reinterpret_cast<OurCppRunException
&>(
1523 std::runtime_error::operator=(toCopy
)));
1526 ~OurCppRunException(void) throw() override
{}
1528 } // end anonymous namespace
1530 /// Throws foreign C++ exception.
1531 /// @param ignoreIt unused parameter that allows function to match implied
1532 /// generated function contract.
1534 void throwCppException (int32_t ignoreIt
) {
1535 throw(OurCppRunException("thrown by throwCppException(...)"));
1538 typedef void (*OurExceptionThrowFunctType
) (int32_t typeToThrow
);
1540 /// This is a test harness which runs test by executing generated
1541 /// function with a type info type to throw. Harness wraps the execution
1542 /// of generated function in a C++ try catch clause.
1543 /// @param engine execution engine to use for executing generated function.
1544 /// This demo program expects this to be a JIT instance for demo
1546 /// @param function generated test function to run
1547 /// @param typeToThrow type info type of generated exception to throw, or
1548 /// indicator to cause foreign exception to be thrown.
1550 void runExceptionThrow(llvm::ExecutionEngine
*engine
,
1551 llvm::Function
*function
,
1552 int32_t typeToThrow
) {
1554 // Find test's function pointer
1555 OurExceptionThrowFunctType functPtr
=
1556 reinterpret_cast<OurExceptionThrowFunctType
>(
1557 reinterpret_cast<intptr_t>(engine
->getPointerToFunction(function
)));
1561 (*functPtr
)(typeToThrow
);
1563 catch (OurCppRunException exc
) {
1564 // Catch foreign C++ exception
1566 "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1567 "with reason: %s.\n",
1571 // Catch all exceptions including our generated ones. This latter
1572 // functionality works according to the example in rules 1.6.4 of
1573 // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22),
1574 // given that these will be exceptions foreign to C++
1575 // (the _Unwind_Exception::exception_class should be different from
1576 // the one used by C++).
1578 "\nrunExceptionThrow(...):In C++ catch all.\n");
1583 // End test functions
1586 typedef llvm::ArrayRef
<llvm::Type
*> TypeArray
;
1588 /// This initialization routine creates type info globals and
1589 /// adds external function declarations to module.
1590 /// @param numTypeInfos number of linear type info associated type info types
1591 /// to create as GlobalVariable instances, starting with the value 1.
1592 /// @param module code for module instance
1593 /// @param builder builder instance
1594 static void createStandardUtilityFunctions(unsigned numTypeInfos
,
1595 llvm::Module
&module
,
1596 llvm::IRBuilder
<> &builder
) {
1598 llvm::LLVMContext
&context
= module
.getContext();
1600 // Exception initializations
1602 // Setup exception catch state
1603 ourExceptionNotThrownState
=
1604 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context
), 0),
1605 ourExceptionThrownState
=
1606 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context
), 1),
1607 ourExceptionCaughtState
=
1608 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context
), 2),
1612 // Create our type info type
1613 ourTypeInfoType
= llvm::StructType::get(context
,
1614 TypeArray(builder
.getInt32Ty()));
1616 llvm::Type
*caughtResultFieldTypes
[] = {
1617 builder
.getInt8PtrTy(),
1618 builder
.getInt32Ty()
1621 // Create our landingpad result type
1622 ourCaughtResultType
= llvm::StructType::get(context
,
1623 TypeArray(caughtResultFieldTypes
));
1625 // Create OurException type
1626 ourExceptionType
= llvm::StructType::get(context
,
1627 TypeArray(ourTypeInfoType
));
1629 // Create portion of _Unwind_Exception type
1631 // Note: Declaring only a portion of the _Unwind_Exception struct.
1632 // Does this cause problems?
1633 ourUnwindExceptionType
=
1634 llvm::StructType::get(context
,
1635 TypeArray(builder
.getInt64Ty()));
1637 struct OurBaseException_t dummyException
;
1639 // Calculate offset of OurException::unwindException member.
1640 ourBaseFromUnwindOffset
= ((uintptr_t) &dummyException
) -
1641 ((uintptr_t) &(dummyException
.unwindException
));
1645 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1646 "= %" PRIi64
", sizeof(struct OurBaseException_t) - "
1647 "sizeof(struct _Unwind_Exception) = %lu.\n",
1648 ourBaseFromUnwindOffset
,
1649 sizeof(struct OurBaseException_t
) -
1650 sizeof(struct _Unwind_Exception
));
1653 size_t numChars
= sizeof(ourBaseExcpClassChars
) / sizeof(char);
1655 // Create our _Unwind_Exception::exception_class value
1656 ourBaseExceptionClass
= genClass(ourBaseExcpClassChars
, numChars
);
1660 std::string baseStr
= "typeInfo", typeInfoName
;
1661 std::ostringstream typeInfoNameBuilder
;
1662 std::vector
<llvm::Constant
*> structVals
;
1664 llvm::Constant
*nextStruct
;
1666 // Generate each type info
1668 // Note: First type info is not used.
1669 for (unsigned i
= 0; i
<= numTypeInfos
; ++i
) {
1671 structVals
.push_back(llvm::ConstantInt::get(builder
.getInt32Ty(), i
));
1672 nextStruct
= llvm::ConstantStruct::get(ourTypeInfoType
, structVals
);
1674 typeInfoNameBuilder
.str("");
1675 typeInfoNameBuilder
<< baseStr
<< i
;
1676 typeInfoName
= typeInfoNameBuilder
.str();
1678 // Note: Does not seem to work without allocation
1679 new llvm::GlobalVariable(module
,
1682 llvm::GlobalValue::ExternalLinkage
,
1686 ourTypeInfoNames
.push_back(typeInfoName
);
1687 ourTypeInfoNamesIndex
[i
] = typeInfoName
;
1692 llvm::Function
*funct
= NULL
;
1696 llvm::Type
*retType
= builder
.getVoidTy();
1699 argTypes
.push_back(builder
.getInt32Ty());
1700 argTypes
.push_back(builder
.getInt8PtrTy());
1704 createFunction(module
,
1709 llvm::Function::ExternalLinkage
,
1715 retType
= builder
.getVoidTy();
1718 argTypes
.push_back(builder
.getInt64Ty());
1719 argTypes
.push_back(builder
.getInt8PtrTy());
1723 createFunction(module
,
1728 llvm::Function::ExternalLinkage
,
1734 retType
= builder
.getVoidTy();
1737 argTypes
.push_back(builder
.getInt8PtrTy());
1741 createFunction(module
,
1746 llvm::Function::ExternalLinkage
,
1750 // throwCppException
1752 retType
= builder
.getVoidTy();
1755 argTypes
.push_back(builder
.getInt32Ty());
1759 createFunction(module
,
1763 "throwCppException",
1764 llvm::Function::ExternalLinkage
,
1768 // deleteOurException
1770 retType
= builder
.getVoidTy();
1773 argTypes
.push_back(builder
.getInt8PtrTy());
1777 createFunction(module
,
1781 "deleteOurException",
1782 llvm::Function::ExternalLinkage
,
1786 // createOurException
1788 retType
= builder
.getInt8PtrTy();
1791 argTypes
.push_back(builder
.getInt32Ty());
1795 createFunction(module
,
1799 "createOurException",
1800 llvm::Function::ExternalLinkage
,
1804 // _Unwind_RaiseException
1806 retType
= builder
.getInt32Ty();
1809 argTypes
.push_back(builder
.getInt8PtrTy());
1813 funct
= createFunction(module
,
1817 "_Unwind_RaiseException",
1818 llvm::Function::ExternalLinkage
,
1822 funct
->setDoesNotReturn();
1826 retType
= builder
.getInt32Ty();
1829 argTypes
.push_back(builder
.getInt8PtrTy());
1833 funct
= createFunction(module
,
1838 llvm::Function::ExternalLinkage
,
1842 funct
->setDoesNotReturn();
1846 retType
= builder
.getInt32Ty();
1849 argTypes
.push_back(builder
.getInt32Ty());
1850 argTypes
.push_back(builder
.getInt32Ty());
1851 argTypes
.push_back(builder
.getInt64Ty());
1852 argTypes
.push_back(builder
.getInt8PtrTy());
1853 argTypes
.push_back(builder
.getInt8PtrTy());
1857 createFunction(module
,
1862 llvm::Function::ExternalLinkage
,
1866 // llvm.eh.typeid.for intrinsic
1868 getDeclaration(&module
, llvm::Intrinsic::eh_typeid_for
);
1872 //===----------------------------------------------------------------------===//
1873 // Main test driver code.
1874 //===----------------------------------------------------------------------===//
1876 /// Demo main routine which takes the type info types to throw. A test will
1877 /// be run for each given type info type. While type info types with the value
1878 /// of -1 will trigger a foreign C++ exception to be thrown; type info types
1879 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1880 /// will result in exceptions which pass through to the test harness. All other
1881 /// type info types are not supported and could cause a crash.
1882 int main(int argc
, char *argv
[]) {
1885 "\nUsage: ExceptionDemo <exception type to throw> "
1886 "[<type 2>...<type n>].\n"
1887 " Each type must have the value of 1 - 6 for "
1888 "generated exceptions to be caught;\n"
1889 " the value -1 for foreign C++ exceptions to be "
1890 "generated and thrown;\n"
1891 " or the values > 6 for exceptions to be ignored.\n"
1892 "\nTry: ExceptionDemo 2 3 7 -1\n"
1893 " for a full test.\n\n");
1897 // If not set, exception handling will not be turned on
1898 llvm::TargetOptions Opts
;
1900 llvm::InitializeNativeTarget();
1901 llvm::InitializeNativeTargetAsmPrinter();
1902 llvm::LLVMContext Context
;
1903 llvm::IRBuilder
<> theBuilder(Context
);
1905 // Make the module, which holds all the code.
1906 std::unique_ptr
<llvm::Module
> Owner
=
1907 llvm::make_unique
<llvm::Module
>("my cool jit", Context
);
1908 llvm::Module
*module
= Owner
.get();
1910 std::unique_ptr
<llvm::RTDyldMemoryManager
> MemMgr(new llvm::SectionMemoryManager());
1912 // Build engine with JIT
1913 llvm::EngineBuilder
factory(std::move(Owner
));
1914 factory
.setEngineKind(llvm::EngineKind::JIT
);
1915 factory
.setTargetOptions(Opts
);
1916 factory
.setMCJITMemoryManager(std::move(MemMgr
));
1917 llvm::ExecutionEngine
*executionEngine
= factory
.create();
1920 llvm::legacy::FunctionPassManager
fpm(module
);
1922 // Set up the optimizer pipeline.
1923 // Start with registering info about how the
1924 // target lays out data structures.
1925 module
->setDataLayout(executionEngine
->getDataLayout());
1927 // Optimizations turned on
1928 #ifdef ADD_OPT_PASSES
1930 // Basic AliasAnslysis support for GVN.
1931 fpm
.add(llvm::createBasicAliasAnalysisPass());
1933 // Promote allocas to registers.
1934 fpm
.add(llvm::createPromoteMemoryToRegisterPass());
1936 // Do simple "peephole" optimizations and bit-twiddling optzns.
1937 fpm
.add(llvm::createInstructionCombiningPass());
1939 // Reassociate expressions.
1940 fpm
.add(llvm::createReassociatePass());
1942 // Eliminate Common SubExpressions.
1943 fpm
.add(llvm::createGVNPass());
1945 // Simplify the control flow graph (deleting unreachable
1947 fpm
.add(llvm::createCFGSimplificationPass());
1948 #endif // ADD_OPT_PASSES
1950 fpm
.doInitialization();
1952 // Generate test code using function throwCppException(...) as
1953 // the function which throws foreign exceptions.
1954 llvm::Function
*toRun
=
1955 createUnwindExceptionTest(*module
,
1958 "throwCppException");
1960 executionEngine
->finalizeObject();
1962 fprintf(stderr
, "\nBegin module dump:\n\n");
1966 fprintf(stderr
, "\nEnd module dump:\n");
1968 fprintf(stderr
, "\n\nBegin Test:\n");
1970 for (int i
= 1; i
< argc
; ++i
) {
1971 // Run test for each argument whose value is the exception
1973 runExceptionThrow(executionEngine
,
1975 (unsigned) strtoul(argv
[i
], NULL
, 10));
1978 fprintf(stderr
, "\nEnd Test:\n\n");
1981 delete executionEngine
;