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