blob: fcc8b5c790d17bf93d78c15dc8db70682e25bd9e [file] [log] [blame]
Chris Lattner626ab1c2011-04-08 18:02:51 +00001//===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===//
Garrison Venna2c2f1a2010-02-09 23:22:43 +00002//
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//
Chris Lattner626ab1c2011-04-08 18:02:51 +00008//===----------------------------------------------------------------------===//
Garrison Venna2c2f1a2010-02-09 23:22:43 +00009//
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//
Chris Lattner626ab1c2011-04-08 18:02:51 +000048//===----------------------------------------------------------------------===//
Garrison Venna2c2f1a2010-02-09 23:22:43 +000049
50#include "llvm/LLVMContext.h"
51#include "llvm/DerivedTypes.h"
52#include "llvm/ExecutionEngine/ExecutionEngine.h"
53#include "llvm/ExecutionEngine/JIT.h"
54#include "llvm/Module.h"
55#include "llvm/PassManager.h"
56#include "llvm/Intrinsics.h"
57#include "llvm/Analysis/Verifier.h"
58#include "llvm/Target/TargetData.h"
59#include "llvm/Target/TargetSelect.h"
60#include "llvm/Target/TargetOptions.h"
61#include "llvm/Transforms/Scalar.h"
62#include "llvm/Support/IRBuilder.h"
63#include "llvm/Support/Dwarf.h"
64
Garrison Venn2a7d4ad2011-04-11 19:52:49 +000065#include <cstdio>
Garrison Venna2c2f1a2010-02-09 23:22:43 +000066#include <sstream>
Garrison Venna2c2f1a2010-02-09 23:22:43 +000067#include <stdexcept>
68
69
70#ifndef USE_GLOBAL_STR_CONSTS
71#define USE_GLOBAL_STR_CONSTS true
72#endif
73
74// System C++ ABI unwind types from:
75// http://refspecs.freestandards.org/abi-eh-1.21.html
76
77extern "C" {
Chris Lattner626ab1c2011-04-08 18:02:51 +000078
79 typedef enum {
Garrison Venna2c2f1a2010-02-09 23:22:43 +000080 _URC_NO_REASON = 0,
81 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
82 _URC_FATAL_PHASE2_ERROR = 2,
83 _URC_FATAL_PHASE1_ERROR = 3,
84 _URC_NORMAL_STOP = 4,
85 _URC_END_OF_STACK = 5,
86 _URC_HANDLER_FOUND = 6,
87 _URC_INSTALL_CONTEXT = 7,
88 _URC_CONTINUE_UNWIND = 8
Chris Lattner626ab1c2011-04-08 18:02:51 +000089 } _Unwind_Reason_Code;
90
91 typedef enum {
Garrison Venna2c2f1a2010-02-09 23:22:43 +000092 _UA_SEARCH_PHASE = 1,
93 _UA_CLEANUP_PHASE = 2,
94 _UA_HANDLER_FRAME = 4,
95 _UA_FORCE_UNWIND = 8,
96 _UA_END_OF_STACK = 16
Chris Lattner626ab1c2011-04-08 18:02:51 +000097 } _Unwind_Action;
98
99 struct _Unwind_Exception;
100
101 typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
102 struct _Unwind_Exception *);
103
104 struct _Unwind_Exception {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000105 uint64_t exception_class;
106 _Unwind_Exception_Cleanup_Fn exception_cleanup;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000107
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000108 uintptr_t private_1;
109 uintptr_t private_2;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000110
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000111 // @@@ The IA-64 ABI says that this structure must be double-word aligned.
112 // Taking that literally does not make much sense generically. Instead
113 // we provide the maximum alignment required by any type for the machine.
Chris Lattner626ab1c2011-04-08 18:02:51 +0000114 } __attribute__((__aligned__));
115
116 struct _Unwind_Context;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000117 typedef struct _Unwind_Context *_Unwind_Context_t;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000118
Garrison Venn64cfcef2011-04-10 14:06:52 +0000119 extern const uint8_t *_Unwind_GetLanguageSpecificData (_Unwind_Context_t c);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000120 extern uintptr_t _Unwind_GetGR (_Unwind_Context_t c, int i);
121 extern void _Unwind_SetGR (_Unwind_Context_t c, int i, uintptr_t n);
122 extern void _Unwind_SetIP (_Unwind_Context_t, uintptr_t new_value);
123 extern uintptr_t _Unwind_GetIP (_Unwind_Context_t context);
124 extern uintptr_t _Unwind_GetRegionStart (_Unwind_Context_t context);
125
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000126} // extern "C"
127
128//
129// Example types
130//
131
132/// This is our simplistic type info
133struct OurExceptionType_t {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000134 /// type info type
135 int type;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000136};
137
138
139/// This is our Exception class which relies on a negative offset to calculate
140/// pointers to its instances from pointers to its unwindException member.
141///
142/// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
143/// on a double word boundary. This is necessary to match the standard:
144/// http://refspecs.freestandards.org/abi-eh-1.21.html
145struct OurBaseException_t {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000146 struct OurExceptionType_t type;
147
148 // Note: This is properly aligned in unwind.h
149 struct _Unwind_Exception unwindException;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000150};
151
152
153// Note: Not needed since we are C++
154typedef struct OurBaseException_t OurException;
155typedef struct _Unwind_Exception OurUnwindException;
156
157//
158// Various globals used to support typeinfo and generatted exceptions in
159// general
160//
161
162static std::map<std::string, llvm::Value*> namedValues;
163
164int64_t ourBaseFromUnwindOffset;
165
166const unsigned char ourBaseExcpClassChars[] =
Chris Lattner626ab1c2011-04-08 18:02:51 +0000167{'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000168
169
170static uint64_t ourBaseExceptionClass = 0;
171
172static std::vector<std::string> ourTypeInfoNames;
173static std::map<int, std::string> ourTypeInfoNamesIndex;
174
Garrison Venn64cfcef2011-04-10 14:06:52 +0000175static llvm::StructType *ourTypeInfoType;
176static llvm::StructType *ourExceptionType;
177static llvm::StructType *ourUnwindExceptionType;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000178
Garrison Venn64cfcef2011-04-10 14:06:52 +0000179static llvm::ConstantInt *ourExceptionNotThrownState;
180static llvm::ConstantInt *ourExceptionThrownState;
181static llvm::ConstantInt *ourExceptionCaughtState;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000182
183typedef std::vector<std::string> ArgNames;
184typedef std::vector<const llvm::Type*> ArgTypes;
185
186//
187// Code Generation Utilities
188//
189
190/// Utility used to create a function, both declarations and definitions
191/// @param module for module instance
192/// @param retType function return type
193/// @param theArgTypes function's ordered argument types
194/// @param theArgNames function's ordered arguments needed if use of this
195/// function corresponds to a function definition. Use empty
196/// aggregate for function declarations.
197/// @param functName function name
198/// @param linkage function linkage
199/// @param declarationOnly for function declarations
200/// @param isVarArg function uses vararg arguments
201/// @returns function instance
Garrison Venn64cfcef2011-04-10 14:06:52 +0000202llvm::Function *createFunction(llvm::Module &module,
203 const llvm::Type *retType,
204 const ArgTypes &theArgTypes,
205 const ArgNames &theArgNames,
206 const std::string &functName,
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000207 llvm::GlobalValue::LinkageTypes linkage,
208 bool declarationOnly,
209 bool isVarArg) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000210 llvm::FunctionType *functType =
211 llvm::FunctionType::get(retType, theArgTypes, isVarArg);
212 llvm::Function *ret =
213 llvm::Function::Create(functType, linkage, functName, &module);
214 if (!ret || declarationOnly)
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000215 return(ret);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000216
217 namedValues.clear();
218 unsigned i = 0;
219 for (llvm::Function::arg_iterator argIndex = ret->arg_begin();
220 i != theArgNames.size();
221 ++argIndex, ++i) {
222
223 argIndex->setName(theArgNames[i]);
224 namedValues[theArgNames[i]] = argIndex;
225 }
226
227 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000228}
229
230
231/// Create an alloca instruction in the entry block of
232/// the parent function. This is used for mutable variables etc.
233/// @param function parent instance
234/// @param varName stack variable name
235/// @param type stack variable type
236/// @param initWith optional constant initialization value
237/// @returns AllocaInst instance
Garrison Venn64cfcef2011-04-10 14:06:52 +0000238static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000239 const std::string &varName,
Garrison Venn64cfcef2011-04-10 14:06:52 +0000240 const llvm::Type *type,
241 llvm::Constant *initWith = 0) {
242 llvm::BasicBlock &block = function.getEntryBlock();
Chris Lattner626ab1c2011-04-08 18:02:51 +0000243 llvm::IRBuilder<> tmp(&block, block.begin());
Garrison Venn64cfcef2011-04-10 14:06:52 +0000244 llvm::AllocaInst *ret = tmp.CreateAlloca(type, 0, varName.c_str());
Chris Lattner626ab1c2011-04-08 18:02:51 +0000245
246 if (initWith)
247 tmp.CreateStore(initWith, ret);
248
249 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000250}
251
252
253//
254// Code Generation Utilities End
255//
256
257//
258// Runtime C Library functions
259//
260
261// Note: using an extern "C" block so that static functions can be used
262extern "C" {
263
264// Note: Better ways to decide on bit width
265//
266/// Prints a 32 bit number, according to the format, to stderr.
267/// @param intToPrint integer to print
268/// @param format printf like format to use when printing
Garrison Venn64cfcef2011-04-10 14:06:52 +0000269void print32Int(int intToPrint, const char *format) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000270 if (format) {
271 // Note: No NULL check
272 fprintf(stderr, format, intToPrint);
273 }
274 else {
275 // Note: No NULL check
276 fprintf(stderr, "::print32Int(...):NULL arg.\n");
277 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000278}
279
280
281// Note: Better ways to decide on bit width
282//
283/// Prints a 64 bit number, according to the format, to stderr.
284/// @param intToPrint integer to print
285/// @param format printf like format to use when printing
Garrison Venn64cfcef2011-04-10 14:06:52 +0000286void print64Int(long int intToPrint, const char *format) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000287 if (format) {
288 // Note: No NULL check
289 fprintf(stderr, format, intToPrint);
290 }
291 else {
292 // Note: No NULL check
293 fprintf(stderr, "::print64Int(...):NULL arg.\n");
294 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000295}
296
297
298/// Prints a C string to stderr
299/// @param toPrint string to print
Garrison Venn64cfcef2011-04-10 14:06:52 +0000300void printStr(char *toPrint) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000301 if (toPrint) {
302 fprintf(stderr, "%s", toPrint);
303 }
304 else {
305 fprintf(stderr, "::printStr(...):NULL arg.\n");
306 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000307}
308
309
310/// Deletes the true previosly allocated exception whose address
311/// is calculated from the supplied OurBaseException_t::unwindException
312/// member address. Handles (ignores), NULL pointers.
313/// @param expToDelete exception to delete
Garrison Venn64cfcef2011-04-10 14:06:52 +0000314void deleteOurException(OurUnwindException *expToDelete) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000315#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000316 fprintf(stderr,
317 "deleteOurException(...).\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000318#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000319
320 if (expToDelete &&
321 (expToDelete->exception_class == ourBaseExceptionClass)) {
322
323 free(((char*) expToDelete) + ourBaseFromUnwindOffset);
324 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000325}
326
327
328/// This function is the struct _Unwind_Exception API mandated delete function
329/// used by foreign exception handlers when deleting our exception
330/// (OurException), instances.
331/// @param reason @link http://refspecs.freestandards.org/abi-eh-1.21.html
332/// @unlink
333/// @param expToDelete exception instance to delete
334void deleteFromUnwindOurException(_Unwind_Reason_Code reason,
Garrison Venn64cfcef2011-04-10 14:06:52 +0000335 OurUnwindException *expToDelete) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000336#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000337 fprintf(stderr,
338 "deleteFromUnwindOurException(...).\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000339#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000340
341 deleteOurException(expToDelete);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000342}
343
344
345/// Creates (allocates on the heap), an exception (OurException instance),
346/// of the supplied type info type.
347/// @param type type info type
Garrison Venn64cfcef2011-04-10 14:06:52 +0000348OurUnwindException *createOurException(int type) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000349 size_t size = sizeof(OurException);
Garrison Venn64cfcef2011-04-10 14:06:52 +0000350 OurException *ret = (OurException*) memset(malloc(size), 0, size);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000351 (ret->type).type = type;
352 (ret->unwindException).exception_class = ourBaseExceptionClass;
353 (ret->unwindException).exception_cleanup = deleteFromUnwindOurException;
354
355 return(&(ret->unwindException));
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000356}
357
358
359/// Read a uleb128 encoded value and advance pointer
360/// See Variable Length Data in:
361/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
362/// @param data reference variable holding memory pointer to decode from
363/// @returns decoded value
Garrison Venn64cfcef2011-04-10 14:06:52 +0000364static uintptr_t readULEB128(const uint8_t **data) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000365 uintptr_t result = 0;
366 uintptr_t shift = 0;
367 unsigned char byte;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000368 const uint8_t *p = *data;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000369
370 do {
371 byte = *p++;
372 result |= (byte & 0x7f) << shift;
373 shift += 7;
374 }
375 while (byte & 0x80);
376
377 *data = p;
378
379 return result;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000380}
381
382
383/// Read a sleb128 encoded value and advance pointer
384/// See Variable Length Data in:
385/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
386/// @param data reference variable holding memory pointer to decode from
387/// @returns decoded value
Garrison Venn64cfcef2011-04-10 14:06:52 +0000388static uintptr_t readSLEB128(const uint8_t **data) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000389 uintptr_t result = 0;
390 uintptr_t shift = 0;
391 unsigned char byte;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000392 const uint8_t *p = *data;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000393
394 do {
395 byte = *p++;
396 result |= (byte & 0x7f) << shift;
397 shift += 7;
398 }
399 while (byte & 0x80);
400
401 *data = p;
402
403 if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
404 result |= (~0 << shift);
405 }
406
407 return result;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000408}
409
410
411/// Read a pointer encoded value and advance pointer
412/// See Variable Length Data in:
413/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
414/// @param data reference variable holding memory pointer to decode from
415/// @param encoding dwarf encoding type
416/// @returns decoded value
Garrison Venn64cfcef2011-04-10 14:06:52 +0000417static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000418 uintptr_t result = 0;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000419 const uint8_t *p = *data;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000420
421 if (encoding == llvm::dwarf::DW_EH_PE_omit)
422 return(result);
423
424 // first get value
425 switch (encoding & 0x0F) {
426 case llvm::dwarf::DW_EH_PE_absptr:
427 result = *((uintptr_t*)p);
428 p += sizeof(uintptr_t);
429 break;
430 case llvm::dwarf::DW_EH_PE_uleb128:
431 result = readULEB128(&p);
432 break;
433 // Note: This case has not been tested
434 case llvm::dwarf::DW_EH_PE_sleb128:
435 result = readSLEB128(&p);
436 break;
437 case llvm::dwarf::DW_EH_PE_udata2:
438 result = *((uint16_t*)p);
439 p += sizeof(uint16_t);
440 break;
441 case llvm::dwarf::DW_EH_PE_udata4:
442 result = *((uint32_t*)p);
443 p += sizeof(uint32_t);
444 break;
445 case llvm::dwarf::DW_EH_PE_udata8:
446 result = *((uint64_t*)p);
447 p += sizeof(uint64_t);
448 break;
449 case llvm::dwarf::DW_EH_PE_sdata2:
450 result = *((int16_t*)p);
451 p += sizeof(int16_t);
452 break;
453 case llvm::dwarf::DW_EH_PE_sdata4:
454 result = *((int32_t*)p);
455 p += sizeof(int32_t);
456 break;
457 case llvm::dwarf::DW_EH_PE_sdata8:
458 result = *((int64_t*)p);
459 p += sizeof(int64_t);
460 break;
461 default:
462 // not supported
463 abort();
464 break;
465 }
466
467 // then add relative offset
468 switch (encoding & 0x70) {
469 case llvm::dwarf::DW_EH_PE_absptr:
470 // do nothing
471 break;
472 case llvm::dwarf::DW_EH_PE_pcrel:
473 result += (uintptr_t)(*data);
474 break;
475 case llvm::dwarf::DW_EH_PE_textrel:
476 case llvm::dwarf::DW_EH_PE_datarel:
477 case llvm::dwarf::DW_EH_PE_funcrel:
478 case llvm::dwarf::DW_EH_PE_aligned:
479 default:
480 // not supported
481 abort();
482 break;
483 }
484
485 // then apply indirection
486 if (encoding & llvm::dwarf::DW_EH_PE_indirect) {
487 result = *((uintptr_t*)result);
488 }
489
490 *data = p;
491
492 return result;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000493}
494
495
496/// Deals with Dwarf actions matching our type infos
497/// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
498/// action matches the supplied exception type. If such a match succeeds,
499/// the resultAction argument will be set with > 0 index value. Only
500/// corresponding llvm.eh.selector type info arguments, cleanup arguments
501/// are supported. Filters are not supported.
502/// See Variable Length Data in:
503/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
504/// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
505/// @param resultAction reference variable which will be set with result
506/// @param classInfo our array of type info pointers (to globals)
507/// @param actionEntry index into above type info array or 0 (clean up).
508/// We do not support filters.
509/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
510/// of thrown exception.
511/// @param exceptionObject thrown _Unwind_Exception instance.
512/// @returns whether or not a type info was found. False is returned if only
513/// a cleanup was found
514static bool handleActionValue(int64_t *resultAction,
515 struct OurExceptionType_t **classInfo,
516 uintptr_t actionEntry,
517 uint64_t exceptionClass,
518 struct _Unwind_Exception *exceptionObject) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000519 bool ret = false;
520
521 if (!resultAction ||
522 !exceptionObject ||
523 (exceptionClass != ourBaseExceptionClass))
524 return(ret);
525
Garrison Venn64cfcef2011-04-10 14:06:52 +0000526 struct OurBaseException_t *excp = (struct OurBaseException_t*)
Chris Lattner626ab1c2011-04-08 18:02:51 +0000527 (((char*) exceptionObject) + ourBaseFromUnwindOffset);
528 struct OurExceptionType_t *excpType = &(excp->type);
529 int type = excpType->type;
530
531#ifdef DEBUG
532 fprintf(stderr,
533 "handleActionValue(...): exceptionObject = <%p>, "
534 "excp = <%p>.\n",
535 exceptionObject,
536 excp);
537#endif
538
539 const uint8_t *actionPos = (uint8_t*) actionEntry,
540 *tempActionPos;
541 int64_t typeOffset = 0,
542 actionOffset;
543
544 for (int i = 0; true; ++i) {
545 // Each emitted dwarf action corresponds to a 2 tuple of
546 // type info address offset, and action offset to the next
547 // emitted action.
548 typeOffset = readSLEB128(&actionPos);
549 tempActionPos = actionPos;
550 actionOffset = readSLEB128(&tempActionPos);
551
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000552#ifdef DEBUG
553 fprintf(stderr,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000554 "handleActionValue(...):typeOffset: <%lld>, "
555 "actionOffset: <%lld>.\n",
556 typeOffset,
557 actionOffset);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000558#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000559 assert((typeOffset >= 0) &&
560 "handleActionValue(...):filters are not supported.");
561
562 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
563 // argument has been matched.
564 if ((typeOffset > 0) &&
565 (type == (classInfo[-typeOffset])->type)) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000566#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000567 fprintf(stderr,
568 "handleActionValue(...):actionValue <%d> found.\n",
569 i);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000570#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000571 *resultAction = i + 1;
572 ret = true;
573 break;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000574 }
Chris Lattner626ab1c2011-04-08 18:02:51 +0000575
576#ifdef DEBUG
577 fprintf(stderr,
578 "handleActionValue(...):actionValue not found.\n");
579#endif
580 if (!actionOffset)
581 break;
582
583 actionPos += actionOffset;
584 }
585
586 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000587}
588
589
590/// Deals with the Language specific data portion of the emitted dwarf code.
591/// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
592/// @param version unsupported (ignored), unwind version
593/// @param lsda language specific data area
594/// @param _Unwind_Action actions minimally supported unwind stage
595/// (forced specifically not supported)
596/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
597/// of thrown exception.
598/// @param exceptionObject thrown _Unwind_Exception instance.
599/// @param context unwind system context
600/// @returns minimally supported unwinding control indicator
601static _Unwind_Reason_Code handleLsda(int version,
Garrison Venn64cfcef2011-04-10 14:06:52 +0000602 const uint8_t *lsda,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000603 _Unwind_Action actions,
604 uint64_t exceptionClass,
Garrison Venn64cfcef2011-04-10 14:06:52 +0000605 struct _Unwind_Exception *exceptionObject,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000606 _Unwind_Context_t context) {
607 _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND;
608
609 if (!lsda)
610 return(ret);
611
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000612#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000613 fprintf(stderr,
614 "handleLsda(...):lsda is non-zero.\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000615#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000616
617 // Get the current instruction pointer and offset it before next
618 // instruction in the current frame which threw the exception.
619 uintptr_t pc = _Unwind_GetIP(context)-1;
620
621 // Get beginning current frame's code (as defined by the
622 // emitted dwarf code)
623 uintptr_t funcStart = _Unwind_GetRegionStart(context);
624 uintptr_t pcOffset = pc - funcStart;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000625 struct OurExceptionType_t **classInfo = NULL;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000626
627 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
628 // dwarf emission
629
630 // Parse LSDA header.
631 uint8_t lpStartEncoding = *lsda++;
632
633 if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) {
634 readEncodedPointer(&lsda, lpStartEncoding);
635 }
636
637 uint8_t ttypeEncoding = *lsda++;
638 uintptr_t classInfoOffset;
639
640 if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) {
641 // Calculate type info locations in emitted dwarf code which
642 // were flagged by type info arguments to llvm.eh.selector
643 // intrinsic
644 classInfoOffset = readULEB128(&lsda);
645 classInfo = (struct OurExceptionType_t**) (lsda + classInfoOffset);
646 }
647
648 // Walk call-site table looking for range that
649 // includes current PC.
650
651 uint8_t callSiteEncoding = *lsda++;
652 uint32_t callSiteTableLength = readULEB128(&lsda);
Garrison Venn64cfcef2011-04-10 14:06:52 +0000653 const uint8_t *callSiteTableStart = lsda;
654 const uint8_t *callSiteTableEnd = callSiteTableStart +
Chris Lattner626ab1c2011-04-08 18:02:51 +0000655 callSiteTableLength;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000656 const uint8_t *actionTableStart = callSiteTableEnd;
657 const uint8_t *callSitePtr = callSiteTableStart;
Chris Lattner626ab1c2011-04-08 18:02:51 +0000658
659 bool foreignException = false;
660
661 while (callSitePtr < callSiteTableEnd) {
662 uintptr_t start = readEncodedPointer(&callSitePtr,
663 callSiteEncoding);
664 uintptr_t length = readEncodedPointer(&callSitePtr,
665 callSiteEncoding);
666 uintptr_t landingPad = readEncodedPointer(&callSitePtr,
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000667 callSiteEncoding);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000668
669 // Note: Action value
670 uintptr_t actionEntry = readULEB128(&callSitePtr);
671
672 if (exceptionClass != ourBaseExceptionClass) {
673 // We have been notified of a foreign exception being thrown,
674 // and we therefore need to execute cleanup landing pads
675 actionEntry = 0;
676 foreignException = true;
677 }
678
679 if (landingPad == 0) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000680#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000681 fprintf(stderr,
682 "handleLsda(...): No landing pad found.\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000683#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000684
685 continue; // no landing pad for this entry
686 }
687
688 if (actionEntry) {
689 actionEntry += ((uintptr_t) actionTableStart) - 1;
690 }
691 else {
692#ifdef DEBUG
693 fprintf(stderr,
694 "handleLsda(...):No action table found.\n");
695#endif
696 }
697
698 bool exceptionMatched = false;
699
700 if ((start <= pcOffset) && (pcOffset < (start + length))) {
701#ifdef DEBUG
702 fprintf(stderr,
703 "handleLsda(...): Landing pad found.\n");
704#endif
705 int64_t actionValue = 0;
706
707 if (actionEntry) {
Garrison Venn64cfcef2011-04-10 14:06:52 +0000708 exceptionMatched = handleActionValue(&actionValue,
709 classInfo,
710 actionEntry,
711 exceptionClass,
712 exceptionObject);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000713 }
714
715 if (!(actions & _UA_SEARCH_PHASE)) {
716#ifdef DEBUG
717 fprintf(stderr,
718 "handleLsda(...): installed landing pad "
719 "context.\n");
720#endif
721
722 // Found landing pad for the PC.
723 // Set Instruction Pointer to so we re-enter function
724 // at landing pad. The landing pad is created by the
725 // compiler to take two parameters in registers.
726 _Unwind_SetGR(context,
727 __builtin_eh_return_data_regno(0),
728 (uintptr_t)exceptionObject);
729
730 // Note: this virtual register directly corresponds
731 // to the return of the llvm.eh.selector intrinsic
732 if (!actionEntry || !exceptionMatched) {
733 // We indicate cleanup only
734 _Unwind_SetGR(context,
735 __builtin_eh_return_data_regno(1),
736 0);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000737 }
738 else {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000739 // Matched type info index of llvm.eh.selector intrinsic
740 // passed here.
741 _Unwind_SetGR(context,
742 __builtin_eh_return_data_regno(1),
743 actionValue);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000744 }
Chris Lattner626ab1c2011-04-08 18:02:51 +0000745
746 // To execute landing pad set here
747 _Unwind_SetIP(context, funcStart + landingPad);
748 ret = _URC_INSTALL_CONTEXT;
749 }
750 else if (exceptionMatched) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000751#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000752 fprintf(stderr,
753 "handleLsda(...): setting handler found.\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000754#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000755 ret = _URC_HANDLER_FOUND;
756 }
757 else {
758 // Note: Only non-clean up handlers are marked as
759 // found. Otherwise the clean up handlers will be
760 // re-found and executed during the clean up
761 // phase.
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000762#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000763 fprintf(stderr,
764 "handleLsda(...): cleanup handler found.\n");
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000765#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000766 }
767
768 break;
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000769 }
Chris Lattner626ab1c2011-04-08 18:02:51 +0000770 }
771
772 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000773}
774
775
776/// This is the personality function which is embedded (dwarf emitted), in the
777/// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
778/// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
779/// @param version unsupported (ignored), unwind version
780/// @param _Unwind_Action actions minimally supported unwind stage
781/// (forced specifically not supported)
782/// @param exceptionClass exception class (_Unwind_Exception::exception_class)
783/// of thrown exception.
784/// @param exceptionObject thrown _Unwind_Exception instance.
785/// @param context unwind system context
786/// @returns minimally supported unwinding control indicator
787_Unwind_Reason_Code ourPersonality(int version,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000788 _Unwind_Action actions,
789 uint64_t exceptionClass,
Garrison Venn64cfcef2011-04-10 14:06:52 +0000790 struct _Unwind_Exception *exceptionObject,
Chris Lattner626ab1c2011-04-08 18:02:51 +0000791 _Unwind_Context_t context) {
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000792#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000793 fprintf(stderr,
794 "We are in ourPersonality(...):actions is <%d>.\n",
795 actions);
796
797 if (actions & _UA_SEARCH_PHASE) {
798 fprintf(stderr, "ourPersonality(...):In search phase.\n");
799 }
800 else {
801 fprintf(stderr, "ourPersonality(...):In non-search phase.\n");
802 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000803#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000804
Garrison Venn64cfcef2011-04-10 14:06:52 +0000805 const uint8_t *lsda = _Unwind_GetLanguageSpecificData(context);
Chris Lattner626ab1c2011-04-08 18:02:51 +0000806
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000807#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +0000808 fprintf(stderr,
809 "ourPersonality(...):lsda = <%p>.\n",
810 lsda);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000811#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +0000812
813 // The real work of the personality function is captured here
814 return(handleLsda(version,
815 lsda,
816 actions,
817 exceptionClass,
818 exceptionObject,
819 context));
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000820}
821
822
823/// Generates our _Unwind_Exception class from a given character array.
824/// thereby handling arbitrary lengths (not in standard), and handling
825/// embedded \0s.
826/// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
827/// @param classChars char array to encode. NULL values not checkedf
828/// @param classCharsSize number of chars in classChars. Value is not checked.
829/// @returns class value
830uint64_t genClass(const unsigned char classChars[], size_t classCharsSize)
831{
Chris Lattner626ab1c2011-04-08 18:02:51 +0000832 uint64_t ret = classChars[0];
833
834 for (unsigned i = 1; i < classCharsSize; ++i) {
835 ret <<= 8;
836 ret += classChars[i];
837 }
838
839 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000840}
841
842} // extern "C"
843
844//
845// Runtime C Library functions End
846//
847
848//
849// Code generation functions
850//
851
852/// Generates code to print given constant string
853/// @param context llvm context
854/// @param module code for module instance
855/// @param builder builder instance
856/// @param toPrint string to print
857/// @param useGlobal A value of true (default) indicates a GlobalValue is
858/// generated, and is used to hold the constant string. A value of
859/// false indicates that the constant string will be stored on the
860/// stack.
Garrison Venn64cfcef2011-04-10 14:06:52 +0000861void generateStringPrint(llvm::LLVMContext &context,
862 llvm::Module &module,
863 llvm::IRBuilder<> &builder,
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000864 std::string toPrint,
865 bool useGlobal = true) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000866 llvm::Function *printFunct = module.getFunction("printStr");
867
868 llvm::Value *stringVar;
Garrison Venn64cfcef2011-04-10 14:06:52 +0000869 llvm::Constant *stringConstant =
Chris Lattner626ab1c2011-04-08 18:02:51 +0000870 llvm::ConstantArray::get(context, toPrint);
871
872 if (useGlobal) {
873 // Note: Does not work without allocation
874 stringVar =
875 new llvm::GlobalVariable(module,
876 stringConstant->getType(),
877 true,
878 llvm::GlobalValue::LinkerPrivateLinkage,
879 stringConstant,
880 "");
881 }
882 else {
883 stringVar = builder.CreateAlloca(stringConstant->getType());
884 builder.CreateStore(stringConstant, stringVar);
885 }
886
Garrison Venn64cfcef2011-04-10 14:06:52 +0000887 llvm::Value *cast =
Chris Lattner626ab1c2011-04-08 18:02:51 +0000888 builder.CreatePointerCast(stringVar,
889 builder.getInt8Ty()->getPointerTo());
890 builder.CreateCall(printFunct, cast);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000891}
892
893
894/// Generates code to print given runtime integer according to constant
895/// string format, and a given print function.
896/// @param context llvm context
897/// @param module code for module instance
898/// @param builder builder instance
899/// @param printFunct function used to "print" integer
900/// @param toPrint string to print
901/// @param format printf like formating string for print
902/// @param useGlobal A value of true (default) indicates a GlobalValue is
903/// generated, and is used to hold the constant string. A value of
904/// false indicates that the constant string will be stored on the
905/// stack.
Garrison Venn64cfcef2011-04-10 14:06:52 +0000906void generateIntegerPrint(llvm::LLVMContext &context,
907 llvm::Module &module,
908 llvm::IRBuilder<> &builder,
909 llvm::Function &printFunct,
910 llvm::Value &toPrint,
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000911 std::string format,
912 bool useGlobal = true) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000913 llvm::Constant *stringConstant = llvm::ConstantArray::get(context, format);
914 llvm::Value *stringVar;
915
916 if (useGlobal) {
917 // Note: Does not seem to work without allocation
918 stringVar =
919 new llvm::GlobalVariable(module,
920 stringConstant->getType(),
921 true,
922 llvm::GlobalValue::LinkerPrivateLinkage,
923 stringConstant,
924 "");
925 }
926 else {
927 stringVar = builder.CreateAlloca(stringConstant->getType());
928 builder.CreateStore(stringConstant, stringVar);
929 }
930
Garrison Venn64cfcef2011-04-10 14:06:52 +0000931 llvm::Value *cast =
Chris Lattner626ab1c2011-04-08 18:02:51 +0000932 builder.CreateBitCast(stringVar,
933 builder.getInt8Ty()->getPointerTo());
934 builder.CreateCall2(&printFunct, &toPrint, cast);
Garrison Venna2c2f1a2010-02-09 23:22:43 +0000935}
936
937
938/// Generates code to handle finally block type semantics: always runs
939/// regardless of whether a thrown exception is passing through or the
940/// parent function is simply exiting. In addition to printing some state
941/// to stderr, this code will resume the exception handling--runs the
942/// unwind resume block, if the exception has not been previously caught
943/// by a catch clause, and will otherwise execute the end block (terminator
944/// block). In addition this function creates the corresponding function's
945/// stack storage for the exception pointer and catch flag status.
946/// @param context llvm context
947/// @param module code for module instance
948/// @param builder builder instance
949/// @param toAddTo parent function to add block to
950/// @param blockName block name of new "finally" block.
951/// @param functionId output id used for printing
952/// @param terminatorBlock terminator "end" block
953/// @param unwindResumeBlock unwind resume block
954/// @param exceptionCaughtFlag reference exception caught/thrown status storage
955/// @param exceptionStorage reference to exception pointer storage
956/// @returns newly created block
Garrison Venn64cfcef2011-04-10 14:06:52 +0000957static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
958 llvm::Module &module,
959 llvm::IRBuilder<> &builder,
960 llvm::Function &toAddTo,
961 std::string &blockName,
962 std::string &functionId,
963 llvm::BasicBlock &terminatorBlock,
964 llvm::BasicBlock &unwindResumeBlock,
965 llvm::Value **exceptionCaughtFlag,
966 llvm::Value **exceptionStorage) {
Chris Lattner626ab1c2011-04-08 18:02:51 +0000967 assert(exceptionCaughtFlag &&
968 "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
969 "is NULL");
970 assert(exceptionStorage &&
971 "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
972 "is NULL");
973
974 *exceptionCaughtFlag =
975 createEntryBlockAlloca(toAddTo,
976 "exceptionCaught",
977 ourExceptionNotThrownState->getType(),
978 ourExceptionNotThrownState);
979
Garrison Venn64cfcef2011-04-10 14:06:52 +0000980 const llvm::PointerType *exceptionStorageType =
Chris Lattner626ab1c2011-04-08 18:02:51 +0000981 builder.getInt8Ty()->getPointerTo();
982 *exceptionStorage =
983 createEntryBlockAlloca(toAddTo,
984 "exceptionStorage",
985 exceptionStorageType,
986 llvm::ConstantPointerNull::get(
987 exceptionStorageType));
988
989 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
990 blockName,
991 &toAddTo);
992
993 builder.SetInsertPoint(ret);
994
995 std::ostringstream bufferToPrint;
996 bufferToPrint << "Gen: Executing finally block "
997 << blockName << " in " << functionId << "\n";
998 generateStringPrint(context,
999 module,
1000 builder,
1001 bufferToPrint.str(),
1002 USE_GLOBAL_STR_CONSTS);
1003
Garrison Venn64cfcef2011-04-10 14:06:52 +00001004 llvm::SwitchInst *theSwitch =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001005 builder.CreateSwitch(builder.CreateLoad(*exceptionCaughtFlag),
1006 &terminatorBlock,
1007 2);
1008 theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
1009 theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
1010
1011 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001012}
1013
1014
1015/// Generates catch block semantics which print a string to indicate type of
1016/// catch executed, sets an exception caught flag, and executes passed in
1017/// end block (terminator block).
1018/// @param context llvm context
1019/// @param module code for module instance
1020/// @param builder builder instance
1021/// @param toAddTo parent function to add block to
1022/// @param blockName block name of new "catch" block.
1023/// @param functionId output id used for printing
1024/// @param terminatorBlock terminator "end" block
1025/// @param exceptionCaughtFlag exception caught/thrown status
1026/// @returns newly created block
Garrison Venn64cfcef2011-04-10 14:06:52 +00001027static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context,
1028 llvm::Module &module,
1029 llvm::IRBuilder<> &builder,
1030 llvm::Function &toAddTo,
1031 std::string &blockName,
1032 std::string &functionId,
1033 llvm::BasicBlock &terminatorBlock,
1034 llvm::Value &exceptionCaughtFlag) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001035
1036 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1037 blockName,
1038 &toAddTo);
1039
1040 builder.SetInsertPoint(ret);
1041
1042 std::ostringstream bufferToPrint;
1043 bufferToPrint << "Gen: Executing catch block "
1044 << blockName
1045 << " in "
1046 << functionId
1047 << std::endl;
1048 generateStringPrint(context,
1049 module,
1050 builder,
1051 bufferToPrint.str(),
1052 USE_GLOBAL_STR_CONSTS);
1053 builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
1054 builder.CreateBr(&terminatorBlock);
1055
1056 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001057}
1058
1059
1060/// Generates a function which invokes a function (toInvoke) and, whose
1061/// unwind block will "catch" the type info types correspondingly held in the
1062/// exceptionTypesToCatch argument. If the toInvoke function throws an
1063/// exception which does not match any type info types contained in
1064/// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1065/// with the raised exception. On the other hand the generated code will
1066/// normally exit if the toInvoke function does not throw an exception.
1067/// The generated "finally" block is always run regardless of the cause of
1068/// the generated function exit.
1069/// The generated function is returned after being verified.
1070/// @param module code for module instance
1071/// @param builder builder instance
1072/// @param fpm a function pass manager holding optional IR to IR
1073/// transformations
1074/// @param toInvoke inner function to invoke
1075/// @param ourId id used to printing purposes
1076/// @param numExceptionsToCatch length of exceptionTypesToCatch array
1077/// @param exceptionTypesToCatch array of type info types to "catch"
1078/// @returns generated function
1079static
Garrison Venn64cfcef2011-04-10 14:06:52 +00001080llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module,
1081 llvm::IRBuilder<> &builder,
1082 llvm::FunctionPassManager &fpm,
1083 llvm::Function &toInvoke,
1084 std::string ourId,
1085 unsigned numExceptionsToCatch,
1086 unsigned exceptionTypesToCatch[]) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001087
Garrison Venn64cfcef2011-04-10 14:06:52 +00001088 llvm::LLVMContext &context = module.getContext();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001089 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1090
1091 ArgTypes argTypes;
1092 argTypes.push_back(builder.getInt32Ty());
1093
1094 ArgNames argNames;
1095 argNames.push_back("exceptTypeToThrow");
1096
Garrison Venn64cfcef2011-04-10 14:06:52 +00001097 llvm::Function *ret = createFunction(module,
Chris Lattner626ab1c2011-04-08 18:02:51 +00001098 builder.getVoidTy(),
1099 argTypes,
1100 argNames,
1101 ourId,
1102 llvm::Function::ExternalLinkage,
1103 false,
1104 false);
1105
1106 // Block which calls invoke
1107 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1108 "entry",
1109 ret);
1110 // Normal block for invoke
1111 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
1112 "normal",
1113 ret);
1114 // Unwind block for invoke
1115 llvm::BasicBlock *exceptionBlock =
1116 llvm::BasicBlock::Create(context, "exception", ret);
1117
1118 // Block which routes exception to correct catch handler block
1119 llvm::BasicBlock *exceptionRouteBlock =
1120 llvm::BasicBlock::Create(context, "exceptionRoute", ret);
1121
1122 // Foreign exception handler
1123 llvm::BasicBlock *externalExceptionBlock =
1124 llvm::BasicBlock::Create(context, "externalException", ret);
1125
1126 // Block which calls _Unwind_Resume
1127 llvm::BasicBlock *unwindResumeBlock =
1128 llvm::BasicBlock::Create(context, "unwindResume", ret);
1129
1130 // Clean up block which delete exception if needed
1131 llvm::BasicBlock *endBlock =
1132 llvm::BasicBlock::Create(context, "end", ret);
1133
1134 std::string nextName;
1135 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
Garrison Venn64cfcef2011-04-10 14:06:52 +00001136 llvm::Value *exceptionCaughtFlag = NULL;
1137 llvm::Value *exceptionStorage = NULL;
Chris Lattner626ab1c2011-04-08 18:02:51 +00001138
1139 // Finally block which will branch to unwindResumeBlock if
1140 // exception is not caught. Initializes/allocates stack locations.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001141 llvm::BasicBlock *finallyBlock = createFinallyBlock(context,
Chris Lattner626ab1c2011-04-08 18:02:51 +00001142 module,
1143 builder,
1144 *ret,
1145 nextName = "finally",
1146 ourId,
1147 *endBlock,
1148 *unwindResumeBlock,
1149 &exceptionCaughtFlag,
1150 &exceptionStorage);
1151
1152 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1153 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
1154
1155 // One catch block per type info to be caught
1156 catchBlocks[i] = createCatchBlock(context,
1157 module,
1158 builder,
1159 *ret,
1160 nextName,
1161 ourId,
1162 *finallyBlock,
1163 *exceptionCaughtFlag);
1164 }
1165
1166 // Entry Block
1167
1168 builder.SetInsertPoint(entryBlock);
1169
1170 std::vector<llvm::Value*> args;
1171 args.push_back(namedValues["exceptTypeToThrow"]);
1172 builder.CreateInvoke(&toInvoke,
1173 normalBlock,
1174 exceptionBlock,
1175 args.begin(),
1176 args.end());
1177
1178 // End Block
1179
1180 builder.SetInsertPoint(endBlock);
1181
1182 generateStringPrint(context,
1183 module,
1184 builder,
1185 "Gen: In end block: exiting in " + ourId + ".\n",
1186 USE_GLOBAL_STR_CONSTS);
1187 llvm::Function *deleteOurException =
1188 module.getFunction("deleteOurException");
1189
1190 // Note: function handles NULL exceptions
1191 builder.CreateCall(deleteOurException,
1192 builder.CreateLoad(exceptionStorage));
1193 builder.CreateRetVoid();
1194
1195 // Normal Block
1196
1197 builder.SetInsertPoint(normalBlock);
1198
1199 generateStringPrint(context,
1200 module,
1201 builder,
1202 "Gen: No exception in " + ourId + "!\n",
1203 USE_GLOBAL_STR_CONSTS);
1204
1205 // Finally block is always called
1206 builder.CreateBr(finallyBlock);
1207
1208 // Unwind Resume Block
1209
1210 builder.SetInsertPoint(unwindResumeBlock);
1211
1212 llvm::Function *resumeOurException =
1213 module.getFunction("_Unwind_Resume");
1214 builder.CreateCall(resumeOurException,
1215 builder.CreateLoad(exceptionStorage));
1216 builder.CreateUnreachable();
1217
1218 // Exception Block
1219
1220 builder.SetInsertPoint(exceptionBlock);
1221
1222 llvm::Function *ehException = module.getFunction("llvm.eh.exception");
1223
1224 // Retrieve thrown exception
Garrison Venn64cfcef2011-04-10 14:06:52 +00001225 llvm::Value *unwindException = builder.CreateCall(ehException);
Chris Lattner626ab1c2011-04-08 18:02:51 +00001226
1227 // Store exception and flag
1228 builder.CreateStore(unwindException, exceptionStorage);
1229 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag);
1230 llvm::Function *personality = module.getFunction("ourPersonality");
Garrison Venn64cfcef2011-04-10 14:06:52 +00001231 llvm::Value *functPtr =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001232 builder.CreatePointerCast(personality,
1233 builder.getInt8Ty()->getPointerTo());
1234
1235 args.clear();
1236 args.push_back(unwindException);
1237 args.push_back(functPtr);
1238
1239 // Note: Skipping index 0
1240 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1241 // Set up type infos to be caught
1242 args.push_back(module.getGlobalVariable(
1243 ourTypeInfoNames[exceptionTypesToCatch[i]]));
1244 }
1245
1246 args.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), 0));
1247
1248 llvm::Function *ehSelector = module.getFunction("llvm.eh.selector");
1249
1250 // Set up this exeption block as the landing pad which will handle
1251 // given type infos. See case Intrinsic::eh_selector in
1252 // SelectionDAGBuilder::visitIntrinsicCall(...) and AddCatchInfo(...)
1253 // implemented in FunctionLoweringInfo.cpp to see how the implementation
1254 // handles this call. This landing pad (this exception block), will be
1255 // called either because it nees to cleanup (call finally) or a type
1256 // info was found which matched the thrown exception.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001257 llvm::Value *retTypeInfoIndex = builder.CreateCall(ehSelector,
Chris Lattner626ab1c2011-04-08 18:02:51 +00001258 args.begin(),
1259 args.end());
1260
1261 // Retrieve exception_class member from thrown exception
1262 // (_Unwind_Exception instance). This member tells us whether or not
1263 // the exception is foreign.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001264 llvm::Value *unwindExceptionClass =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001265 builder.CreateLoad(builder.CreateStructGEP(
1266 builder.CreatePointerCast(unwindException,
1267 ourUnwindExceptionType->getPointerTo()),
1268 0));
1269
1270 // Branch to the externalExceptionBlock if the exception is foreign or
1271 // to a catch router if not. Either way the finally block will be run.
1272 builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass,
1273 llvm::ConstantInt::get(builder.getInt64Ty(),
1274 ourBaseExceptionClass)),
1275 exceptionRouteBlock,
1276 externalExceptionBlock);
1277
1278 // External Exception Block
1279
1280 builder.SetInsertPoint(externalExceptionBlock);
1281
1282 generateStringPrint(context,
1283 module,
1284 builder,
1285 "Gen: Foreign exception received.\n",
1286 USE_GLOBAL_STR_CONSTS);
1287
1288 // Branch to the finally block
1289 builder.CreateBr(finallyBlock);
1290
1291 // Exception Route Block
1292
1293 builder.SetInsertPoint(exceptionRouteBlock);
1294
1295 // Casts exception pointer (_Unwind_Exception instance) to parent
1296 // (OurException instance).
1297 //
1298 // Note: ourBaseFromUnwindOffset is usually negative
Garrison Venn64cfcef2011-04-10 14:06:52 +00001299 llvm::Value *typeInfoThrown =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001300 builder.CreatePointerCast(builder.CreateConstGEP1_64(unwindException,
1301 ourBaseFromUnwindOffset),
1302 ourExceptionType->getPointerTo());
1303
1304 // Retrieve thrown exception type info type
1305 //
1306 // Note: Index is not relative to pointer but instead to structure
1307 // unlike a true getelementptr (GEP) instruction
1308 typeInfoThrown = builder.CreateStructGEP(typeInfoThrown, 0);
1309
Garrison Venn64cfcef2011-04-10 14:06:52 +00001310 llvm::Value *typeInfoThrownType =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001311 builder.CreateStructGEP(typeInfoThrown, 0);
1312
1313 generateIntegerPrint(context,
1314 module,
1315 builder,
1316 *toPrint32Int,
1317 *(builder.CreateLoad(typeInfoThrownType)),
1318 "Gen: Exception type <%d> received (stack unwound) "
1319 " in " +
1320 ourId +
1321 ".\n",
1322 USE_GLOBAL_STR_CONSTS);
1323
1324 // Route to matched type info catch block or run cleanup finally block
Garrison Venn64cfcef2011-04-10 14:06:52 +00001325 llvm::SwitchInst *switchToCatchBlock =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001326 builder.CreateSwitch(retTypeInfoIndex,
1327 finallyBlock,
1328 numExceptionsToCatch);
1329
1330 unsigned nextTypeToCatch;
1331
1332 for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
1333 nextTypeToCatch = i - 1;
1334 switchToCatchBlock->addCase(llvm::ConstantInt::get(
1335 llvm::Type::getInt32Ty(context), i),
1336 catchBlocks[nextTypeToCatch]);
1337 }
1338
1339 llvm::verifyFunction(*ret);
1340 fpm.run(*ret);
1341
1342 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001343}
1344
1345
1346/// Generates function which throws either an exception matched to a runtime
1347/// determined type info type (argument to generated function), or if this
1348/// runtime value matches nativeThrowType, throws a foreign exception by
1349/// calling nativeThrowFunct.
1350/// @param module code for module instance
1351/// @param builder builder instance
1352/// @param fpm a function pass manager holding optional IR to IR
1353/// transformations
1354/// @param ourId id used to printing purposes
1355/// @param nativeThrowType a runtime argument of this value results in
1356/// nativeThrowFunct being called to generate/throw exception.
1357/// @param nativeThrowFunct function which will throw a foreign exception
1358/// if the above nativeThrowType matches generated function's arg.
1359/// @returns generated function
1360static
Garrison Venn64cfcef2011-04-10 14:06:52 +00001361llvm::Function *createThrowExceptionFunction(llvm::Module &module,
1362 llvm::IRBuilder<> &builder,
1363 llvm::FunctionPassManager &fpm,
Chris Lattner626ab1c2011-04-08 18:02:51 +00001364 std::string ourId,
1365 int32_t nativeThrowType,
Garrison Venn64cfcef2011-04-10 14:06:52 +00001366 llvm::Function &nativeThrowFunct) {
1367 llvm::LLVMContext &context = module.getContext();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001368 namedValues.clear();
1369 ArgTypes unwindArgTypes;
1370 unwindArgTypes.push_back(builder.getInt32Ty());
1371 ArgNames unwindArgNames;
1372 unwindArgNames.push_back("exceptTypeToThrow");
1373
1374 llvm::Function *ret = createFunction(module,
1375 builder.getVoidTy(),
1376 unwindArgTypes,
1377 unwindArgNames,
1378 ourId,
1379 llvm::Function::ExternalLinkage,
1380 false,
1381 false);
1382
1383 // Throws either one of our exception or a native C++ exception depending
1384 // on a runtime argument value containing a type info type.
1385 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1386 "entry",
1387 ret);
1388 // Throws a foreign exception
1389 llvm::BasicBlock *nativeThrowBlock =
1390 llvm::BasicBlock::Create(context,
1391 "nativeThrow",
1392 ret);
1393 // Throws one of our Exceptions
1394 llvm::BasicBlock *generatedThrowBlock =
1395 llvm::BasicBlock::Create(context,
1396 "generatedThrow",
1397 ret);
1398 // Retrieved runtime type info type to throw
Garrison Venn64cfcef2011-04-10 14:06:52 +00001399 llvm::Value *exceptionType = namedValues["exceptTypeToThrow"];
Chris Lattner626ab1c2011-04-08 18:02:51 +00001400
1401 // nativeThrowBlock block
1402
1403 builder.SetInsertPoint(nativeThrowBlock);
1404
1405 // Throws foreign exception
1406 builder.CreateCall(&nativeThrowFunct, exceptionType);
1407 builder.CreateUnreachable();
1408
1409 // entry block
1410
1411 builder.SetInsertPoint(entryBlock);
1412
1413 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1414 generateIntegerPrint(context,
1415 module,
1416 builder,
1417 *toPrint32Int,
1418 *exceptionType,
1419 "\nGen: About to throw exception type <%d> in " +
1420 ourId +
1421 ".\n",
1422 USE_GLOBAL_STR_CONSTS);
1423
1424 // Switches on runtime type info type value to determine whether or not
1425 // a foreign exception is thrown. Defaults to throwing one of our
1426 // generated exceptions.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001427 llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType,
Chris Lattner626ab1c2011-04-08 18:02:51 +00001428 generatedThrowBlock,
1429 1);
1430
1431 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
1432 nativeThrowType),
1433 nativeThrowBlock);
1434
1435 // generatedThrow block
1436
1437 builder.SetInsertPoint(generatedThrowBlock);
1438
1439 llvm::Function *createOurException =
1440 module.getFunction("createOurException");
1441 llvm::Function *raiseOurException =
1442 module.getFunction("_Unwind_RaiseException");
1443
1444 // Creates exception to throw with runtime type info type.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001445 llvm::Value *exception =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001446 builder.CreateCall(createOurException,
1447 namedValues["exceptTypeToThrow"]);
1448
1449 // Throw generated Exception
1450 builder.CreateCall(raiseOurException, exception);
1451 builder.CreateUnreachable();
1452
1453 llvm::verifyFunction(*ret);
1454 fpm.run(*ret);
1455
1456 return(ret);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001457}
1458
1459static void createStandardUtilityFunctions(unsigned numTypeInfos,
Garrison Venn64cfcef2011-04-10 14:06:52 +00001460 llvm::Module &module,
1461 llvm::IRBuilder<> &builder);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001462
1463/// Creates test code by generating and organizing these functions into the
1464/// test case. The test case consists of an outer function setup to invoke
1465/// an inner function within an environment having multiple catch and single
1466/// finally blocks. This inner function is also setup to invoke a throw
1467/// function within an evironment similar in nature to the outer function's
1468/// catch and finally blocks. Each of these two functions catch mutually
1469/// exclusive subsets (even or odd) of the type info types configured
1470/// for this this. All generated functions have a runtime argument which
1471/// holds a type info type to throw that each function takes and passes it
1472/// to the inner one if such a inner function exists. This type info type is
1473/// looked at by the generated throw function to see whether or not it should
1474/// throw a generated exception with the same type info type, or instead call
1475/// a supplied a function which in turn will throw a foreign exception.
1476/// @param module code for module instance
1477/// @param builder builder instance
1478/// @param fpm a function pass manager holding optional IR to IR
1479/// transformations
1480/// @param nativeThrowFunctName name of external function which will throw
1481/// a foreign exception
1482/// @returns outermost generated test function.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001483llvm::Function *createUnwindExceptionTest(llvm::Module &module,
1484 llvm::IRBuilder<> &builder,
1485 llvm::FunctionPassManager &fpm,
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001486 std::string nativeThrowFunctName) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001487 // Number of type infos to generate
1488 unsigned numTypeInfos = 6;
1489
1490 // Initialze intrisics and external functions to use along with exception
1491 // and type info globals.
1492 createStandardUtilityFunctions(numTypeInfos,
1493 module,
1494 builder);
1495 llvm::Function *nativeThrowFunct =
1496 module.getFunction(nativeThrowFunctName);
1497
1498 // Create exception throw function using the value ~0 to cause
1499 // foreign exceptions to be thrown.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001500 llvm::Function *throwFunct =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001501 createThrowExceptionFunction(module,
1502 builder,
1503 fpm,
1504 "throwFunct",
1505 ~0,
1506 *nativeThrowFunct);
1507 // Inner function will catch even type infos
1508 unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
1509 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
1510 sizeof(unsigned);
1511
1512 // Generate inner function.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001513 llvm::Function *innerCatchFunct =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001514 createCatchWrappedInvokeFunction(module,
1515 builder,
1516 fpm,
1517 *throwFunct,
1518 "innerCatchFunct",
1519 numExceptionTypesToCatch,
1520 innerExceptionTypesToCatch);
1521
1522 // Outer function will catch odd type infos
1523 unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
1524 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
1525 sizeof(unsigned);
1526
1527 // Generate outer function
Garrison Venn64cfcef2011-04-10 14:06:52 +00001528 llvm::Function *outerCatchFunct =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001529 createCatchWrappedInvokeFunction(module,
1530 builder,
1531 fpm,
1532 *innerCatchFunct,
1533 "outerCatchFunct",
1534 numExceptionTypesToCatch,
1535 outerExceptionTypesToCatch);
1536
1537 // Return outer function to run
1538 return(outerCatchFunct);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001539}
1540
1541
1542/// Represents our foreign exceptions
1543class OurCppRunException : public std::runtime_error {
1544public:
Chris Lattner626ab1c2011-04-08 18:02:51 +00001545 OurCppRunException(const std::string reason) :
1546 std::runtime_error(reason) {}
1547
Garrison Venn64cfcef2011-04-10 14:06:52 +00001548 OurCppRunException (const OurCppRunException &toCopy) :
Chris Lattner626ab1c2011-04-08 18:02:51 +00001549 std::runtime_error(toCopy) {}
1550
Garrison Venn64cfcef2011-04-10 14:06:52 +00001551 OurCppRunException &operator = (const OurCppRunException &toCopy) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001552 return(reinterpret_cast<OurCppRunException&>(
1553 std::runtime_error::operator=(toCopy)));
1554 }
1555
1556 ~OurCppRunException (void) throw () {}
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001557};
1558
1559
1560/// Throws foreign C++ exception.
1561/// @param ignoreIt unused parameter that allows function to match implied
1562/// generated function contract.
1563extern "C"
1564void throwCppException (int32_t ignoreIt) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001565 throw(OurCppRunException("thrown by throwCppException(...)"));
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001566}
1567
1568typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
1569
1570/// This is a test harness which runs test by executing generated
1571/// function with a type info type to throw. Harness wraps the excecution
1572/// of generated function in a C++ try catch clause.
1573/// @param engine execution engine to use for executing generated function.
1574/// This demo program expects this to be a JIT instance for demo
1575/// purposes.
1576/// @param function generated test function to run
1577/// @param typeToThrow type info type of generated exception to throw, or
1578/// indicator to cause foreign exception to be thrown.
1579static
Garrison Venn64cfcef2011-04-10 14:06:52 +00001580void runExceptionThrow(llvm::ExecutionEngine *engine,
1581 llvm::Function *function,
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001582 int32_t typeToThrow) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001583
1584 // Find test's function pointer
1585 OurExceptionThrowFunctType functPtr =
1586 reinterpret_cast<OurExceptionThrowFunctType>(
1587 reinterpret_cast<intptr_t>(engine->getPointerToFunction(function)));
1588
1589 try {
1590 // Run test
1591 (*functPtr)(typeToThrow);
1592 }
1593 catch (OurCppRunException exc) {
1594 // Catch foreign C++ exception
1595 fprintf(stderr,
1596 "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1597 "with reason: %s.\n",
1598 exc.what());
1599 }
1600 catch (...) {
1601 // Catch all exceptions including our generated ones. I'm not sure
1602 // why this latter functionality should work, as it seems that
1603 // our exceptions should be foreign to C++ (the _Unwind_Exception::
1604 // exception_class should be different from the one used by C++), and
1605 // therefore C++ should ignore the generated exceptions.
1606
1607 fprintf(stderr,
1608 "\nrunExceptionThrow(...):In C++ catch all.\n");
1609 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001610}
1611
1612//
1613// End test functions
1614//
1615
Chris Lattnercad3f772011-04-08 17:56:47 +00001616typedef llvm::ArrayRef<const llvm::Type*> TypeArray;
1617
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001618/// This initialization routine creates type info globals and
1619/// adds external function declarations to module.
1620/// @param numTypeInfos number of linear type info associated type info types
1621/// to create as GlobalVariable instances, starting with the value 1.
1622/// @param module code for module instance
1623/// @param builder builder instance
1624static void createStandardUtilityFunctions(unsigned numTypeInfos,
Garrison Venn64cfcef2011-04-10 14:06:52 +00001625 llvm::Module &module,
1626 llvm::IRBuilder<> &builder) {
Chris Lattnercad3f772011-04-08 17:56:47 +00001627
Garrison Venn64cfcef2011-04-10 14:06:52 +00001628 llvm::LLVMContext &context = module.getContext();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001629
1630 // Exception initializations
1631
1632 // Setup exception catch state
1633 ourExceptionNotThrownState =
1634 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
1635 ourExceptionThrownState =
1636 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
1637 ourExceptionCaughtState =
1638 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
1639
1640
1641
1642 // Create our type info type
1643 ourTypeInfoType = llvm::StructType::get(context,
1644 TypeArray(builder.getInt32Ty()));
1645
1646 // Create OurException type
1647 ourExceptionType = llvm::StructType::get(context,
1648 TypeArray(ourTypeInfoType));
1649
1650 // Create portion of _Unwind_Exception type
1651 //
1652 // Note: Declaring only a portion of the _Unwind_Exception struct.
1653 // Does this cause problems?
1654 ourUnwindExceptionType =
1655 llvm::StructType::get(context, TypeArray(builder.getInt64Ty()));
1656 struct OurBaseException_t dummyException;
1657
1658 // Calculate offset of OurException::unwindException member.
1659 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
1660 ((uintptr_t) &(dummyException.unwindException));
1661
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001662#ifdef DEBUG
Chris Lattner626ab1c2011-04-08 18:02:51 +00001663 fprintf(stderr,
1664 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1665 "= %lld, sizeof(struct OurBaseException_t) - "
1666 "sizeof(struct _Unwind_Exception) = %lu.\n",
1667 ourBaseFromUnwindOffset,
1668 sizeof(struct OurBaseException_t) -
1669 sizeof(struct _Unwind_Exception));
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001670#endif
Chris Lattner626ab1c2011-04-08 18:02:51 +00001671
1672 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
1673
1674 // Create our _Unwind_Exception::exception_class value
1675 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
1676
1677 // Type infos
1678
1679 std::string baseStr = "typeInfo", typeInfoName;
1680 std::ostringstream typeInfoNameBuilder;
1681 std::vector<llvm::Constant*> structVals;
1682
1683 llvm::Constant *nextStruct;
Garrison Venn64cfcef2011-04-10 14:06:52 +00001684 llvm::GlobalVariable *nextGlobal = NULL;
Chris Lattner626ab1c2011-04-08 18:02:51 +00001685
1686 // Generate each type info
1687 //
1688 // Note: First type info is not used.
1689 for (unsigned i = 0; i <= numTypeInfos; ++i) {
1690 structVals.clear();
1691 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
1692 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001693
Chris Lattner626ab1c2011-04-08 18:02:51 +00001694 typeInfoNameBuilder.str("");
1695 typeInfoNameBuilder << baseStr << i;
1696 typeInfoName = typeInfoNameBuilder.str();
1697
1698 // Note: Does not seem to work without allocation
1699 nextGlobal =
1700 new llvm::GlobalVariable(module,
1701 ourTypeInfoType,
1702 true,
1703 llvm::GlobalValue::ExternalLinkage,
1704 nextStruct,
1705 typeInfoName);
1706
1707 ourTypeInfoNames.push_back(typeInfoName);
1708 ourTypeInfoNamesIndex[i] = typeInfoName;
1709 }
1710
1711 ArgNames argNames;
1712 ArgTypes argTypes;
Garrison Venn64cfcef2011-04-10 14:06:52 +00001713 llvm::Function *funct = NULL;
Chris Lattner626ab1c2011-04-08 18:02:51 +00001714
1715 // print32Int
1716
Garrison Venn64cfcef2011-04-10 14:06:52 +00001717 const llvm::Type *retType = builder.getVoidTy();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001718
1719 argTypes.clear();
1720 argTypes.push_back(builder.getInt32Ty());
1721 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1722
1723 argNames.clear();
1724
1725 createFunction(module,
1726 retType,
1727 argTypes,
1728 argNames,
1729 "print32Int",
1730 llvm::Function::ExternalLinkage,
1731 true,
1732 false);
1733
1734 // print64Int
1735
1736 retType = builder.getVoidTy();
1737
1738 argTypes.clear();
1739 argTypes.push_back(builder.getInt64Ty());
1740 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1741
1742 argNames.clear();
1743
1744 createFunction(module,
1745 retType,
1746 argTypes,
1747 argNames,
1748 "print64Int",
1749 llvm::Function::ExternalLinkage,
1750 true,
1751 false);
1752
1753 // printStr
1754
1755 retType = builder.getVoidTy();
1756
1757 argTypes.clear();
1758 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1759
1760 argNames.clear();
1761
1762 createFunction(module,
1763 retType,
1764 argTypes,
1765 argNames,
1766 "printStr",
1767 llvm::Function::ExternalLinkage,
1768 true,
1769 false);
1770
1771 // throwCppException
1772
1773 retType = builder.getVoidTy();
1774
1775 argTypes.clear();
1776 argTypes.push_back(builder.getInt32Ty());
1777
1778 argNames.clear();
1779
1780 createFunction(module,
1781 retType,
1782 argTypes,
1783 argNames,
1784 "throwCppException",
1785 llvm::Function::ExternalLinkage,
1786 true,
1787 false);
1788
1789 // deleteOurException
1790
1791 retType = builder.getVoidTy();
1792
1793 argTypes.clear();
1794 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1795
1796 argNames.clear();
1797
1798 createFunction(module,
1799 retType,
1800 argTypes,
1801 argNames,
1802 "deleteOurException",
1803 llvm::Function::ExternalLinkage,
1804 true,
1805 false);
1806
1807 // createOurException
1808
1809 retType = builder.getInt8Ty()->getPointerTo();
1810
1811 argTypes.clear();
1812 argTypes.push_back(builder.getInt32Ty());
1813
1814 argNames.clear();
1815
1816 createFunction(module,
1817 retType,
1818 argTypes,
1819 argNames,
1820 "createOurException",
1821 llvm::Function::ExternalLinkage,
1822 true,
1823 false);
1824
1825 // _Unwind_RaiseException
1826
1827 retType = builder.getInt32Ty();
1828
1829 argTypes.clear();
1830 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1831
1832 argNames.clear();
1833
1834 funct = createFunction(module,
1835 retType,
1836 argTypes,
1837 argNames,
1838 "_Unwind_RaiseException",
1839 llvm::Function::ExternalLinkage,
1840 true,
1841 false);
1842
1843 funct->addFnAttr(llvm::Attribute::NoReturn);
1844
1845 // _Unwind_Resume
1846
1847 retType = builder.getInt32Ty();
1848
1849 argTypes.clear();
1850 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1851
1852 argNames.clear();
1853
1854 funct = createFunction(module,
1855 retType,
1856 argTypes,
1857 argNames,
1858 "_Unwind_Resume",
1859 llvm::Function::ExternalLinkage,
1860 true,
1861 false);
1862
1863 funct->addFnAttr(llvm::Attribute::NoReturn);
1864
1865 // ourPersonality
1866
1867 retType = builder.getInt32Ty();
1868
1869 argTypes.clear();
1870 argTypes.push_back(builder.getInt32Ty());
1871 argTypes.push_back(builder.getInt32Ty());
1872 argTypes.push_back(builder.getInt64Ty());
1873 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1874 argTypes.push_back(builder.getInt8Ty()->getPointerTo());
1875
1876 argNames.clear();
1877
1878 createFunction(module,
1879 retType,
1880 argTypes,
1881 argNames,
1882 "ourPersonality",
1883 llvm::Function::ExternalLinkage,
1884 true,
1885 false);
1886
1887 // llvm.eh.selector intrinsic
1888
1889 getDeclaration(&module, llvm::Intrinsic::eh_selector);
1890
1891 // llvm.eh.exception intrinsic
1892
1893 getDeclaration(&module, llvm::Intrinsic::eh_exception);
1894
1895 // llvm.eh.typeid.for intrinsic
1896
1897 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for);
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001898}
1899
1900
Chris Lattner626ab1c2011-04-08 18:02:51 +00001901//===----------------------------------------------------------------------===//
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001902// Main test driver code.
Chris Lattner626ab1c2011-04-08 18:02:51 +00001903//===----------------------------------------------------------------------===//
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001904
1905/// Demo main routine which takes the type info types to throw. A test will
1906/// be run for each given type info type. While type info types with the value
1907/// of -1 will trigger a foreign C++ exception to be thrown; type info types
1908/// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1909/// will result in exceptions which pass through to the test harness. All other
1910/// type info types are not supported and could cause a crash.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001911int main(int argc, char *argv[]) {
Chris Lattner626ab1c2011-04-08 18:02:51 +00001912 if (argc == 1) {
1913 fprintf(stderr,
1914 "\nUsage: ExceptionDemo <exception type to throw> "
1915 "[<type 2>...<type n>].\n"
1916 " Each type must have the value of 1 - 6 for "
1917 "generated exceptions to be caught;\n"
1918 " the value -1 for foreign C++ exceptions to be "
1919 "generated and thrown;\n"
1920 " or the values > 6 for exceptions to be ignored.\n"
1921 "\nTry: ExceptionDemo 2 3 7 -1\n"
1922 " for a full test.\n\n");
1923 return(0);
1924 }
Garrison Venna2c2f1a2010-02-09 23:22:43 +00001925
Chris Lattner626ab1c2011-04-08 18:02:51 +00001926 // If not set, exception handling will not be turned on
1927 llvm::JITExceptionHandling = true;
1928
1929 llvm::InitializeNativeTarget();
Garrison Venn64cfcef2011-04-10 14:06:52 +00001930 llvm::LLVMContext &context = llvm::getGlobalContext();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001931 llvm::IRBuilder<> theBuilder(context);
1932
1933 // Make the module, which holds all the code.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001934 llvm::Module *module = new llvm::Module("my cool jit", context);
Chris Lattner626ab1c2011-04-08 18:02:51 +00001935
1936 // Build engine with JIT
1937 llvm::EngineBuilder factory(module);
1938 factory.setEngineKind(llvm::EngineKind::JIT);
1939 factory.setAllocateGVsWithCode(false);
Garrison Venn64cfcef2011-04-10 14:06:52 +00001940 llvm::ExecutionEngine *executionEngine = factory.create();
Chris Lattner626ab1c2011-04-08 18:02:51 +00001941
1942 {
1943 llvm::FunctionPassManager fpm(module);
1944
1945 // Set up the optimizer pipeline.
1946 // Start with registering info about how the
1947 // target lays out data structures.
1948 fpm.add(new llvm::TargetData(*executionEngine->getTargetData()));
1949
1950 // Optimizations turned on
1951#ifdef ADD_OPT_PASSES
1952
1953 // Basic AliasAnslysis support for GVN.
1954 fpm.add(llvm::createBasicAliasAnalysisPass());
1955
1956 // Promote allocas to registers.
1957 fpm.add(llvm::createPromoteMemoryToRegisterPass());
1958
1959 // Do simple "peephole" optimizations and bit-twiddling optzns.
1960 fpm.add(llvm::createInstructionCombiningPass());
1961
1962 // Reassociate expressions.
1963 fpm.add(llvm::createReassociatePass());
1964
1965 // Eliminate Common SubExpressions.
1966 fpm.add(llvm::createGVNPass());
1967
1968 // Simplify the control flow graph (deleting unreachable
1969 // blocks, etc).
1970 fpm.add(llvm::createCFGSimplificationPass());
1971#endif // ADD_OPT_PASSES
1972
1973 fpm.doInitialization();
1974
1975 // Generate test code using function throwCppException(...) as
1976 // the function which throws foreign exceptions.
Garrison Venn64cfcef2011-04-10 14:06:52 +00001977 llvm::Function *toRun =
Chris Lattner626ab1c2011-04-08 18:02:51 +00001978 createUnwindExceptionTest(*module,
1979 theBuilder,
1980 fpm,
1981 "throwCppException");
1982
1983 fprintf(stderr, "\nBegin module dump:\n\n");
1984
1985 module->dump();
1986
1987 fprintf(stderr, "\nEnd module dump:\n");
1988
1989 fprintf(stderr, "\n\nBegin Test:\n");
1990
1991 for (int i = 1; i < argc; ++i) {
1992 // Run test for each argument whose value is the exception
1993 // type to throw.
1994 runExceptionThrow(executionEngine,
1995 toRun,
1996 (unsigned) strtoul(argv[i], NULL, 10));
1997 }
1998
1999 fprintf(stderr, "\nEnd Test:\n\n");
2000 }
2001
2002 delete executionEngine;
2003
2004 return 0;
Garrison Venna2c2f1a2010-02-09 23:22:43 +00002005}
2006