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   return true; // not a function, so an indirect call - can throw, we can't tell
210 }
211 
212 // Returns an available name for a global value.
213 // If the proposed name already exists in the module, adds '_' at the end of
214 // the name until the name is available.
215 static inline std::string createGlobalValueName(const Module &M,
216                                                 const std::string &Propose) {
217   std::string Name = Propose;
218   while (M.getNamedGlobal(Name))
219     Name += "_";
220   return Name;
221 }
222 
223 // Simple function name mangler.
224 // This function simply takes LLVM's string representation of parameter types
225 // and concatenate them with '_'. There are non-alphanumeric characters but llc
226 // is ok with it, and we need to postprocess these names after the lowering
227 // phase anyway.
228 static std::string getSignature(FunctionType *FTy) {
229   std::string Sig;
230   raw_string_ostream OS(Sig);
231   OS << *FTy->getReturnType();
232   for (Type *ParamTy : FTy->params())
233     OS << "_" << *ParamTy;
234   if (FTy->isVarArg())
235     OS << "_...";
236   Sig = OS.str();
237   Sig.erase(remove_if(Sig, isspace), Sig.end());
238   // When s2wasm parses .s file, a comma means the end of an argument. So a
239   // mangled function name can contain any character but a comma.
240   std::replace(Sig.begin(), Sig.end(), ',', '.');
241   return Sig;
242 }
243 
244 Function *
245 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
246                                                        unsigned NumClauses) {
247   if (FindMatchingCatches.count(NumClauses))
248     return FindMatchingCatches[NumClauses];
249   PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
250   SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
251   FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
252   Function *F =
253       Function::Create(FTy, GlobalValue::ExternalLinkage,
254                        FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
255   FindMatchingCatches[NumClauses] = F;
256   return F;
257 }
258 
259 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(Module &M,
260                                                              InvokeInst *II) {
261   SmallVector<Type *, 16> ArgTys;
262   Value *Callee = II->getCalledValue();
263   FunctionType *CalleeFTy;
264   if (auto *F = dyn_cast<Function>(Callee))
265     CalleeFTy = F->getFunctionType();
266   else {
267     auto *CalleeTy = dyn_cast<PointerType>(Callee->getType())->getElementType();
268     CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
269   }
270 
271   std::string Sig = getSignature(CalleeFTy);
272   if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
273     return InvokeWrappers[Sig];
274 
275   // Put the pointer to the callee as first argument
276   ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
277   // Add argument types
278   ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
279 
280   FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
281                                         CalleeFTy->isVarArg());
282   Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
283                                  InvokePrefix + Sig, &M);
284   InvokeWrappers[Sig] = F;
285   return F;
286 }
287 
288 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
289   LLVMContext &C = M.getContext();
290   IRBuilder<> IRB(C);
291   IntegerType *Int1Ty = IRB.getInt1Ty();
292   PointerType *Int8PtrTy = IRB.getInt8PtrTy();
293   IntegerType *Int32Ty = IRB.getInt32Ty();
294   Type *VoidTy = IRB.getVoidTy();
295 
296   // Create global variables __THREW__, threwValue, and tempRet0, which are
297   // used in common for both exception handling and setjmp/longjmp handling
298   ThrewGV =
299       new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage,
300                          IRB.getFalse(), createGlobalValueName(M, ThrewGVName));
301   ThrewValueGV = new GlobalVariable(
302       M, Int32Ty, false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
303       createGlobalValueName(M, ThrewValueGVName));
304   TempRet0GV = new GlobalVariable(M, Int32Ty, false,
305                                   GlobalValue::ExternalLinkage, IRB.getInt32(0),
306                                   createGlobalValueName(M, TempRet0GVName));
307 
308   bool Changed = false;
309 
310   // Exception handling
311   if (DoEH) {
312     // Register __resumeException function
313     FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false);
314     ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
315                                ResumeFName, &M);
316 
317     // Register llvm_eh_typeid_for function
318     FunctionType *EHTypeIDTy = FunctionType::get(Int32Ty, Int8PtrTy, false);
319     EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
320                                  EHTypeIDFName, &M);
321 
322     for (Function &F : M) {
323       if (F.isDeclaration())
324         continue;
325       Changed |= runEHOnFunction(F);
326     }
327   }
328 
329   // TODO: Run CFGSimplify like the emscripten JSBackend?
330 
331   // Setjmp/longjmp handling
332   if (DoSjLj) {
333     for (Function &F : M) {
334       if (F.isDeclaration())
335         continue;
336       Changed |= runSjLjOnFunction(F);
337     }
338   }
339 
340   if (!Changed)
341     return false;
342 
343   // If we have made any changes while doing exception handling or
344   // setjmp/longjmp handling, we have to create these functions for JavaScript
345   // to call.
346   assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
347   assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
348 
349   // Create setThrew function
350   SmallVector<Type *, 2> Params = {Int1Ty, Int32Ty};
351   FunctionType *FTy = FunctionType::get(VoidTy, Params, false);
352   Function *F =
353       Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
354   Argument *Arg1 = &*(F->arg_begin());
355   Argument *Arg2 = &*(++F->arg_begin());
356   Arg1->setName("threw");
357   Arg2->setName("value");
358   BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
359   BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
360   BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
361 
362   IRB.SetInsertPoint(EntryBB);
363   Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
364   Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getFalse(), "cmp");
365   IRB.CreateCondBr(Cmp, ThenBB, EndBB);
366 
367   IRB.SetInsertPoint(ThenBB);
368   IRB.CreateStore(Arg1, ThrewGV);
369   IRB.CreateStore(Arg2, ThrewValueGV);
370   IRB.CreateBr(EndBB);
371 
372   IRB.SetInsertPoint(EndBB);
373   IRB.CreateRetVoid();
374 
375   // Create setTempRet0 function
376   Params = {Int32Ty};
377   FTy = FunctionType::get(VoidTy, Params, false);
378   F = Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
379   F->arg_begin()->setName("value");
380   EntryBB = BasicBlock::Create(C, "entry", F);
381   IRB.SetInsertPoint(EntryBB);
382   IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
383   IRB.CreateRetVoid();
384 
385   return true;
386 }
387 
388 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
389   Module &M = *F.getParent();
390   LLVMContext &C = F.getContext();
391   IRBuilder<> IRB(C);
392   bool Changed = false;
393   SmallVector<Instruction *, 64> ToErase;
394   SmallPtrSet<LandingPadInst *, 32> LandingPads;
395   bool AllowExceptions =
396       areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName());
397 
398   for (BasicBlock &BB : F) {
399     auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
400     if (!II)
401       continue;
402     Changed = true;
403     LandingPads.insert(II->getLandingPadInst());
404     IRB.SetInsertPoint(II);
405 
406     bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
407     if (NeedInvoke) {
408       // If we are calling a function that is noreturn, we must remove that
409       // attribute. The code we insert here does expect it to return, after we
410       // catch the exception.
411       if (II->doesNotReturn()) {
412         if (auto *F = dyn_cast<Function>(II->getCalledValue()))
413           F->removeFnAttr(Attribute::NoReturn);
414         AttributeSet NewAttrs = II->getAttributes();
415         NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
416                                  Attribute::NoReturn);
417         II->setAttributes(NewAttrs);
418       }
419 
420       // Pre-invoke
421       // __THREW__ = 0;
422       IRB.CreateStore(IRB.getFalse(), ThrewGV);
423 
424       // Invoke function wrapper in JavaScript
425       SmallVector<Value *, 16> CallArgs;
426       // Put the pointer to the callee as first argument, so it can be called
427       // within the invoke wrapper later
428       CallArgs.push_back(II->getCalledValue());
429       CallArgs.append(II->arg_begin(), II->arg_end());
430       CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(M, II), CallArgs);
431       NewCall->takeName(II);
432       NewCall->setCallingConv(II->getCallingConv());
433       NewCall->setDebugLoc(II->getDebugLoc());
434 
435       // Because we added the pointer to the callee as first argument, all
436       // argument attribute indices have to be incremented by one.
437       SmallVector<AttributeSet, 8> AttributesVec;
438       const AttributeSet &InvokePAL = II->getAttributes();
439       CallSite::arg_iterator AI = II->arg_begin();
440       unsigned i = 1; // Argument attribute index starts from 1
441       for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) {
442         if (InvokePAL.hasAttributes(i)) {
443           AttrBuilder B(InvokePAL, i);
444           AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
445         }
446       }
447       // Add any return attributes.
448       if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
449         AttributesVec.push_back(
450             AttributeSet::get(C, InvokePAL.getRetAttributes()));
451       // Add any function attributes.
452       if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
453         AttributesVec.push_back(
454             AttributeSet::get(C, InvokePAL.getFnAttributes()));
455       // Reconstruct the AttributesList based on the vector we constructed.
456       AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
457       NewCall->setAttributes(NewCallPAL);
458 
459       II->replaceAllUsesWith(NewCall);
460       ToErase.push_back(II);
461 
462       // Post-invoke
463       // %__THREW__.val = __THREW__; __THREW__ = 0;
464       Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
465       IRB.CreateStore(IRB.getFalse(), ThrewGV);
466 
467       // Insert a branch based on __THREW__ variable
468       IRB.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest());
469 
470     } else {
471       // This can't throw, and we don't need this invoke, just replace it with a
472       // call+branch
473       SmallVector<Value *, 16> CallArgs(II->arg_begin(), II->arg_end());
474       CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), CallArgs);
475       NewCall->takeName(II);
476       NewCall->setCallingConv(II->getCallingConv());
477       NewCall->setDebugLoc(II->getDebugLoc());
478       NewCall->setAttributes(II->getAttributes());
479       II->replaceAllUsesWith(NewCall);
480       ToErase.push_back(II);
481 
482       IRB.CreateBr(II->getNormalDest());
483 
484       // Remove any PHI node entries from the exception destination
485       II->getUnwindDest()->removePredecessor(&BB);
486     }
487   }
488 
489   // Process resume instructions
490   for (BasicBlock &BB : F) {
491     // Scan the body of the basic block for resumes
492     for (Instruction &I : BB) {
493       auto *RI = dyn_cast<ResumeInst>(&I);
494       if (!RI)
495         continue;
496 
497       // Split the input into legal values
498       Value *Input = RI->getValue();
499       IRB.SetInsertPoint(RI);
500       Value *Low = IRB.CreateExtractValue(Input, 0, "low");
501 
502       // Create a call to __resumeException function
503       Value *Args[] = {Low};
504       IRB.CreateCall(ResumeF, Args);
505 
506       // Add a terminator to the block
507       IRB.CreateUnreachable();
508       ToErase.push_back(RI);
509     }
510   }
511 
512   // Process llvm.eh.typeid.for intrinsics
513   for (BasicBlock &BB : F) {
514     for (Instruction &I : BB) {
515       auto *CI = dyn_cast<CallInst>(&I);
516       if (!CI)
517         continue;
518       const Function *Callee = CI->getCalledFunction();
519       if (!Callee)
520         continue;
521       if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
522         continue;
523 
524       IRB.SetInsertPoint(CI);
525       CallInst *NewCI =
526           IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
527       CI->replaceAllUsesWith(NewCI);
528       ToErase.push_back(CI);
529     }
530   }
531 
532   // Look for orphan landingpads, can occur in blocks with no predecesors
533   for (BasicBlock &BB : F) {
534     Instruction *I = BB.getFirstNonPHI();
535     if (auto *LPI = dyn_cast<LandingPadInst>(I))
536       LandingPads.insert(LPI);
537   }
538 
539   // Handle all the landingpad for this function together, as multiple invokes
540   // may share a single lp
541   for (LandingPadInst *LPI : LandingPads) {
542     IRB.SetInsertPoint(LPI);
543     SmallVector<Value *, 16> FMCArgs;
544     for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
545       Constant *Clause = LPI->getClause(i);
546       // As a temporary workaround for the lack of aggregate varargs support
547       // in the interface between JS and wasm, break out filter operands into
548       // their component elements.
549       if (LPI->isFilter(i)) {
550         ArrayType *ATy = cast<ArrayType>(Clause->getType());
551         for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
552           Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
553           FMCArgs.push_back(EV);
554         }
555       } else
556         FMCArgs.push_back(Clause);
557     }
558 
559     // Create a call to __cxa_find_matching_catch_N function
560     Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
561     CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
562     Value *Undef = UndefValue::get(LPI->getType());
563     Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
564     Value *TempRet0 = IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val");
565     Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
566 
567     LPI->replaceAllUsesWith(Pair1);
568     ToErase.push_back(LPI);
569   }
570 
571   // Erase everything we no longer need in this function
572   for (Instruction *I : ToErase)
573     I->eraseFromParent();
574 
575   return Changed;
576 }
577 
578 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
579   // TODO
580   return false;
581 }
582