1 //=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file lowers exception-related instructions in order to use
12 /// Emscripten's JavaScript try and catch mechanism to handle exceptions.
13 ///
14 /// To handle exceptions, this scheme relies on JavaScript's try and catch
15 /// syntax and relevant exception-related libraries implemented in JavaScript
16 /// glue code that will be produced by Emscripten. This is similar to the
17 /// current Emscripten asm.js exception handling in fastcomp.
18 /// For fastcomp's EH scheme, see these files in fastcomp LLVM branch:
19 /// (Location: https://github.com/kripken/emscripten-fastcomp)
20 /// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp
21 /// lib/Target/JSBackend/JSBackend.cpp
22 /// lib/Target/JSBackend/CallHandlers.h
23 ///
24 /// This pass does following things:
25 ///
26 /// 1) Create three global variables: __THREW__, __threwValue, and tempRet0.
27 ///    tempRet0 will be set within __cxa_find_matching_catch() function in
28 ///    JS library, and __THREW__ and __threwValue will be set in invoke wrappers
29 ///    in JS glue code. For what invoke wrappers are, refer to 3).
30 ///
31 /// 2) Create setThrew and setTempRet0 functions.
32 ///    The global variables created in 1) will exist in wasm address space,
33 ///    but their values should be set in JS code, so we provide these functions
34 ///    as interfaces to JS glue code. These functions are equivalent to the
35 ///    following JS functions, which actually exist in asm.js version of JS
36 ///    library.
37 ///
38 ///    function setThrew(threw, value) {
39 ///      if (__THREW__ == 0) {
40 ///        __THREW__ = threw;
41 ///        __threwValue = value;
42 ///      }
43 ///    }
44 ///
45 ///    function setTempRet0(value) {
46 ///      tempRet0 = value;
47 ///    }
48 ///
49 /// 3) Lower
50 ///      invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
51 ///    into
52 ///      __THREW__ = 0;
53 ///      call @invoke_SIG(func, arg1, arg2)
54 ///      %__THREW__.val = __THREW__;
55 ///      __THREW__ = 0;
56 ///      br %__THREW__.val, label %lpad, label %invoke.cont
57 ///    SIG is a mangled string generated based on the LLVM IR-level function
58 ///    signature. After LLVM IR types are lowered to the target wasm types,
59 ///    the names for these wrappers will change based on wasm types as well,
60 ///    as in invoke_vi (function takes an int and returns void). The bodies of
61 ///    these wrappers will be generated in JS glue code, and inside those
62 ///    wrappers we use JS try-catch to generate actual exception effects. It
63 ///    also calls the original callee function. An example wrapper in JS code
64 ///    would look like this:
65 ///      function invoke_vi(index,a1) {
66 ///        try {
67 ///          Module["dynCall_vi"](index,a1); // This calls original callee
68 ///        } catch(e) {
69 ///          if (typeof e !== 'number' && e !== 'longjmp') throw e;
70 ///          asm["setThrew"](1, 0); // setThrew is called here
71 ///        }
72 ///      }
73 ///    If an exception is thrown, __THREW__ will be set to true in a wrapper,
74 ///    so we can jump to the right BB based on this value.
75 ///
76 /// 4) Lower
77 ///      %val = landingpad catch c1 catch c2 catch c3 ...
78 ///      ... use %val ...
79 ///    into
80 ///      %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
81 ///      %val = {%fmc, tempRet0}
82 ///      ... use %val ...
83 ///    Here N is a number calculated based on the number of clauses.
84 ///    Global variable tempRet0 is set within __cxa_find_matching_catch() in
85 ///    JS glue code.
86 ///
87 /// 5) Lower
88 ///      resume {%a, %b}
89 ///    into
90 ///      call @__resumeException(%a)
91 ///    where __resumeException() is a function in JS glue code.
92 ///
93 /// 6) Lower
94 ///      call @llvm.eh.typeid.for(type) (intrinsic)
95 ///    into
96 ///      call @llvm_eh_typeid_for(type)
97 ///    llvm_eh_typeid_for function will be generated in JS glue code.
98 ///
99 ///===----------------------------------------------------------------------===//
100 
101 #include "WebAssembly.h"
102 #include "llvm/IR/CallSite.h"
103 #include "llvm/IR/IRBuilder.h"
104 #include "llvm/IR/Module.h"
105 #include "llvm/Support/raw_ostream.h"
106 #include <set>
107 
108 using namespace llvm;
109 
110 #define DEBUG_TYPE "wasm-lower-em-ehsjlj"
111 
112 static cl::list<std::string>
113     EHWhitelist("emscripten-cxx-exceptions-whitelist",
114                 cl::desc("The list of function names in which Emscripten-style "
115                          "exception handling is enabled (see emscripten "
116                          "EMSCRIPTEN_CATCHING_WHITELIST options)"),
117                 cl::CommaSeparated);
118 
119 namespace {
120 class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
121   static const char *ThrewGVName;
122   static const char *ThrewValueGVName;
123   static const char *TempRet0GVName;
124   static const char *ResumeFName;
125   static const char *EHTypeIDFName;
126   static const char *SetThrewFName;
127   static const char *SetTempRet0FName;
128   static const char *FindMatchingCatchPrefix;
129   static const char *InvokePrefix;
130 
131   bool DoEH;   // Enable exception handling
132   bool DoSjLj; // Enable setjmp/longjmp handling
133 
134   GlobalVariable *ThrewGV;
135   GlobalVariable *ThrewValueGV;
136   GlobalVariable *TempRet0GV;
137   Function *ResumeF;
138   Function *EHTypeIDF;
139   // __cxa_find_matching_catch_N functions.
140   // Indexed by the number of clauses in an original landingpad instruction.
141   DenseMap<int, Function *> FindMatchingCatches;
142   // Map of <function signature string, invoke_ wrappers>
143   StringMap<Function *> InvokeWrappers;
144   // Set of whitelisted function names for exception handling
145   std::set<std::string> EHWhitelistSet;
146 
147   const char *getPassName() const override {
148     return "WebAssembly Lower Emscripten Exceptions";
149   }
150 
151   bool runEHOnFunction(Function &F);
152   bool runSjLjOnFunction(Function &F);
153   // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
154   // This is because a landingpad instruction contains two more arguments,
155   // a personality function and a cleanup bit, and __cxa_find_matching_catch_N
156   // functions are named after the number of arguments in the original
157   // landingpad instruction.
158   Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
159 
160   Function *getInvokeWrapper(Module &M, InvokeInst *II);
161   bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
162 
163 public:
164   static char ID;
165 
166   WebAssemblyLowerEmscriptenEHSjLj(bool DoEH = true, bool DoSjLj = true)
167       : ModulePass(ID), DoEH(DoEH), DoSjLj(DoSjLj), ThrewGV(nullptr),
168         ThrewValueGV(nullptr), TempRet0GV(nullptr), ResumeF(nullptr),
169         EHTypeIDF(nullptr) {
170     EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
171   }
172   bool runOnModule(Module &M) override;
173 };
174 } // End anonymous namespace
175 
176 const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewGVName = "__THREW__";
177 const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewValueGVName = "__threwValue";
178 const char *WebAssemblyLowerEmscriptenEHSjLj::TempRet0GVName = "__tempRet0";
179 const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException";
180 const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
181     "llvm_eh_typeid_for";
182 const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew";
183 const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0";
184 const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
185     "__cxa_find_matching_catch_";
186 const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
187 
188 char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
189 INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
190                 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
191                 false, false)
192 
193 ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH,
194                                                          bool DoSjLj) {
195   return new WebAssemblyLowerEmscriptenEHSjLj(DoEH, DoSjLj);
196 }
197 
198 static bool canThrow(const Value *V) {
199   if (const auto *F = dyn_cast<const Function>(V)) {
200     // Intrinsics cannot throw
201     if (F->isIntrinsic())
202       return false;
203     StringRef Name = F->getName();
204     // leave setjmp and longjmp (mostly) alone, we process them properly later
205     if (Name == "setjmp" || Name == "longjmp")
206       return false;
207     return true;
208   }
209   // not a function, so an indirect call - can throw, we can't tell
210   return true;
211 }
212 
213 // Returns an available name for a global value.
214 // If the proposed name already exists in the module, adds '_' at the end of
215 // the name until the name is available.
216 static inline std::string createGlobalValueName(const Module &M,
217                                                 const std::string &Propose) {
218   std::string Name = Propose;
219   while (M.getNamedGlobal(Name))
220     Name += "_";
221   return Name;
222 }
223 
224 // Simple function name mangler.
225 // This function simply takes LLVM's string representation of parameter types
226 // and concatenate them with '_'. There are non-alphanumeric characters but llc
227 // is ok with it, and we need to postprocess these names after the lowering
228 // phase anyway.
229 static std::string getSignature(FunctionType *FTy) {
230   std::string Sig;
231   raw_string_ostream OS(Sig);
232   OS << *FTy->getReturnType();
233   for (Type *ParamTy : FTy->params())
234     OS << "_" << *ParamTy;
235   if (FTy->isVarArg())
236     OS << "_...";
237   Sig = OS.str();
238   Sig.erase(remove_if(Sig, isspace), Sig.end());
239   // When s2wasm parses .s file, a comma means the end of an argument. So a
240   // mangled function name can contain any character but a comma.
241   std::replace(Sig.begin(), Sig.end(), ',', '.');
242   return Sig;
243 }
244 
245 Function *
246 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
247                                                        unsigned NumClauses) {
248   if (FindMatchingCatches.count(NumClauses))
249     return FindMatchingCatches[NumClauses];
250   PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
251   SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
252   FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
253   Function *F =
254       Function::Create(FTy, GlobalValue::ExternalLinkage,
255                        FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
256   FindMatchingCatches[NumClauses] = F;
257   return F;
258 }
259 
260 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(Module &M,
261                                                              InvokeInst *II) {
262   SmallVector<Type *, 16> ArgTys;
263   Value *Callee = II->getCalledValue();
264   FunctionType *CalleeFTy;
265   if (auto *F = dyn_cast<Function>(Callee))
266     CalleeFTy = F->getFunctionType();
267   else {
268     auto *CalleeTy = dyn_cast<PointerType>(Callee->getType())->getElementType();
269     CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
270   }
271 
272   std::string Sig = getSignature(CalleeFTy);
273   if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
274     return InvokeWrappers[Sig];
275 
276   // Put the pointer to the callee as first argument
277   ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
278   // Add argument types
279   ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
280 
281   FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
282                                         CalleeFTy->isVarArg());
283   Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
284                                  InvokePrefix + Sig, &M);
285   InvokeWrappers[Sig] = F;
286   return F;
287 }
288 
289 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
290   LLVMContext &C = M.getContext();
291   IRBuilder<> IRB(C);
292   IntegerType *Int1Ty = IRB.getInt1Ty();
293   PointerType *Int8PtrTy = IRB.getInt8PtrTy();
294   IntegerType *Int32Ty = IRB.getInt32Ty();
295   Type *VoidTy = IRB.getVoidTy();
296 
297   // Create global variables __THREW__, threwValue, and tempRet0, which are
298   // used in common for both exception handling and setjmp/longjmp handling
299   ThrewGV =
300       new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage,
301                          IRB.getFalse(), createGlobalValueName(M, ThrewGVName));
302   ThrewValueGV = new GlobalVariable(
303       M, Int32Ty, false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
304       createGlobalValueName(M, ThrewValueGVName));
305   TempRet0GV = new GlobalVariable(M, Int32Ty, false,
306                                   GlobalValue::ExternalLinkage, IRB.getInt32(0),
307                                   createGlobalValueName(M, TempRet0GVName));
308 
309   bool Changed = false;
310 
311   // Exception handling
312   if (DoEH) {
313     // Register __resumeException function
314     FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false);
315     ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
316                                ResumeFName, &M);
317 
318     // Register llvm_eh_typeid_for function
319     FunctionType *EHTypeIDTy = FunctionType::get(Int32Ty, Int8PtrTy, false);
320     EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
321                                  EHTypeIDFName, &M);
322 
323     for (Function &F : M) {
324       if (F.isDeclaration())
325         continue;
326       Changed |= runEHOnFunction(F);
327     }
328   }
329 
330   // TODO: Run CFGSimplify like the emscripten JSBackend?
331 
332   // Setjmp/longjmp handling
333   if (DoSjLj) {
334     for (Function &F : M) {
335       if (F.isDeclaration())
336         continue;
337       Changed |= runSjLjOnFunction(F);
338     }
339   }
340 
341   if (!Changed)
342     return false;
343 
344   // If we have made any changes while doing exception handling or
345   // setjmp/longjmp handling, we have to create these functions for JavaScript
346   // to call.
347   assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
348   assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
349 
350   // Create setThrew function
351   SmallVector<Type *, 2> Params = {Int1Ty, Int32Ty};
352   FunctionType *FTy = FunctionType::get(VoidTy, Params, false);
353   Function *F =
354       Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
355   Argument *Arg1 = &*(F->arg_begin());
356   Argument *Arg2 = &*(++F->arg_begin());
357   Arg1->setName("threw");
358   Arg2->setName("value");
359   BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
360   BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
361   BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
362 
363   IRB.SetInsertPoint(EntryBB);
364   Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
365   Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getFalse(), "cmp");
366   IRB.CreateCondBr(Cmp, ThenBB, EndBB);
367 
368   IRB.SetInsertPoint(ThenBB);
369   IRB.CreateStore(Arg1, ThrewGV);
370   IRB.CreateStore(Arg2, ThrewValueGV);
371   IRB.CreateBr(EndBB);
372 
373   IRB.SetInsertPoint(EndBB);
374   IRB.CreateRetVoid();
375 
376   // Create setTempRet0 function
377   Params = {Int32Ty};
378   FTy = FunctionType::get(VoidTy, Params, false);
379   F = Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
380   F->arg_begin()->setName("value");
381   EntryBB = BasicBlock::Create(C, "entry", F);
382   IRB.SetInsertPoint(EntryBB);
383   IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
384   IRB.CreateRetVoid();
385 
386   return true;
387 }
388 
389 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
390   Module &M = *F.getParent();
391   LLVMContext &C = F.getContext();
392   IRBuilder<> IRB(C);
393   bool Changed = false;
394   SmallVector<Instruction *, 64> ToErase;
395   SmallPtrSet<LandingPadInst *, 32> LandingPads;
396   bool AllowExceptions =
397       areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName());
398 
399   for (BasicBlock &BB : F) {
400     auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
401     if (!II)
402       continue;
403     Changed = true;
404     LandingPads.insert(II->getLandingPadInst());
405     IRB.SetInsertPoint(II);
406 
407     bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
408     if (NeedInvoke) {
409       // If we are calling a function that is noreturn, we must remove that
410       // attribute. The code we insert here does expect it to return, after we
411       // catch the exception.
412       if (II->doesNotReturn()) {
413         if (auto *F = dyn_cast<Function>(II->getCalledValue()))
414           F->removeFnAttr(Attribute::NoReturn);
415         AttributeSet NewAttrs = II->getAttributes();
416         NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
417                                  Attribute::NoReturn);
418         II->setAttributes(NewAttrs);
419       }
420 
421       // Pre-invoke
422       // __THREW__ = 0;
423       IRB.CreateStore(IRB.getFalse(), ThrewGV);
424 
425       // Invoke function wrapper in JavaScript
426       SmallVector<Value *, 16> CallArgs;
427       // Put the pointer to the callee as first argument, so it can be called
428       // within the invoke wrapper later
429       CallArgs.push_back(II->getCalledValue());
430       CallArgs.append(II->arg_begin(), II->arg_end());
431       CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(M, II), CallArgs);
432       NewCall->takeName(II);
433       NewCall->setCallingConv(II->getCallingConv());
434       NewCall->setDebugLoc(II->getDebugLoc());
435 
436       // Because we added the pointer to the callee as first argument, all
437       // argument attribute indices have to be incremented by one.
438       SmallVector<AttributeSet, 8> AttributesVec;
439       const AttributeSet &InvokePAL = II->getAttributes();
440       CallSite::arg_iterator AI = II->arg_begin();
441       unsigned i = 1; // Argument attribute index starts from 1
442       for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) {
443         if (InvokePAL.hasAttributes(i)) {
444           AttrBuilder B(InvokePAL, i);
445           AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
446         }
447       }
448       // Add any return attributes.
449       if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
450         AttributesVec.push_back(
451             AttributeSet::get(C, InvokePAL.getRetAttributes()));
452       // Add any function attributes.
453       if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
454         AttributesVec.push_back(
455             AttributeSet::get(C, InvokePAL.getFnAttributes()));
456       // Reconstruct the AttributesList based on the vector we constructed.
457       AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
458       NewCall->setAttributes(NewCallPAL);
459 
460       II->replaceAllUsesWith(NewCall);
461       ToErase.push_back(II);
462 
463       // Post-invoke
464       // %__THREW__.val = __THREW__; __THREW__ = 0;
465       Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
466       IRB.CreateStore(IRB.getFalse(), ThrewGV);
467 
468       // Insert a branch based on __THREW__ variable
469       IRB.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest());
470 
471     } else {
472       // This can't throw, and we don't need this invoke, just replace it with a
473       // call+branch
474       SmallVector<Value *, 16> CallArgs(II->arg_begin(), II->arg_end());
475       CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), CallArgs);
476       NewCall->takeName(II);
477       NewCall->setCallingConv(II->getCallingConv());
478       NewCall->setDebugLoc(II->getDebugLoc());
479       NewCall->setAttributes(II->getAttributes());
480       II->replaceAllUsesWith(NewCall);
481       ToErase.push_back(II);
482 
483       IRB.CreateBr(II->getNormalDest());
484 
485       // Remove any PHI node entries from the exception destination
486       II->getUnwindDest()->removePredecessor(&BB);
487     }
488   }
489 
490   // Process resume instructions
491   for (BasicBlock &BB : F) {
492     // Scan the body of the basic block for resumes
493     for (Instruction &I : BB) {
494       auto *RI = dyn_cast<ResumeInst>(&I);
495       if (!RI)
496         continue;
497 
498       // Split the input into legal values
499       Value *Input = RI->getValue();
500       IRB.SetInsertPoint(RI);
501       Value *Low = IRB.CreateExtractValue(Input, 0, "low");
502 
503       // Create a call to __resumeException function
504       Value *Args[] = {Low};
505       IRB.CreateCall(ResumeF, Args);
506 
507       // Add a terminator to the block
508       IRB.CreateUnreachable();
509       ToErase.push_back(RI);
510     }
511   }
512 
513   // Process llvm.eh.typeid.for intrinsics
514   for (BasicBlock &BB : F) {
515     for (Instruction &I : BB) {
516       auto *CI = dyn_cast<CallInst>(&I);
517       if (!CI)
518         continue;
519       const Function *Callee = CI->getCalledFunction();
520       if (!Callee)
521         continue;
522       if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
523         continue;
524 
525       IRB.SetInsertPoint(CI);
526       CallInst *NewCI =
527           IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
528       CI->replaceAllUsesWith(NewCI);
529       ToErase.push_back(CI);
530     }
531   }
532 
533   // Look for orphan landingpads, can occur in blocks with no predecesors
534   for (BasicBlock &BB : F) {
535     Instruction *I = BB.getFirstNonPHI();
536     if (auto *LPI = dyn_cast<LandingPadInst>(I))
537       LandingPads.insert(LPI);
538   }
539 
540   // Handle all the landingpad for this function together, as multiple invokes
541   // may share a single lp
542   for (LandingPadInst *LPI : LandingPads) {
543     IRB.SetInsertPoint(LPI);
544     SmallVector<Value *, 16> FMCArgs;
545     for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
546       Constant *Clause = LPI->getClause(i);
547       // As a temporary workaround for the lack of aggregate varargs support
548       // in the interface between JS and wasm, break out filter operands into
549       // their component elements.
550       if (LPI->isFilter(i)) {
551         ArrayType *ATy = cast<ArrayType>(Clause->getType());
552         for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
553           Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
554           FMCArgs.push_back(EV);
555         }
556       } else
557         FMCArgs.push_back(Clause);
558     }
559 
560     // Create a call to __cxa_find_matching_catch_N function
561     Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
562     CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
563     Value *Undef = UndefValue::get(LPI->getType());
564     Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
565     Value *TempRet0 = IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val");
566     Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
567 
568     LPI->replaceAllUsesWith(Pair1);
569     ToErase.push_back(LPI);
570   }
571 
572   // Erase everything we no longer need in this function
573   for (Instruction *I : ToErase)
574     I->eraseFromParent();
575 
576   return Changed;
577 }
578 
579 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
580   // TODO
581   return false;
582 }
583