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