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