blob: 46dc4810214ba74f57b8008e19b23653ddc7fdfc [file] [log] [blame]
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001//===-- examples/ExceptionDemo/ExceptionDemo.cpp -
2// An example use of the llvm Exception mechanism --===//
3//
4// The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===--------------------------------------------------------------------===//
10//
11// Demo program which implements an example LLVM exception implementation, and
12// shows several test cases including the handling of foreign exceptions.
13// It is run with type info types arguments to throw. A test will
14// be run for each given type info type. While type info types with the value
15// of -1 will trigger a foreign C++ exception to be thrown; type info types
16// <= 6 and >= 1 will cause the associated generated exceptions to be thrown
17// and caught by generated test functions; and type info types > 6
18// will result in exceptions which pass through to the test harness. All other
19// type info types are not supported and could cause a crash. In all cases,
20// the "finally" blocks of every generated test functions will executed
21// regardless of whether or not that test function ignores or catches the
22// thrown exception.
23//
24// examples:
25//
26// ExceptionDemo
27//
28// causes a usage to be printed to stderr
29//
30// ExceptionDemo 2 3 7 -1
31//
32// results in the following cases:
33// - Value 2 causes an exception with a type info type of 2 to be
34// thrown and caught by an inner generated test function.
35// - Value 3 causes an exception with a type info type of 3 to be
36// thrown and caught by an outer generated test function.
37// - Value 7 causes an exception with a type info type of 7 to be
38// thrown and NOT be caught by any generated function.
39// - Value -1 causes a foreign C++ exception to be thrown and not be
40// caught by any generated function
41//
42// Cases -1 and 7 are caught by a C++ test harness where the validity of
43// of a C++ catch(...) clause catching a generated exception with a
44// type info type of 7 is questionable.
45//
46// This code uses code from the llvm compiler-rt project and the llvm
47// Kaleidoscope project.
48//
49//===--------------------------------------------------------------------===//
50
51
52#include "llvm/LLVMContext.h"
53#include "llvm/DerivedTypes.h"
54#include "llvm/ExecutionEngine/ExecutionEngine.h"
55#include "llvm/ExecutionEngine/JIT.h"
56#include "llvm/Module.h"
57#include "llvm/PassManager.h"
58#include "llvm/Intrinsics.h"
59#include "llvm/Analysis/Verifier.h"
60#include "llvm/Target/TargetData.h"
61#include "llvm/Target/TargetSelect.h"
62#include "llvm/Target/TargetOptions.h"
63#include "llvm/Transforms/Scalar.h"
64#include "llvm/Support/IRBuilder.h"
65#include "llvm/Support/Dwarf.h"
66
67#include <cstdio>
68#include <string>
69#include <sstream>
70#include <map>
71#include <vector>
72#include <stdexcept>
73
74
75#ifndef USE_GLOBAL_STR_CONSTS
76#define USE_GLOBAL_STR_CONSTS true
77#endif
78
79// System C++ ABI unwind types from:
80// http://refspecs.freestandards.org/abi-eh-1.21.html
81
82extern "C" {
83
84typedef enum {
85 _URC_NO_REASON = 0,
86 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
87 _URC_FATAL_PHASE2_ERROR = 2,
88 _URC_FATAL_PHASE1_ERROR = 3,
89 _URC_NORMAL_STOP = 4,
90 _URC_END_OF_STACK = 5,
91 _URC_HANDLER_FOUND = 6,
92 _URC_INSTALL_CONTEXT = 7,
93 _URC_CONTINUE_UNWIND = 8
94} _Unwind_Reason_Code;
95
96typedef enum {
97 _UA_SEARCH_PHASE = 1,
98 _UA_CLEANUP_PHASE = 2,
99 _UA_HANDLER_FRAME = 4,
100 _UA_FORCE_UNWIND = 8,
101 _UA_END_OF_STACK = 16
102} _Unwind_Action;
103
104struct _Unwind_Exception;
105
106typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
107 struct _Unwind_Exception *);
108
109struct _Unwind_Exception {
110 uint64_t exception_class;
111 _Unwind_Exception_Cleanup_Fn exception_cleanup;
112
113 uintptr_t private_1;
114 uintptr_t private_2;
115
116 // @@@ The IA-64 ABI says that this structure must be double-word aligned.
117 // Taking that literally does not make much sense generically. Instead
118 // we provide the maximum alignment required by any type for the machine.
119} __attribute__((__aligned__));
120
121struct _Unwind_Context;
122typedef struct _Unwind_Context* _Unwind_Context_t;
123
124extern const uint8_t* _Unwind_GetLanguageSpecificData (_Unwind_Context_t c);
125extern uintptr_t _Unwind_GetGR (_Unwind_Context_t c, int i);
126extern void _Unwind_SetGR (_Unwind_Context_t c, int i, uintptr_t n);
127extern void _Unwind_SetIP (_Unwind_Context_t, uintptr_t new_value);
128extern uintptr_t _Unwind_GetIP (_Unwind_Context_t context);
129extern uintptr_t _Unwind_GetRegionStart (_Unwind_Context_t context);
130
131} // extern "C"
132
133//
134// Example types
135//
136
137/// This is our simplistic type info
138struct OurExceptionType_t {
139 /// type info type
140 int type;
141};
142
143
144/// This is our Exception class which relies on a negative offset to calculate
145/// pointers to its instances from pointers to its unwindException member.
146///
147/// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
148/// on a double word boundary. This is necessary to match the standard:
149/// http://refspecs.freestandards.org/abi-eh-1.21.html
150struct OurBaseException_t {
151 struct OurExceptionType_t type;
152
153 // Note: This is properly aligned in unwind.h
154 struct _Unwind_Exception unwindException;
155};
156
157
158// Note: Not needed since we are C++
159typedef struct OurBaseException_t OurException;
160typedef struct _Unwind_Exception OurUnwindException;
161
162//
163// Various globals used to support typeinfo and generatted exceptions in
164// general
165//
166
167static std::map<std::string, llvm::Value*> namedValues;
168
169int64_t ourBaseFromUnwindOffset;
170
171const unsigned char ourBaseExcpClassChars[] =
172 {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
173
174
175static uint64_t ourBaseExceptionClass = 0;
176
177static std::vector<std::string> ourTypeInfoNames;
178static std::map<int, std::string> ourTypeInfoNamesIndex;
179
180static llvm::StructType* ourTypeInfoType;
181static llvm::StructType* ourExceptionType;
182static llvm::StructType* ourUnwindExceptionType;
183
184static llvm::ConstantInt* ourExceptionNotThrownState;
185static llvm::ConstantInt* ourExceptionThrownState;
186static llvm::ConstantInt* ourExceptionCaughtState;
187
188typedef std::vector<std::string> ArgNames;
189typedef std::vector<const llvm::Type*> ArgTypes;
190
191//
192// Code Generation Utilities
193//
194
195/// Utility used to create a function, both declarations and definitions
196/// @param module for module instance
197/// @param retType function return type
198/// @param theArgTypes function's ordered argument types
199/// @param theArgNames function's ordered arguments needed if use of this
200/// function corresponds to a function definition. Use empty
201/// aggregate for function declarations.
202/// @param functName function name
203/// @param linkage function linkage
204/// @param declarationOnly for function declarations
205/// @param isVarArg function uses vararg arguments
206/// @returns function instance
207llvm::Function *createFunction(llvm::Module& module,
208 const llvm::Type* retType,
209 const ArgTypes& theArgTypes,
210 const ArgNames& theArgNames,
211 const std::string& functName,
212 llvm::GlobalValue::LinkageTypes linkage,
213 bool declarationOnly,
214 bool isVarArg) {
215 llvm::FunctionType* functType = llvm::FunctionType::get(retType,
216 theArgTypes,
217 isVarArg);
218 llvm::Function* ret = llvm::Function::Create(functType,
219 linkage,
220 functName,
221 &module);
222 if (!ret || declarationOnly)
223 return(ret);
224
225 namedValues.clear();
226 unsigned i = 0;
227 for (llvm::Function::arg_iterator argIndex = ret->arg_begin();
228 i != theArgNames.size();
229 ++argIndex, ++i) {
230
231 argIndex->setName(theArgNames[i]);
232 namedValues[theArgNames[i]] = argIndex;
233 }
234
235 return(ret);
236}
237
238
239/// Create an alloca instruction in the entry block of
240/// the parent function. This is used for mutable variables etc.
241/// @param function parent instance
242/// @param varName stack variable name
243/// @param type stack variable type
244/// @param initWith optional constant initialization value
245/// @returns AllocaInst instance
246static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function& function,
247 const std::string &varName,
248 const llvm::Type* type,
249 llvm::Constant* initWith = NULL) {
250 llvm::BasicBlock& block = function.getEntryBlock();
251 llvm::IRBuilder<> tmp(&block, block.begin());
252 llvm::AllocaInst* ret = tmp.CreateAlloca(type, 0, varName.c_str());
253
254 if (initWith)
255 tmp.CreateStore(initWith, ret);
256
257 return(ret);
258}
259
260
261//
262// Code Generation Utilities End
263//
264
265//
266// Runtime C Library functions
267//
268
269// Note: using an extern "C" block so that static functions can be used
270extern "C" {
271
272// Note: Better ways to decide on bit width
273//
274/// Prints a 32 bit number, according to the format, to stderr.
275/// @param intToPrint integer to print
276/// @param format printf like format to use when printing
277void print32Int(int intToPrint, const char* format) {
278 if (format) {
279 // Note: No NULL check
280 fprintf(stderr, format, intToPrint);
281 }
282 else {
283 // Note: No NULL check
284 fprintf(stderr, "::print32Int(...):NULL arg.\n");
285 }
286}
287
288
289// Note: Better ways to decide on bit width
290//
291/// Prints a 64 bit number, according to the format, to stderr.
292/// @param intToPrint integer to print
293/// @param format printf like format to use when printing
294void print64Int(long int intToPrint, const char* format) {
295 if (format) {
296 // Note: No NULL check
297 fprintf(stderr, format, intToPrint);
298 }
299 else {
300 // Note: No NULL check
301 fprintf(stderr, "::print64Int(...):NULL arg.\n");
302 }
303}
304
305
306/// Prints a C string to stderr
307/// @param toPrint string to print
308void printStr(char* toPrint) {
309 if (toPrint) {
310 fprintf(stderr, "%s", toPrint);
311 }
312 else {
313 fprintf(stderr, "::printStr(...):NULL arg.\n");
314 }
315}
316
317
318/// Deletes the true previosly allocated exception whose address
319/// is calculated from the supplied OurBaseException_t::unwindException
320/// member address. Handles (ignores), NULL pointers.
321/// @param expToDelete exception to delete
322void deleteOurException(OurUnwindException* expToDelete) {
323#ifdef DEBUG
324 fprintf(stderr,
325 "deleteOurException(...).\n");
326#endif
327
328 if (expToDelete &&
329 (expToDelete->exception_class == ourBaseExceptionClass)) {
330
331 free(((char*) expToDelete) + ourBaseFromUnwindOffset);
332 }
333}
334
335
336/// This function is the struct _Unwind_Exception API mandated delete function
337/// used by foreign exception handlers when deleting our exception
338/// (OurException), instances.
339/// @param reason @link http://refspecs.freestandards.org/abi-eh-1.21.html
340/// @unlink
341/// @param expToDelete exception instance to delete
342void deleteFromUnwindOurException(_Unwind_Reason_Code reason,
343 OurUnwindException* expToDelete) {
344#ifdef DEBUG
345 fprintf(stderr,
346 "deleteFromUnwindOurException(...).\n");
347#endif
348
349 deleteOurException(expToDelete);
350}
351
352
353/// Creates (allocates on the heap), an exception (OurException instance),
354/// of the supplied type info type.
355/// @param type type info type
356OurUnwindException* createOurException(int type) {
357 size_t size = sizeof(OurException);
358 OurException* ret = (OurException*) memset(malloc(size), 0, size);
359 (ret->type).type = type;
360 (ret->unwindException).exception_class = ourBaseExceptionClass;
361 (ret->unwindException).exception_cleanup = deleteFromUnwindOurException;
362
363 return(&(ret->unwindException));
364}
365
366
367/// Read a uleb128 encoded value and advance pointer
368/// See Variable Length Data in:
369/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
370/// @param data reference variable holding memory pointer to decode from
371/// @returns decoded value
372static uintptr_t readULEB128(const uint8_t** data) {
373 uintptr_t result = 0;
374 uintptr_t shift = 0;
375 unsigned char byte;
376 const uint8_t* p = *data;
377
378 do {
379 byte = *p++;
380 result |= (byte & 0x7f) << shift;
381 shift += 7;
382 }
383 while (byte & 0x80);
384
385 *data = p;
386
387 return result;
388}
389
390
391/// Read a sleb128 encoded value and advance pointer
392/// See Variable Length Data in:
393/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
394/// @param data reference variable holding memory pointer to decode from
395/// @returns decoded value
396static uintptr_t readSLEB128(const uint8_t** data) {
397 uintptr_t result = 0;
398 uintptr_t shift = 0;
399 unsigned char byte;
400 const uint8_t* p = *data;
401
402 do {
403 byte = *p++;
404 result |= (byte & 0x7f) << shift;
405 shift += 7;
406 }
407 while (byte & 0x80);
408
409 *data = p;
410
411 if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
412 result |= (~0 << shift);
413 }
414
415 return result;
416}
417
418
419/// Read a pointer encoded value and advance pointer
420/// See Variable Length Data in:
421/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
422/// @param data reference variable holding memory pointer to decode from
423/// @param encoding dwarf encoding type
424/// @returns decoded value
425static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) {
426 uintptr_t result = 0;
427 const uint8_t* p = *data;
428
429 if (encoding == llvm::dwarf::DW_EH_PE_omit)
430 return(result);
431
432 // first get value
433 switch (encoding & 0x0F) {
434 case llvm::dwarf::DW_EH_PE_absptr:
435 result = *((uintptr_t*)p);
436 p += sizeof(uintptr_t);
437 break;
438 case llvm::dwarf::DW_EH_PE_uleb128:
439 result = readULEB128(&p);
440 break;
441 // Note: This case has not been tested
442 case llvm::dwarf::DW_EH_PE_sleb128:
443 result = readSLEB128(&p);
444 break;
445 case llvm::dwarf::DW_EH_PE_udata2:
446 result = *((uint16_t*)p);
447 p += sizeof(uint16_t);
448 break;
449 case llvm::dwarf::DW_EH_PE_udata4:
450 result = *((uint32_t*)p);
451 p += sizeof(uint32_t);
452 break;
453 case llvm::dwarf::DW_EH_PE_udata8:
454 result = *((uint64_t*)p);
455 p += sizeof(uint64_t);
456 break;
457 case llvm::dwarf::DW_EH_PE_sdata2:
458 result = *((int16_t*)p);
459 p += sizeof(int16_t);
460 break;
461 case llvm::dwarf::DW_EH_PE_sdata4:
462 result = *((int32_t*)p);
463 p += sizeof(int32_t);
464 break;
465 case llvm::dwarf::DW_EH_PE_sdata8:
466 result = *((int64_t*)p);
467 p += sizeof(int64_t);
468 break;
469 default:
470 // not supported
471 abort();
472 break;
473 }
474
475 // then add relative offset
476 switch (encoding & 0x70) {
477 case llvm::dwarf::DW_EH_PE_absptr:
478 // do nothing
479 break;
480 case llvm::dwarf::DW_EH_PE_pcrel:
481 result += (uintptr_t)(*data);
482 break;
483 case llvm::dwarf::DW_EH_PE_textrel:
484 case llvm::dwarf::DW_EH_PE_datarel:
485 case llvm::dwarf::DW_EH_PE_funcrel:
486 case llvm::dwarf::DW_EH_PE_aligned:
487 default:
488 // not supported
489 abort();
490 break;
491 }
492
493 // then apply indirection
494 if (encoding & llvm::dwarf::DW_EH_PE_indirect) {
495 result = *((uintptr_t*)result);
496 }
497
498 *data = p;
499
500 return result;
501}
502
503
504/// Deals with Dwarf actions matching our type infos
505/// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
506/// action matches the supplied exception type. If such a match succeeds,
507/// the resultAction argument will be set with > 0 index value. Only
508/// corresponding llvm.eh.selector type info arguments, cleanup arguments
509/// are supported. Filters are not supported.
510/// See Variable Length Data in:
511/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
512/// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
513/// @param resultAction reference variable which will be set with result
514/// @param classInfo our array of type info pointers (to globals)
515/// @param actionEntry index into above type info array or 0 (clean up).
516/// We do not support filters.
517/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
518/// of thrown exception.
519/// @param exceptionObject thrown _Unwind_Exception instance.
520/// @returns whether or not a type info was found. False is returned if only
521/// a cleanup was found
522static bool handleActionValue(int64_t *resultAction,
523 struct OurExceptionType_t **classInfo,
524 uintptr_t actionEntry,
525 uint64_t exceptionClass,
526 struct _Unwind_Exception *exceptionObject) {
527 bool ret = false;
528
529 if (!resultAction ||
530 !exceptionObject ||
531 (exceptionClass != ourBaseExceptionClass))
532 return(ret);
533
534 struct OurBaseException_t* excp = (struct OurBaseException_t*)
535 (((char*) exceptionObject) + ourBaseFromUnwindOffset);
536 struct OurExceptionType_t *excpType = &(excp->type);
537 int type = excpType->type;
538
539#ifdef DEBUG
540 fprintf(stderr,
541 "handleActionValue(...): exceptionObject = <%p>, "
542 "excp = <%p>.\n",
543 exceptionObject,
544 excp);
545#endif
546
547 const uint8_t *actionPos = (uint8_t*) actionEntry,
548 *tempActionPos;
549 int64_t typeOffset = 0,
550 actionOffset;
551
552 for (int i = 0; true; ++i) {
553 // Each emitted dwarf action corresponds to a 2 tuple of
554 // type info address offset, and action offset to the next
555 // emitted action.
556 typeOffset = readSLEB128(&actionPos);
557 tempActionPos = actionPos;
558 actionOffset = readSLEB128(&tempActionPos);
559
560#ifdef DEBUG
561 fprintf(stderr,
562 "handleActionValue(...):typeOffset: <%lld>, "
563 "actionOffset: <%lld>.\n",
564 typeOffset,
565 actionOffset);
566#endif
567 assert((typeOffset >= 0) &&
568 "handleActionValue(...):filters are not supported.");
569
570 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
571 // argument has been matched.
572 if ((typeOffset > 0) &&
573 (type == (classInfo[-typeOffset])->type)) {
574#ifdef DEBUG
575 fprintf(stderr,
576 "handleActionValue(...):actionValue <%d> found.\n",
577 i);
578#endif
579 *resultAction = i + 1;
580 ret = true;
581 break;
582 }
583
584#ifdef DEBUG
585 fprintf(stderr,
586 "handleActionValue(...):actionValue not found.\n");
587#endif
588 if (!actionOffset)
589 break;
590
591 actionPos += actionOffset;
592 }
593
594 return(ret);
595}
596
597
598/// Deals with the Language specific data portion of the emitted dwarf code.
599/// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
600/// @param version unsupported (ignored), unwind version
601/// @param lsda language specific data area
602/// @param _Unwind_Action actions minimally supported unwind stage
603/// (forced specifically not supported)
604/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
605/// of thrown exception.
606/// @param exceptionObject thrown _Unwind_Exception instance.
607/// @param context unwind system context
608/// @returns minimally supported unwinding control indicator
609static _Unwind_Reason_Code handleLsda(int version,
610 const uint8_t* lsda,
611 _Unwind_Action actions,
612 uint64_t exceptionClass,
613 struct _Unwind_Exception* exceptionObject,
614 _Unwind_Context_t context) {
615 _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND;
616
617 if (!lsda)
618 return(ret);
619
620#ifdef DEBUG
621 fprintf(stderr,
622 "handleLsda(...):lsda is non-zero.\n");
623#endif
624
625 // Get the current instruction pointer and offset it before next
626 // instruction in the current frame which threw the exception.
627 uintptr_t pc = _Unwind_GetIP(context)-1;
628
629 // Get beginning current frame's code (as defined by the
630 // emitted dwarf code)
631 uintptr_t funcStart = _Unwind_GetRegionStart(context);
632 uintptr_t pcOffset = pc - funcStart;
633 struct OurExceptionType_t** classInfo = NULL;
634
635 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
636 // dwarf emission
637
638 // Parse LSDA header.
639 uint8_t lpStartEncoding = *lsda++;
640
641 if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) {
642 readEncodedPointer(&lsda, lpStartEncoding);
643 }
644
645 uint8_t ttypeEncoding = *lsda++;
646 uintptr_t classInfoOffset;
647
648 if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) {
649 // Calculate type info locations in emitted dwarf code which
650 // were flagged by type info arguments to llvm.eh.selector
651 // intrinsic
652 classInfoOffset = readULEB128(&lsda);
653 classInfo = (struct OurExceptionType_t**) (lsda + classInfoOffset);
654 }
655
656 // Walk call-site table looking for range that
657 // includes current PC.
658
659 uint8_t callSiteEncoding = *lsda++;
660 uint32_t callSiteTableLength = readULEB128(&lsda);
661 const uint8_t* callSiteTableStart = lsda;
662 const uint8_t* callSiteTableEnd = callSiteTableStart +
663 callSiteTableLength;
664 const uint8_t* actionTableStart = callSiteTableEnd;
665 const uint8_t* callSitePtr = callSiteTableStart;
666
667 bool foreignException = false;
668
669 while (callSitePtr < callSiteTableEnd) {
670 uintptr_t start = readEncodedPointer(&callSitePtr,
671 callSiteEncoding);
672 uintptr_t length = readEncodedPointer(&callSitePtr,
673 callSiteEncoding);
674 uintptr_t landingPad = readEncodedPointer(&callSitePtr,
675 callSiteEncoding);
676
677 // Note: Action value
678 uintptr_t actionEntry = readULEB128(&callSitePtr);
679
680 if (exceptionClass != ourBaseExceptionClass) {
681 // We have been notified of a foreign exception being thrown,
682 // and we therefore need to execute cleanup landing pads
683 actionEntry = 0;
684 foreignException = true;
685 }
686
687 if (landingPad == 0) {
688#ifdef DEBUG
689 fprintf(stderr,
690 "handleLsda(...): No landing pad found.\n");
691#endif
692
693 continue; // no landing pad for this entry
694 }
695
696 if (actionEntry) {
697 actionEntry += ((uintptr_t) actionTableStart) - 1;
698 }
699 else {
700#ifdef DEBUG
701 fprintf(stderr,
702 "handleLsda(...):No action table found.\n");
703#endif
704 }
705
706 bool exceptionMatched = false;
707
708 if ((start <= pcOffset) && (pcOffset < (start + length))) {
709#ifdef DEBUG
710 fprintf(stderr,
711 "handleLsda(...): Landing pad found.\n");
712#endif
713 int64_t actionValue = 0;
714
715 if (actionEntry) {
716 exceptionMatched = handleActionValue
717 (
718 &actionValue,
719 classInfo,
720 actionEntry,
721 exceptionClass,
722 exceptionObject
723 );
724 }
725
726 if (!(actions & _UA_SEARCH_PHASE)) {
727#ifdef DEBUG
728 fprintf(stderr,
729 "handleLsda(...): installed landing pad "
730 "context.\n");
731#endif
732
733 // Found landing pad for the PC.
734 // Set Instruction Pointer to so we re-enter function
735 // at landing pad. The landing pad is created by the
736 // compiler to take two parameters in registers.
737 _Unwind_SetGR(context,
738 __builtin_eh_return_data_regno(0),
739 (uintptr_t)exceptionObject);
740
741 // Note: this virtual register directly corresponds
742 // to the return of the llvm.eh.selector intrinsic
743 if (!actionEntry || !exceptionMatched) {
744 // We indicate cleanup only
745 _Unwind_SetGR(context,
746 __builtin_eh_return_data_regno(1),
747 0);
748 }
749 else {
750 // Matched type info index of llvm.eh.selector intrinsic
751 // passed here.
752 _Unwind_SetGR(context,
753 __builtin_eh_return_data_regno(1),
754 actionValue);
755 }
756
757 // To execute landing pad set here
758 _Unwind_SetIP(context, funcStart + landingPad);
759 ret = _URC_INSTALL_CONTEXT;
760 }
761 else if (exceptionMatched) {
762#ifdef DEBUG
763 fprintf(stderr,
764 "handleLsda(...): setting handler found.\n");
765#endif
766 ret = _URC_HANDLER_FOUND;
767 }
768 else {
769 // Note: Only non-clean up handlers are marked as
770 // found. Otherwise the clean up handlers will be
771 // re-found and executed during the clean up
772 // phase.
773#ifdef DEBUG
774 fprintf(stderr,
775 "handleLsda(...): cleanup handler found.\n");
776#endif
777 }
778
779 break;
780 }
781 }
782
783 return(ret);
784}
785
786
787/// This is the personality function which is embedded (dwarf emitted), in the
788/// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
789/// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
790/// @param version unsupported (ignored), unwind version
791/// @param _Unwind_Action actions minimally supported unwind stage
792/// (forced specifically not supported)
793/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
794/// of thrown exception.
795/// @param exceptionObject thrown _Unwind_Exception instance.
796/// @param context unwind system context
797/// @returns minimally supported unwinding control indicator
798_Unwind_Reason_Code ourPersonality(int version,
799 _Unwind_Action actions,
800 uint64_t exceptionClass,
801 struct _Unwind_Exception* exceptionObject,
802 _Unwind_Context_t context) {
803#ifdef DEBUG
804 fprintf(stderr,
805 "We are in ourPersonality(...):actions is <%d>.\n",
806 actions);
807
808 if (actions & _UA_SEARCH_PHASE) {
809 fprintf(stderr, "ourPersonality(...):In search phase.\n");
810 }
811 else {
812 fprintf(stderr, "ourPersonality(...):In non-search phase.\n");
813 }
814#endif
815
816 const uint8_t* lsda = (uint8_t*)
817 _Unwind_GetLanguageSpecificData(context);
818
819#ifdef DEBUG
820 fprintf(stderr,
821 "ourPersonality(...):lsda = <%p>.\n",
822 lsda);
823#endif
824
825 // The real work of the personality function is captured here
826 return(handleLsda(version,
827 lsda,
828 actions,
829 exceptionClass,
830 exceptionObject,
831 context));
832}
833
834
835/// Generates our _Unwind_Exception class from a given character array.
836/// thereby handling arbitrary lengths (not in standard), and handling
837/// embedded \0s.
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
842uint64_t genClass(const unsigned char classChars[], size_t classCharsSize)
843{
844 uint64_t ret = classChars[0];
845
846 for (unsigned i = 1; i < classCharsSize; ++i) {
847 ret <<= 8;
848 ret += classChars[i];
849 }
850
851 return(ret);
852}
853
854} // extern "C"
855
856//
857// Runtime C Library functions End
858//
859
860//
861// Code generation functions
862//
863
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
872/// stack.
873void generateStringPrint(llvm::LLVMContext& context,
874 llvm::Module& module,
875 llvm::IRBuilder<>& builder,
876 std::string toPrint,
877 bool useGlobal = true) {
878 llvm::Function *printFunct = module.getFunction("printStr");
879
880 llvm::Value *stringVar;
881 llvm::Constant* stringConstant =
882 llvm::ConstantArray::get(context, toPrint);
883
884 if (useGlobal) {
885 // Note: Does not work without allocation
886 stringVar =
887 new llvm::GlobalVariable(module,
888 stringConstant->getType(),
889 true,
890 llvm::GlobalValue::LinkerPrivateLinkage,
891 stringConstant,
892 "");
893 }
894 else {
895 stringVar = builder.CreateAlloca(stringConstant->getType());
896 builder.CreateStore(stringConstant, stringVar);
897 }
898
899 llvm::Value* cast =
900 builder.CreatePointerCast(stringVar,
901 builder.getInt8Ty()->getPointerTo());
902 builder.CreateCall(printFunct, cast);
903}
904
905
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
917/// stack.
918void generateIntegerPrint(llvm::LLVMContext& context,
919 llvm::Module& module,
920 llvm::IRBuilder<>& builder,
921 llvm::Function& printFunct,
922 llvm::Value& toPrint,
923 std::string format,
924 bool useGlobal = true) {
925 llvm::Constant *stringConstant = llvm::ConstantArray::get(context, format);
926 llvm::Value *stringVar;
927
928 if (useGlobal) {
929 // Note: Does not seem to work without allocation
930 stringVar =
931 new llvm::GlobalVariable(module,
932 stringConstant->getType(),
933 true,
934 llvm::GlobalValue::LinkerPrivateLinkage,
935 stringConstant,
936 "");
937 }
938 else {
939 stringVar = builder.CreateAlloca(stringConstant->getType());
940 builder.CreateStore(stringConstant, stringVar);
941 }
942
943 llvm::Value* cast =
944 builder.CreateBitCast(stringVar,
945 builder.getInt8Ty()->getPointerTo());
946 builder.CreateCall2(&printFunct, &toPrint, cast);
947}
948
949
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
969static 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 "
981 "is NULL");
982 assert(exceptionStorage &&
983 "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
984 "is NULL");
985
986 *exceptionCaughtFlag =
987 createEntryBlockAlloca(toAddTo,
988 "exceptionCaught",
989 ourExceptionNotThrownState->getType(),
990 ourExceptionNotThrownState);
991
992 const llvm::PointerType* exceptionStorageType =
993 builder.getInt8Ty()->getPointerTo();
994 *exceptionStorage =
995 createEntryBlockAlloca(toAddTo,
996 "exceptionStorage",
997 exceptionStorageType,
998 llvm::ConstantPointerNull::get(
999 exceptionStorageType));
1000
1001 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1002 blockName,
1003 &toAddTo);
1004
1005 builder.SetInsertPoint(ret);
1006
1007 std::ostringstream bufferToPrint;
1008 bufferToPrint << "Gen: Executing finally block "
1009 << blockName
1010 << " in "
1011 << functionId
1012 << std::endl;
1013 generateStringPrint(context,
1014 module,
1015 builder,
1016 bufferToPrint.str(),
1017 USE_GLOBAL_STR_CONSTS);
1018
1019 llvm::SwitchInst* theSwitch =
1020 builder.CreateSwitch(builder.CreateLoad(*exceptionCaughtFlag),
1021 &terminatorBlock,
1022 2);
1023 theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
1024 theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
1025
1026 return(ret);
1027}
1028
1029
1030/// Generates catch block semantics which print a string to indicate type of
1031/// catch executed, sets an exception caught flag, and executes passed in
1032/// end block (terminator block).
1033/// @param context llvm context
1034/// @param module code for module instance
1035/// @param builder builder instance
1036/// @param toAddTo parent function to add block to
1037/// @param blockName block name of new "catch" block.
1038/// @param functionId output id used for printing
1039/// @param terminatorBlock terminator "end" block
1040/// @param exceptionCaughtFlag exception caught/thrown status
1041/// @returns newly created block
1042static llvm::BasicBlock* createCatchBlock(llvm::LLVMContext& context,
1043 llvm::Module& module,
1044 llvm::IRBuilder<>& builder,
1045 llvm::Function& toAddTo,
1046 std::string& blockName,
1047 std::string& functionId,
1048 llvm::BasicBlock& terminatorBlock,
1049 llvm::Value& exceptionCaughtFlag) {
1050
1051 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1052 blockName,
1053 &toAddTo);
1054
1055 builder.SetInsertPoint(ret);
1056
1057 std::ostringstream bufferToPrint;
1058 bufferToPrint << "Gen: Executing catch block "
1059 << blockName
1060 << " in "
1061 << functionId
1062 << std::endl;
1063 generateStringPrint(context,
1064 module,
1065 builder,
1066 bufferToPrint.str(),
1067 USE_GLOBAL_STR_CONSTS);
1068 builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
1069 builder.CreateBr(&terminatorBlock);
1070
1071 return(ret);
1072}
1073
1074
1075/// Generates a function which invokes a function (toInvoke) and, whose
1076/// unwind block will "catch" the type info types correspondingly held in the
1077/// exceptionTypesToCatch argument. If the toInvoke function throws an
1078/// exception which does not match any type info types contained in
1079/// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1080/// with the raised exception. On the other hand the generated code will
1081/// normally exit if the toInvoke function does not throw an exception.
1082/// The generated "finally" block is always run regardless of the cause of
1083/// the generated function exit.
1084/// The generated function is returned after being verified.
1085/// @param module code for module instance
1086/// @param builder builder instance
1087/// @param fpm a function pass manager holding optional IR to IR
1088/// transformations
1089/// @param toInvoke inner function to invoke
1090/// @param ourId id used to printing purposes
1091/// @param numExceptionsToCatch length of exceptionTypesToCatch array
1092/// @param exceptionTypesToCatch array of type info types to "catch"
1093/// @returns generated function
1094static
1095llvm::Function* createCatchWrappedInvokeFunction(llvm::Module& module,
1096 llvm::IRBuilder<>& builder,
1097 llvm::FunctionPassManager& fpm,
1098 llvm::Function& toInvoke,
1099 std::string ourId,
1100 unsigned numExceptionsToCatch,
1101 unsigned exceptionTypesToCatch[]) {
1102
1103 llvm::LLVMContext& context = module.getContext();
1104 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1105
1106 ArgTypes argTypes;
1107 argTypes.push_back(builder.getInt32Ty());
1108
1109 ArgNames argNames;
1110 argNames.push_back("exceptTypeToThrow");
1111
1112 llvm::Function* ret = createFunction(module,
1113 builder.getVoidTy(),
1114 argTypes,
1115 argNames,
1116 ourId,
1117 llvm::Function::ExternalLinkage,
1118 false,
1119 false);
1120
1121 // Block which calls invoke
1122 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1123 "entry",
1124 ret);
1125 // Normal block for invoke
1126 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
1127 "normal",
1128 ret);
1129 // Unwind block for invoke
1130 llvm::BasicBlock *exceptionBlock =
1131 llvm::BasicBlock::Create(context, "exception", ret);
1132
1133 // Block which routes exception to correct catch handler block
1134 llvm::BasicBlock *exceptionRouteBlock =
1135 llvm::BasicBlock::Create(context, "exceptionRoute", ret);
1136
1137 // Foreign exception handler
1138 llvm::BasicBlock *externalExceptionBlock =
1139 llvm::BasicBlock::Create(context, "externalException", ret);
1140
1141 // Block which calls _Unwind_Resume
1142 llvm::BasicBlock *unwindResumeBlock =
1143 llvm::BasicBlock::Create(context, "unwindResume", ret);
1144
1145 // Clean up block which delete exception if needed
1146 llvm::BasicBlock *endBlock =
1147 llvm::BasicBlock::Create(context, "end", ret);
1148
1149 std::string nextName;
1150 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
1151 llvm::Value* exceptionCaughtFlag = NULL;
1152 llvm::Value* exceptionStorage = NULL;
1153
1154 // Finally block which will branch to unwindResumeBlock if
1155 // exception is not caught. Initializes/allocates stack locations.
1156 llvm::BasicBlock* finallyBlock = createFinallyBlock(context,
1157 module,
1158 builder,
1159 *ret,
1160 nextName = "finally",
1161 ourId,
1162 *endBlock,
1163 *unwindResumeBlock,
1164 &exceptionCaughtFlag,
1165 &exceptionStorage);
1166
1167 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1168 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
1169
1170 // One catch block per type info to be caught
1171 catchBlocks[i] = createCatchBlock(context,
1172 module,
1173 builder,
1174 *ret,
1175 nextName,
1176 ourId,
1177 *finallyBlock,
1178 *exceptionCaughtFlag);
1179 }
1180
1181 // Entry Block
1182
1183 builder.SetInsertPoint(entryBlock);
1184
1185 std::vector<llvm::Value*> args;
1186 args.push_back(namedValues["exceptTypeToThrow"]);
1187 builder.CreateInvoke(&toInvoke,
1188 normalBlock,
1189 exceptionBlock,
1190 args.begin(),
1191 args.end());
1192
1193 // End Block
1194
1195 builder.SetInsertPoint(endBlock);
1196
1197 generateStringPrint(context,
1198 module,
1199 builder,
1200 "Gen: In end block: exiting in " + ourId + ".\n",
1201 USE_GLOBAL_STR_CONSTS);
1202 llvm::Function *deleteOurException =
1203 module.getFunction("deleteOurException");
1204
1205 // Note: function handles NULL exceptions
1206 builder.CreateCall(deleteOurException,
1207 builder.CreateLoad(exceptionStorage));
1208 builder.CreateRetVoid();
1209
1210 // Normal Block
1211
1212 builder.SetInsertPoint(normalBlock);
1213
1214 generateStringPrint(context,
1215 module,
1216 builder,
1217 "Gen: No exception in " + ourId + "!\n",
1218 USE_GLOBAL_STR_CONSTS);
1219
1220 // Finally block is always called
1221 builder.CreateBr(finallyBlock);
1222
1223 // Unwind Resume Block
1224
1225 builder.SetInsertPoint(unwindResumeBlock);
1226
1227 llvm::Function *resumeOurException =
1228 module.getFunction("_Unwind_Resume");
1229 builder.CreateCall(resumeOurException,
1230 builder.CreateLoad(exceptionStorage));
1231 builder.CreateUnreachable();
1232
1233 // Exception Block
1234
1235 builder.SetInsertPoint(exceptionBlock);
1236
1237 llvm::Function *ehException = module.getFunction("llvm.eh.exception");
1238
1239 // Retrieve thrown exception
1240 llvm::Value* unwindException = builder.CreateCall(ehException);
1241
1242 // Store exception and flag
1243 builder.CreateStore(unwindException, exceptionStorage);
1244 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag);
1245 llvm::Function *personality = module.getFunction("ourPersonality");
1246 llvm::Value* functPtr =
1247 builder.CreatePointerCast(personality,
1248 builder.getInt8Ty()->getPointerTo());
1249
1250 args.clear();
1251 args.push_back(unwindException);
1252 args.push_back(functPtr);
1253
1254 // Note: Skipping index 0
1255 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1256 // Set up type infos to be caught
1257 args.push_back(
1258 module.getGlobalVariable(
1259 ourTypeInfoNames[exceptionTypesToCatch[i]]));
1260 }
1261
1262 args.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), 0));
1263
1264 llvm::Function *ehSelector = module.getFunction("llvm.eh.selector");
1265
1266 // Set up this exeption block as the landing pad which will handle
1267 // given type infos. See case Intrinsic::eh_selector in
1268 // SelectionDAGBuilder::visitIntrinsicCall(...) and AddCatchInfo(...)
1269 // implemented in FunctionLoweringInfo.cpp to see how the implementation
1270 // handles this call. This landing pad (this exception block), will be
1271 // called either because it nees to cleanup (call finally) or a type
1272 // info was found which matched the thrown exception.
1273 llvm::Value* retTypeInfoIndex = builder.CreateCall(ehSelector,
1274 args.begin(),
1275 args.end());
1276
1277 // Retrieve exception_class member from thrown exception
1278 // (_Unwind_Exception instance). This member tells us whether or not
1279 // the exception is foreign.
1280 llvm::Value* unwindExceptionClass =
1281 builder.CreateLoad(
1282 builder.CreateStructGEP(
1283 builder.CreatePointerCast(
1284 unwindException,
1285 ourUnwindExceptionType->getPointerTo()),
1286 0));
1287
1288 // Branch to the externalExceptionBlock if the exception is foreign or
1289 // to a catch router if not. Either way the finally block will be run.
1290 builder.CreateCondBr(
1291 builder.CreateICmpEQ(unwindExceptionClass,
1292 llvm::ConstantInt::get(builder.getInt64Ty(),
1293 ourBaseExceptionClass)),
1294 exceptionRouteBlock,
1295 externalExceptionBlock);
1296
1297 // External Exception Block
1298
1299 builder.SetInsertPoint(externalExceptionBlock);
1300
1301 generateStringPrint(context,
1302 module,
1303 builder,
1304 "Gen: Foreign exception received.\n",
1305 USE_GLOBAL_STR_CONSTS);
1306
1307 // Branch to the finally block
1308 builder.CreateBr(finallyBlock);
1309
1310 // Exception Route Block
1311
1312 builder.SetInsertPoint(exceptionRouteBlock);
1313
1314 // Casts exception pointer (_Unwind_Exception instance) to parent
1315 // (OurException instance).
1316 //
1317 // Note: ourBaseFromUnwindOffset is usually negative
1318 llvm::Value* typeInfoThrown =
1319 builder.CreatePointerCast(
1320 builder.CreateConstGEP1_64(unwindException,
1321 ourBaseFromUnwindOffset),
1322 ourExceptionType->getPointerTo());
1323
1324 // Retrieve thrown exception type info type
1325 //
1326 // Note: Index is not relative to pointer but instead to structure
1327 // unlike a true getelementptr (GEP) instruction
1328 typeInfoThrown = builder.CreateStructGEP(typeInfoThrown, 0);
1329
1330 llvm::Value* typeInfoThrownType =
1331 builder.CreateStructGEP(typeInfoThrown, 0);
1332
1333 generateIntegerPrint(context,
1334 module,
1335 builder,
1336 *toPrint32Int,
1337 *(builder.CreateLoad(typeInfoThrownType)),
1338 "Gen: Exception type <%d> received (stack unwound) "
1339 " in " +
1340 ourId +
1341 ".\n",
1342 USE_GLOBAL_STR_CONSTS);
1343
1344 // Route to matched type info catch block or run cleanup finally block
1345 llvm::SwitchInst* switchToCatchBlock =
1346 builder.CreateSwitch(retTypeInfoIndex,
1347 finallyBlock,
1348 numExceptionsToCatch);
1349
1350 unsigned nextTypeToCatch;
1351
1352 for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
1353 nextTypeToCatch = i - 1;
1354 switchToCatchBlock->addCase(llvm::ConstantInt::get(
1355 llvm::Type::getInt32Ty(context),
1356 i),
1357 catchBlocks[nextTypeToCatch]);
1358 }
1359
1360 llvm::verifyFunction(*ret);
1361 fpm.run(*ret);
1362
1363 return(ret);
1364}
1365
1366
1367/// Generates function which throws either an exception matched to a runtime
1368/// determined type info type (argument to generated function), or if this
1369/// runtime value matches nativeThrowType, throws a foreign exception by
1370/// calling nativeThrowFunct.
1371/// @param module code for module instance
1372/// @param builder builder instance
1373/// @param fpm a function pass manager holding optional IR to IR
1374/// transformations
1375/// @param ourId id used to printing purposes
1376/// @param nativeThrowType a runtime argument of this value results in
1377/// nativeThrowFunct being called to generate/throw exception.
1378/// @param nativeThrowFunct function which will throw a foreign exception
1379/// if the above nativeThrowType matches generated function's arg.
1380/// @returns generated function
1381static
1382llvm::Function* createThrowExceptionFunction(llvm::Module& module,
1383 llvm::IRBuilder<>& builder,
1384 llvm::FunctionPassManager& fpm,
1385 std::string ourId,
1386 int32_t nativeThrowType,
1387 llvm::Function& nativeThrowFunct) {
1388 llvm::LLVMContext& context = module.getContext();
1389 namedValues.clear();
1390 ArgTypes unwindArgTypes;
1391 unwindArgTypes.push_back(builder.getInt32Ty());
1392 ArgNames unwindArgNames;
1393 unwindArgNames.push_back("exceptTypeToThrow");
1394
1395 llvm::Function *ret = createFunction(module,
1396 builder.getVoidTy(),
1397 unwindArgTypes,
1398 unwindArgNames,
1399 ourId,
1400 llvm::Function::ExternalLinkage,
1401 false,
1402 false);
1403
1404 // Throws either one of our exception or a native C++ exception depending
1405 // on a runtime argument value containing a type info type.
1406 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1407 "entry",
1408 ret);
1409 // Throws a foreign exception
1410 llvm::BasicBlock *nativeThrowBlock =
1411 llvm::BasicBlock::Create(context,
1412 "nativeThrow",
1413 ret);
1414 // Throws one of our Exceptions
1415 llvm::BasicBlock *generatedThrowBlock =
1416 llvm::BasicBlock::Create(context,
1417 "generatedThrow",
1418 ret);
1419 // Retrieved runtime type info type to throw
1420 llvm::Value* exceptionType = namedValues["exceptTypeToThrow"];
1421
1422 // nativeThrowBlock block
1423
1424 builder.SetInsertPoint(nativeThrowBlock);
1425
1426 // Throws foreign exception
1427 builder.CreateCall(&nativeThrowFunct, exceptionType);
1428 builder.CreateUnreachable();
1429
1430 // entry block
1431
1432 builder.SetInsertPoint(entryBlock);
1433
1434 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1435 generateIntegerPrint(context,
1436 module,
1437 builder,
1438 *toPrint32Int,
1439 *exceptionType,
1440 "\nGen: About to throw exception type <%d> in " +
1441 ourId +
1442 ".\n",
1443 USE_GLOBAL_STR_CONSTS);
1444
1445 // Switches on runtime type info type value to determine whether or not
1446 // a foreign exception is thrown. Defaults to throwing one of our
1447 // generated exceptions.
1448 llvm::SwitchInst* theSwitch = builder.CreateSwitch(exceptionType,
1449 generatedThrowBlock,
1450 1);
1451
1452 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
1453 nativeThrowType),
1454 nativeThrowBlock);
1455
1456 // generatedThrow block
1457
1458 builder.SetInsertPoint(generatedThrowBlock);
1459
1460 llvm::Function *createOurException =
1461 module.getFunction("createOurException");
1462 llvm::Function *raiseOurException =
1463 module.getFunction("_Unwind_RaiseException");
1464
1465 // Creates exception to throw with runtime type info type.
1466 llvm::Value* exception =
1467 builder.CreateCall(createOurException,
1468 namedValues["exceptTypeToThrow"]);
1469
1470 // Throw generated Exception
1471 builder.CreateCall(raiseOurException, exception);
1472 builder.CreateUnreachable();
1473
1474 llvm::verifyFunction(*ret);
1475 fpm.run(*ret);
1476
1477 return(ret);
1478}
1479
1480static void createStandardUtilityFunctions(unsigned numTypeInfos,
1481 llvm::Module& module,
1482 llvm::IRBuilder<>& builder);
1483
1484/// Creates test code by generating and organizing these functions into the
1485/// test case. The test case consists of an outer function setup to invoke
1486/// an inner function within an environment having multiple catch and single
1487/// finally blocks. This inner function is also setup to invoke a throw
1488/// function within an evironment similar in nature to the outer function's
1489/// catch and finally blocks. Each of these two functions catch mutually
1490/// exclusive subsets (even or odd) of the type info types configured
1491/// for this this. All generated functions have a runtime argument which
1492/// holds a type info type to throw that each function takes and passes it
1493/// to the inner one if such a inner function exists. This type info type is
1494/// looked at by the generated throw function to see whether or not it should
1495/// throw a generated exception with the same type info type, or instead call
1496/// a supplied a function which in turn will throw a foreign exception.
1497/// @param module code for module instance
1498/// @param builder builder instance
1499/// @param fpm a function pass manager holding optional IR to IR
1500/// transformations
1501/// @param nativeThrowFunctName name of external function which will throw
1502/// a foreign exception
1503/// @returns outermost generated test function.
1504llvm::Function* createUnwindExceptionTest(llvm::Module& module,
1505 llvm::IRBuilder<>& builder,
1506 llvm::FunctionPassManager& fpm,
1507 std::string nativeThrowFunctName) {
1508 // Number of type infos to generate
1509 unsigned numTypeInfos = 6;
1510
1511 // Initialze intrisics and external functions to use along with exception
1512 // and type info globals.
1513 createStandardUtilityFunctions(numTypeInfos,
1514 module,
1515 builder);
1516 llvm::Function *nativeThrowFunct =
1517 module.getFunction(nativeThrowFunctName);
1518
1519 // Create exception throw function using the value ~0 to cause
1520 // foreign exceptions to be thrown.
1521 llvm::Function* throwFunct =
1522 createThrowExceptionFunction(module,
1523 builder,
1524 fpm,
1525 "throwFunct",
1526 ~0,
1527 *nativeThrowFunct);
1528 // Inner function will catch even type infos
1529 unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
1530 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
1531 sizeof(unsigned);
1532
1533 // Generate inner function.
1534 llvm::Function* innerCatchFunct =
1535 createCatchWrappedInvokeFunction(module,
1536 builder,
1537 fpm,
1538 *throwFunct,
1539 "innerCatchFunct",
1540 numExceptionTypesToCatch,
1541 innerExceptionTypesToCatch);
1542
1543 // Outer function will catch odd type infos
1544 unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
1545 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
1546 sizeof(unsigned);
1547
1548 // Generate outer function
1549 llvm::Function* outerCatchFunct =
1550 createCatchWrappedInvokeFunction(module,
1551 builder,
1552 fpm,
1553 *innerCatchFunct,
1554 "outerCatchFunct",
1555 numExceptionTypesToCatch,
1556 outerExceptionTypesToCatch);
1557
1558 // Return outer function to run
1559 return(outerCatchFunct);
1560}
1561
1562
1563/// Represents our foreign exceptions
1564class OurCppRunException : public std::runtime_error {
1565public:
1566 OurCppRunException(const std::string reason) :
1567 std::runtime_error(reason) {}
1568
1569 OurCppRunException (const OurCppRunException& toCopy) :
1570 std::runtime_error(toCopy) {}
1571
1572 OurCppRunException& operator = (const OurCppRunException& toCopy) {
1573 return(reinterpret_cast<OurCppRunException&>(
1574 std::runtime_error::operator = (toCopy)
1575 ));
1576 }
1577
1578 ~OurCppRunException (void) throw () {};
1579};
1580
1581
1582/// Throws foreign C++ exception.
1583/// @param ignoreIt unused parameter that allows function to match implied
1584/// generated function contract.
1585extern "C"
1586void throwCppException (int32_t ignoreIt) {
1587 throw(OurCppRunException("thrown by throwCppException(...)"));
1588}
1589
1590typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
1591
1592/// This is a test harness which runs test by executing generated
1593/// function with a type info type to throw. Harness wraps the excecution
1594/// of generated function in a C++ try catch clause.
1595/// @param engine execution engine to use for executing generated function.
1596/// This demo program expects this to be a JIT instance for demo
1597/// purposes.
1598/// @param function generated test function to run
1599/// @param typeToThrow type info type of generated exception to throw, or
1600/// indicator to cause foreign exception to be thrown.
1601static
1602void runExceptionThrow(llvm::ExecutionEngine* engine,
1603 llvm::Function* function,
1604 int32_t typeToThrow) {
1605
1606 // Find test's function pointer
1607 OurExceptionThrowFunctType functPtr =
1608 reinterpret_cast<OurExceptionThrowFunctType>(
1609 reinterpret_cast<intptr_t>(
1610 engine->getPointerToFunction(function)
1611 )
1612 );
1613
1614 try {
1615 // Run test
1616 (*functPtr)(typeToThrow);
1617 }
1618 catch (OurCppRunException exc) {
1619 // Catch foreign C++ exception
1620 fprintf(stderr,
1621 "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1622 "with reason: %s.\n",
1623 exc.what());
1624 }
1625 catch (...) {
1626 // Catch all exceptions including our generated ones. I'm not sure
1627 // why this latter functionality should work, as it seems that
1628 // our exceptions should be foreign to C++ (the _Unwind_Exception::
1629 // exception_class should be different from the one used by C++), and
1630 // therefore C++ should ignore the generated exceptions.
1631
1632 fprintf(stderr,
1633 "\nrunExceptionThrow(...):In C++ catch all.\n");
1634 }
1635}
1636
1637//
1638// End test functions
1639//
1640
1641/// This initialization routine creates type info globals and
1642/// adds external function declarations to module.
1643/// @param numTypeInfos number of linear type info associated type info types
1644/// to create as GlobalVariable instances, starting with the value 1.
1645/// @param module code for module instance
1646/// @param builder builder instance
1647static void createStandardUtilityFunctions(unsigned numTypeInfos,
1648 llvm::Module& module,
1649 llvm::IRBuilder<>& builder) {
1650
1651 llvm::LLVMContext& context = module.getContext();
1652
1653 // Exception initializations
1654
1655 // Setup exception catch state
1656 ourExceptionNotThrownState =
1657 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
1658 ourExceptionThrownState =
1659 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
1660 ourExceptionCaughtState =
1661 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
1662
1663
1664 // Create our type info type
1665 ourTypeInfoType = llvm::StructType::get(context,
1666 builder.getInt32Ty(),
1667 NULL);
1668
1669 // Create OurException type
1670 ourExceptionType = llvm::StructType::get(context,
1671 ourTypeInfoType,
1672 NULL);
1673
1674 // Create portion of _Unwind_Exception type
1675 //
1676 // Note: Declaring only a portion of the _Unwind_Exception struct.
1677 // Does this cause problems?
1678 ourUnwindExceptionType = llvm::StructType::get(context,
1679 builder.getInt64Ty(),
1680 NULL);
1681 struct OurBaseException_t dummyException;
1682
1683 // Calculate offset of OurException::unwindException member.
1684 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
1685 ((uintptr_t) &(dummyException.unwindException));
1686
1687#ifdef DEBUG
1688 fprintf(stderr,
1689 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1690 "= %lld, sizeof(struct OurBaseException_t) - "
1691 "sizeof(struct _Unwind_Exception) = %lu.\n",
1692 ourBaseFromUnwindOffset,
1693 sizeof(struct OurBaseException_t) -
1694 sizeof(struct _Unwind_Exception));
1695#endif
1696
1697 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
1698
1699 // Create our _Unwind_Exception::exception_class value
1700 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
1701
1702 // Type infos
1703
1704 std::string baseStr = "typeInfo", typeInfoName;
1705 std::ostringstream typeInfoNameBuilder;
1706 std::vector<llvm::Constant*> structVals;
1707
1708 llvm::Constant *nextStruct;
1709 llvm::GlobalVariable* nextGlobal = NULL;
1710
1711 // Generate each type info
1712 //
1713 // Note: First type info is not used.
1714 for (unsigned i = 0; i <= numTypeInfos; ++i) {
1715 structVals.clear();
1716 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
1717 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
1718
1719 typeInfoNameBuilder.str("");
1720 typeInfoNameBuilder << baseStr << i;
1721 typeInfoName = typeInfoNameBuilder.str();
1722
1723 // Note: Does not seem to work without allocation
1724 nextGlobal =
1725 new llvm::GlobalVariable(module,
1726 ourTypeInfoType,
1727 true,
1728 llvm::GlobalValue::ExternalLinkage,
1729 nextStruct,
1730 typeInfoName);
1731
1732 ourTypeInfoNames.push_back(typeInfoName);
1733 ourTypeInfoNamesIndex[i] = typeInfoName;
1734 }
1735
1736 ArgNames argNames;
1737 ArgTypes argTypes;
1738 llvm::Function* funct = NULL;
1739
1740 // print32Int
1741
1742 const llvm::Type* retType = builder.getVoidTy();
1743
1744 argTypes.clear();
1745 argTypes.push_back(builder.getInt32Ty());
1746 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1747
1748 argNames.clear();
1749
1750 createFunction(module,
1751 retType,
1752 argTypes,
1753 argNames,
1754 "print32Int",
1755 llvm::Function::ExternalLinkage,
1756 true,
1757 false);
1758
1759 // print64Int
1760
1761 retType = builder.getVoidTy();
1762
1763 argTypes.clear();
1764 argTypes.push_back(builder.getInt64Ty());
1765 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1766
1767 argNames.clear();
1768
1769 createFunction(module,
1770 retType,
1771 argTypes,
1772 argNames,
1773 "print64Int",
1774 llvm::Function::ExternalLinkage,
1775 true,
1776 false);
1777
1778 // printStr
1779
1780 retType = builder.getVoidTy();
1781
1782 argTypes.clear();
1783 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1784
1785 argNames.clear();
1786
1787 createFunction(module,
1788 retType,
1789 argTypes,
1790 argNames,
1791 "printStr",
1792 llvm::Function::ExternalLinkage,
1793 true,
1794 false);
1795
1796 // throwCppException
1797
1798 retType = builder.getVoidTy();
1799
1800 argTypes.clear();
1801 argTypes.push_back(builder.getInt32Ty());
1802
1803 argNames.clear();
1804
1805 createFunction(module,
1806 retType,
1807 argTypes,
1808 argNames,
1809 "throwCppException",
1810 llvm::Function::ExternalLinkage,
1811 true,
1812 false);
1813
1814 // deleteOurException
1815
1816 retType = builder.getVoidTy();
1817
1818 argTypes.clear();
1819 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1820
1821 argNames.clear();
1822
1823 createFunction(module,
1824 retType,
1825 argTypes,
1826 argNames,
1827 "deleteOurException",
1828 llvm::Function::ExternalLinkage,
1829 true,
1830 false);
1831
1832 // createOurException
1833
1834 retType = builder.getInt8Ty()->getPointerTo();
1835
1836 argTypes.clear();
1837 argTypes.push_back(builder.getInt32Ty());
1838
1839 argNames.clear();
1840
1841 createFunction(module,
1842 retType,
1843 argTypes,
1844 argNames,
1845 "createOurException",
1846 llvm::Function::ExternalLinkage,
1847 true,
1848 false);
1849
1850 // _Unwind_RaiseException
1851
1852 retType = builder.getInt32Ty();
1853
1854 argTypes.clear();
1855 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1856
1857 argNames.clear();
1858
1859 funct = createFunction(module,
1860 retType,
1861 argTypes,
1862 argNames,
1863 "_Unwind_RaiseException",
1864 llvm::Function::ExternalLinkage,
1865 true,
1866 false);
1867
1868 funct->addFnAttr(llvm::Attribute::NoReturn);
1869
1870 // _Unwind_Resume
1871
1872 retType = builder.getInt32Ty();
1873
1874 argTypes.clear();
1875 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1876
1877 argNames.clear();
1878
1879 funct = createFunction(module,
1880 retType,
1881 argTypes,
1882 argNames,
1883 "_Unwind_Resume",
1884 llvm::Function::ExternalLinkage,
1885 true,
1886 false);
1887
1888 funct->addFnAttr(llvm::Attribute::NoReturn);
1889
1890 // ourPersonality
1891
1892 retType = builder.getInt32Ty();
1893
1894 argTypes.clear();
1895 argTypes.push_back(builder.getInt32Ty());
1896 argTypes.push_back(builder.getInt32Ty());
1897 argTypes.push_back(builder.getInt64Ty());
1898 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1899 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1900
1901 argNames.clear();
1902
1903 createFunction(module,
1904 retType,
1905 argTypes,
1906 argNames,
1907 "ourPersonality",
1908 llvm::Function::ExternalLinkage,
1909 true,
1910 false);
1911
1912 // llvm.eh.selector intrinsic
1913
1914 getDeclaration(&module, llvm::Intrinsic::eh_selector);
1915
1916 // llvm.eh.exception intrinsic
1917
1918 getDeclaration(&module, llvm::Intrinsic::eh_exception);
1919
1920 // llvm.eh.typeid.for intrinsic
1921
1922 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for);
1923}
1924
1925
1926//===---------------------------------------------------------------------===//
1927// Main test driver code.
1928//===---------------------------------------------------------------------===//
1929
1930/// Demo main routine which takes the type info types to throw. A test will
1931/// be run for each given type info type. While type info types with the value
1932/// of -1 will trigger a foreign C++ exception to be thrown; type info types
1933/// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1934/// will result in exceptions which pass through to the test harness. All other
1935/// type info types are not supported and could cause a crash.
1936int main(int argc, char* argv[]) {
1937 if (argc == 1) {
1938 fprintf(stderr,
1939 "\nUsage: ExceptionDemo <exception type to throw> "
1940 "[<type 2>...<type n>].\n"
1941 " Each type must have the value of 1 - 6 for "
1942 "generated exceptions to be caught;\n"
1943 " the value -1 for foreign C++ exceptions to be "
1944 "generated and thrown;\n"
1945 " or the values > 6 for exceptions to be ignored.\n"
1946 "\nTry: ExceptionDemo 2 3 7 -1\n"
1947 " for a full test.\n\n");
1948 return(0);
1949 }
1950
1951 // If not set, exception handling will not be turned on
1952 llvm::DwarfExceptionHandling = true;
1953
1954 llvm::InitializeNativeTarget();
1955 llvm::LLVMContext& context = llvm::getGlobalContext();
1956 llvm::IRBuilder<> theBuilder(context);
1957
1958 // Make the module, which holds all the code.
1959 llvm::Module* module = new llvm::Module("my cool jit", context);
1960
1961 // Build engine with JIT
1962 llvm::EngineBuilder factory(module);
1963 factory.setEngineKind(llvm::EngineKind::JIT);
1964 factory.setAllocateGVsWithCode(false);
1965 llvm::ExecutionEngine* executionEngine = factory.create();
1966
1967 {
1968 llvm::FunctionPassManager fpm(module);
1969
1970 // Set up the optimizer pipeline.
1971 // Start with registering info about how the
1972 // target lays out data structures.
1973 fpm.add(new llvm::TargetData(*executionEngine->getTargetData()));
1974
1975 // Optimizations turned on
1976#ifdef ADD_OPT_PASSES
1977
1978 // Promote allocas to registers.
1979 fpm.add(llvm::createPromoteMemoryToRegisterPass());
1980
1981 // Do simple "peephole" optimizations and bit-twiddling optzns.
1982 fpm.add(llvm::createInstructionCombiningPass());
1983
1984 // Reassociate expressions.
1985 fpm.add(llvm::createReassociatePass());
1986
1987 // Eliminate Common SubExpressions.
1988 fpm.add(llvm::createGVNPass());
1989
1990 // Simplify the control flow graph (deleting unreachable
1991 // blocks, etc).
1992 fpm.add(llvm::createCFGSimplificationPass());
1993#endif // ADD_OPT_PASSES
1994
1995 fpm.doInitialization();
1996
1997 // Generate test code using function throwCppException(...) as
1998 // the function which throws foreign exceptions.
1999 llvm::Function* toRun =
2000 createUnwindExceptionTest(*module,
2001 theBuilder,
2002 fpm,
2003 "throwCppException");
2004
2005 fprintf(stderr, "\nBegin module dump:\n\n");
2006
2007 module->dump();
2008
2009 fprintf(stderr, "\nEnd module dump:\n");
2010
2011 fprintf(stderr, "\n\nBegin Test:\n");
2012
2013 for (int i = 1; i < argc; ++i) {
2014 // Run test for each argument whose value is the exception
2015 // type to throw.
2016 runExceptionThrow(executionEngine,
2017 toRun,
2018 (unsigned) strtoul(argv[i], NULL, 10));
2019 }
2020
2021 fprintf(stderr, "\nEnd Test:\n\n");
2022 }
2023
2024 delete executionEngine;
2025
2026 return 0;
2027}
2028