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