WebAssemblyLowerEmscriptenEHSjLj.cpp revision 344779
1311116Sdim//=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
2311116Sdim//
3311116Sdim//                     The LLVM Compiler Infrastructure
4311116Sdim//
5311116Sdim// This file is distributed under the University of Illinois Open Source
6311116Sdim// License. See LICENSE.TXT for details.
7311116Sdim//
8311116Sdim//===----------------------------------------------------------------------===//
9311116Sdim///
10311116Sdim/// \file
11341825Sdim/// This file lowers exception-related instructions and setjmp/longjmp
12311116Sdim/// function calls in order to use Emscripten's JavaScript try and catch
13311116Sdim/// mechanism.
14311116Sdim///
15311116Sdim/// To handle exceptions and setjmp/longjmps, this scheme relies on JavaScript's
16311116Sdim/// try and catch syntax and relevant exception-related libraries implemented
17311116Sdim/// in JavaScript glue code that will be produced by Emscripten. This is similar
18311116Sdim/// to the current Emscripten asm.js exception handling in fastcomp. For
19311116Sdim/// fastcomp's EH / SjLj scheme, see these files in fastcomp LLVM branch:
20311116Sdim/// (Location: https://github.com/kripken/emscripten-fastcomp)
21311116Sdim/// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp
22311116Sdim/// lib/Target/JSBackend/NaCl/LowerEmSetjmp.cpp
23311116Sdim/// lib/Target/JSBackend/JSBackend.cpp
24311116Sdim/// lib/Target/JSBackend/CallHandlers.h
25311116Sdim///
26311116Sdim/// * Exception handling
27311116Sdim/// This pass lowers invokes and landingpads into library functions in JS glue
28311116Sdim/// code. Invokes are lowered into function wrappers called invoke wrappers that
29311116Sdim/// exist in JS side, which wraps the original function call with JS try-catch.
30311116Sdim/// If an exception occurred, cxa_throw() function in JS side sets some
31311116Sdim/// variables (see below) so we can check whether an exception occurred from
32311116Sdim/// wasm code and handle it appropriately.
33311116Sdim///
34311116Sdim/// * Setjmp-longjmp handling
35311116Sdim/// This pass lowers setjmp to a reasonably-performant approach for emscripten.
36311116Sdim/// The idea is that each block with a setjmp is broken up into two parts: the
37311116Sdim/// part containing setjmp and the part right after the setjmp. The latter part
38311116Sdim/// is either reached from the setjmp, or later from a longjmp. To handle the
39311116Sdim/// longjmp, all calls that might longjmp are also called using invoke wrappers
40311116Sdim/// and thus JS / try-catch. JS longjmp() function also sets some variables so
41311116Sdim/// we can check / whether a longjmp occurred from wasm code. Each block with a
42311116Sdim/// function call that might longjmp is also split up after the longjmp call.
43311116Sdim/// After the longjmp call, we check whether a longjmp occurred, and if it did,
44311116Sdim/// which setjmp it corresponds to, and jump to the right post-setjmp block.
45311116Sdim/// We assume setjmp-longjmp handling always run after EH handling, which means
46311116Sdim/// we don't expect any exception-related instructions when SjLj runs.
47311116Sdim/// FIXME Currently this scheme does not support indirect call of setjmp,
48311116Sdim/// because of the limitation of the scheme itself. fastcomp does not support it
49311116Sdim/// either.
50311116Sdim///
51311116Sdim/// In detail, this pass does following things:
52311116Sdim///
53344779Sdim/// 1) Assumes the existence of global variables: __THREW__, __threwValue
54344779Sdim///    __THREW__ and __threwValue will be set in invoke wrappers
55311116Sdim///    in JS glue code. For what invoke wrappers are, refer to 3). These
56311116Sdim///    variables are used for both exceptions and setjmp/longjmps.
57311116Sdim///    __THREW__ indicates whether an exception or a longjmp occurred or not. 0
58311116Sdim///    means nothing occurred, 1 means an exception occurred, and other numbers
59311116Sdim///    mean a longjmp occurred. In the case of longjmp, __threwValue variable
60311116Sdim///    indicates the corresponding setjmp buffer the longjmp corresponds to.
61311116Sdim///
62311116Sdim/// * Exception handling
63311116Sdim///
64344779Sdim/// 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
65344779Sdim///    at link time.
66344779Sdim///    The global variables in 1) will exist in wasm address space,
67344779Sdim///    but their values should be set in JS code, so these functions
68311116Sdim///    as interfaces to JS glue code. These functions are equivalent to the
69311116Sdim///    following JS functions, which actually exist in asm.js version of JS
70311116Sdim///    library.
71311116Sdim///
72311116Sdim///    function setThrew(threw, value) {
73311116Sdim///      if (__THREW__ == 0) {
74311116Sdim///        __THREW__ = threw;
75311116Sdim///        __threwValue = value;
76311116Sdim///      }
77311116Sdim///    }
78344779Sdim//
79344779Sdim///    setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
80311116Sdim///
81344779Sdim///    In exception handling, getTempRet0 indicates the type of an exception
82344779Sdim///    caught, and in setjmp/longjmp, it means the second argument to longjmp
83344779Sdim///    function.
84311116Sdim///
85311116Sdim/// 3) Lower
86311116Sdim///      invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
87311116Sdim///    into
88311116Sdim///      __THREW__ = 0;
89311116Sdim///      call @__invoke_SIG(func, arg1, arg2)
90311116Sdim///      %__THREW__.val = __THREW__;
91311116Sdim///      __THREW__ = 0;
92311116Sdim///      if (%__THREW__.val == 1)
93311116Sdim///        goto %lpad
94311116Sdim///      else
95311116Sdim///         goto %invoke.cont
96311116Sdim///    SIG is a mangled string generated based on the LLVM IR-level function
97311116Sdim///    signature. After LLVM IR types are lowered to the target wasm types,
98311116Sdim///    the names for these wrappers will change based on wasm types as well,
99311116Sdim///    as in invoke_vi (function takes an int and returns void). The bodies of
100311116Sdim///    these wrappers will be generated in JS glue code, and inside those
101311116Sdim///    wrappers we use JS try-catch to generate actual exception effects. It
102311116Sdim///    also calls the original callee function. An example wrapper in JS code
103311116Sdim///    would look like this:
104311116Sdim///      function invoke_vi(index,a1) {
105311116Sdim///        try {
106311116Sdim///          Module["dynCall_vi"](index,a1); // This calls original callee
107311116Sdim///        } catch(e) {
108311116Sdim///          if (typeof e !== 'number' && e !== 'longjmp') throw e;
109311116Sdim///          asm["setThrew"](1, 0); // setThrew is called here
110311116Sdim///        }
111311116Sdim///      }
112311116Sdim///    If an exception is thrown, __THREW__ will be set to true in a wrapper,
113311116Sdim///    so we can jump to the right BB based on this value.
114311116Sdim///
115311116Sdim/// 4) Lower
116311116Sdim///      %val = landingpad catch c1 catch c2 catch c3 ...
117311116Sdim///      ... use %val ...
118311116Sdim///    into
119311116Sdim///      %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
120344779Sdim///      %val = {%fmc, getTempRet0()}
121311116Sdim///      ... use %val ...
122311116Sdim///    Here N is a number calculated based on the number of clauses.
123344779Sdim///    setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
124311116Sdim///
125311116Sdim/// 5) Lower
126311116Sdim///      resume {%a, %b}
127311116Sdim///    into
128311116Sdim///      call @__resumeException(%a)
129311116Sdim///    where __resumeException() is a function in JS glue code.
130311116Sdim///
131311116Sdim/// 6) Lower
132311116Sdim///      call @llvm.eh.typeid.for(type) (intrinsic)
133311116Sdim///    into
134311116Sdim///      call @llvm_eh_typeid_for(type)
135311116Sdim///    llvm_eh_typeid_for function will be generated in JS glue code.
136311116Sdim///
137311116Sdim/// * Setjmp / Longjmp handling
138311116Sdim///
139344779Sdim/// In case calls to longjmp() exists
140344779Sdim///
141344779Sdim/// 1) Lower
142344779Sdim///      longjmp(buf, value)
143344779Sdim///    into
144344779Sdim///      emscripten_longjmp_jmpbuf(buf, value)
145344779Sdim///    emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later.
146344779Sdim///
147344779Sdim/// In case calls to setjmp() exists
148344779Sdim///
149344779Sdim/// 2) In the function entry that calls setjmp, initialize setjmpTable and
150311116Sdim///    sejmpTableSize as follows:
151311116Sdim///      setjmpTableSize = 4;
152311116Sdim///      setjmpTable = (int *) malloc(40);
153311116Sdim///      setjmpTable[0] = 0;
154311116Sdim///    setjmpTable and setjmpTableSize are used in saveSetjmp() function in JS
155311116Sdim///    code.
156311116Sdim///
157344779Sdim/// 3) Lower
158311116Sdim///      setjmp(buf)
159311116Sdim///    into
160311116Sdim///      setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
161344779Sdim///      setjmpTableSize = getTempRet0();
162311116Sdim///    For each dynamic setjmp call, setjmpTable stores its ID (a number which
163311116Sdim///    is incrementally assigned from 0) and its label (a unique number that
164311116Sdim///    represents each callsite of setjmp). When we need more entries in
165311116Sdim///    setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
166311116Sdim///    return the new table address, and assign the new table size in
167344779Sdim///    setTempRet0(). saveSetjmp also stores the setjmp's ID into the buffer
168344779Sdim///    buf. A BB with setjmp is split into two after setjmp call in order to
169344779Sdim///    make the post-setjmp BB the possible destination of longjmp BB.
170311116Sdim///
171311116Sdim///
172344779Sdim/// 4) Lower every call that might longjmp into
173311116Sdim///      __THREW__ = 0;
174311116Sdim///      call @__invoke_SIG(func, arg1, arg2)
175311116Sdim///      %__THREW__.val = __THREW__;
176311116Sdim///      __THREW__ = 0;
177311116Sdim///      if (%__THREW__.val != 0 & __threwValue != 0) {
178311116Sdim///        %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
179311116Sdim///                            setjmpTableSize);
180311116Sdim///        if (%label == 0)
181311116Sdim///          emscripten_longjmp(%__THREW__.val, __threwValue);
182344779Sdim///        setTempRet0(__threwValue);
183311116Sdim///      } else {
184311116Sdim///        %label = -1;
185311116Sdim///      }
186344779Sdim///      longjmp_result = getTempRet0();
187311116Sdim///      switch label {
188311116Sdim///        label 1: goto post-setjmp BB 1
189311116Sdim///        label 2: goto post-setjmp BB 2
190311116Sdim///        ...
191311116Sdim///        default: goto splitted next BB
192311116Sdim///      }
193344779Sdim///    testSetjmp examines setjmpTable to see if there is a matching setjmp
194344779Sdim///    call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
195344779Sdim///    will be the address of matching jmp_buf buffer and __threwValue be the
196344779Sdim///    second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is
197344779Sdim///    stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
198344779Sdim///    each setjmp callsite. Label 0 means this longjmp buffer does not
199344779Sdim///    correspond to one of the setjmp callsites in this function, so in this
200344779Sdim///    case we just chain the longjmp to the caller. (Here we call
201344779Sdim///    emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf.
202344779Sdim///    emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while
203344779Sdim///    emscripten_longjmp takes an int. Both of them will eventually be lowered
204344779Sdim///    to emscripten_longjmp in s2wasm, but here we need two signatures - we
205344779Sdim///    can't translate an int value to a jmp_buf.)
206344779Sdim///    Label -1 means no longjmp occurred. Otherwise we jump to the right
207344779Sdim///    post-setjmp BB based on the label.
208311116Sdim///
209311116Sdim///===----------------------------------------------------------------------===//
210311116Sdim
211311116Sdim#include "WebAssembly.h"
212311116Sdim#include "llvm/IR/CallSite.h"
213311116Sdim#include "llvm/IR/Dominators.h"
214311116Sdim#include "llvm/IR/IRBuilder.h"
215311116Sdim#include "llvm/Transforms/Utils/BasicBlockUtils.h"
216311116Sdim#include "llvm/Transforms/Utils/SSAUpdater.h"
217311116Sdim
218311116Sdimusing namespace llvm;
219311116Sdim
220311116Sdim#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
221311116Sdim
222311116Sdimstatic cl::list<std::string>
223311116Sdim    EHWhitelist("emscripten-cxx-exceptions-whitelist",
224311116Sdim                cl::desc("The list of function names in which Emscripten-style "
225311116Sdim                         "exception handling is enabled (see emscripten "
226311116Sdim                         "EMSCRIPTEN_CATCHING_WHITELIST options)"),
227311116Sdim                cl::CommaSeparated);
228311116Sdim
229311116Sdimnamespace {
230311116Sdimclass WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
231311116Sdim  static const char *ResumeFName;
232311116Sdim  static const char *EHTypeIDFName;
233311116Sdim  static const char *EmLongjmpFName;
234311116Sdim  static const char *EmLongjmpJmpbufFName;
235311116Sdim  static const char *SaveSetjmpFName;
236311116Sdim  static const char *TestSetjmpFName;
237311116Sdim  static const char *FindMatchingCatchPrefix;
238311116Sdim  static const char *InvokePrefix;
239311116Sdim
240311116Sdim  bool EnableEH;   // Enable exception handling
241311116Sdim  bool EnableSjLj; // Enable setjmp/longjmp handling
242311116Sdim
243311116Sdim  GlobalVariable *ThrewGV;
244311116Sdim  GlobalVariable *ThrewValueGV;
245344779Sdim  Function *GetTempRet0Func;
246344779Sdim  Function *SetTempRet0Func;
247311116Sdim  Function *ResumeF;
248311116Sdim  Function *EHTypeIDF;
249311116Sdim  Function *EmLongjmpF;
250311116Sdim  Function *EmLongjmpJmpbufF;
251311116Sdim  Function *SaveSetjmpF;
252311116Sdim  Function *TestSetjmpF;
253311116Sdim
254311116Sdim  // __cxa_find_matching_catch_N functions.
255311116Sdim  // Indexed by the number of clauses in an original landingpad instruction.
256311116Sdim  DenseMap<int, Function *> FindMatchingCatches;
257311116Sdim  // Map of <function signature string, invoke_ wrappers>
258311116Sdim  StringMap<Function *> InvokeWrappers;
259311116Sdim  // Set of whitelisted function names for exception handling
260311116Sdim  std::set<std::string> EHWhitelistSet;
261311116Sdim
262311116Sdim  StringRef getPassName() const override {
263311116Sdim    return "WebAssembly Lower Emscripten Exceptions";
264311116Sdim  }
265311116Sdim
266311116Sdim  bool runEHOnFunction(Function &F);
267311116Sdim  bool runSjLjOnFunction(Function &F);
268311116Sdim  Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
269311116Sdim
270311116Sdim  template <typename CallOrInvoke> Value *wrapInvoke(CallOrInvoke *CI);
271311116Sdim  void wrapTestSetjmp(BasicBlock *BB, Instruction *InsertPt, Value *Threw,
272311116Sdim                      Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
273311116Sdim                      Value *&LongjmpResult, BasicBlock *&EndBB);
274311116Sdim  template <typename CallOrInvoke> Function *getInvokeWrapper(CallOrInvoke *CI);
275311116Sdim
276311116Sdim  bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
277311116Sdim  bool canLongjmp(Module &M, const Value *Callee) const;
278311116Sdim
279311116Sdim  void rebuildSSA(Function &F);
280311116Sdim
281311116Sdimpublic:
282311116Sdim  static char ID;
283311116Sdim
284311116Sdim  WebAssemblyLowerEmscriptenEHSjLj(bool EnableEH = true, bool EnableSjLj = true)
285311116Sdim      : ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
286344779Sdim        ThrewGV(nullptr), ThrewValueGV(nullptr), GetTempRet0Func(nullptr),
287344779Sdim        SetTempRet0Func(nullptr), ResumeF(nullptr), EHTypeIDF(nullptr),
288344779Sdim        EmLongjmpF(nullptr), EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr),
289344779Sdim        TestSetjmpF(nullptr) {
290311116Sdim    EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
291311116Sdim  }
292311116Sdim  bool runOnModule(Module &M) override;
293311116Sdim
294311116Sdim  void getAnalysisUsage(AnalysisUsage &AU) const override {
295311116Sdim    AU.addRequired<DominatorTreeWrapperPass>();
296311116Sdim  }
297311116Sdim};
298311116Sdim} // End anonymous namespace
299311116Sdim
300311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException";
301311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
302311116Sdim    "llvm_eh_typeid_for";
303311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
304311116Sdim    "emscripten_longjmp";
305311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
306311116Sdim    "emscripten_longjmp_jmpbuf";
307311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName = "saveSetjmp";
308311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName = "testSetjmp";
309311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
310311116Sdim    "__cxa_find_matching_catch_";
311311116Sdimconst char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
312311116Sdim
313311116Sdimchar WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
314311116SdimINITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
315311116Sdim                "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
316311116Sdim                false, false)
317311116Sdim
318311116SdimModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool EnableEH,
319311116Sdim                                                         bool EnableSjLj) {
320311116Sdim  return new WebAssemblyLowerEmscriptenEHSjLj(EnableEH, EnableSjLj);
321311116Sdim}
322311116Sdim
323311116Sdimstatic bool canThrow(const Value *V) {
324311116Sdim  if (const auto *F = dyn_cast<const Function>(V)) {
325311116Sdim    // Intrinsics cannot throw
326311116Sdim    if (F->isIntrinsic())
327311116Sdim      return false;
328311116Sdim    StringRef Name = F->getName();
329311116Sdim    // leave setjmp and longjmp (mostly) alone, we process them properly later
330311116Sdim    if (Name == "setjmp" || Name == "longjmp")
331311116Sdim      return false;
332311116Sdim    return !F->doesNotThrow();
333311116Sdim  }
334311116Sdim  // not a function, so an indirect call - can throw, we can't tell
335311116Sdim  return true;
336311116Sdim}
337311116Sdim
338344779Sdim// Get a global variable with the given name.  If it doesn't exist declare it,
339344779Sdim// which will generate an import and asssumes that it will exist at link time.
340344779Sdimstatic GlobalVariable *getGlobalVariableI32(Module &M, IRBuilder<> &IRB,
341344779Sdim                                            const char *Name) {
342341825Sdim  if (M.getNamedGlobal(Name))
343341825Sdim    report_fatal_error(Twine("variable name is reserved: ") + Name);
344341825Sdim
345341825Sdim  return new GlobalVariable(M, IRB.getInt32Ty(), false,
346344779Sdim                            GlobalValue::ExternalLinkage, nullptr, Name);
347311116Sdim}
348311116Sdim
349311116Sdim// Simple function name mangler.
350311116Sdim// This function simply takes LLVM's string representation of parameter types
351311116Sdim// and concatenate them with '_'. There are non-alphanumeric characters but llc
352311116Sdim// is ok with it, and we need to postprocess these names after the lowering
353311116Sdim// phase anyway.
354311116Sdimstatic std::string getSignature(FunctionType *FTy) {
355311116Sdim  std::string Sig;
356311116Sdim  raw_string_ostream OS(Sig);
357311116Sdim  OS << *FTy->getReturnType();
358311116Sdim  for (Type *ParamTy : FTy->params())
359311116Sdim    OS << "_" << *ParamTy;
360311116Sdim  if (FTy->isVarArg())
361311116Sdim    OS << "_...";
362311116Sdim  Sig = OS.str();
363311116Sdim  Sig.erase(remove_if(Sig, isspace), Sig.end());
364311116Sdim  // When s2wasm parses .s file, a comma means the end of an argument. So a
365311116Sdim  // mangled function name can contain any character but a comma.
366311116Sdim  std::replace(Sig.begin(), Sig.end(), ',', '.');
367311116Sdim  return Sig;
368311116Sdim}
369311116Sdim
370311116Sdim// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
371311116Sdim// This is because a landingpad instruction contains two more arguments, a
372311116Sdim// personality function and a cleanup bit, and __cxa_find_matching_catch_N
373311116Sdim// functions are named after the number of arguments in the original landingpad
374311116Sdim// instruction.
375311116SdimFunction *
376311116SdimWebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
377311116Sdim                                                       unsigned NumClauses) {
378311116Sdim  if (FindMatchingCatches.count(NumClauses))
379311116Sdim    return FindMatchingCatches[NumClauses];
380311116Sdim  PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
381311116Sdim  SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
382311116Sdim  FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
383311116Sdim  Function *F =
384311116Sdim      Function::Create(FTy, GlobalValue::ExternalLinkage,
385311116Sdim                       FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
386311116Sdim  FindMatchingCatches[NumClauses] = F;
387311116Sdim  return F;
388311116Sdim}
389311116Sdim
390311116Sdim// Generate invoke wrapper seqence with preamble and postamble
391311116Sdim// Preamble:
392311116Sdim// __THREW__ = 0;
393311116Sdim// Postamble:
394311116Sdim// %__THREW__.val = __THREW__; __THREW__ = 0;
395311116Sdim// Returns %__THREW__.val, which indicates whether an exception is thrown (or
396311116Sdim// whether longjmp occurred), for future use.
397311116Sdimtemplate <typename CallOrInvoke>
398311116SdimValue *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
399311116Sdim  LLVMContext &C = CI->getModule()->getContext();
400311116Sdim
401311116Sdim  // If we are calling a function that is noreturn, we must remove that
402311116Sdim  // attribute. The code we insert here does expect it to return, after we
403311116Sdim  // catch the exception.
404311116Sdim  if (CI->doesNotReturn()) {
405311116Sdim    if (auto *F = dyn_cast<Function>(CI->getCalledValue()))
406311116Sdim      F->removeFnAttr(Attribute::NoReturn);
407321369Sdim    CI->removeAttribute(AttributeList::FunctionIndex, Attribute::NoReturn);
408311116Sdim  }
409311116Sdim
410311116Sdim  IRBuilder<> IRB(C);
411311116Sdim  IRB.SetInsertPoint(CI);
412311116Sdim
413311116Sdim  // Pre-invoke
414311116Sdim  // __THREW__ = 0;
415311116Sdim  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
416311116Sdim
417311116Sdim  // Invoke function wrapper in JavaScript
418311116Sdim  SmallVector<Value *, 16> Args;
419311116Sdim  // Put the pointer to the callee as first argument, so it can be called
420311116Sdim  // within the invoke wrapper later
421311116Sdim  Args.push_back(CI->getCalledValue());
422311116Sdim  Args.append(CI->arg_begin(), CI->arg_end());
423311116Sdim  CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
424311116Sdim  NewCall->takeName(CI);
425311116Sdim  NewCall->setCallingConv(CI->getCallingConv());
426311116Sdim  NewCall->setDebugLoc(CI->getDebugLoc());
427311116Sdim
428311116Sdim  // Because we added the pointer to the callee as first argument, all
429311116Sdim  // argument attribute indices have to be incremented by one.
430321369Sdim  SmallVector<AttributeSet, 8> ArgAttributes;
431321369Sdim  const AttributeList &InvokeAL = CI->getAttributes();
432321369Sdim
433321369Sdim  // No attributes for the callee pointer.
434321369Sdim  ArgAttributes.push_back(AttributeSet());
435321369Sdim  // Copy the argument attributes from the original
436321369Sdim  for (unsigned i = 0, e = CI->getNumArgOperands(); i < e; ++i)
437321369Sdim    ArgAttributes.push_back(InvokeAL.getParamAttributes(i));
438321369Sdim
439311116Sdim  // Reconstruct the AttributesList based on the vector we constructed.
440321369Sdim  AttributeList NewCallAL =
441321369Sdim      AttributeList::get(C, InvokeAL.getFnAttributes(),
442321369Sdim                         InvokeAL.getRetAttributes(), ArgAttributes);
443321369Sdim  NewCall->setAttributes(NewCallAL);
444311116Sdim
445311116Sdim  CI->replaceAllUsesWith(NewCall);
446311116Sdim
447311116Sdim  // Post-invoke
448311116Sdim  // %__THREW__.val = __THREW__; __THREW__ = 0;
449311116Sdim  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
450311116Sdim  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
451311116Sdim  return Threw;
452311116Sdim}
453311116Sdim
454311116Sdim// Get matching invoke wrapper based on callee signature
455311116Sdimtemplate <typename CallOrInvoke>
456311116SdimFunction *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
457311116Sdim  Module *M = CI->getModule();
458311116Sdim  SmallVector<Type *, 16> ArgTys;
459311116Sdim  Value *Callee = CI->getCalledValue();
460311116Sdim  FunctionType *CalleeFTy;
461311116Sdim  if (auto *F = dyn_cast<Function>(Callee))
462311116Sdim    CalleeFTy = F->getFunctionType();
463311116Sdim  else {
464311116Sdim    auto *CalleeTy = cast<PointerType>(Callee->getType())->getElementType();
465311116Sdim    CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
466311116Sdim  }
467311116Sdim
468311116Sdim  std::string Sig = getSignature(CalleeFTy);
469311116Sdim  if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
470311116Sdim    return InvokeWrappers[Sig];
471311116Sdim
472311116Sdim  // Put the pointer to the callee as first argument
473311116Sdim  ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
474311116Sdim  // Add argument types
475311116Sdim  ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
476311116Sdim
477311116Sdim  FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
478311116Sdim                                        CalleeFTy->isVarArg());
479311116Sdim  Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
480311116Sdim                                 InvokePrefix + Sig, M);
481311116Sdim  InvokeWrappers[Sig] = F;
482311116Sdim  return F;
483311116Sdim}
484311116Sdim
485311116Sdimbool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
486311116Sdim                                                  const Value *Callee) const {
487311116Sdim  if (auto *CalleeF = dyn_cast<Function>(Callee))
488311116Sdim    if (CalleeF->isIntrinsic())
489311116Sdim      return false;
490311116Sdim
491311116Sdim  // The reason we include malloc/free here is to exclude the malloc/free
492311116Sdim  // calls generated in setjmp prep / cleanup routines.
493311116Sdim  Function *SetjmpF = M.getFunction("setjmp");
494311116Sdim  Function *MallocF = M.getFunction("malloc");
495311116Sdim  Function *FreeF = M.getFunction("free");
496311116Sdim  if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
497311116Sdim    return false;
498311116Sdim
499311116Sdim  // There are functions in JS glue code
500311116Sdim  if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
501311116Sdim      Callee == TestSetjmpF)
502311116Sdim    return false;
503311116Sdim
504311116Sdim  // __cxa_find_matching_catch_N functions cannot longjmp
505311116Sdim  if (Callee->getName().startswith(FindMatchingCatchPrefix))
506311116Sdim    return false;
507311116Sdim
508311116Sdim  // Exception-catching related functions
509311116Sdim  Function *BeginCatchF = M.getFunction("__cxa_begin_catch");
510311116Sdim  Function *EndCatchF = M.getFunction("__cxa_end_catch");
511311116Sdim  Function *AllocExceptionF = M.getFunction("__cxa_allocate_exception");
512311116Sdim  Function *ThrowF = M.getFunction("__cxa_throw");
513311116Sdim  Function *TerminateF = M.getFunction("__clang_call_terminate");
514311116Sdim  if (Callee == BeginCatchF || Callee == EndCatchF ||
515344779Sdim      Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF ||
516344779Sdim      Callee == GetTempRet0Func || Callee == SetTempRet0Func)
517311116Sdim    return false;
518311116Sdim
519311116Sdim  // Otherwise we don't know
520311116Sdim  return true;
521311116Sdim}
522311116Sdim
523311116Sdim// Generate testSetjmp function call seqence with preamble and postamble.
524311116Sdim// The code this generates is equivalent to the following JavaScript code:
525311116Sdim// if (%__THREW__.val != 0 & threwValue != 0) {
526311116Sdim//   %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
527311116Sdim//   if (%label == 0)
528311116Sdim//     emscripten_longjmp(%__THREW__.val, threwValue);
529344779Sdim//   setTempRet0(threwValue);
530311116Sdim// } else {
531311116Sdim//   %label = -1;
532311116Sdim// }
533344779Sdim// %longjmp_result = getTempRet0();
534311116Sdim//
535311116Sdim// As output parameters. returns %label, %longjmp_result, and the BB the last
536311116Sdim// instruction (%longjmp_result = ...) is in.
537311116Sdimvoid WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
538311116Sdim    BasicBlock *BB, Instruction *InsertPt, Value *Threw, Value *SetjmpTable,
539311116Sdim    Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
540311116Sdim    BasicBlock *&EndBB) {
541311116Sdim  Function *F = BB->getParent();
542311116Sdim  LLVMContext &C = BB->getModule()->getContext();
543311116Sdim  IRBuilder<> IRB(C);
544311116Sdim  IRB.SetInsertPoint(InsertPt);
545311116Sdim
546311116Sdim  // if (%__THREW__.val != 0 & threwValue != 0)
547311116Sdim  IRB.SetInsertPoint(BB);
548311116Sdim  BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
549311116Sdim  BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
550311116Sdim  BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
551311116Sdim  Value *ThrewCmp = IRB.CreateICmpNE(Threw, IRB.getInt32(0));
552311116Sdim  Value *ThrewValue =
553311116Sdim      IRB.CreateLoad(ThrewValueGV, ThrewValueGV->getName() + ".val");
554311116Sdim  Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
555311116Sdim  Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
556311116Sdim  IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
557311116Sdim
558311116Sdim  // %label = _testSetjmp(mem[%__THREW__.val], _setjmpTable, _setjmpTableSize);
559311116Sdim  // if (%label == 0)
560311116Sdim  IRB.SetInsertPoint(ThenBB1);
561311116Sdim  BasicBlock *ThenBB2 = BasicBlock::Create(C, "if.then2", F);
562311116Sdim  BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
563311116Sdim  Value *ThrewInt = IRB.CreateIntToPtr(Threw, Type::getInt32PtrTy(C),
564311116Sdim                                       Threw->getName() + ".i32p");
565311116Sdim  Value *LoadedThrew =
566311116Sdim      IRB.CreateLoad(ThrewInt, ThrewInt->getName() + ".loaded");
567311116Sdim  Value *ThenLabel = IRB.CreateCall(
568311116Sdim      TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
569311116Sdim  Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
570311116Sdim  IRB.CreateCondBr(Cmp2, ThenBB2, EndBB2);
571311116Sdim
572311116Sdim  // emscripten_longjmp(%__THREW__.val, threwValue);
573311116Sdim  IRB.SetInsertPoint(ThenBB2);
574311116Sdim  IRB.CreateCall(EmLongjmpF, {Threw, ThrewValue});
575311116Sdim  IRB.CreateUnreachable();
576311116Sdim
577344779Sdim  // setTempRet0(threwValue);
578311116Sdim  IRB.SetInsertPoint(EndBB2);
579344779Sdim  IRB.CreateCall(SetTempRet0Func, ThrewValue);
580311116Sdim  IRB.CreateBr(EndBB1);
581311116Sdim
582311116Sdim  IRB.SetInsertPoint(ElseBB1);
583311116Sdim  IRB.CreateBr(EndBB1);
584311116Sdim
585344779Sdim  // longjmp_result = getTempRet0();
586311116Sdim  IRB.SetInsertPoint(EndBB1);
587311116Sdim  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
588311116Sdim  LabelPHI->addIncoming(ThenLabel, EndBB2);
589311116Sdim
590311116Sdim  LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
591311116Sdim
592311116Sdim  // Output parameter assignment
593311116Sdim  Label = LabelPHI;
594311116Sdim  EndBB = EndBB1;
595344779Sdim  LongjmpResult = IRB.CreateCall(GetTempRet0Func, None, "longjmp_result");
596311116Sdim}
597311116Sdim
598311116Sdimvoid WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
599311116Sdim  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
600311116Sdim  DT.recalculate(F); // CFG has been changed
601311116Sdim  SSAUpdater SSA;
602311116Sdim  for (BasicBlock &BB : F) {
603311116Sdim    for (Instruction &I : BB) {
604311116Sdim      for (auto UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
605311116Sdim        Use &U = *UI;
606311116Sdim        ++UI;
607311116Sdim        SSA.Initialize(I.getType(), I.getName());
608311116Sdim        SSA.AddAvailableValue(&BB, &I);
609311116Sdim        Instruction *User = cast<Instruction>(U.getUser());
610311116Sdim        if (User->getParent() == &BB)
611311116Sdim          continue;
612311116Sdim
613311116Sdim        if (PHINode *UserPN = dyn_cast<PHINode>(User))
614311116Sdim          if (UserPN->getIncomingBlock(U) == &BB)
615311116Sdim            continue;
616311116Sdim
617311116Sdim        if (DT.dominates(&I, User))
618311116Sdim          continue;
619311116Sdim        SSA.RewriteUseAfterInsertions(U);
620311116Sdim      }
621311116Sdim    }
622311116Sdim  }
623311116Sdim}
624311116Sdim
625311116Sdimbool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
626344779Sdim  LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
627344779Sdim
628311116Sdim  LLVMContext &C = M.getContext();
629311116Sdim  IRBuilder<> IRB(C);
630311116Sdim
631311116Sdim  Function *SetjmpF = M.getFunction("setjmp");
632311116Sdim  Function *LongjmpF = M.getFunction("longjmp");
633311116Sdim  bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty();
634311116Sdim  bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
635311116Sdim  bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
636311116Sdim
637344779Sdim  // Declare (or get) global variables __THREW__, __threwValue, and
638344779Sdim  // getTempRet0/setTempRet0 function which are used in common for both
639344779Sdim  // exception handling and setjmp/longjmp handling
640344779Sdim  ThrewGV = getGlobalVariableI32(M, IRB, "__THREW__");
641344779Sdim  ThrewValueGV = getGlobalVariableI32(M, IRB, "__threwValue");
642344779Sdim  GetTempRet0Func =
643344779Sdim      Function::Create(FunctionType::get(IRB.getInt32Ty(), false),
644344779Sdim                       GlobalValue::ExternalLinkage, "getTempRet0", &M);
645344779Sdim  SetTempRet0Func = Function::Create(
646344779Sdim      FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
647344779Sdim      GlobalValue::ExternalLinkage, "setTempRet0", &M);
648344779Sdim  GetTempRet0Func->setDoesNotThrow();
649344779Sdim  SetTempRet0Func->setDoesNotThrow();
650311116Sdim
651311116Sdim  bool Changed = false;
652311116Sdim
653311116Sdim  // Exception handling
654311116Sdim  if (EnableEH) {
655311116Sdim    // Register __resumeException function
656311116Sdim    FunctionType *ResumeFTy =
657311116Sdim        FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
658311116Sdim    ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
659311116Sdim                               ResumeFName, &M);
660311116Sdim
661311116Sdim    // Register llvm_eh_typeid_for function
662311116Sdim    FunctionType *EHTypeIDTy =
663311116Sdim        FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
664311116Sdim    EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
665311116Sdim                                 EHTypeIDFName, &M);
666311116Sdim
667311116Sdim    for (Function &F : M) {
668311116Sdim      if (F.isDeclaration())
669311116Sdim        continue;
670311116Sdim      Changed |= runEHOnFunction(F);
671311116Sdim    }
672311116Sdim  }
673311116Sdim
674311116Sdim  // Setjmp/longjmp handling
675311116Sdim  if (DoSjLj) {
676311116Sdim    Changed = true; // We have setjmp or longjmp somewhere
677311116Sdim
678311116Sdim    if (LongjmpF) {
679311116Sdim      // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is
680311116Sdim      // defined in JS code
681311116Sdim      EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(),
682311116Sdim                                          GlobalValue::ExternalLinkage,
683311116Sdim                                          EmLongjmpJmpbufFName, &M);
684311116Sdim
685311116Sdim      LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF);
686311116Sdim    }
687311116Sdim
688344779Sdim    if (SetjmpF) {
689344779Sdim      // Register saveSetjmp function
690344779Sdim      FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
691344779Sdim      SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0),
692344779Sdim                                       IRB.getInt32Ty(), Type::getInt32PtrTy(C),
693344779Sdim                                       IRB.getInt32Ty()};
694344779Sdim      FunctionType *FTy =
695344779Sdim          FunctionType::get(Type::getInt32PtrTy(C), Params, false);
696344779Sdim      SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
697344779Sdim                                     SaveSetjmpFName, &M);
698344779Sdim
699344779Sdim      // Register testSetjmp function
700344779Sdim      Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()};
701344779Sdim      FTy = FunctionType::get(IRB.getInt32Ty(), Params, false);
702344779Sdim      TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
703344779Sdim                                     TestSetjmpFName, &M);
704344779Sdim
705344779Sdim      FTy = FunctionType::get(IRB.getVoidTy(),
706344779Sdim                              {IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
707344779Sdim      EmLongjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
708344779Sdim                                    EmLongjmpFName, &M);
709344779Sdim
710344779Sdim      // Only traverse functions that uses setjmp in order not to insert
711344779Sdim      // unnecessary prep / cleanup code in every function
712344779Sdim      SmallPtrSet<Function *, 8> SetjmpUsers;
713344779Sdim      for (User *U : SetjmpF->users()) {
714344779Sdim        auto *UI = cast<Instruction>(U);
715344779Sdim        SetjmpUsers.insert(UI->getFunction());
716344779Sdim      }
717344779Sdim      for (Function *F : SetjmpUsers)
718344779Sdim        runSjLjOnFunction(*F);
719311116Sdim    }
720311116Sdim  }
721311116Sdim
722311116Sdim  if (!Changed) {
723311116Sdim    // Delete unused global variables and functions
724311116Sdim    if (ResumeF)
725311116Sdim      ResumeF->eraseFromParent();
726311116Sdim    if (EHTypeIDF)
727311116Sdim      EHTypeIDF->eraseFromParent();
728311116Sdim    if (EmLongjmpF)
729311116Sdim      EmLongjmpF->eraseFromParent();
730311116Sdim    if (SaveSetjmpF)
731311116Sdim      SaveSetjmpF->eraseFromParent();
732311116Sdim    if (TestSetjmpF)
733311116Sdim      TestSetjmpF->eraseFromParent();
734311116Sdim    return false;
735311116Sdim  }
736311116Sdim
737311116Sdim  return true;
738311116Sdim}
739311116Sdim
740311116Sdimbool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
741311116Sdim  Module &M = *F.getParent();
742311116Sdim  LLVMContext &C = F.getContext();
743311116Sdim  IRBuilder<> IRB(C);
744311116Sdim  bool Changed = false;
745311116Sdim  SmallVector<Instruction *, 64> ToErase;
746311116Sdim  SmallPtrSet<LandingPadInst *, 32> LandingPads;
747311116Sdim  bool AllowExceptions =
748311116Sdim      areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName());
749311116Sdim
750311116Sdim  for (BasicBlock &BB : F) {
751311116Sdim    auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
752311116Sdim    if (!II)
753311116Sdim      continue;
754311116Sdim    Changed = true;
755311116Sdim    LandingPads.insert(II->getLandingPadInst());
756311116Sdim    IRB.SetInsertPoint(II);
757311116Sdim
758311116Sdim    bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
759311116Sdim    if (NeedInvoke) {
760311116Sdim      // Wrap invoke with invoke wrapper and generate preamble/postamble
761311116Sdim      Value *Threw = wrapInvoke(II);
762311116Sdim      ToErase.push_back(II);
763311116Sdim
764311116Sdim      // Insert a branch based on __THREW__ variable
765311116Sdim      Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(1), "cmp");
766311116Sdim      IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
767311116Sdim
768311116Sdim    } else {
769311116Sdim      // This can't throw, and we don't need this invoke, just replace it with a
770311116Sdim      // call+branch
771311116Sdim      SmallVector<Value *, 16> Args(II->arg_begin(), II->arg_end());
772311116Sdim      CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), Args);
773311116Sdim      NewCall->takeName(II);
774311116Sdim      NewCall->setCallingConv(II->getCallingConv());
775311116Sdim      NewCall->setDebugLoc(II->getDebugLoc());
776311116Sdim      NewCall->setAttributes(II->getAttributes());
777311116Sdim      II->replaceAllUsesWith(NewCall);
778311116Sdim      ToErase.push_back(II);
779311116Sdim
780311116Sdim      IRB.CreateBr(II->getNormalDest());
781311116Sdim
782311116Sdim      // Remove any PHI node entries from the exception destination
783311116Sdim      II->getUnwindDest()->removePredecessor(&BB);
784311116Sdim    }
785311116Sdim  }
786311116Sdim
787311116Sdim  // Process resume instructions
788311116Sdim  for (BasicBlock &BB : F) {
789311116Sdim    // Scan the body of the basic block for resumes
790311116Sdim    for (Instruction &I : BB) {
791311116Sdim      auto *RI = dyn_cast<ResumeInst>(&I);
792311116Sdim      if (!RI)
793311116Sdim        continue;
794311116Sdim
795311116Sdim      // Split the input into legal values
796311116Sdim      Value *Input = RI->getValue();
797311116Sdim      IRB.SetInsertPoint(RI);
798311116Sdim      Value *Low = IRB.CreateExtractValue(Input, 0, "low");
799311116Sdim      // Create a call to __resumeException function
800311116Sdim      IRB.CreateCall(ResumeF, {Low});
801311116Sdim      // Add a terminator to the block
802311116Sdim      IRB.CreateUnreachable();
803311116Sdim      ToErase.push_back(RI);
804311116Sdim    }
805311116Sdim  }
806311116Sdim
807311116Sdim  // Process llvm.eh.typeid.for intrinsics
808311116Sdim  for (BasicBlock &BB : F) {
809311116Sdim    for (Instruction &I : BB) {
810311116Sdim      auto *CI = dyn_cast<CallInst>(&I);
811311116Sdim      if (!CI)
812311116Sdim        continue;
813311116Sdim      const Function *Callee = CI->getCalledFunction();
814311116Sdim      if (!Callee)
815311116Sdim        continue;
816311116Sdim      if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
817311116Sdim        continue;
818311116Sdim
819311116Sdim      IRB.SetInsertPoint(CI);
820311116Sdim      CallInst *NewCI =
821311116Sdim          IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
822311116Sdim      CI->replaceAllUsesWith(NewCI);
823311116Sdim      ToErase.push_back(CI);
824311116Sdim    }
825311116Sdim  }
826311116Sdim
827321369Sdim  // Look for orphan landingpads, can occur in blocks with no predecessors
828311116Sdim  for (BasicBlock &BB : F) {
829311116Sdim    Instruction *I = BB.getFirstNonPHI();
830311116Sdim    if (auto *LPI = dyn_cast<LandingPadInst>(I))
831311116Sdim      LandingPads.insert(LPI);
832311116Sdim  }
833311116Sdim
834311116Sdim  // Handle all the landingpad for this function together, as multiple invokes
835311116Sdim  // may share a single lp
836311116Sdim  for (LandingPadInst *LPI : LandingPads) {
837311116Sdim    IRB.SetInsertPoint(LPI);
838311116Sdim    SmallVector<Value *, 16> FMCArgs;
839311116Sdim    for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
840311116Sdim      Constant *Clause = LPI->getClause(i);
841311116Sdim      // As a temporary workaround for the lack of aggregate varargs support
842311116Sdim      // in the interface between JS and wasm, break out filter operands into
843311116Sdim      // their component elements.
844311116Sdim      if (LPI->isFilter(i)) {
845311116Sdim        auto *ATy = cast<ArrayType>(Clause->getType());
846311116Sdim        for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
847311116Sdim          Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
848311116Sdim          FMCArgs.push_back(EV);
849311116Sdim        }
850311116Sdim      } else
851311116Sdim        FMCArgs.push_back(Clause);
852311116Sdim    }
853311116Sdim
854311116Sdim    // Create a call to __cxa_find_matching_catch_N function
855311116Sdim    Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
856311116Sdim    CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
857311116Sdim    Value *Undef = UndefValue::get(LPI->getType());
858311116Sdim    Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
859344779Sdim    Value *TempRet0 = IRB.CreateCall(GetTempRet0Func, None, "tempret0");
860311116Sdim    Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
861311116Sdim
862311116Sdim    LPI->replaceAllUsesWith(Pair1);
863311116Sdim    ToErase.push_back(LPI);
864311116Sdim  }
865311116Sdim
866311116Sdim  // Erase everything we no longer need in this function
867311116Sdim  for (Instruction *I : ToErase)
868311116Sdim    I->eraseFromParent();
869311116Sdim
870311116Sdim  return Changed;
871311116Sdim}
872311116Sdim
873311116Sdimbool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
874311116Sdim  Module &M = *F.getParent();
875311116Sdim  LLVMContext &C = F.getContext();
876311116Sdim  IRBuilder<> IRB(C);
877311116Sdim  SmallVector<Instruction *, 64> ToErase;
878311116Sdim  // Vector of %setjmpTable values
879311116Sdim  std::vector<Instruction *> SetjmpTableInsts;
880311116Sdim  // Vector of %setjmpTableSize values
881311116Sdim  std::vector<Instruction *> SetjmpTableSizeInsts;
882311116Sdim
883311116Sdim  // Setjmp preparation
884311116Sdim
885311116Sdim  // This instruction effectively means %setjmpTableSize = 4.
886311116Sdim  // We create this as an instruction intentionally, and we don't want to fold
887311116Sdim  // this instruction to a constant 4, because this value will be used in
888311116Sdim  // SSAUpdater.AddAvailableValue(...) later.
889311116Sdim  BasicBlock &EntryBB = F.getEntryBlock();
890311116Sdim  BinaryOperator *SetjmpTableSize = BinaryOperator::Create(
891311116Sdim      Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize",
892311116Sdim      &*EntryBB.getFirstInsertionPt());
893311116Sdim  // setjmpTable = (int *) malloc(40);
894311116Sdim  Instruction *SetjmpTable = CallInst::CreateMalloc(
895311116Sdim      SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
896311116Sdim      nullptr, nullptr, "setjmpTable");
897311116Sdim  // setjmpTable[0] = 0;
898311116Sdim  IRB.SetInsertPoint(SetjmpTableSize);
899311116Sdim  IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
900311116Sdim  SetjmpTableInsts.push_back(SetjmpTable);
901311116Sdim  SetjmpTableSizeInsts.push_back(SetjmpTableSize);
902311116Sdim
903311116Sdim  // Setjmp transformation
904311116Sdim  std::vector<PHINode *> SetjmpRetPHIs;
905311116Sdim  Function *SetjmpF = M.getFunction("setjmp");
906311116Sdim  for (User *U : SetjmpF->users()) {
907311116Sdim    auto *CI = dyn_cast<CallInst>(U);
908311116Sdim    if (!CI)
909311116Sdim      report_fatal_error("Does not support indirect calls to setjmp");
910311116Sdim
911311116Sdim    BasicBlock *BB = CI->getParent();
912311116Sdim    if (BB->getParent() != &F) // in other function
913311116Sdim      continue;
914311116Sdim
915311116Sdim    // The tail is everything right after the call, and will be reached once
916311116Sdim    // when setjmp is called, and later when longjmp returns to the setjmp
917311116Sdim    BasicBlock *Tail = SplitBlock(BB, CI->getNextNode());
918311116Sdim    // Add a phi to the tail, which will be the output of setjmp, which
919311116Sdim    // indicates if this is the first call or a longjmp back. The phi directly
920311116Sdim    // uses the right value based on where we arrive from
921311116Sdim    IRB.SetInsertPoint(Tail->getFirstNonPHI());
922311116Sdim    PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
923311116Sdim
924311116Sdim    // setjmp initial call returns 0
925311116Sdim    SetjmpRet->addIncoming(IRB.getInt32(0), BB);
926311116Sdim    // The proper output is now this, not the setjmp call itself
927311116Sdim    CI->replaceAllUsesWith(SetjmpRet);
928311116Sdim    // longjmp returns to the setjmp will add themselves to this phi
929311116Sdim    SetjmpRetPHIs.push_back(SetjmpRet);
930311116Sdim
931311116Sdim    // Fix call target
932311116Sdim    // Our index in the function is our place in the array + 1 to avoid index
933311116Sdim    // 0, because index 0 means the longjmp is not ours to handle.
934311116Sdim    IRB.SetInsertPoint(CI);
935311116Sdim    Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
936311116Sdim                     SetjmpTable, SetjmpTableSize};
937311116Sdim    Instruction *NewSetjmpTable =
938311116Sdim        IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
939311116Sdim    Instruction *NewSetjmpTableSize =
940344779Sdim        IRB.CreateCall(GetTempRet0Func, None, "setjmpTableSize");
941311116Sdim    SetjmpTableInsts.push_back(NewSetjmpTable);
942311116Sdim    SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
943311116Sdim    ToErase.push_back(CI);
944311116Sdim  }
945311116Sdim
946311116Sdim  // Update each call that can longjmp so it can return to a setjmp where
947311116Sdim  // relevant.
948311116Sdim
949311116Sdim  // Because we are creating new BBs while processing and don't want to make
950311116Sdim  // all these newly created BBs candidates again for longjmp processing, we
951311116Sdim  // first make the vector of candidate BBs.
952311116Sdim  std::vector<BasicBlock *> BBs;
953311116Sdim  for (BasicBlock &BB : F)
954311116Sdim    BBs.push_back(&BB);
955311116Sdim
956311116Sdim  // BBs.size() will change within the loop, so we query it every time
957311116Sdim  for (unsigned i = 0; i < BBs.size(); i++) {
958311116Sdim    BasicBlock *BB = BBs[i];
959311116Sdim    for (Instruction &I : *BB) {
960311116Sdim      assert(!isa<InvokeInst>(&I));
961311116Sdim      auto *CI = dyn_cast<CallInst>(&I);
962311116Sdim      if (!CI)
963311116Sdim        continue;
964311116Sdim
965311116Sdim      const Value *Callee = CI->getCalledValue();
966311116Sdim      if (!canLongjmp(M, Callee))
967311116Sdim        continue;
968311116Sdim
969311116Sdim      Value *Threw = nullptr;
970311116Sdim      BasicBlock *Tail;
971311116Sdim      if (Callee->getName().startswith(InvokePrefix)) {
972311116Sdim        // If invoke wrapper has already been generated for this call in
973311116Sdim        // previous EH phase, search for the load instruction
974311116Sdim        // %__THREW__.val = __THREW__;
975311116Sdim        // in postamble after the invoke wrapper call
976311116Sdim        LoadInst *ThrewLI = nullptr;
977311116Sdim        StoreInst *ThrewResetSI = nullptr;
978311116Sdim        for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
979311116Sdim             I != IE; ++I) {
980311116Sdim          if (auto *LI = dyn_cast<LoadInst>(I))
981311116Sdim            if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
982311116Sdim              if (GV == ThrewGV) {
983311116Sdim                Threw = ThrewLI = LI;
984311116Sdim                break;
985311116Sdim              }
986311116Sdim        }
987311116Sdim        // Search for the store instruction after the load above
988311116Sdim        // __THREW__ = 0;
989311116Sdim        for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
990311116Sdim             I != IE; ++I) {
991311116Sdim          if (auto *SI = dyn_cast<StoreInst>(I))
992311116Sdim            if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand()))
993311116Sdim              if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) {
994311116Sdim                ThrewResetSI = SI;
995311116Sdim                break;
996311116Sdim              }
997311116Sdim        }
998311116Sdim        assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
999311116Sdim        assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
1000311116Sdim        Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
1001311116Sdim
1002311116Sdim      } else {
1003311116Sdim        // Wrap call with invoke wrapper and generate preamble/postamble
1004311116Sdim        Threw = wrapInvoke(CI);
1005311116Sdim        ToErase.push_back(CI);
1006311116Sdim        Tail = SplitBlock(BB, CI->getNextNode());
1007311116Sdim      }
1008311116Sdim
1009311116Sdim      // We need to replace the terminator in Tail - SplitBlock makes BB go
1010311116Sdim      // straight to Tail, we need to check if a longjmp occurred, and go to the
1011311116Sdim      // right setjmp-tail if so
1012311116Sdim      ToErase.push_back(BB->getTerminator());
1013311116Sdim
1014311116Sdim      // Generate a function call to testSetjmp function and preamble/postamble
1015311116Sdim      // code to figure out (1) whether longjmp occurred (2) if longjmp
1016311116Sdim      // occurred, which setjmp it corresponds to
1017311116Sdim      Value *Label = nullptr;
1018311116Sdim      Value *LongjmpResult = nullptr;
1019311116Sdim      BasicBlock *EndBB = nullptr;
1020311116Sdim      wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label,
1021311116Sdim                     LongjmpResult, EndBB);
1022311116Sdim      assert(Label && LongjmpResult && EndBB);
1023311116Sdim
1024311116Sdim      // Create switch instruction
1025311116Sdim      IRB.SetInsertPoint(EndBB);
1026311116Sdim      SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
1027311116Sdim      // -1 means no longjmp happened, continue normally (will hit the default
1028311116Sdim      // switch case). 0 means a longjmp that is not ours to handle, needs a
1029311116Sdim      // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1030311116Sdim      // 0).
1031311116Sdim      for (unsigned i = 0; i < SetjmpRetPHIs.size(); i++) {
1032311116Sdim        SI->addCase(IRB.getInt32(i + 1), SetjmpRetPHIs[i]->getParent());
1033311116Sdim        SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB);
1034311116Sdim      }
1035311116Sdim
1036311116Sdim      // We are splitting the block here, and must continue to find other calls
1037311116Sdim      // in the block - which is now split. so continue to traverse in the Tail
1038311116Sdim      BBs.push_back(Tail);
1039311116Sdim    }
1040311116Sdim  }
1041311116Sdim
1042311116Sdim  // Erase everything we no longer need in this function
1043311116Sdim  for (Instruction *I : ToErase)
1044311116Sdim    I->eraseFromParent();
1045311116Sdim
1046311116Sdim  // Free setjmpTable buffer before each return instruction
1047311116Sdim  for (BasicBlock &BB : F) {
1048344779Sdim    Instruction *TI = BB.getTerminator();
1049311116Sdim    if (isa<ReturnInst>(TI))
1050311116Sdim      CallInst::CreateFree(SetjmpTable, TI);
1051311116Sdim  }
1052311116Sdim
1053311116Sdim  // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
1054311116Sdim  // (when buffer reallocation occurs)
1055311116Sdim  // entry:
1056311116Sdim  //   setjmpTableSize = 4;
1057311116Sdim  //   setjmpTable = (int *) malloc(40);
1058311116Sdim  //   setjmpTable[0] = 0;
1059311116Sdim  // ...
1060311116Sdim  // somebb:
1061311116Sdim  //   setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
1062344779Sdim  //   setjmpTableSize = getTempRet0();
1063311116Sdim  // So we need to make sure the SSA for these variables is valid so that every
1064311116Sdim  // saveSetjmp and testSetjmp calls have the correct arguments.
1065311116Sdim  SSAUpdater SetjmpTableSSA;
1066311116Sdim  SSAUpdater SetjmpTableSizeSSA;
1067311116Sdim  SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
1068311116Sdim  SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
1069311116Sdim  for (Instruction *I : SetjmpTableInsts)
1070311116Sdim    SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
1071311116Sdim  for (Instruction *I : SetjmpTableSizeInsts)
1072311116Sdim    SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
1073311116Sdim
1074311116Sdim  for (auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end();
1075311116Sdim       UI != UE;) {
1076311116Sdim    // Grab the use before incrementing the iterator.
1077311116Sdim    Use &U = *UI;
1078311116Sdim    // Increment the iterator before removing the use from the list.
1079311116Sdim    ++UI;
1080311116Sdim    if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
1081311116Sdim      if (I->getParent() != &EntryBB)
1082311116Sdim        SetjmpTableSSA.RewriteUse(U);
1083311116Sdim  }
1084311116Sdim  for (auto UI = SetjmpTableSize->use_begin(), UE = SetjmpTableSize->use_end();
1085311116Sdim       UI != UE;) {
1086311116Sdim    Use &U = *UI;
1087311116Sdim    ++UI;
1088311116Sdim    if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
1089311116Sdim      if (I->getParent() != &EntryBB)
1090311116Sdim        SetjmpTableSizeSSA.RewriteUse(U);
1091311116Sdim  }
1092311116Sdim
1093311116Sdim  // Finally, our modifications to the cfg can break dominance of SSA variables.
1094311116Sdim  // For example, in this code,
1095311116Sdim  // if (x()) { .. setjmp() .. }
1096311116Sdim  // if (y()) { .. longjmp() .. }
1097311116Sdim  // We must split the longjmp block, and it can jump into the block splitted
1098311116Sdim  // from setjmp one. But that means that when we split the setjmp block, it's
1099311116Sdim  // first part no longer dominates its second part - there is a theoretically
1100311116Sdim  // possible control flow path where x() is false, then y() is true and we
1101311116Sdim  // reach the second part of the setjmp block, without ever reaching the first
1102311116Sdim  // part. So, we rebuild SSA form here.
1103311116Sdim  rebuildSSA(F);
1104311116Sdim  return true;
1105311116Sdim}
1106