LLVM 22.0.0git
WebAssemblyLowerEmscriptenEHSjLj.cpp File Reference

This file lowers exception-related instructions and setjmp/longjmp function calls to use Emscripten's library functions. More...

Go to the source code of this file.

Macros

#define DEBUG_TYPE   "wasm-lower-em-ehsjlj"

Functions

 INITIALIZE_PASS (WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE, "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", false, false) ModulePass *llvm
static bool canThrow (const Value *V)
static GlobalVariablegetGlobalVariable (Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
static std::string getSignature (FunctionType *FTy)
static FunctiongetFunction (FunctionType *Ty, const Twine &Name, Module *M)
static void markAsImported (Function *F)
static TypegetAddrIntType (Module *M)
static TypegetAddrPtrType (Module *M)
static ValuegetAddrSizeInt (Module *M, uint64_t C)
static bool canLongjmp (const Value *Callee)
static bool isEmAsmCall (const Value *Callee)
static bool containsLongjmpableCalls (const Function *F)
static void nullifySetjmp (Function *F)
static DebugLoc getOrCreateDebugLoc (const Instruction *InsertBefore, DISubprogram *SP)
static BasicBlockgetCleanupRetUnwindDest (const CleanupPadInst *CPI)

Variables

static cl::list< std::stringEHAllowlist ("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated)

Detailed Description

This file lowers exception-related instructions and setjmp/longjmp function calls to use Emscripten's library functions.

The pass uses JavaScript's try and catch mechanism in case of Emscripten EH/SjLj and Wasm EH intrinsics in case of Emscripten SjLJ.

  • Emscripten exception handling This pass lowers invokes and landingpads into library functions in JS glue code. Invokes are lowered into function wrappers called invoke wrappers that exist in JS side, which wraps the original function call with JS try-catch. If an exception occurred, cxa_throw() function in JS side sets some variables (see below) so we can check whether an exception occurred from wasm code and handle it appropriately.
  • Emscripten setjmp-longjmp handling This pass lowers setjmp to a reasonably-performant approach for emscripten. The idea is that each block with a setjmp is broken up into two parts: the part containing setjmp and the part right after the setjmp. The latter part is either reached from the setjmp, or later from a longjmp. To handle the longjmp, all calls that might longjmp are also called using invoke wrappers and thus JS / try-catch. JS longjmp() function also sets some variables so we can check / whether a longjmp occurred from wasm code. Each block with a function call that might longjmp is also split up after the longjmp call. After the longjmp call, we check whether a longjmp occurred, and if it did, which setjmp it corresponds to, and jump to the right post-setjmp block. We assume setjmp-longjmp handling always run after EH handling, which means we don't expect any exception-related instructions when SjLj runs. FIXME Currently this scheme does not support indirect call of setjmp, because of the limitation of the scheme itself. fastcomp does not support it either.

In detail, this pass does following things:

1) Assumes the existence of global variables: THREW, threwValue __THREW and threwValue are defined in compiler-rt in Emscripten. These variables are used for both exceptions and setjmp/longjmps. __THREW indicates whether an exception or a longjmp occurred or not. 0 means nothing occurred, 1 means an exception occurred, and other numbers mean a longjmp occurred. In the case of longjmp, THREW variable indicates the corresponding setjmp buffer the longjmp corresponds to. __threwValue is 0 for exceptions, and the argument to longjmp in case of longjmp.

  • Emscripten exception handling

2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions at link time. setThrew exists in Emscripten's compiler-rt:

void setThrew(uintptr_t threw, int value) { if (THREW == 0) { THREW = threw; __threwValue = value; } }

Definition in file WebAssemblyLowerEmscriptenEHSjLj.cpp.

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   "wasm-lower-em-ehsjlj"

Definition at line 283 of file WebAssemblyLowerEmscriptenEHSjLj.cpp.

Function Documentation

◆ canLongjmp()

bool canLongjmp ( const Value * Callee)
static

◆ canThrow()

◆ containsLongjmpableCalls()

bool containsLongjmpableCalls ( const Function * F)
static

Definition at line 868 of file WebAssemblyLowerEmscriptenEHSjLj.cpp.

References canLongjmp(), llvm::dyn_cast(), F, and I.

◆ getAddrIntType()

Type * getAddrIntType ( Module * M)
static

◆ getAddrPtrType()

Type * getAddrPtrType ( Module * M)
static

◆ getAddrSizeInt()

Value * getAddrSizeInt ( Module * M,
uint64_t C )
static

◆ getCleanupRetUnwindDest()

BasicBlock * getCleanupRetUnwindDest ( const CleanupPadInst * CPI)
static

◆ getFunction()

◆ getGlobalVariable()

◆ getOrCreateDebugLoc()

◆ getSignature()

◆ INITIALIZE_PASS()

INITIALIZE_PASS ( WebAssemblyLowerEmscriptenEHSjLj ,
DEBUG_TYPE ,
"WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp" ,
false ,
false  )

◆ isEmAsmCall()

bool isEmAsmCall ( const Value * Callee)
static

Definition at line 677 of file WebAssemblyLowerEmscriptenEHSjLj.cpp.

◆ markAsImported()

void markAsImported ( Function * F)
static

Definition at line 446 of file WebAssemblyLowerEmscriptenEHSjLj.cpp.

References B(), and F.

◆ nullifySetjmp()

Variable Documentation

◆ EHAllowlist

cl::list< std::string > EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated) ( "emscripten-cxx-exceptions-allowed" ,
cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)") ,
cl::CommaSeparated  )
static