ExceptionDemo.cpp 70 KB

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