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