WebAssemblyLowerEmscriptenEHSjLj.cpp 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. //=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
  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. /// \file
  10. /// This file lowers exception-related instructions and setjmp/longjmp function
  11. /// calls to use Emscripten's library functions. The pass uses JavaScript's try
  12. /// and catch mechanism in case of Emscripten EH/SjLj and Wasm EH intrinsics in
  13. /// case of Emscripten SjLJ.
  14. ///
  15. /// * Emscripten exception handling
  16. /// This pass lowers invokes and landingpads into library functions in JS glue
  17. /// code. Invokes are lowered into function wrappers called invoke wrappers that
  18. /// exist in JS side, which wraps the original function call with JS try-catch.
  19. /// If an exception occurred, cxa_throw() function in JS side sets some
  20. /// variables (see below) so we can check whether an exception occurred from
  21. /// wasm code and handle it appropriately.
  22. ///
  23. /// * Emscripten setjmp-longjmp handling
  24. /// This pass lowers setjmp to a reasonably-performant approach for emscripten.
  25. /// The idea is that each block with a setjmp is broken up into two parts: the
  26. /// part containing setjmp and the part right after the setjmp. The latter part
  27. /// is either reached from the setjmp, or later from a longjmp. To handle the
  28. /// longjmp, all calls that might longjmp are also called using invoke wrappers
  29. /// and thus JS / try-catch. JS longjmp() function also sets some variables so
  30. /// we can check / whether a longjmp occurred from wasm code. Each block with a
  31. /// function call that might longjmp is also split up after the longjmp call.
  32. /// After the longjmp call, we check whether a longjmp occurred, and if it did,
  33. /// which setjmp it corresponds to, and jump to the right post-setjmp block.
  34. /// We assume setjmp-longjmp handling always run after EH handling, which means
  35. /// we don't expect any exception-related instructions when SjLj runs.
  36. /// FIXME Currently this scheme does not support indirect call of setjmp,
  37. /// because of the limitation of the scheme itself. fastcomp does not support it
  38. /// either.
  39. ///
  40. /// In detail, this pass does following things:
  41. ///
  42. /// 1) Assumes the existence of global variables: __THREW__, __threwValue
  43. /// __THREW__ and __threwValue are defined in compiler-rt in Emscripten.
  44. /// These variables are used for both exceptions and setjmp/longjmps.
  45. /// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
  46. /// means nothing occurred, 1 means an exception occurred, and other numbers
  47. /// mean a longjmp occurred. In the case of longjmp, __THREW__ variable
  48. /// indicates the corresponding setjmp buffer the longjmp corresponds to.
  49. /// __threwValue is 0 for exceptions, and the argument to longjmp in case of
  50. /// longjmp.
  51. ///
  52. /// * Emscripten exception handling
  53. ///
  54. /// 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
  55. /// at link time. setThrew exists in Emscripten's compiler-rt:
  56. ///
  57. /// void setThrew(uintptr_t threw, int value) {
  58. /// if (__THREW__ == 0) {
  59. /// __THREW__ = threw;
  60. /// __threwValue = value;
  61. /// }
  62. /// }
  63. //
  64. /// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
  65. /// In exception handling, getTempRet0 indicates the type of an exception
  66. /// caught, and in setjmp/longjmp, it means the second argument to longjmp
  67. /// function.
  68. ///
  69. /// 3) Lower
  70. /// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
  71. /// into
  72. /// __THREW__ = 0;
  73. /// call @__invoke_SIG(func, arg1, arg2)
  74. /// %__THREW__.val = __THREW__;
  75. /// __THREW__ = 0;
  76. /// if (%__THREW__.val == 1)
  77. /// goto %lpad
  78. /// else
  79. /// goto %invoke.cont
  80. /// SIG is a mangled string generated based on the LLVM IR-level function
  81. /// signature. After LLVM IR types are lowered to the target wasm types,
  82. /// the names for these wrappers will change based on wasm types as well,
  83. /// as in invoke_vi (function takes an int and returns void). The bodies of
  84. /// these wrappers will be generated in JS glue code, and inside those
  85. /// wrappers we use JS try-catch to generate actual exception effects. It
  86. /// also calls the original callee function. An example wrapper in JS code
  87. /// would look like this:
  88. /// function invoke_vi(index,a1) {
  89. /// try {
  90. /// Module["dynCall_vi"](index,a1); // This calls original callee
  91. /// } catch(e) {
  92. /// if (typeof e !== 'number' && e !== 'longjmp') throw e;
  93. /// _setThrew(1, 0); // setThrew is called here
  94. /// }
  95. /// }
  96. /// If an exception is thrown, __THREW__ will be set to true in a wrapper,
  97. /// so we can jump to the right BB based on this value.
  98. ///
  99. /// 4) Lower
  100. /// %val = landingpad catch c1 catch c2 catch c3 ...
  101. /// ... use %val ...
  102. /// into
  103. /// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
  104. /// %val = {%fmc, getTempRet0()}
  105. /// ... use %val ...
  106. /// Here N is a number calculated based on the number of clauses.
  107. /// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
  108. ///
  109. /// 5) Lower
  110. /// resume {%a, %b}
  111. /// into
  112. /// call @__resumeException(%a)
  113. /// where __resumeException() is a function in JS glue code.
  114. ///
  115. /// 6) Lower
  116. /// call @llvm.eh.typeid.for(type) (intrinsic)
  117. /// into
  118. /// call @llvm_eh_typeid_for(type)
  119. /// llvm_eh_typeid_for function will be generated in JS glue code.
  120. ///
  121. /// * Emscripten setjmp / longjmp handling
  122. ///
  123. /// If there are calls to longjmp()
  124. ///
  125. /// 1) Lower
  126. /// longjmp(env, val)
  127. /// into
  128. /// emscripten_longjmp(env, val)
  129. ///
  130. /// If there are calls to setjmp()
  131. ///
  132. /// 2) In the function entry that calls setjmp, initialize setjmpTable and
  133. /// sejmpTableSize as follows:
  134. /// setjmpTableSize = 4;
  135. /// setjmpTable = (int *) malloc(40);
  136. /// setjmpTable[0] = 0;
  137. /// setjmpTable and setjmpTableSize are used to call saveSetjmp() function in
  138. /// Emscripten compiler-rt.
  139. ///
  140. /// 3) Lower
  141. /// setjmp(env)
  142. /// into
  143. /// setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize);
  144. /// setjmpTableSize = getTempRet0();
  145. /// For each dynamic setjmp call, setjmpTable stores its ID (a number which
  146. /// is incrementally assigned from 0) and its label (a unique number that
  147. /// represents each callsite of setjmp). When we need more entries in
  148. /// setjmpTable, it is reallocated in saveSetjmp() in Emscripten's
  149. /// compiler-rt and it will return the new table address, and assign the new
  150. /// table size in setTempRet0(). saveSetjmp also stores the setjmp's ID into
  151. /// the buffer 'env'. A BB with setjmp is split into two after setjmp call in
  152. /// order to make the post-setjmp BB the possible destination of longjmp BB.
  153. ///
  154. /// 4) Lower every call that might longjmp into
  155. /// __THREW__ = 0;
  156. /// call @__invoke_SIG(func, arg1, arg2)
  157. /// %__THREW__.val = __THREW__;
  158. /// __THREW__ = 0;
  159. /// %__threwValue.val = __threwValue;
  160. /// if (%__THREW__.val != 0 & %__threwValue.val != 0) {
  161. /// %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
  162. /// setjmpTableSize);
  163. /// if (%label == 0)
  164. /// emscripten_longjmp(%__THREW__.val, %__threwValue.val);
  165. /// setTempRet0(%__threwValue.val);
  166. /// } else {
  167. /// %label = -1;
  168. /// }
  169. /// longjmp_result = getTempRet0();
  170. /// switch %label {
  171. /// label 1: goto post-setjmp BB 1
  172. /// label 2: goto post-setjmp BB 2
  173. /// ...
  174. /// default: goto splitted next BB
  175. /// }
  176. /// testSetjmp examines setjmpTable to see if there is a matching setjmp
  177. /// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
  178. /// will be the address of matching jmp_buf buffer and __threwValue be the
  179. /// second argument to longjmp. mem[%__THREW__.val] is a setjmp ID that is
  180. /// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
  181. /// each setjmp callsite. Label 0 means this longjmp buffer does not
  182. /// correspond to one of the setjmp callsites in this function, so in this
  183. /// case we just chain the longjmp to the caller. Label -1 means no longjmp
  184. /// occurred. Otherwise we jump to the right post-setjmp BB based on the
  185. /// label.
  186. ///
  187. /// * Wasm setjmp / longjmp handling
  188. /// This mode still uses some Emscripten library functions but not JavaScript's
  189. /// try-catch mechanism. It instead uses Wasm exception handling intrinsics,
  190. /// which will be lowered to exception handling instructions.
  191. ///
  192. /// If there are calls to longjmp()
  193. ///
  194. /// 1) Lower
  195. /// longjmp(env, val)
  196. /// into
  197. /// __wasm_longjmp(env, val)
  198. ///
  199. /// If there are calls to setjmp()
  200. ///
  201. /// 2) and 3): The same as 2) and 3) in Emscripten SjLj.
  202. /// (setjmpTable/setjmpTableSize initialization + setjmp callsite
  203. /// transformation)
  204. ///
  205. /// 4) Create a catchpad with a wasm.catch() intrinsic, which returns the value
  206. /// thrown by __wasm_longjmp function. In Emscripten library, we have this
  207. /// struct:
  208. ///
  209. /// struct __WasmLongjmpArgs {
  210. /// void *env;
  211. /// int val;
  212. /// };
  213. /// struct __WasmLongjmpArgs __wasm_longjmp_args;
  214. ///
  215. /// The thrown value here is a pointer to __wasm_longjmp_args struct object. We
  216. /// use this struct to transfer two values by throwing a single value. Wasm
  217. /// throw and catch instructions are capable of throwing and catching multiple
  218. /// values, but it also requires multivalue support that is currently not very
  219. /// reliable.
  220. /// TODO Switch to throwing and catching two values without using the struct
  221. ///
  222. /// All longjmpable function calls will be converted to an invoke that will
  223. /// unwind to this catchpad in case a longjmp occurs. Within the catchpad, we
  224. /// test the thrown values using testSetjmp function as we do for Emscripten
  225. /// SjLj. The main difference is, in Emscripten SjLj, we need to transform every
  226. /// longjmpable callsite into a sequence of code including testSetjmp() call; in
  227. /// Wasm SjLj we do the testing in only one place, in this catchpad.
  228. ///
  229. /// After testing calling testSetjmp(), if the longjmp does not correspond to
  230. /// one of the setjmps within the current function, it rethrows the longjmp
  231. /// by calling __wasm_longjmp(). If it corresponds to one of setjmps in the
  232. /// function, we jump to the beginning of the function, which contains a switch
  233. /// to each post-setjmp BB. Again, in Emscripten SjLj, this switch is added for
  234. /// every longjmpable callsite; in Wasm SjLj we do this only once at the top of
  235. /// the function. (after setjmpTable/setjmpTableSize initialization)
  236. ///
  237. /// The below is the pseudocode for what we have described
  238. ///
  239. /// entry:
  240. /// Initialize setjmpTable and setjmpTableSize
  241. ///
  242. /// setjmp.dispatch:
  243. /// switch %label {
  244. /// label 1: goto post-setjmp BB 1
  245. /// label 2: goto post-setjmp BB 2
  246. /// ...
  247. /// default: goto splitted next BB
  248. /// }
  249. /// ...
  250. ///
  251. /// bb:
  252. /// invoke void @foo() ;; foo is a longjmpable function
  253. /// to label %next unwind label %catch.dispatch.longjmp
  254. /// ...
  255. ///
  256. /// catch.dispatch.longjmp:
  257. /// %0 = catchswitch within none [label %catch.longjmp] unwind to caller
  258. ///
  259. /// catch.longjmp:
  260. /// %longjmp.args = wasm.catch() ;; struct __WasmLongjmpArgs
  261. /// %env = load 'env' field from __WasmLongjmpArgs
  262. /// %val = load 'val' field from __WasmLongjmpArgs
  263. /// %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize);
  264. /// if (%label == 0)
  265. /// __wasm_longjmp(%env, %val)
  266. /// catchret to %setjmp.dispatch
  267. ///
  268. ///===----------------------------------------------------------------------===//
  269. #include "Utils/WebAssemblyUtilities.h"
  270. #include "WebAssembly.h"
  271. #include "WebAssemblyTargetMachine.h"
  272. #include "llvm/ADT/StringExtras.h"
  273. #include "llvm/CodeGen/TargetPassConfig.h"
  274. #include "llvm/CodeGen/WasmEHFuncInfo.h"
  275. #include "llvm/IR/DebugInfoMetadata.h"
  276. #include "llvm/IR/Dominators.h"
  277. #include "llvm/IR/IRBuilder.h"
  278. #include "llvm/IR/IntrinsicsWebAssembly.h"
  279. #include "llvm/Support/CommandLine.h"
  280. #include "llvm/Transforms/Utils/BasicBlockUtils.h"
  281. #include "llvm/Transforms/Utils/Local.h"
  282. #include "llvm/Transforms/Utils/SSAUpdater.h"
  283. #include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
  284. using namespace llvm;
  285. #define DEBUG_TYPE "wasm-lower-em-ehsjlj"
  286. static cl::list<std::string>
  287. EHAllowlist("emscripten-cxx-exceptions-allowed",
  288. cl::desc("The list of function names in which Emscripten-style "
  289. "exception handling is enabled (see emscripten "
  290. "EMSCRIPTEN_CATCHING_ALLOWED options)"),
  291. cl::CommaSeparated);
  292. namespace {
  293. class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
  294. bool EnableEmEH; // Enable Emscripten exception handling
  295. bool EnableEmSjLj; // Enable Emscripten setjmp/longjmp handling
  296. bool EnableWasmSjLj; // Enable Wasm setjmp/longjmp handling
  297. bool DoSjLj; // Whether we actually perform setjmp/longjmp handling
  298. GlobalVariable *ThrewGV = nullptr; // __THREW__ (Emscripten)
  299. GlobalVariable *ThrewValueGV = nullptr; // __threwValue (Emscripten)
  300. Function *GetTempRet0F = nullptr; // getTempRet0() (Emscripten)
  301. Function *SetTempRet0F = nullptr; // setTempRet0() (Emscripten)
  302. Function *ResumeF = nullptr; // __resumeException() (Emscripten)
  303. Function *EHTypeIDF = nullptr; // llvm.eh.typeid.for() (intrinsic)
  304. Function *EmLongjmpF = nullptr; // emscripten_longjmp() (Emscripten)
  305. Function *SaveSetjmpF = nullptr; // saveSetjmp() (Emscripten)
  306. Function *TestSetjmpF = nullptr; // testSetjmp() (Emscripten)
  307. Function *WasmLongjmpF = nullptr; // __wasm_longjmp() (Emscripten)
  308. Function *CatchF = nullptr; // wasm.catch() (intrinsic)
  309. // type of 'struct __WasmLongjmpArgs' defined in emscripten
  310. Type *LongjmpArgsTy = nullptr;
  311. // __cxa_find_matching_catch_N functions.
  312. // Indexed by the number of clauses in an original landingpad instruction.
  313. DenseMap<int, Function *> FindMatchingCatches;
  314. // Map of <function signature string, invoke_ wrappers>
  315. StringMap<Function *> InvokeWrappers;
  316. // Set of allowed function names for exception handling
  317. std::set<std::string> EHAllowlistSet;
  318. // Functions that contains calls to setjmp
  319. SmallPtrSet<Function *, 8> SetjmpUsers;
  320. StringRef getPassName() const override {
  321. return "WebAssembly Lower Emscripten Exceptions";
  322. }
  323. using InstVector = SmallVectorImpl<Instruction *>;
  324. bool runEHOnFunction(Function &F);
  325. bool runSjLjOnFunction(Function &F);
  326. void handleLongjmpableCallsForEmscriptenSjLj(
  327. Function &F, InstVector &SetjmpTableInsts,
  328. InstVector &SetjmpTableSizeInsts,
  329. SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
  330. void
  331. handleLongjmpableCallsForWasmSjLj(Function &F, InstVector &SetjmpTableInsts,
  332. InstVector &SetjmpTableSizeInsts,
  333. SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
  334. Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
  335. Value *wrapInvoke(CallBase *CI);
  336. void wrapTestSetjmp(BasicBlock *BB, DebugLoc DL, Value *Threw,
  337. Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
  338. Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
  339. PHINode *&CallEmLongjmpBBThrewPHI,
  340. PHINode *&CallEmLongjmpBBThrewValuePHI,
  341. BasicBlock *&EndBB);
  342. Function *getInvokeWrapper(CallBase *CI);
  343. bool areAllExceptionsAllowed() const { return EHAllowlistSet.empty(); }
  344. bool supportsException(const Function *F) const {
  345. return EnableEmEH && (areAllExceptionsAllowed() ||
  346. EHAllowlistSet.count(std::string(F->getName())));
  347. }
  348. void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
  349. void rebuildSSA(Function &F);
  350. public:
  351. static char ID;
  352. WebAssemblyLowerEmscriptenEHSjLj()
  353. : ModulePass(ID), EnableEmEH(WebAssembly::WasmEnableEmEH),
  354. EnableEmSjLj(WebAssembly::WasmEnableEmSjLj),
  355. EnableWasmSjLj(WebAssembly::WasmEnableSjLj) {
  356. assert(!(EnableEmSjLj && EnableWasmSjLj) &&
  357. "Two SjLj modes cannot be turned on at the same time");
  358. assert(!(EnableEmEH && EnableWasmSjLj) &&
  359. "Wasm SjLj should be only used with Wasm EH");
  360. EHAllowlistSet.insert(EHAllowlist.begin(), EHAllowlist.end());
  361. }
  362. bool runOnModule(Module &M) override;
  363. void getAnalysisUsage(AnalysisUsage &AU) const override {
  364. AU.addRequired<DominatorTreeWrapperPass>();
  365. }
  366. };
  367. } // End anonymous namespace
  368. char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
  369. INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
  370. "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
  371. false, false)
  372. ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj() {
  373. return new WebAssemblyLowerEmscriptenEHSjLj();
  374. }
  375. static bool canThrow(const Value *V) {
  376. if (const auto *F = dyn_cast<const Function>(V)) {
  377. // Intrinsics cannot throw
  378. if (F->isIntrinsic())
  379. return false;
  380. StringRef Name = F->getName();
  381. // leave setjmp and longjmp (mostly) alone, we process them properly later
  382. if (Name == "setjmp" || Name == "longjmp" || Name == "emscripten_longjmp")
  383. return false;
  384. return !F->doesNotThrow();
  385. }
  386. // not a function, so an indirect call - can throw, we can't tell
  387. return true;
  388. }
  389. // Get a thread-local global variable with the given name. If it doesn't exist
  390. // declare it, which will generate an import and assume that it will exist at
  391. // link time.
  392. static GlobalVariable *getGlobalVariable(Module &M, Type *Ty,
  393. WebAssemblyTargetMachine &TM,
  394. const char *Name) {
  395. auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, Ty));
  396. if (!GV)
  397. report_fatal_error(Twine("unable to create global: ") + Name);
  398. // Variables created by this function are thread local. If the target does not
  399. // support TLS, we depend on CoalesceFeaturesAndStripAtomics to downgrade it
  400. // to non-thread-local ones, in which case we don't allow this object to be
  401. // linked with other objects using shared memory.
  402. GV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel);
  403. return GV;
  404. }
  405. // Simple function name mangler.
  406. // This function simply takes LLVM's string representation of parameter types
  407. // and concatenate them with '_'. There are non-alphanumeric characters but llc
  408. // is ok with it, and we need to postprocess these names after the lowering
  409. // phase anyway.
  410. static std::string getSignature(FunctionType *FTy) {
  411. std::string Sig;
  412. raw_string_ostream OS(Sig);
  413. OS << *FTy->getReturnType();
  414. for (Type *ParamTy : FTy->params())
  415. OS << "_" << *ParamTy;
  416. if (FTy->isVarArg())
  417. OS << "_...";
  418. Sig = OS.str();
  419. erase_if(Sig, isSpace);
  420. // When s2wasm parses .s file, a comma means the end of an argument. So a
  421. // mangled function name can contain any character but a comma.
  422. std::replace(Sig.begin(), Sig.end(), ',', '.');
  423. return Sig;
  424. }
  425. static Function *getEmscriptenFunction(FunctionType *Ty, const Twine &Name,
  426. Module *M) {
  427. Function* F = Function::Create(Ty, GlobalValue::ExternalLinkage, Name, M);
  428. // Tell the linker that this function is expected to be imported from the
  429. // 'env' module.
  430. if (!F->hasFnAttribute("wasm-import-module")) {
  431. llvm::AttrBuilder B(M->getContext());
  432. B.addAttribute("wasm-import-module", "env");
  433. F->addFnAttrs(B);
  434. }
  435. if (!F->hasFnAttribute("wasm-import-name")) {
  436. llvm::AttrBuilder B(M->getContext());
  437. B.addAttribute("wasm-import-name", F->getName());
  438. F->addFnAttrs(B);
  439. }
  440. return F;
  441. }
  442. // Returns an integer type for the target architecture's address space.
  443. // i32 for wasm32 and i64 for wasm64.
  444. static Type *getAddrIntType(Module *M) {
  445. IRBuilder<> IRB(M->getContext());
  446. return IRB.getIntNTy(M->getDataLayout().getPointerSizeInBits());
  447. }
  448. // Returns an integer pointer type for the target architecture's address space.
  449. // i32* for wasm32 and i64* for wasm64.
  450. static Type *getAddrPtrType(Module *M) {
  451. return Type::getIntNPtrTy(M->getContext(),
  452. M->getDataLayout().getPointerSizeInBits());
  453. }
  454. // Returns an integer whose type is the integer type for the target's address
  455. // space. Returns (i32 C) for wasm32 and (i64 C) for wasm64, when C is the
  456. // integer.
  457. static Value *getAddrSizeInt(Module *M, uint64_t C) {
  458. IRBuilder<> IRB(M->getContext());
  459. return IRB.getIntN(M->getDataLayout().getPointerSizeInBits(), C);
  460. }
  461. // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
  462. // This is because a landingpad instruction contains two more arguments, a
  463. // personality function and a cleanup bit, and __cxa_find_matching_catch_N
  464. // functions are named after the number of arguments in the original landingpad
  465. // instruction.
  466. Function *
  467. WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
  468. unsigned NumClauses) {
  469. if (FindMatchingCatches.count(NumClauses))
  470. return FindMatchingCatches[NumClauses];
  471. PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
  472. SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
  473. FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
  474. Function *F = getEmscriptenFunction(
  475. FTy, "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
  476. FindMatchingCatches[NumClauses] = F;
  477. return F;
  478. }
  479. // Generate invoke wrapper seqence with preamble and postamble
  480. // Preamble:
  481. // __THREW__ = 0;
  482. // Postamble:
  483. // %__THREW__.val = __THREW__; __THREW__ = 0;
  484. // Returns %__THREW__.val, which indicates whether an exception is thrown (or
  485. // whether longjmp occurred), for future use.
  486. Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
  487. Module *M = CI->getModule();
  488. LLVMContext &C = M->getContext();
  489. IRBuilder<> IRB(C);
  490. IRB.SetInsertPoint(CI);
  491. // Pre-invoke
  492. // __THREW__ = 0;
  493. IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
  494. // Invoke function wrapper in JavaScript
  495. SmallVector<Value *, 16> Args;
  496. // Put the pointer to the callee as first argument, so it can be called
  497. // within the invoke wrapper later
  498. Args.push_back(CI->getCalledOperand());
  499. Args.append(CI->arg_begin(), CI->arg_end());
  500. CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
  501. NewCall->takeName(CI);
  502. NewCall->setCallingConv(CallingConv::WASM_EmscriptenInvoke);
  503. NewCall->setDebugLoc(CI->getDebugLoc());
  504. // Because we added the pointer to the callee as first argument, all
  505. // argument attribute indices have to be incremented by one.
  506. SmallVector<AttributeSet, 8> ArgAttributes;
  507. const AttributeList &InvokeAL = CI->getAttributes();
  508. // No attributes for the callee pointer.
  509. ArgAttributes.push_back(AttributeSet());
  510. // Copy the argument attributes from the original
  511. for (unsigned I = 0, E = CI->arg_size(); I < E; ++I)
  512. ArgAttributes.push_back(InvokeAL.getParamAttrs(I));
  513. AttrBuilder FnAttrs(CI->getContext(), InvokeAL.getFnAttrs());
  514. if (auto Args = FnAttrs.getAllocSizeArgs()) {
  515. // The allocsize attribute (if any) referes to parameters by index and needs
  516. // to be adjusted.
  517. auto [SizeArg, NEltArg] = *Args;
  518. SizeArg += 1;
  519. if (NEltArg)
  520. NEltArg = *NEltArg + 1;
  521. FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
  522. }
  523. // In case the callee has 'noreturn' attribute, We need to remove it, because
  524. // we expect invoke wrappers to return.
  525. FnAttrs.removeAttribute(Attribute::NoReturn);
  526. // Reconstruct the AttributesList based on the vector we constructed.
  527. AttributeList NewCallAL = AttributeList::get(
  528. C, AttributeSet::get(C, FnAttrs), InvokeAL.getRetAttrs(), ArgAttributes);
  529. NewCall->setAttributes(NewCallAL);
  530. CI->replaceAllUsesWith(NewCall);
  531. // Post-invoke
  532. // %__THREW__.val = __THREW__; __THREW__ = 0;
  533. Value *Threw =
  534. IRB.CreateLoad(getAddrIntType(M), ThrewGV, ThrewGV->getName() + ".val");
  535. IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
  536. return Threw;
  537. }
  538. // Get matching invoke wrapper based on callee signature
  539. Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
  540. Module *M = CI->getModule();
  541. SmallVector<Type *, 16> ArgTys;
  542. FunctionType *CalleeFTy = CI->getFunctionType();
  543. std::string Sig = getSignature(CalleeFTy);
  544. if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
  545. return InvokeWrappers[Sig];
  546. // Put the pointer to the callee as first argument
  547. ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
  548. // Add argument types
  549. ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
  550. FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
  551. CalleeFTy->isVarArg());
  552. Function *F = getEmscriptenFunction(FTy, "__invoke_" + Sig, M);
  553. InvokeWrappers[Sig] = F;
  554. return F;
  555. }
  556. static bool canLongjmp(const Value *Callee) {
  557. if (auto *CalleeF = dyn_cast<Function>(Callee))
  558. if (CalleeF->isIntrinsic())
  559. return false;
  560. // Attempting to transform inline assembly will result in something like:
  561. // call void @__invoke_void(void ()* asm ...)
  562. // which is invalid because inline assembly blocks do not have addresses
  563. // and can't be passed by pointer. The result is a crash with illegal IR.
  564. if (isa<InlineAsm>(Callee))
  565. return false;
  566. StringRef CalleeName = Callee->getName();
  567. // TODO Include more functions or consider checking with mangled prefixes
  568. // The reason we include malloc/free here is to exclude the malloc/free
  569. // calls generated in setjmp prep / cleanup routines.
  570. if (CalleeName == "setjmp" || CalleeName == "malloc" || CalleeName == "free")
  571. return false;
  572. // There are functions in Emscripten's JS glue code or compiler-rt
  573. if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" ||
  574. CalleeName == "saveSetjmp" || CalleeName == "testSetjmp" ||
  575. CalleeName == "getTempRet0" || CalleeName == "setTempRet0")
  576. return false;
  577. // __cxa_find_matching_catch_N functions cannot longjmp
  578. if (Callee->getName().startswith("__cxa_find_matching_catch_"))
  579. return false;
  580. // Exception-catching related functions
  581. //
  582. // We intentionally treat __cxa_end_catch longjmpable in Wasm SjLj even though
  583. // it surely cannot longjmp, in order to maintain the unwind relationship from
  584. // all existing catchpads (and calls within them) to catch.dispatch.longjmp.
  585. //
  586. // In Wasm EH + Wasm SjLj, we
  587. // 1. Make all catchswitch and cleanuppad that unwind to caller unwind to
  588. // catch.dispatch.longjmp instead
  589. // 2. Convert all longjmpable calls to invokes that unwind to
  590. // catch.dispatch.longjmp
  591. // But catchswitch BBs are removed in isel, so if an EH catchswitch (generated
  592. // from an exception)'s catchpad does not contain any calls that are converted
  593. // into invokes unwinding to catch.dispatch.longjmp, this unwind relationship
  594. // (EH catchswitch BB -> catch.dispatch.longjmp BB) is lost and
  595. // catch.dispatch.longjmp BB can be placed before the EH catchswitch BB in
  596. // CFGSort.
  597. // int ret = setjmp(buf);
  598. // try {
  599. // foo(); // longjmps
  600. // } catch (...) {
  601. // }
  602. // Then in this code, if 'foo' longjmps, it first unwinds to 'catch (...)'
  603. // catchswitch, and is not caught by that catchswitch because it is a longjmp,
  604. // then it should next unwind to catch.dispatch.longjmp BB. But if this 'catch
  605. // (...)' catchswitch -> catch.dispatch.longjmp unwind relationship is lost,
  606. // it will not unwind to catch.dispatch.longjmp, producing an incorrect
  607. // result.
  608. //
  609. // Every catchpad generated by Wasm C++ contains __cxa_end_catch, so we
  610. // intentionally treat it as longjmpable to work around this problem. This is
  611. // a hacky fix but an easy one.
  612. //
  613. // The comment block in findWasmUnwindDestinations() in
  614. // SelectionDAGBuilder.cpp is addressing a similar problem.
  615. if (CalleeName == "__cxa_end_catch")
  616. return WebAssembly::WasmEnableSjLj;
  617. if (CalleeName == "__cxa_begin_catch" ||
  618. CalleeName == "__cxa_allocate_exception" || CalleeName == "__cxa_throw" ||
  619. CalleeName == "__clang_call_terminate")
  620. return false;
  621. // std::terminate, which is generated when another exception occurs while
  622. // handling an exception, cannot longjmp.
  623. if (CalleeName == "_ZSt9terminatev")
  624. return false;
  625. // Otherwise we don't know
  626. return true;
  627. }
  628. static bool isEmAsmCall(const Value *Callee) {
  629. StringRef CalleeName = Callee->getName();
  630. // This is an exhaustive list from Emscripten's <emscripten/em_asm.h>.
  631. return CalleeName == "emscripten_asm_const_int" ||
  632. CalleeName == "emscripten_asm_const_double" ||
  633. CalleeName == "emscripten_asm_const_int_sync_on_main_thread" ||
  634. CalleeName == "emscripten_asm_const_double_sync_on_main_thread" ||
  635. CalleeName == "emscripten_asm_const_async_on_main_thread";
  636. }
  637. // Generate testSetjmp function call seqence with preamble and postamble.
  638. // The code this generates is equivalent to the following JavaScript code:
  639. // %__threwValue.val = __threwValue;
  640. // if (%__THREW__.val != 0 & %__threwValue.val != 0) {
  641. // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
  642. // if (%label == 0)
  643. // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
  644. // setTempRet0(%__threwValue.val);
  645. // } else {
  646. // %label = -1;
  647. // }
  648. // %longjmp_result = getTempRet0();
  649. //
  650. // As output parameters. returns %label, %longjmp_result, and the BB the last
  651. // instruction (%longjmp_result = ...) is in.
  652. void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
  653. BasicBlock *BB, DebugLoc DL, Value *Threw, Value *SetjmpTable,
  654. Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
  655. BasicBlock *&CallEmLongjmpBB, PHINode *&CallEmLongjmpBBThrewPHI,
  656. PHINode *&CallEmLongjmpBBThrewValuePHI, BasicBlock *&EndBB) {
  657. Function *F = BB->getParent();
  658. Module *M = F->getParent();
  659. LLVMContext &C = M->getContext();
  660. IRBuilder<> IRB(C);
  661. IRB.SetCurrentDebugLocation(DL);
  662. // if (%__THREW__.val != 0 & %__threwValue.val != 0)
  663. IRB.SetInsertPoint(BB);
  664. BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
  665. BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
  666. BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
  667. Value *ThrewCmp = IRB.CreateICmpNE(Threw, getAddrSizeInt(M, 0));
  668. Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
  669. ThrewValueGV->getName() + ".val");
  670. Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
  671. Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
  672. IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
  673. // Generate call.em.longjmp BB once and share it within the function
  674. if (!CallEmLongjmpBB) {
  675. // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
  676. CallEmLongjmpBB = BasicBlock::Create(C, "call.em.longjmp", F);
  677. IRB.SetInsertPoint(CallEmLongjmpBB);
  678. CallEmLongjmpBBThrewPHI = IRB.CreatePHI(getAddrIntType(M), 4, "threw.phi");
  679. CallEmLongjmpBBThrewValuePHI =
  680. IRB.CreatePHI(IRB.getInt32Ty(), 4, "threwvalue.phi");
  681. CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
  682. CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
  683. IRB.CreateCall(EmLongjmpF,
  684. {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
  685. IRB.CreateUnreachable();
  686. } else {
  687. CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
  688. CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
  689. }
  690. // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
  691. // if (%label == 0)
  692. IRB.SetInsertPoint(ThenBB1);
  693. BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
  694. Value *ThrewPtr =
  695. IRB.CreateIntToPtr(Threw, getAddrPtrType(M), Threw->getName() + ".p");
  696. Value *LoadedThrew = IRB.CreateLoad(getAddrIntType(M), ThrewPtr,
  697. ThrewPtr->getName() + ".loaded");
  698. Value *ThenLabel = IRB.CreateCall(
  699. TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
  700. Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
  701. IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
  702. // setTempRet0(%__threwValue.val);
  703. IRB.SetInsertPoint(EndBB2);
  704. IRB.CreateCall(SetTempRet0F, ThrewValue);
  705. IRB.CreateBr(EndBB1);
  706. IRB.SetInsertPoint(ElseBB1);
  707. IRB.CreateBr(EndBB1);
  708. // longjmp_result = getTempRet0();
  709. IRB.SetInsertPoint(EndBB1);
  710. PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
  711. LabelPHI->addIncoming(ThenLabel, EndBB2);
  712. LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
  713. // Output parameter assignment
  714. Label = LabelPHI;
  715. EndBB = EndBB1;
  716. LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt, "longjmp_result");
  717. }
  718. void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
  719. DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
  720. DT.recalculate(F); // CFG has been changed
  721. SSAUpdaterBulk SSA;
  722. for (BasicBlock &BB : F) {
  723. for (Instruction &I : BB) {
  724. unsigned VarID = SSA.AddVariable(I.getName(), I.getType());
  725. // If a value is defined by an invoke instruction, it is only available in
  726. // its normal destination and not in its unwind destination.
  727. if (auto *II = dyn_cast<InvokeInst>(&I))
  728. SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
  729. else
  730. SSA.AddAvailableValue(VarID, &BB, &I);
  731. for (auto &U : I.uses()) {
  732. auto *User = cast<Instruction>(U.getUser());
  733. if (auto *UserPN = dyn_cast<PHINode>(User))
  734. if (UserPN->getIncomingBlock(U) == &BB)
  735. continue;
  736. if (DT.dominates(&I, User))
  737. continue;
  738. SSA.AddUse(VarID, &U);
  739. }
  740. }
  741. }
  742. SSA.RewriteAllUses(&DT);
  743. }
  744. // Replace uses of longjmp with a new longjmp function in Emscripten library.
  745. // In Emscripten SjLj, the new function is
  746. // void emscripten_longjmp(uintptr_t, i32)
  747. // In Wasm SjLj, the new function is
  748. // void __wasm_longjmp(i8*, i32)
  749. // Because the original libc longjmp function takes (jmp_buf*, i32), we need a
  750. // ptrtoint/bitcast instruction here to make the type match. jmp_buf* will
  751. // eventually be lowered to i32/i64 in the wasm backend.
  752. void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
  753. Function *NewF) {
  754. assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
  755. Module *M = LongjmpF->getParent();
  756. SmallVector<CallInst *, 8> ToErase;
  757. LLVMContext &C = LongjmpF->getParent()->getContext();
  758. IRBuilder<> IRB(C);
  759. // For calls to longjmp, replace it with emscripten_longjmp/__wasm_longjmp and
  760. // cast its first argument (jmp_buf*) appropriately
  761. for (User *U : LongjmpF->users()) {
  762. auto *CI = dyn_cast<CallInst>(U);
  763. if (CI && CI->getCalledFunction() == LongjmpF) {
  764. IRB.SetInsertPoint(CI);
  765. Value *Env = nullptr;
  766. if (NewF == EmLongjmpF)
  767. Env =
  768. IRB.CreatePtrToInt(CI->getArgOperand(0), getAddrIntType(M), "env");
  769. else // WasmLongjmpF
  770. Env =
  771. IRB.CreateBitCast(CI->getArgOperand(0), IRB.getInt8PtrTy(), "env");
  772. IRB.CreateCall(NewF, {Env, CI->getArgOperand(1)});
  773. ToErase.push_back(CI);
  774. }
  775. }
  776. for (auto *I : ToErase)
  777. I->eraseFromParent();
  778. // If we have any remaining uses of longjmp's function pointer, replace it
  779. // with (void(*)(jmp_buf*, int))emscripten_longjmp / __wasm_longjmp.
  780. if (!LongjmpF->uses().empty()) {
  781. Value *NewLongjmp =
  782. IRB.CreateBitCast(NewF, LongjmpF->getType(), "longjmp.cast");
  783. LongjmpF->replaceAllUsesWith(NewLongjmp);
  784. }
  785. }
  786. static bool containsLongjmpableCalls(const Function *F) {
  787. for (const auto &BB : *F)
  788. for (const auto &I : BB)
  789. if (const auto *CB = dyn_cast<CallBase>(&I))
  790. if (canLongjmp(CB->getCalledOperand()))
  791. return true;
  792. return false;
  793. }
  794. // When a function contains a setjmp call but not other calls that can longjmp,
  795. // we don't do setjmp transformation for that setjmp. But we need to convert the
  796. // setjmp calls into "i32 0" so they don't cause link time errors. setjmp always
  797. // returns 0 when called directly.
  798. static void nullifySetjmp(Function *F) {
  799. Module &M = *F->getParent();
  800. IRBuilder<> IRB(M.getContext());
  801. Function *SetjmpF = M.getFunction("setjmp");
  802. SmallVector<Instruction *, 1> ToErase;
  803. for (User *U : make_early_inc_range(SetjmpF->users())) {
  804. auto *CB = cast<CallBase>(U);
  805. BasicBlock *BB = CB->getParent();
  806. if (BB->getParent() != F) // in other function
  807. continue;
  808. CallInst *CI = nullptr;
  809. // setjmp cannot throw. So if it is an invoke, lower it to a call
  810. if (auto *II = dyn_cast<InvokeInst>(CB))
  811. CI = llvm::changeToCall(II);
  812. else
  813. CI = cast<CallInst>(CB);
  814. ToErase.push_back(CI);
  815. CI->replaceAllUsesWith(IRB.getInt32(0));
  816. }
  817. for (auto *I : ToErase)
  818. I->eraseFromParent();
  819. }
  820. bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
  821. LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
  822. LLVMContext &C = M.getContext();
  823. IRBuilder<> IRB(C);
  824. Function *SetjmpF = M.getFunction("setjmp");
  825. Function *LongjmpF = M.getFunction("longjmp");
  826. // In some platforms _setjmp and _longjmp are used instead. Change these to
  827. // use setjmp/longjmp instead, because we later detect these functions by
  828. // their names.
  829. Function *SetjmpF2 = M.getFunction("_setjmp");
  830. Function *LongjmpF2 = M.getFunction("_longjmp");
  831. if (SetjmpF2) {
  832. if (SetjmpF) {
  833. if (SetjmpF->getFunctionType() != SetjmpF2->getFunctionType())
  834. report_fatal_error("setjmp and _setjmp have different function types");
  835. } else {
  836. SetjmpF = Function::Create(SetjmpF2->getFunctionType(),
  837. GlobalValue::ExternalLinkage, "setjmp", M);
  838. }
  839. SetjmpF2->replaceAllUsesWith(SetjmpF);
  840. }
  841. if (LongjmpF2) {
  842. if (LongjmpF) {
  843. if (LongjmpF->getFunctionType() != LongjmpF2->getFunctionType())
  844. report_fatal_error(
  845. "longjmp and _longjmp have different function types");
  846. } else {
  847. LongjmpF = Function::Create(LongjmpF2->getFunctionType(),
  848. GlobalValue::ExternalLinkage, "setjmp", M);
  849. }
  850. LongjmpF2->replaceAllUsesWith(LongjmpF);
  851. }
  852. auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
  853. assert(TPC && "Expected a TargetPassConfig");
  854. auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
  855. // Declare (or get) global variables __THREW__, __threwValue, and
  856. // getTempRet0/setTempRet0 function which are used in common for both
  857. // exception handling and setjmp/longjmp handling
  858. ThrewGV = getGlobalVariable(M, getAddrIntType(&M), TM, "__THREW__");
  859. ThrewValueGV = getGlobalVariable(M, IRB.getInt32Ty(), TM, "__threwValue");
  860. GetTempRet0F = getEmscriptenFunction(
  861. FunctionType::get(IRB.getInt32Ty(), false), "getTempRet0", &M);
  862. SetTempRet0F = getEmscriptenFunction(
  863. FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
  864. "setTempRet0", &M);
  865. GetTempRet0F->setDoesNotThrow();
  866. SetTempRet0F->setDoesNotThrow();
  867. bool Changed = false;
  868. // Function registration for exception handling
  869. if (EnableEmEH) {
  870. // Register __resumeException function
  871. FunctionType *ResumeFTy =
  872. FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
  873. ResumeF = getEmscriptenFunction(ResumeFTy, "__resumeException", &M);
  874. ResumeF->addFnAttr(Attribute::NoReturn);
  875. // Register llvm_eh_typeid_for function
  876. FunctionType *EHTypeIDTy =
  877. FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
  878. EHTypeIDF = getEmscriptenFunction(EHTypeIDTy, "llvm_eh_typeid_for", &M);
  879. }
  880. // Functions that contains calls to setjmp but don't have other longjmpable
  881. // calls within them.
  882. SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
  883. if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
  884. // Precompute setjmp users
  885. for (User *U : SetjmpF->users()) {
  886. if (auto *CB = dyn_cast<CallBase>(U)) {
  887. auto *UserF = CB->getFunction();
  888. // If a function that calls setjmp does not contain any other calls that
  889. // can longjmp, we don't need to do any transformation on that function,
  890. // so can ignore it
  891. if (containsLongjmpableCalls(UserF))
  892. SetjmpUsers.insert(UserF);
  893. else
  894. SetjmpUsersToNullify.insert(UserF);
  895. } else {
  896. std::string S;
  897. raw_string_ostream SS(S);
  898. SS << *U;
  899. report_fatal_error(Twine("Indirect use of setjmp is not supported: ") +
  900. SS.str());
  901. }
  902. }
  903. }
  904. bool SetjmpUsed = SetjmpF && !SetjmpUsers.empty();
  905. bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
  906. DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
  907. // Function registration and data pre-gathering for setjmp/longjmp handling
  908. if (DoSjLj) {
  909. assert(EnableEmSjLj || EnableWasmSjLj);
  910. if (EnableEmSjLj) {
  911. // Register emscripten_longjmp function
  912. FunctionType *FTy = FunctionType::get(
  913. IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()}, false);
  914. EmLongjmpF = getEmscriptenFunction(FTy, "emscripten_longjmp", &M);
  915. EmLongjmpF->addFnAttr(Attribute::NoReturn);
  916. } else { // EnableWasmSjLj
  917. // Register __wasm_longjmp function, which calls __builtin_wasm_longjmp.
  918. FunctionType *FTy = FunctionType::get(
  919. IRB.getVoidTy(), {IRB.getInt8PtrTy(), IRB.getInt32Ty()}, false);
  920. WasmLongjmpF = getEmscriptenFunction(FTy, "__wasm_longjmp", &M);
  921. WasmLongjmpF->addFnAttr(Attribute::NoReturn);
  922. }
  923. if (SetjmpF) {
  924. // Register saveSetjmp function
  925. FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
  926. FunctionType *FTy =
  927. FunctionType::get(Type::getInt32PtrTy(C),
  928. {SetjmpFTy->getParamType(0), IRB.getInt32Ty(),
  929. Type::getInt32PtrTy(C), IRB.getInt32Ty()},
  930. false);
  931. SaveSetjmpF = getEmscriptenFunction(FTy, "saveSetjmp", &M);
  932. // Register testSetjmp function
  933. FTy = FunctionType::get(
  934. IRB.getInt32Ty(),
  935. {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
  936. false);
  937. TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M);
  938. // wasm.catch() will be lowered down to wasm 'catch' instruction in
  939. // instruction selection.
  940. CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
  941. // Type for struct __WasmLongjmpArgs
  942. LongjmpArgsTy = StructType::get(IRB.getInt8PtrTy(), // env
  943. IRB.getInt32Ty() // val
  944. );
  945. }
  946. }
  947. // Exception handling transformation
  948. if (EnableEmEH) {
  949. for (Function &F : M) {
  950. if (F.isDeclaration())
  951. continue;
  952. Changed |= runEHOnFunction(F);
  953. }
  954. }
  955. // Setjmp/longjmp handling transformation
  956. if (DoSjLj) {
  957. Changed = true; // We have setjmp or longjmp somewhere
  958. if (LongjmpF)
  959. replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
  960. // Only traverse functions that uses setjmp in order not to insert
  961. // unnecessary prep / cleanup code in every function
  962. if (SetjmpF)
  963. for (Function *F : SetjmpUsers)
  964. runSjLjOnFunction(*F);
  965. }
  966. // Replace unnecessary setjmp calls with 0
  967. if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.empty()) {
  968. Changed = true;
  969. assert(SetjmpF);
  970. for (Function *F : SetjmpUsersToNullify)
  971. nullifySetjmp(F);
  972. }
  973. // Delete unused global variables and functions
  974. for (auto *V : {ThrewGV, ThrewValueGV})
  975. if (V && V->use_empty())
  976. V->eraseFromParent();
  977. for (auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
  978. SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF})
  979. if (V && V->use_empty())
  980. V->eraseFromParent();
  981. return Changed;
  982. }
  983. bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
  984. Module &M = *F.getParent();
  985. LLVMContext &C = F.getContext();
  986. IRBuilder<> IRB(C);
  987. bool Changed = false;
  988. SmallVector<Instruction *, 64> ToErase;
  989. SmallPtrSet<LandingPadInst *, 32> LandingPads;
  990. // rethrow.longjmp BB that will be shared within the function.
  991. BasicBlock *RethrowLongjmpBB = nullptr;
  992. // PHI node for the loaded value of __THREW__ global variable in
  993. // rethrow.longjmp BB
  994. PHINode *RethrowLongjmpBBThrewPHI = nullptr;
  995. for (BasicBlock &BB : F) {
  996. auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
  997. if (!II)
  998. continue;
  999. Changed = true;
  1000. LandingPads.insert(II->getLandingPadInst());
  1001. IRB.SetInsertPoint(II);
  1002. const Value *Callee = II->getCalledOperand();
  1003. bool NeedInvoke = supportsException(&F) && canThrow(Callee);
  1004. if (NeedInvoke) {
  1005. // Wrap invoke with invoke wrapper and generate preamble/postamble
  1006. Value *Threw = wrapInvoke(II);
  1007. ToErase.push_back(II);
  1008. // If setjmp/longjmp handling is enabled, the thrown value can be not an
  1009. // exception but a longjmp. If the current function contains calls to
  1010. // setjmp, it will be appropriately handled in runSjLjOnFunction. But even
  1011. // if the function does not contain setjmp calls, we shouldn't silently
  1012. // ignore longjmps; we should rethrow them so they can be correctly
  1013. // handled in somewhere up the call chain where setjmp is. __THREW__'s
  1014. // value is 0 when nothing happened, 1 when an exception is thrown, and
  1015. // other values when longjmp is thrown.
  1016. //
  1017. // if (%__THREW__.val == 0 || %__THREW__.val == 1)
  1018. // goto %tail
  1019. // else
  1020. // goto %longjmp.rethrow
  1021. //
  1022. // rethrow.longjmp: ;; This is longjmp. Rethrow it
  1023. // %__threwValue.val = __threwValue
  1024. // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
  1025. //
  1026. // tail: ;; Nothing happened or an exception is thrown
  1027. // ... Continue exception handling ...
  1028. if (DoSjLj && EnableEmSjLj && !SetjmpUsers.count(&F) &&
  1029. canLongjmp(Callee)) {
  1030. // Create longjmp.rethrow BB once and share it within the function
  1031. if (!RethrowLongjmpBB) {
  1032. RethrowLongjmpBB = BasicBlock::Create(C, "rethrow.longjmp", &F);
  1033. IRB.SetInsertPoint(RethrowLongjmpBB);
  1034. RethrowLongjmpBBThrewPHI =
  1035. IRB.CreatePHI(getAddrIntType(&M), 4, "threw.phi");
  1036. RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
  1037. Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
  1038. ThrewValueGV->getName() + ".val");
  1039. IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
  1040. IRB.CreateUnreachable();
  1041. } else {
  1042. RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
  1043. }
  1044. IRB.SetInsertPoint(II); // Restore the insert point back
  1045. BasicBlock *Tail = BasicBlock::Create(C, "tail", &F);
  1046. Value *CmpEqOne =
  1047. IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
  1048. Value *CmpEqZero =
  1049. IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 0), "cmp.eq.zero");
  1050. Value *Or = IRB.CreateOr(CmpEqZero, CmpEqOne, "or");
  1051. IRB.CreateCondBr(Or, Tail, RethrowLongjmpBB);
  1052. IRB.SetInsertPoint(Tail);
  1053. BB.replaceSuccessorsPhiUsesWith(&BB, Tail);
  1054. }
  1055. // Insert a branch based on __THREW__ variable
  1056. Value *Cmp = IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp");
  1057. IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
  1058. } else {
  1059. // This can't throw, and we don't need this invoke, just replace it with a
  1060. // call+branch
  1061. changeToCall(II);
  1062. }
  1063. }
  1064. // Process resume instructions
  1065. for (BasicBlock &BB : F) {
  1066. // Scan the body of the basic block for resumes
  1067. for (Instruction &I : BB) {
  1068. auto *RI = dyn_cast<ResumeInst>(&I);
  1069. if (!RI)
  1070. continue;
  1071. Changed = true;
  1072. // Split the input into legal values
  1073. Value *Input = RI->getValue();
  1074. IRB.SetInsertPoint(RI);
  1075. Value *Low = IRB.CreateExtractValue(Input, 0, "low");
  1076. // Create a call to __resumeException function
  1077. IRB.CreateCall(ResumeF, {Low});
  1078. // Add a terminator to the block
  1079. IRB.CreateUnreachable();
  1080. ToErase.push_back(RI);
  1081. }
  1082. }
  1083. // Process llvm.eh.typeid.for intrinsics
  1084. for (BasicBlock &BB : F) {
  1085. for (Instruction &I : BB) {
  1086. auto *CI = dyn_cast<CallInst>(&I);
  1087. if (!CI)
  1088. continue;
  1089. const Function *Callee = CI->getCalledFunction();
  1090. if (!Callee)
  1091. continue;
  1092. if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
  1093. continue;
  1094. Changed = true;
  1095. IRB.SetInsertPoint(CI);
  1096. CallInst *NewCI =
  1097. IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
  1098. CI->replaceAllUsesWith(NewCI);
  1099. ToErase.push_back(CI);
  1100. }
  1101. }
  1102. // Look for orphan landingpads, can occur in blocks with no predecessors
  1103. for (BasicBlock &BB : F) {
  1104. Instruction *I = BB.getFirstNonPHI();
  1105. if (auto *LPI = dyn_cast<LandingPadInst>(I))
  1106. LandingPads.insert(LPI);
  1107. }
  1108. Changed |= !LandingPads.empty();
  1109. // Handle all the landingpad for this function together, as multiple invokes
  1110. // may share a single lp
  1111. for (LandingPadInst *LPI : LandingPads) {
  1112. IRB.SetInsertPoint(LPI);
  1113. SmallVector<Value *, 16> FMCArgs;
  1114. for (unsigned I = 0, E = LPI->getNumClauses(); I < E; ++I) {
  1115. Constant *Clause = LPI->getClause(I);
  1116. // TODO Handle filters (= exception specifications).
  1117. // https://bugs.llvm.org/show_bug.cgi?id=50396
  1118. if (LPI->isCatch(I))
  1119. FMCArgs.push_back(Clause);
  1120. }
  1121. // Create a call to __cxa_find_matching_catch_N function
  1122. Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
  1123. CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
  1124. Value *Poison = PoisonValue::get(LPI->getType());
  1125. Value *Pair0 = IRB.CreateInsertValue(Poison, FMCI, 0, "pair0");
  1126. Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt, "tempret0");
  1127. Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
  1128. LPI->replaceAllUsesWith(Pair1);
  1129. ToErase.push_back(LPI);
  1130. }
  1131. // Erase everything we no longer need in this function
  1132. for (Instruction *I : ToErase)
  1133. I->eraseFromParent();
  1134. return Changed;
  1135. }
  1136. // This tries to get debug info from the instruction before which a new
  1137. // instruction will be inserted, and if there's no debug info in that
  1138. // instruction, tries to get the info instead from the previous instruction (if
  1139. // any). If none of these has debug info and a DISubprogram is provided, it
  1140. // creates a dummy debug info with the first line of the function, because IR
  1141. // verifier requires all inlinable callsites should have debug info when both a
  1142. // caller and callee have DISubprogram. If none of these conditions are met,
  1143. // returns empty info.
  1144. static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore,
  1145. DISubprogram *SP) {
  1146. assert(InsertBefore);
  1147. if (InsertBefore->getDebugLoc())
  1148. return InsertBefore->getDebugLoc();
  1149. const Instruction *Prev = InsertBefore->getPrevNode();
  1150. if (Prev && Prev->getDebugLoc())
  1151. return Prev->getDebugLoc();
  1152. if (SP)
  1153. return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
  1154. return DebugLoc();
  1155. }
  1156. bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
  1157. assert(EnableEmSjLj || EnableWasmSjLj);
  1158. Module &M = *F.getParent();
  1159. LLVMContext &C = F.getContext();
  1160. IRBuilder<> IRB(C);
  1161. SmallVector<Instruction *, 64> ToErase;
  1162. // Vector of %setjmpTable values
  1163. SmallVector<Instruction *, 4> SetjmpTableInsts;
  1164. // Vector of %setjmpTableSize values
  1165. SmallVector<Instruction *, 4> SetjmpTableSizeInsts;
  1166. // Setjmp preparation
  1167. // This instruction effectively means %setjmpTableSize = 4.
  1168. // We create this as an instruction intentionally, and we don't want to fold
  1169. // this instruction to a constant 4, because this value will be used in
  1170. // SSAUpdater.AddAvailableValue(...) later.
  1171. BasicBlock *Entry = &F.getEntryBlock();
  1172. DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
  1173. SplitBlock(Entry, &*Entry->getFirstInsertionPt());
  1174. BinaryOperator *SetjmpTableSize =
  1175. BinaryOperator::Create(Instruction::Add, IRB.getInt32(4), IRB.getInt32(0),
  1176. "setjmpTableSize", Entry->getTerminator());
  1177. SetjmpTableSize->setDebugLoc(FirstDL);
  1178. // setjmpTable = (int *) malloc(40);
  1179. Type *IntPtrTy = getAddrIntType(&M);
  1180. Constant *size = ConstantInt::get(IntPtrTy, 40);
  1181. Instruction *SetjmpTable =
  1182. CallInst::CreateMalloc(SetjmpTableSize, IntPtrTy, IRB.getInt32Ty(), size,
  1183. nullptr, nullptr, "setjmpTable");
  1184. SetjmpTable->setDebugLoc(FirstDL);
  1185. // CallInst::CreateMalloc may return a bitcast instruction if the result types
  1186. // mismatch. We need to set the debug loc for the original call too.
  1187. auto *MallocCall = SetjmpTable->stripPointerCasts();
  1188. if (auto *MallocCallI = dyn_cast<Instruction>(MallocCall)) {
  1189. MallocCallI->setDebugLoc(FirstDL);
  1190. }
  1191. // setjmpTable[0] = 0;
  1192. IRB.SetInsertPoint(SetjmpTableSize);
  1193. IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
  1194. SetjmpTableInsts.push_back(SetjmpTable);
  1195. SetjmpTableSizeInsts.push_back(SetjmpTableSize);
  1196. // Setjmp transformation
  1197. SmallVector<PHINode *, 4> SetjmpRetPHIs;
  1198. Function *SetjmpF = M.getFunction("setjmp");
  1199. for (auto *U : make_early_inc_range(SetjmpF->users())) {
  1200. auto *CB = cast<CallBase>(U);
  1201. BasicBlock *BB = CB->getParent();
  1202. if (BB->getParent() != &F) // in other function
  1203. continue;
  1204. if (CB->getOperandBundle(LLVMContext::OB_funclet)) {
  1205. std::string S;
  1206. raw_string_ostream SS(S);
  1207. SS << "In function " + F.getName() +
  1208. ": setjmp within a catch clause is not supported in Wasm EH:\n";
  1209. SS << *CB;
  1210. report_fatal_error(StringRef(SS.str()));
  1211. }
  1212. CallInst *CI = nullptr;
  1213. // setjmp cannot throw. So if it is an invoke, lower it to a call
  1214. if (auto *II = dyn_cast<InvokeInst>(CB))
  1215. CI = llvm::changeToCall(II);
  1216. else
  1217. CI = cast<CallInst>(CB);
  1218. // The tail is everything right after the call, and will be reached once
  1219. // when setjmp is called, and later when longjmp returns to the setjmp
  1220. BasicBlock *Tail = SplitBlock(BB, CI->getNextNode());
  1221. // Add a phi to the tail, which will be the output of setjmp, which
  1222. // indicates if this is the first call or a longjmp back. The phi directly
  1223. // uses the right value based on where we arrive from
  1224. IRB.SetInsertPoint(Tail->getFirstNonPHI());
  1225. PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
  1226. // setjmp initial call returns 0
  1227. SetjmpRet->addIncoming(IRB.getInt32(0), BB);
  1228. // The proper output is now this, not the setjmp call itself
  1229. CI->replaceAllUsesWith(SetjmpRet);
  1230. // longjmp returns to the setjmp will add themselves to this phi
  1231. SetjmpRetPHIs.push_back(SetjmpRet);
  1232. // Fix call target
  1233. // Our index in the function is our place in the array + 1 to avoid index
  1234. // 0, because index 0 means the longjmp is not ours to handle.
  1235. IRB.SetInsertPoint(CI);
  1236. Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
  1237. SetjmpTable, SetjmpTableSize};
  1238. Instruction *NewSetjmpTable =
  1239. IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
  1240. Instruction *NewSetjmpTableSize =
  1241. IRB.CreateCall(GetTempRet0F, std::nullopt, "setjmpTableSize");
  1242. SetjmpTableInsts.push_back(NewSetjmpTable);
  1243. SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
  1244. ToErase.push_back(CI);
  1245. }
  1246. // Handle longjmpable calls.
  1247. if (EnableEmSjLj)
  1248. handleLongjmpableCallsForEmscriptenSjLj(
  1249. F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
  1250. else // EnableWasmSjLj
  1251. handleLongjmpableCallsForWasmSjLj(F, SetjmpTableInsts, SetjmpTableSizeInsts,
  1252. SetjmpRetPHIs);
  1253. // Erase everything we no longer need in this function
  1254. for (Instruction *I : ToErase)
  1255. I->eraseFromParent();
  1256. // Free setjmpTable buffer before each return instruction + function-exiting
  1257. // call
  1258. SmallVector<Instruction *, 16> ExitingInsts;
  1259. for (BasicBlock &BB : F) {
  1260. Instruction *TI = BB.getTerminator();
  1261. if (isa<ReturnInst>(TI))
  1262. ExitingInsts.push_back(TI);
  1263. // Any 'call' instruction with 'noreturn' attribute exits the function at
  1264. // this point. If this throws but unwinds to another EH pad within this
  1265. // function instead of exiting, this would have been an 'invoke', which
  1266. // happens if we use Wasm EH or Wasm SjLJ.
  1267. for (auto &I : BB) {
  1268. if (auto *CI = dyn_cast<CallInst>(&I)) {
  1269. bool IsNoReturn = CI->hasFnAttr(Attribute::NoReturn);
  1270. if (Function *CalleeF = CI->getCalledFunction())
  1271. IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
  1272. if (IsNoReturn)
  1273. ExitingInsts.push_back(&I);
  1274. }
  1275. }
  1276. }
  1277. for (auto *I : ExitingInsts) {
  1278. DebugLoc DL = getOrCreateDebugLoc(I, F.getSubprogram());
  1279. // If this existing instruction is a call within a catchpad, we should add
  1280. // it as "funclet" to the operand bundle of 'free' call
  1281. SmallVector<OperandBundleDef, 1> Bundles;
  1282. if (auto *CB = dyn_cast<CallBase>(I))
  1283. if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))
  1284. Bundles.push_back(OperandBundleDef(*Bundle));
  1285. auto *Free = CallInst::CreateFree(SetjmpTable, Bundles, I);
  1286. Free->setDebugLoc(DL);
  1287. // CallInst::CreateFree may create a bitcast instruction if its argument
  1288. // types mismatch. We need to set the debug loc for the bitcast too.
  1289. if (auto *FreeCallI = dyn_cast<CallInst>(Free)) {
  1290. if (auto *BitCastI = dyn_cast<BitCastInst>(FreeCallI->getArgOperand(0)))
  1291. BitCastI->setDebugLoc(DL);
  1292. }
  1293. }
  1294. // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
  1295. // (when buffer reallocation occurs)
  1296. // entry:
  1297. // setjmpTableSize = 4;
  1298. // setjmpTable = (int *) malloc(40);
  1299. // setjmpTable[0] = 0;
  1300. // ...
  1301. // somebb:
  1302. // setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize);
  1303. // setjmpTableSize = getTempRet0();
  1304. // So we need to make sure the SSA for these variables is valid so that every
  1305. // saveSetjmp and testSetjmp calls have the correct arguments.
  1306. SSAUpdater SetjmpTableSSA;
  1307. SSAUpdater SetjmpTableSizeSSA;
  1308. SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
  1309. SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
  1310. for (Instruction *I : SetjmpTableInsts)
  1311. SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
  1312. for (Instruction *I : SetjmpTableSizeInsts)
  1313. SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
  1314. for (auto &U : make_early_inc_range(SetjmpTable->uses()))
  1315. if (auto *I = dyn_cast<Instruction>(U.getUser()))
  1316. if (I->getParent() != Entry)
  1317. SetjmpTableSSA.RewriteUse(U);
  1318. for (auto &U : make_early_inc_range(SetjmpTableSize->uses()))
  1319. if (auto *I = dyn_cast<Instruction>(U.getUser()))
  1320. if (I->getParent() != Entry)
  1321. SetjmpTableSizeSSA.RewriteUse(U);
  1322. // Finally, our modifications to the cfg can break dominance of SSA variables.
  1323. // For example, in this code,
  1324. // if (x()) { .. setjmp() .. }
  1325. // if (y()) { .. longjmp() .. }
  1326. // We must split the longjmp block, and it can jump into the block splitted
  1327. // from setjmp one. But that means that when we split the setjmp block, it's
  1328. // first part no longer dominates its second part - there is a theoretically
  1329. // possible control flow path where x() is false, then y() is true and we
  1330. // reach the second part of the setjmp block, without ever reaching the first
  1331. // part. So, we rebuild SSA form here.
  1332. rebuildSSA(F);
  1333. return true;
  1334. }
  1335. // Update each call that can longjmp so it can return to the corresponding
  1336. // setjmp. Refer to 4) of "Emscripten setjmp/longjmp handling" section in the
  1337. // comments at top of the file for details.
  1338. void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
  1339. Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
  1340. SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
  1341. Module &M = *F.getParent();
  1342. LLVMContext &C = F.getContext();
  1343. IRBuilder<> IRB(C);
  1344. SmallVector<Instruction *, 64> ToErase;
  1345. // We need to pass setjmpTable and setjmpTableSize to testSetjmp function.
  1346. // These values are defined in the beginning of the function and also in each
  1347. // setjmp callsite, but we don't know which values we should use at this
  1348. // point. So here we arbitraily use the ones defined in the beginning of the
  1349. // function, and SSAUpdater will later update them to the correct values.
  1350. Instruction *SetjmpTable = *SetjmpTableInsts.begin();
  1351. Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
  1352. // call.em.longjmp BB that will be shared within the function.
  1353. BasicBlock *CallEmLongjmpBB = nullptr;
  1354. // PHI node for the loaded value of __THREW__ global variable in
  1355. // call.em.longjmp BB
  1356. PHINode *CallEmLongjmpBBThrewPHI = nullptr;
  1357. // PHI node for the loaded value of __threwValue global variable in
  1358. // call.em.longjmp BB
  1359. PHINode *CallEmLongjmpBBThrewValuePHI = nullptr;
  1360. // rethrow.exn BB that will be shared within the function.
  1361. BasicBlock *RethrowExnBB = nullptr;
  1362. // Because we are creating new BBs while processing and don't want to make
  1363. // all these newly created BBs candidates again for longjmp processing, we
  1364. // first make the vector of candidate BBs.
  1365. std::vector<BasicBlock *> BBs;
  1366. for (BasicBlock &BB : F)
  1367. BBs.push_back(&BB);
  1368. // BBs.size() will change within the loop, so we query it every time
  1369. for (unsigned I = 0; I < BBs.size(); I++) {
  1370. BasicBlock *BB = BBs[I];
  1371. for (Instruction &I : *BB) {
  1372. if (isa<InvokeInst>(&I)) {
  1373. std::string S;
  1374. raw_string_ostream SS(S);
  1375. SS << "In function " << F.getName()
  1376. << ": When using Wasm EH with Emscripten SjLj, there is a "
  1377. "restriction that `setjmp` function call and exception cannot be "
  1378. "used within the same function:\n";
  1379. SS << I;
  1380. report_fatal_error(StringRef(SS.str()));
  1381. }
  1382. auto *CI = dyn_cast<CallInst>(&I);
  1383. if (!CI)
  1384. continue;
  1385. const Value *Callee = CI->getCalledOperand();
  1386. if (!canLongjmp(Callee))
  1387. continue;
  1388. if (isEmAsmCall(Callee))
  1389. report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
  1390. F.getName() +
  1391. ". Please consider using EM_JS, or move the "
  1392. "EM_ASM into another function.",
  1393. false);
  1394. Value *Threw = nullptr;
  1395. BasicBlock *Tail;
  1396. if (Callee->getName().startswith("__invoke_")) {
  1397. // If invoke wrapper has already been generated for this call in
  1398. // previous EH phase, search for the load instruction
  1399. // %__THREW__.val = __THREW__;
  1400. // in postamble after the invoke wrapper call
  1401. LoadInst *ThrewLI = nullptr;
  1402. StoreInst *ThrewResetSI = nullptr;
  1403. for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
  1404. I != IE; ++I) {
  1405. if (auto *LI = dyn_cast<LoadInst>(I))
  1406. if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
  1407. if (GV == ThrewGV) {
  1408. Threw = ThrewLI = LI;
  1409. break;
  1410. }
  1411. }
  1412. // Search for the store instruction after the load above
  1413. // __THREW__ = 0;
  1414. for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
  1415. I != IE; ++I) {
  1416. if (auto *SI = dyn_cast<StoreInst>(I)) {
  1417. if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
  1418. if (GV == ThrewGV &&
  1419. SI->getValueOperand() == getAddrSizeInt(&M, 0)) {
  1420. ThrewResetSI = SI;
  1421. break;
  1422. }
  1423. }
  1424. }
  1425. }
  1426. assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
  1427. assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
  1428. Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
  1429. } else {
  1430. // Wrap call with invoke wrapper and generate preamble/postamble
  1431. Threw = wrapInvoke(CI);
  1432. ToErase.push_back(CI);
  1433. Tail = SplitBlock(BB, CI->getNextNode());
  1434. // If exception handling is enabled, the thrown value can be not a
  1435. // longjmp but an exception, in which case we shouldn't silently ignore
  1436. // exceptions; we should rethrow them.
  1437. // __THREW__'s value is 0 when nothing happened, 1 when an exception is
  1438. // thrown, other values when longjmp is thrown.
  1439. //
  1440. // if (%__THREW__.val == 1)
  1441. // goto %eh.rethrow
  1442. // else
  1443. // goto %normal
  1444. //
  1445. // eh.rethrow: ;; Rethrow exception
  1446. // %exn = call @__cxa_find_matching_catch_2() ;; Retrieve thrown ptr
  1447. // __resumeException(%exn)
  1448. //
  1449. // normal:
  1450. // <-- Insertion point. Will insert sjlj handling code from here
  1451. // goto %tail
  1452. //
  1453. // tail:
  1454. // ...
  1455. if (supportsException(&F) && canThrow(Callee)) {
  1456. // We will add a new conditional branch. So remove the branch created
  1457. // when we split the BB
  1458. ToErase.push_back(BB->getTerminator());
  1459. // Generate rethrow.exn BB once and share it within the function
  1460. if (!RethrowExnBB) {
  1461. RethrowExnBB = BasicBlock::Create(C, "rethrow.exn", &F);
  1462. IRB.SetInsertPoint(RethrowExnBB);
  1463. CallInst *Exn =
  1464. IRB.CreateCall(getFindMatchingCatch(M, 0), {}, "exn");
  1465. IRB.CreateCall(ResumeF, {Exn});
  1466. IRB.CreateUnreachable();
  1467. }
  1468. IRB.SetInsertPoint(CI);
  1469. BasicBlock *NormalBB = BasicBlock::Create(C, "normal", &F);
  1470. Value *CmpEqOne =
  1471. IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
  1472. IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
  1473. IRB.SetInsertPoint(NormalBB);
  1474. IRB.CreateBr(Tail);
  1475. BB = NormalBB; // New insertion point to insert testSetjmp()
  1476. }
  1477. }
  1478. // We need to replace the terminator in Tail - SplitBlock makes BB go
  1479. // straight to Tail, we need to check if a longjmp occurred, and go to the
  1480. // right setjmp-tail if so
  1481. ToErase.push_back(BB->getTerminator());
  1482. // Generate a function call to testSetjmp function and preamble/postamble
  1483. // code to figure out (1) whether longjmp occurred (2) if longjmp
  1484. // occurred, which setjmp it corresponds to
  1485. Value *Label = nullptr;
  1486. Value *LongjmpResult = nullptr;
  1487. BasicBlock *EndBB = nullptr;
  1488. wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize,
  1489. Label, LongjmpResult, CallEmLongjmpBB,
  1490. CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI,
  1491. EndBB);
  1492. assert(Label && LongjmpResult && EndBB);
  1493. // Create switch instruction
  1494. IRB.SetInsertPoint(EndBB);
  1495. IRB.SetCurrentDebugLocation(EndBB->back().getDebugLoc());
  1496. SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
  1497. // -1 means no longjmp happened, continue normally (will hit the default
  1498. // switch case). 0 means a longjmp that is not ours to handle, needs a
  1499. // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
  1500. // 0).
  1501. for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
  1502. SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
  1503. SetjmpRetPHIs[I]->addIncoming(LongjmpResult, EndBB);
  1504. }
  1505. // We are splitting the block here, and must continue to find other calls
  1506. // in the block - which is now split. so continue to traverse in the Tail
  1507. BBs.push_back(Tail);
  1508. }
  1509. }
  1510. for (Instruction *I : ToErase)
  1511. I->eraseFromParent();
  1512. }
  1513. static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CPI) {
  1514. for (const User *U : CPI->users())
  1515. if (const auto *CRI = dyn_cast<CleanupReturnInst>(U))
  1516. return CRI->getUnwindDest();
  1517. return nullptr;
  1518. }
  1519. // Create a catchpad in which we catch a longjmp's env and val arguments, test
  1520. // if the longjmp corresponds to one of setjmps in the current function, and if
  1521. // so, jump to the setjmp dispatch BB from which we go to one of post-setjmp
  1522. // BBs. Refer to 4) of "Wasm setjmp/longjmp handling" section in the comments at
  1523. // top of the file for details.
  1524. void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
  1525. Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
  1526. SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
  1527. Module &M = *F.getParent();
  1528. LLVMContext &C = F.getContext();
  1529. IRBuilder<> IRB(C);
  1530. // A function with catchswitch/catchpad instruction should have a personality
  1531. // function attached to it. Search for the wasm personality function, and if
  1532. // it exists, use it, and if it doesn't, create a dummy personality function.
  1533. // (SjLj is not going to call it anyway.)
  1534. if (!F.hasPersonalityFn()) {
  1535. StringRef PersName = getEHPersonalityName(EHPersonality::Wasm_CXX);
  1536. FunctionType *PersType =
  1537. FunctionType::get(IRB.getInt32Ty(), /* isVarArg */ true);
  1538. Value *PersF = M.getOrInsertFunction(PersName, PersType).getCallee();
  1539. F.setPersonalityFn(
  1540. cast<Constant>(IRB.CreateBitCast(PersF, IRB.getInt8PtrTy())));
  1541. }
  1542. // Use the entry BB's debugloc as a fallback
  1543. BasicBlock *Entry = &F.getEntryBlock();
  1544. DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
  1545. IRB.SetCurrentDebugLocation(FirstDL);
  1546. // Arbitrarily use the ones defined in the beginning of the function.
  1547. // SSAUpdater will later update them to the correct values.
  1548. Instruction *SetjmpTable = *SetjmpTableInsts.begin();
  1549. Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
  1550. // Add setjmp.dispatch BB right after the entry block. Because we have
  1551. // initialized setjmpTable/setjmpTableSize in the entry block and split the
  1552. // rest into another BB, here 'OrigEntry' is the function's original entry
  1553. // block before the transformation.
  1554. //
  1555. // entry:
  1556. // setjmpTable / setjmpTableSize initialization
  1557. // setjmp.dispatch:
  1558. // switch will be inserted here later
  1559. // entry.split: (OrigEntry)
  1560. // the original function starts here
  1561. BasicBlock *OrigEntry = Entry->getNextNode();
  1562. BasicBlock *SetjmpDispatchBB =
  1563. BasicBlock::Create(C, "setjmp.dispatch", &F, OrigEntry);
  1564. cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
  1565. // Create catch.dispatch.longjmp BB and a catchswitch instruction
  1566. BasicBlock *CatchDispatchLongjmpBB =
  1567. BasicBlock::Create(C, "catch.dispatch.longjmp", &F);
  1568. IRB.SetInsertPoint(CatchDispatchLongjmpBB);
  1569. CatchSwitchInst *CatchSwitchLongjmp =
  1570. IRB.CreateCatchSwitch(ConstantTokenNone::get(C), nullptr, 1);
  1571. // Create catch.longjmp BB and a catchpad instruction
  1572. BasicBlock *CatchLongjmpBB = BasicBlock::Create(C, "catch.longjmp", &F);
  1573. CatchSwitchLongjmp->addHandler(CatchLongjmpBB);
  1574. IRB.SetInsertPoint(CatchLongjmpBB);
  1575. CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
  1576. // Wasm throw and catch instructions can throw and catch multiple values, but
  1577. // that requires multivalue support in the toolchain, which is currently not
  1578. // very reliable. We instead throw and catch a pointer to a struct value of
  1579. // type 'struct __WasmLongjmpArgs', which is defined in Emscripten.
  1580. Instruction *CatchCI =
  1581. IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::C_LONGJMP)}, "thrown");
  1582. Value *LongjmpArgs =
  1583. IRB.CreateBitCast(CatchCI, LongjmpArgsTy->getPointerTo(), "longjmp.args");
  1584. Value *EnvField =
  1585. IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0, "env_gep");
  1586. Value *ValField =
  1587. IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1, "val_gep");
  1588. // void *env = __wasm_longjmp_args.env;
  1589. Instruction *Env = IRB.CreateLoad(IRB.getInt8PtrTy(), EnvField, "env");
  1590. // int val = __wasm_longjmp_args.val;
  1591. Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField, "val");
  1592. // %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize);
  1593. // if (%label == 0)
  1594. // __wasm_longjmp(%env, %val)
  1595. // catchret to %setjmp.dispatch
  1596. BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", &F);
  1597. BasicBlock *EndBB = BasicBlock::Create(C, "if.end", &F);
  1598. Value *EnvP = IRB.CreateBitCast(Env, getAddrPtrType(&M), "env.p");
  1599. Value *SetjmpID = IRB.CreateLoad(getAddrIntType(&M), EnvP, "setjmp.id");
  1600. Value *Label =
  1601. IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize},
  1602. OperandBundleDef("funclet", CatchPad), "label");
  1603. Value *Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
  1604. IRB.CreateCondBr(Cmp, ThenBB, EndBB);
  1605. IRB.SetInsertPoint(ThenBB);
  1606. CallInst *WasmLongjmpCI = IRB.CreateCall(
  1607. WasmLongjmpF, {Env, Val}, OperandBundleDef("funclet", CatchPad));
  1608. IRB.CreateUnreachable();
  1609. IRB.SetInsertPoint(EndBB);
  1610. // Jump to setjmp.dispatch block
  1611. IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
  1612. // Go back to setjmp.dispatch BB
  1613. // setjmp.dispatch:
  1614. // switch %label {
  1615. // label 1: goto post-setjmp BB 1
  1616. // label 2: goto post-setjmp BB 2
  1617. // ...
  1618. // default: goto splitted next BB
  1619. // }
  1620. IRB.SetInsertPoint(SetjmpDispatchBB);
  1621. PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label.phi");
  1622. LabelPHI->addIncoming(Label, EndBB);
  1623. LabelPHI->addIncoming(IRB.getInt32(-1), Entry);
  1624. SwitchInst *SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.size());
  1625. // -1 means no longjmp happened, continue normally (will hit the default
  1626. // switch case). 0 means a longjmp that is not ours to handle, needs a
  1627. // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
  1628. // 0).
  1629. for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
  1630. SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
  1631. SetjmpRetPHIs[I]->addIncoming(Val, SetjmpDispatchBB);
  1632. }
  1633. // Convert all longjmpable call instructions to invokes that unwind to the
  1634. // newly created catch.dispatch.longjmp BB.
  1635. SmallVector<CallInst *, 64> LongjmpableCalls;
  1636. for (auto *BB = &*F.begin(); BB; BB = BB->getNextNode()) {
  1637. for (auto &I : *BB) {
  1638. auto *CI = dyn_cast<CallInst>(&I);
  1639. if (!CI)
  1640. continue;
  1641. const Value *Callee = CI->getCalledOperand();
  1642. if (!canLongjmp(Callee))
  1643. continue;
  1644. if (isEmAsmCall(Callee))
  1645. report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
  1646. F.getName() +
  1647. ". Please consider using EM_JS, or move the "
  1648. "EM_ASM into another function.",
  1649. false);
  1650. // This is __wasm_longjmp() call we inserted in this function, which
  1651. // rethrows the longjmp when the longjmp does not correspond to one of
  1652. // setjmps in this function. We should not convert this call to an invoke.
  1653. if (CI == WasmLongjmpCI)
  1654. continue;
  1655. LongjmpableCalls.push_back(CI);
  1656. }
  1657. }
  1658. for (auto *CI : LongjmpableCalls) {
  1659. // Even if the callee function has attribute 'nounwind', which is true for
  1660. // all C functions, it can longjmp, which means it can throw a Wasm
  1661. // exception now.
  1662. CI->removeFnAttr(Attribute::NoUnwind);
  1663. if (Function *CalleeF = CI->getCalledFunction())
  1664. CalleeF->removeFnAttr(Attribute::NoUnwind);
  1665. // Change it to an invoke and make it unwind to the catch.dispatch.longjmp
  1666. // BB. If the call is enclosed in another catchpad/cleanuppad scope, unwind
  1667. // to its parent pad's unwind destination instead to preserve the scope
  1668. // structure. It will eventually unwind to the catch.dispatch.longjmp.
  1669. SmallVector<OperandBundleDef, 1> Bundles;
  1670. BasicBlock *UnwindDest = nullptr;
  1671. if (auto Bundle = CI->getOperandBundle(LLVMContext::OB_funclet)) {
  1672. Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
  1673. while (!UnwindDest) {
  1674. if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
  1675. UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
  1676. break;
  1677. }
  1678. if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
  1679. // getCleanupRetUnwindDest() can return nullptr when
  1680. // 1. This cleanuppad's matching cleanupret uwninds to caller
  1681. // 2. There is no matching cleanupret because it ends with
  1682. // unreachable.
  1683. // In case of 2, we need to traverse the parent pad chain.
  1684. UnwindDest = getCleanupRetUnwindDest(CPI);
  1685. Value *ParentPad = CPI->getParentPad();
  1686. if (isa<ConstantTokenNone>(ParentPad))
  1687. break;
  1688. FromPad = cast<Instruction>(ParentPad);
  1689. }
  1690. }
  1691. }
  1692. if (!UnwindDest)
  1693. UnwindDest = CatchDispatchLongjmpBB;
  1694. changeToInvokeAndSplitBasicBlock(CI, UnwindDest);
  1695. }
  1696. SmallVector<Instruction *, 16> ToErase;
  1697. for (auto &BB : F) {
  1698. if (auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
  1699. if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
  1700. IRB.SetInsertPoint(CSI);
  1701. ToErase.push_back(CSI);
  1702. auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
  1703. CatchDispatchLongjmpBB, 1);
  1704. NewCSI->addHandler(*CSI->handler_begin());
  1705. NewCSI->takeName(CSI);
  1706. CSI->replaceAllUsesWith(NewCSI);
  1707. }
  1708. }
  1709. if (auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
  1710. if (CRI->unwindsToCaller()) {
  1711. IRB.SetInsertPoint(CRI);
  1712. ToErase.push_back(CRI);
  1713. IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
  1714. }
  1715. }
  1716. }
  1717. for (Instruction *I : ToErase)
  1718. I->eraseFromParent();
  1719. }