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