ExceptionDemo.cpp 69 KB

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