blob: 7a7587b02db6bb79fc969e0459b3052ffedf2aea [file] [log] [blame]
Derek Schufff41f67d2016-08-01 21:34:04 +00001// WebAssemblyLowerEmscriptenExceptions.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.
Derek Schuff53b9af02016-08-09 00:29:55 +000027/// tempRet0 will be set within __cxa_find_matching_catch() function in
Derek Schufff41f67d2016-08-01 21:34:04 +000028/// 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
Derek Schuff53b9af02016-08-09 00:29:55 +000080/// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
Derek Schufff41f67d2016-08-01 21:34:04 +000081/// %val = {%fmc, tempRet0}
82/// ... use %val ...
83/// Here N is a number calculated based on the number of clauses.
Derek Schuff53b9af02016-08-09 00:29:55 +000084/// Global variable tempRet0 is set within __cxa_find_matching_catch() in
Derek Schufff41f67d2016-08-01 21:34:04 +000085/// JS glue code.
86///
87/// 5) Lower
88/// resume {%a, %b}
89/// into
Derek Schuff53b9af02016-08-09 00:29:55 +000090/// call @__resumeException(%a)
91/// where __resumeException() is a function in JS glue code.
Derek Schufff41f67d2016-08-01 21:34:04 +000092///
Derek Schuff53b9af02016-08-09 00:29:55 +000093/// 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.
Derek Schufff41f67d2016-08-01 21:34:04 +000098///
99///===----------------------------------------------------------------------===//
100
101#include "WebAssembly.h"
Derek Schuff53b9af02016-08-09 00:29:55 +0000102#include "llvm/IR/CallSite.h"
Derek Schufff41f67d2016-08-01 21:34:04 +0000103#include "llvm/IR/IRBuilder.h"
Derek Schufff41f67d2016-08-01 21:34:04 +0000104#include "llvm/IR/Module.h"
Derek Schufff41f67d2016-08-01 21:34:04 +0000105#include "llvm/Support/raw_ostream.h"
Derek Schuff53b9af02016-08-09 00:29:55 +0000106#include <set>
Derek Schufff41f67d2016-08-01 21:34:04 +0000107
108using namespace llvm;
109
110#define DEBUG_TYPE "wasm-lower-em-exceptions"
111
Derek Schuff66641322016-08-09 22:37:00 +0000112static cl::list<std::string>
113 Whitelist("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
Derek Schufff41f67d2016-08-01 21:34:04 +0000119namespace {
120class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
121 const char *getPassName() const override {
122 return "WebAssembly Lower Emscripten Exceptions";
123 }
124
125 bool runOnFunction(Function &F);
Derek Schuff53b9af02016-08-09 00:29:55 +0000126 // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
Derek Schufff41f67d2016-08-01 21:34:04 +0000127 // This is because a landingpad instruction contains two more arguments,
Derek Schuff53b9af02016-08-09 00:29:55 +0000128 // a personality function and a cleanup bit, and __cxa_find_matching_catch_N
Derek Schufff41f67d2016-08-01 21:34:04 +0000129 // functions are named after the number of arguments in the original
130 // landingpad instruction.
131 Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
132
133 Function *getInvokeWrapper(Module &M, InvokeInst *II);
Derek Schuff66641322016-08-09 22:37:00 +0000134 bool areAllExceptionsAllowed() const { return WhitelistSet.empty(); }
Derek Schufff41f67d2016-08-01 21:34:04 +0000135
136 GlobalVariable *ThrewGV; // __THREW__
137 GlobalVariable *ThrewValueGV; // threwValue
138 GlobalVariable *TempRet0GV; // tempRet0
Derek Schuff53b9af02016-08-09 00:29:55 +0000139 Function *ResumeF; // __resumeException
140 Function *EHTypeIdF; // llvm_eh_typeid_for
141 // __cxa_find_matching_catch_N functions.
Derek Schufff41f67d2016-08-01 21:34:04 +0000142 // Indexed by the number of clauses in an original landingpad instruction.
143 DenseMap<int, Function *> FindMatchingCatches;
144 // Map of <function signature string, invoke_ wrappers>
145 StringMap<Function *> InvokeWrappers;
Derek Schuff66641322016-08-09 22:37:00 +0000146 // Set of whitelisted function names
147 std::set<std::string> WhitelistSet;
Derek Schufff41f67d2016-08-01 21:34:04 +0000148
149public:
150 static char ID;
151
152 WebAssemblyLowerEmscriptenExceptions()
153 : ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr),
Derek Schuff66641322016-08-09 22:37:00 +0000154 TempRet0GV(nullptr) {
155 WhitelistSet.insert(Whitelist.begin(), Whitelist.end());
156 }
Derek Schufff41f67d2016-08-01 21:34:04 +0000157 bool runOnModule(Module &M) override;
158};
159} // End anonymous namespace
160
161char WebAssemblyLowerEmscriptenExceptions::ID = 0;
162INITIALIZE_PASS(WebAssemblyLowerEmscriptenExceptions, DEBUG_TYPE,
163 "WebAssembly Lower Emscripten Exceptions", false, false)
164
165ModulePass *llvm::createWebAssemblyLowerEmscriptenExceptions() {
166 return new WebAssemblyLowerEmscriptenExceptions();
167}
168
169static bool canThrow(const Value *V) {
170 if (const auto *F = dyn_cast<const Function>(V)) {
171 // Intrinsics cannot throw
172 if (F->isIntrinsic())
173 return false;
174 StringRef Name = F->getName();
175 // leave setjmp and longjmp (mostly) alone, we process them properly later
176 if (Name == "setjmp" || Name == "longjmp")
177 return false;
178 return true;
179 }
180 return true; // not a function, so an indirect call - can throw, we can't tell
181}
182
183// Returns an available name for a global value.
184// If the proposed name already exists in the module, adds '_' at the end of
185// the name until the name is available.
186static inline std::string createGlobalValueName(const Module &M,
187 const std::string &Propose) {
188 std::string Name = Propose;
189 while (M.getNamedGlobal(Name))
190 Name += "_";
191 return Name;
192}
193
194// Simple function name mangler.
195// This function simply takes LLVM's string representation of parameter types
Derek Schuff53b9af02016-08-09 00:29:55 +0000196// and concatenate them with '_'. There are non-alphanumeric characters but llc
197// is ok with it, and we need to postprocess these names after the lowering
198// phase anyway.
Derek Schufff41f67d2016-08-01 21:34:04 +0000199static std::string getSignature(FunctionType *FTy) {
200 std::string Sig;
201 raw_string_ostream OS(Sig);
202 OS << *FTy->getReturnType();
203 for (Type *ParamTy : FTy->params())
204 OS << "_" << *ParamTy;
205 if (FTy->isVarArg())
206 OS << "_...";
207 Sig = OS.str();
208 Sig.erase(std::remove_if(Sig.begin(), Sig.end(), isspace), Sig.end());
Derek Schuff53b9af02016-08-09 00:29:55 +0000209 // When s2wasm parses .s file, a comma means the end of an argument. So a
210 // mangled function name can contain any character but a comma.
211 std::replace(Sig.begin(), Sig.end(), ',', '.');
Derek Schufff41f67d2016-08-01 21:34:04 +0000212 return Sig;
213}
214
215Function *WebAssemblyLowerEmscriptenExceptions::getFindMatchingCatch(
216 Module &M, unsigned NumClauses) {
217 if (FindMatchingCatches.count(NumClauses))
218 return FindMatchingCatches[NumClauses];
219 PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
220 SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
221 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
222 Function *F = Function::Create(
223 FTy, GlobalValue::ExternalLinkage,
Derek Schuff53b9af02016-08-09 00:29:55 +0000224 "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
Derek Schufff41f67d2016-08-01 21:34:04 +0000225 FindMatchingCatches[NumClauses] = F;
226 return F;
227}
228
229Function *
230WebAssemblyLowerEmscriptenExceptions::getInvokeWrapper(Module &M,
231 InvokeInst *II) {
232 SmallVector<Type *, 16> ArgTys;
233 Value *Callee = II->getCalledValue();
234 FunctionType *CalleeFTy;
235 if (auto *F = dyn_cast<Function>(Callee))
236 CalleeFTy = F->getFunctionType();
237 else {
238 auto *CalleeTy = dyn_cast<PointerType>(Callee->getType())->getElementType();
239 CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
240 }
241
242 std::string Sig = getSignature(CalleeFTy);
243 if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
244 return InvokeWrappers[Sig];
245
246 // Put the pointer to the callee as first argument
247 ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
248 // Add argument types
249 ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
250
251 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
252 CalleeFTy->isVarArg());
253 Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
254 "__invoke_" + Sig, &M);
255 InvokeWrappers[Sig] = F;
256 return F;
257}
258
259bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) {
Derek Schuff53b9af02016-08-09 00:29:55 +0000260 LLVMContext &C = M.getContext();
261 IRBuilder<> Builder(C);
Derek Schufff41f67d2016-08-01 21:34:04 +0000262 IntegerType *Int1Ty = Builder.getInt1Ty();
263 PointerType *Int8PtrTy = Builder.getInt8PtrTy();
264 IntegerType *Int32Ty = Builder.getInt32Ty();
Derek Schuff53b9af02016-08-09 00:29:55 +0000265 Type *VoidTy = Builder.getVoidTy();
Derek Schufff41f67d2016-08-01 21:34:04 +0000266
267 // Create global variables __THREW__, threwValue, and tempRet0
268 ThrewGV = new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage,
269 Builder.getFalse(),
270 createGlobalValueName(M, "__THREW__"));
271 ThrewValueGV = new GlobalVariable(
272 M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0),
273 createGlobalValueName(M, "threwValue"));
274 TempRet0GV = new GlobalVariable(
275 M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0),
276 createGlobalValueName(M, "tempRet0"));
277
Derek Schuff53b9af02016-08-09 00:29:55 +0000278 // Register __resumeException function
Derek Schufff41f67d2016-08-01 21:34:04 +0000279 FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false);
280 ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
Derek Schuff53b9af02016-08-09 00:29:55 +0000281 "__resumeException", &M);
282
283 // Register llvm_eh_typeid_for function
284 FunctionType *EHTypeIdTy = FunctionType::get(Int32Ty, Int8PtrTy, false);
285 EHTypeIdF = Function::Create(EHTypeIdTy, GlobalValue::ExternalLinkage,
286 "llvm_eh_typeid_for", &M);
Derek Schufff41f67d2016-08-01 21:34:04 +0000287
288 bool Changed = false;
289 for (Function &F : M) {
290 if (F.isDeclaration())
291 continue;
292 Changed |= runOnFunction(F);
293 }
294
295 if (!Changed)
296 return false;
297
298 assert(!M.getNamedGlobal("setThrew") && "setThrew already exists");
299 assert(!M.getNamedGlobal("setTempRet0") && "setTempRet0 already exists");
300
301 // Create setThrew function
302 SmallVector<Type *, 2> Params = {Int1Ty, Int32Ty};
303 FunctionType *FTy = FunctionType::get(VoidTy, Params, false);
304 Function *F =
305 Function::Create(FTy, GlobalValue::ExternalLinkage, "setThrew", &M);
306 Argument *Arg1 = &*(F->arg_begin());
307 Argument *Arg2 = &*(++F->arg_begin());
308 Arg1->setName("threw");
309 Arg2->setName("value");
Derek Schuff53b9af02016-08-09 00:29:55 +0000310 BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
311 BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
312 BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
Derek Schufff41f67d2016-08-01 21:34:04 +0000313
314 Builder.SetInsertPoint(EntryBB);
315 Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
316 Value *Cmp = Builder.CreateICmpEQ(Threw, Builder.getFalse(), "cmp");
317 Builder.CreateCondBr(Cmp, ThenBB, EndBB);
318
319 Builder.SetInsertPoint(ThenBB);
320 Builder.CreateStore(Arg1, ThrewGV);
321 Builder.CreateStore(Arg2, ThrewValueGV);
322 Builder.CreateBr(EndBB);
323
324 Builder.SetInsertPoint(EndBB);
325 Builder.CreateRetVoid();
326
327 // Create setTempRet0 function
328 Params = {Int32Ty};
329 FTy = FunctionType::get(VoidTy, Params, false);
330 F = Function::Create(FTy, GlobalValue::ExternalLinkage, "setTempRet0", &M);
331 F->arg_begin()->setName("value");
Derek Schuff53b9af02016-08-09 00:29:55 +0000332 EntryBB = BasicBlock::Create(C, "entry", F);
Derek Schufff41f67d2016-08-01 21:34:04 +0000333 Builder.SetInsertPoint(EntryBB);
334 Builder.CreateStore(&*F->arg_begin(), TempRet0GV);
335 Builder.CreateRetVoid();
336
337 return true;
338}
339
340bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) {
341 Module &M = *F.getParent();
Derek Schuff53b9af02016-08-09 00:29:55 +0000342 LLVMContext &C = F.getContext();
343 IRBuilder<> Builder(C);
Derek Schufff41f67d2016-08-01 21:34:04 +0000344 bool Changed = false;
345 SmallVector<Instruction *, 64> ToErase;
346 SmallPtrSet<LandingPadInst *, 32> LandingPads;
Derek Schuff66641322016-08-09 22:37:00 +0000347 bool AllowExceptions =
348 areAllExceptionsAllowed() || WhitelistSet.count(F.getName());
Derek Schufff41f67d2016-08-01 21:34:04 +0000349
350 for (BasicBlock &BB : F) {
351 auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
352 if (!II)
353 continue;
354 Changed = true;
355 LandingPads.insert(II->getLandingPadInst());
356 Builder.SetInsertPoint(II);
357
Derek Schuff53b9af02016-08-09 00:29:55 +0000358 bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
359 if (NeedInvoke) {
Derek Schufff41f67d2016-08-01 21:34:04 +0000360 // If we are calling a function that is noreturn, we must remove that
361 // attribute. The code we insert here does expect it to return, after we
362 // catch the exception.
363 if (II->doesNotReturn()) {
364 if (auto *F = dyn_cast<Function>(II->getCalledValue()))
365 F->removeFnAttr(Attribute::NoReturn);
366 AttributeSet NewAttrs = II->getAttributes();
Derek Schuff53b9af02016-08-09 00:29:55 +0000367 NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
Derek Schufff41f67d2016-08-01 21:34:04 +0000368 Attribute::NoReturn);
369 II->setAttributes(NewAttrs);
370 }
371
372 // Pre-invoke
373 // __THREW__ = 0;
374 Builder.CreateStore(Builder.getFalse(), ThrewGV);
375
376 // Invoke function wrapper in JavaScript
377 SmallVector<Value *, 16> CallArgs;
378 // Put the pointer to the callee as first argument, so it can be called
379 // within the invoke wrapper later
380 CallArgs.push_back(II->getCalledValue());
381 CallArgs.append(II->arg_begin(), II->arg_end());
382 CallInst *NewCall = Builder.CreateCall(getInvokeWrapper(M, II), CallArgs);
383 NewCall->takeName(II);
384 NewCall->setCallingConv(II->getCallingConv());
Derek Schufff41f67d2016-08-01 21:34:04 +0000385 NewCall->setDebugLoc(II->getDebugLoc());
Derek Schuff53b9af02016-08-09 00:29:55 +0000386
387 // Because we added the pointer to the callee as first argument, all
388 // argument attribute indices have to be incremented by one.
389 SmallVector<AttributeSet, 8> AttributesVec;
390 const AttributeSet &InvokePAL = II->getAttributes();
391 CallSite::arg_iterator AI = II->arg_begin();
392 unsigned i = 1; // Argument attribute index starts from 1
393 for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) {
394 if (InvokePAL.hasAttributes(i)) {
395 AttrBuilder B(InvokePAL, i);
396 AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
397 }
398 }
399 // Add any return attributes.
400 if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
401 AttributesVec.push_back(
402 AttributeSet::get(C, InvokePAL.getRetAttributes()));
403 // Add any function attributes.
404 if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
405 AttributesVec.push_back(
406 AttributeSet::get(C, InvokePAL.getFnAttributes()));
407 // Reconstruct the AttributesList based on the vector we constructed.
408 AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
409 NewCall->setAttributes(NewCallPAL);
410
Derek Schufff41f67d2016-08-01 21:34:04 +0000411 II->replaceAllUsesWith(NewCall);
412 ToErase.push_back(II);
413
414 // Post-invoke
415 // %__THREW__.val = __THREW__; __THREW__ = 0;
416 Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
417 Builder.CreateStore(Builder.getFalse(), ThrewGV);
418
419 // Insert a branch based on __THREW__ variable
420 Builder.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest());
421
422 } else {
423 // This can't throw, and we don't need this invoke, just replace it with a
424 // call+branch
425 SmallVector<Value *, 16> CallArgs(II->arg_begin(), II->arg_end());
426 CallInst *NewCall = Builder.CreateCall(II->getCalledValue(), CallArgs);
427 NewCall->takeName(II);
428 NewCall->setCallingConv(II->getCallingConv());
Derek Schufff41f67d2016-08-01 21:34:04 +0000429 NewCall->setDebugLoc(II->getDebugLoc());
Derek Schuff53b9af02016-08-09 00:29:55 +0000430 NewCall->setAttributes(II->getAttributes());
Derek Schufff41f67d2016-08-01 21:34:04 +0000431 II->replaceAllUsesWith(NewCall);
432 ToErase.push_back(II);
433
434 Builder.CreateBr(II->getNormalDest());
435
436 // Remove any PHI node entries from the exception destination
437 II->getUnwindDest()->removePredecessor(&BB);
438 }
439 }
440
441 // Process resume instructions
442 for (BasicBlock &BB : F) {
443 // Scan the body of the basic block for resumes
444 for (Instruction &I : BB) {
445 auto *RI = dyn_cast<ResumeInst>(&I);
446 if (!RI)
447 continue;
448
449 // Split the input into legal values
450 Value *Input = RI->getValue();
451 Builder.SetInsertPoint(RI);
452 Value *Low = Builder.CreateExtractValue(Input, 0, "low");
453
Derek Schuff53b9af02016-08-09 00:29:55 +0000454 // Create a call to __resumeException function
Derek Schufff41f67d2016-08-01 21:34:04 +0000455 Value *Args[] = {Low};
456 Builder.CreateCall(ResumeF, Args);
457
458 // Add a terminator to the block
459 Builder.CreateUnreachable();
460 ToErase.push_back(RI);
461 }
462 }
463
Derek Schuff53b9af02016-08-09 00:29:55 +0000464 // Process llvm.eh.typeid.for intrinsics
465 for (BasicBlock &BB : F) {
466 for (Instruction &I : BB) {
467 auto *CI = dyn_cast<CallInst>(&I);
468 if (!CI)
469 continue;
470 const Function *Callee = CI->getCalledFunction();
471 if (!Callee)
472 continue;
473 if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
474 continue;
475
476 Builder.SetInsertPoint(CI);
477 CallInst *NewCI =
478 Builder.CreateCall(EHTypeIdF, CI->getArgOperand(0), "typeid");
479 CI->replaceAllUsesWith(NewCI);
480 ToErase.push_back(CI);
481 }
482 }
483
Derek Schufff41f67d2016-08-01 21:34:04 +0000484 // Look for orphan landingpads, can occur in blocks with no predecesors
485 for (BasicBlock &BB : F) {
486 Instruction *I = BB.getFirstNonPHI();
487 if (auto *LPI = dyn_cast<LandingPadInst>(I))
488 LandingPads.insert(LPI);
489 }
490
491 // Handle all the landingpad for this function together, as multiple invokes
492 // may share a single lp
493 for (LandingPadInst *LPI : LandingPads) {
494 Builder.SetInsertPoint(LPI);
495 SmallVector<Value *, 16> FMCArgs;
496 for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
497 Constant *Clause = LPI->getClause(i);
498 // As a temporary workaround for the lack of aggregate varargs support
499 // in the interface between JS and wasm, break out filter operands into
500 // their component elements.
501 if (LPI->isFilter(i)) {
502 ArrayType *ATy = cast<ArrayType>(Clause->getType());
503 for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
504 Value *EV =
505 Builder.CreateExtractValue(Clause, makeArrayRef(j), "filter");
506 FMCArgs.push_back(EV);
507 }
508 } else
509 FMCArgs.push_back(Clause);
510 }
511
Derek Schuff53b9af02016-08-09 00:29:55 +0000512 // Create a call to __cxa_find_matching_catch_N function
Derek Schufff41f67d2016-08-01 21:34:04 +0000513 Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
514 CallInst *FMCI = Builder.CreateCall(FMCF, FMCArgs, "fmc");
515 Value *Undef = UndefValue::get(LPI->getType());
516 Value *Pair0 = Builder.CreateInsertValue(Undef, FMCI, 0, "pair0");
517 Value *TempRet0 =
518 Builder.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val");
519 Value *Pair1 = Builder.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
520
521 LPI->replaceAllUsesWith(Pair1);
522 ToErase.push_back(LPI);
523 }
524
525 // Erase everything we no longer need in this function
526 for (Instruction *I : ToErase)
527 I->eraseFromParent();
528
529 return Changed;
530}