summaryrefslogtreecommitdiff
path: root/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp')
-rw-r--r--lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp119
1 files changed, 60 insertions, 59 deletions
diff --git a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 960d5134f6e9..1cf397dd060b 100644
--- a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -227,15 +227,6 @@ static cl::list<std::string>
namespace {
class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
- static const char *ResumeFName;
- static const char *EHTypeIDFName;
- static const char *EmLongjmpFName;
- static const char *EmLongjmpJmpbufFName;
- static const char *SaveSetjmpFName;
- static const char *TestSetjmpFName;
- static const char *FindMatchingCatchPrefix;
- static const char *InvokePrefix;
-
bool EnableEH; // Enable exception handling
bool EnableSjLj; // Enable setjmp/longjmp handling
@@ -274,6 +265,7 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
bool canLongjmp(Module &M, const Value *Callee) const;
+ bool isEmAsmCall(Module &M, const Value *Callee) const;
void rebuildSSA(Function &F);
@@ -292,19 +284,6 @@ public:
};
} // End anonymous namespace
-const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException";
-const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
- "llvm_eh_typeid_for";
-const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
- "emscripten_longjmp";
-const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
- "emscripten_longjmp_jmpbuf";
-const char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName = "saveSetjmp";
-const char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName = "testSetjmp";
-const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
- "__cxa_find_matching_catch_";
-const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
-
char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
"WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
@@ -335,7 +314,8 @@ static bool canThrow(const Value *V) {
static GlobalVariable *getGlobalVariableI32(Module &M, IRBuilder<> &IRB,
const char *Name) {
- auto* GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, IRB.getInt32Ty()));
+ auto *GV =
+ dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, IRB.getInt32Ty()));
if (!GV)
report_fatal_error(Twine("unable to create global: ") + Name);
@@ -376,9 +356,9 @@ WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
- Function *F =
- Function::Create(FTy, GlobalValue::ExternalLinkage,
- FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
+ Function *F = Function::Create(
+ FTy, GlobalValue::ExternalLinkage,
+ "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
FindMatchingCatches[NumClauses] = F;
return F;
}
@@ -418,7 +398,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
Args.append(CI->arg_begin(), CI->arg_end());
CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
NewCall->takeName(CI);
- NewCall->setCallingConv(CI->getCallingConv());
+ NewCall->setCallingConv(CallingConv::WASM_EmscriptenInvoke);
NewCall->setDebugLoc(CI->getDebugLoc());
// Because we added the pointer to the callee as first argument, all
@@ -432,9 +412,22 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
for (unsigned I = 0, E = CI->getNumArgOperands(); I < E; ++I)
ArgAttributes.push_back(InvokeAL.getParamAttributes(I));
+ AttrBuilder FnAttrs(InvokeAL.getFnAttributes());
+ if (FnAttrs.contains(Attribute::AllocSize)) {
+ // The allocsize attribute (if any) referes to parameters by index and needs
+ // to be adjusted.
+ unsigned SizeArg;
+ Optional<unsigned> NEltArg;
+ std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs();
+ SizeArg += 1;
+ if (NEltArg.hasValue())
+ NEltArg = NEltArg.getValue() + 1;
+ FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
+ }
+
// Reconstruct the AttributesList based on the vector we constructed.
AttributeList NewCallAL =
- AttributeList::get(C, InvokeAL.getFnAttributes(),
+ AttributeList::get(C, AttributeSet::get(C, FnAttrs),
InvokeAL.getRetAttributes(), ArgAttributes);
NewCall->setAttributes(NewCallAL);
@@ -473,8 +466,8 @@ Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
CalleeFTy->isVarArg());
- Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
- InvokePrefix + Sig, M);
+ Function *F =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, "__invoke_" + Sig, M);
InvokeWrappers[Sig] = F;
return F;
}
@@ -491,39 +484,44 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
// and can't be passed by pointer. The result is a crash with illegal IR.
if (isa<InlineAsm>(Callee))
return false;
+ StringRef CalleeName = Callee->getName();
// The reason we include malloc/free here is to exclude the malloc/free
// calls generated in setjmp prep / cleanup routines.
- Function *SetjmpF = M.getFunction("setjmp");
- Function *MallocF = M.getFunction("malloc");
- Function *FreeF = M.getFunction("free");
- if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
+ if (CalleeName == "setjmp" || CalleeName == "malloc" || CalleeName == "free")
return false;
// There are functions in JS glue code
- if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
- Callee == TestSetjmpF)
+ if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" ||
+ CalleeName == "saveSetjmp" || CalleeName == "testSetjmp" ||
+ CalleeName == "getTempRet0" || CalleeName == "setTempRet0")
return false;
// __cxa_find_matching_catch_N functions cannot longjmp
- if (Callee->getName().startswith(FindMatchingCatchPrefix))
+ if (Callee->getName().startswith("__cxa_find_matching_catch_"))
return false;
// Exception-catching related functions
- Function *BeginCatchF = M.getFunction("__cxa_begin_catch");
- Function *EndCatchF = M.getFunction("__cxa_end_catch");
- Function *AllocExceptionF = M.getFunction("__cxa_allocate_exception");
- Function *ThrowF = M.getFunction("__cxa_throw");
- Function *TerminateF = M.getFunction("__clang_call_terminate");
- if (Callee == BeginCatchF || Callee == EndCatchF ||
- Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF ||
- Callee == GetTempRet0Func || Callee == SetTempRet0Func)
+ if (CalleeName == "__cxa_begin_catch" || CalleeName == "__cxa_end_catch" ||
+ CalleeName == "__cxa_allocate_exception" || CalleeName == "__cxa_throw" ||
+ CalleeName == "__clang_call_terminate")
return false;
// Otherwise we don't know
return true;
}
+bool WebAssemblyLowerEmscriptenEHSjLj::isEmAsmCall(Module &M,
+ const Value *Callee) const {
+ StringRef CalleeName = Callee->getName();
+ // This is an exhaustive list from Emscripten's <emscripten/em_asm.h>.
+ return CalleeName == "emscripten_asm_const_int" ||
+ CalleeName == "emscripten_asm_const_double" ||
+ CalleeName == "emscripten_asm_const_int_sync_on_main_thread" ||
+ CalleeName == "emscripten_asm_const_double_sync_on_main_thread" ||
+ CalleeName == "emscripten_asm_const_async_on_main_thread";
+}
+
// Generate testSetjmp function call seqence with preamble and postamble.
// The code this generates is equivalent to the following JavaScript code:
// if (%__THREW__.val != 0 & threwValue != 0) {
@@ -605,15 +603,12 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
SSAUpdater SSA;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
+ SSA.Initialize(I.getType(), I.getName());
+ SSA.AddAvailableValue(&BB, &I);
for (auto UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
Use &U = *UI;
++UI;
- SSA.Initialize(I.getType(), I.getName());
- SSA.AddAvailableValue(&BB, &I);
auto *User = cast<Instruction>(U.getUser());
- if (User->getParent() == &BB)
- continue;
-
if (auto *UserPN = dyn_cast<PHINode>(User))
if (UserPN->getIncomingBlock(U) == &BB)
continue;
@@ -660,13 +655,13 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
FunctionType *ResumeFTy =
FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
- ResumeFName, &M);
+ "__resumeException", &M);
// Register llvm_eh_typeid_for function
FunctionType *EHTypeIDTy =
FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
- EHTypeIDFName, &M);
+ "llvm_eh_typeid_for", &M);
for (Function &F : M) {
if (F.isDeclaration())
@@ -684,7 +679,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
// defined in JS code
EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(),
GlobalValue::ExternalLinkage,
- EmLongjmpJmpbufFName, &M);
+ "emscripten_longjmp_jmpbuf", &M);
LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF);
}
@@ -697,19 +692,19 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
IRB.getInt32Ty()};
FunctionType *FTy =
FunctionType::get(Type::getInt32PtrTy(C), Params, false);
- SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
- SaveSetjmpFName, &M);
+ SaveSetjmpF =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, "saveSetjmp", &M);
// Register testSetjmp function
Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()};
FTy = FunctionType::get(IRB.getInt32Ty(), Params, false);
- TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
- TestSetjmpFName, &M);
+ TestSetjmpF =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, "testSetjmp", &M);
FTy = FunctionType::get(IRB.getVoidTy(),
{IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
EmLongjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
- EmLongjmpFName, &M);
+ "emscripten_longjmp", &M);
// Only traverse functions that uses setjmp in order not to insert
// unnecessary prep / cleanup code in every function
@@ -970,10 +965,16 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
const Value *Callee = CI->getCalledValue();
if (!canLongjmp(M, Callee))
continue;
+ if (isEmAsmCall(M, Callee))
+ report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
+ F.getName() +
+ ". Please consider using EM_JS, or move the "
+ "EM_ASM into another function.",
+ false);
Value *Threw = nullptr;
BasicBlock *Tail;
- if (Callee->getName().startswith(InvokePrefix)) {
+ if (Callee->getName().startswith("__invoke_")) {
// If invoke wrapper has already been generated for this call in
// previous EH phase, search for the load instruction
// %__THREW__.val = __THREW__;