setjmp-longjmp 支持在 Emscripten 中默认启用。这由 SUPPORT_LONGJMP
设置控制,该设置可以取以下值
emscripten
: 基于 JavaScript 的支持
wasm
: 基于 WebAssembly 异常处理的支持
0: 不支持
1: 默认支持,具体取决于异常模式。如果使用 -fwasm-exception
,则为 wasm
,否则为 emscripten
。
如果使用 原生 Wasm 异常,SUPPORT_LONGJMP
默认值为 wasm
,如果使用 基于 JavaScript 的异常 或不使用异常支持,则默认值为 emscripten
。
setjmp
将有关调用环境的信息保存到一个缓冲区中,longjmp
通过使用该缓冲区将控制权转移回 setjmp
被调用的位置。 longjmp
的调用堆栈应包含调用 setjmp
的函数。
Emscripten 的支持有一个限制,即不支持对 setjmp
的间接调用。例如,以下代码不起作用
jmp_buf env;
int (*fp)(jmp_buf) = setjmp;
fp(env); // Doesn't work
在此模式下,Emscripten 使用 JavaScript 模拟 setjmp-longjmp。此选项可以通过在命令行中添加 -sSUPPORT_LONGJMP=emscripten
来设置,但目前默认情况下已启用。
请注意,此选项在代码大小方面可能会有相对较高的开销,但它将在所有支持 WebAssembly 的 JavaScript 引擎上运行,即使它们尚未支持 新的 WebAssembly 异常处理提案。
或者,你可以选择使用新的支持 WebAssembly 异常处理 提议。要启用它,请在编译时和链接时都传递 -sSUPPORT_LONGJMP=wasm
。
此选项利用了一项新功能,该功能为 WebAssembly 带来了用于抛出和捕获异常的内置指令。因此,与基于 JavaScript 的实现相比,它可以减少代码大小和性能开销。此选项目前在几个主要的 Web 浏览器中受支持,但 可能尚未在所有 WebAssembly 引擎中受支持。
我们还有两种 异常处理支持:基于 JavaScript 的支持和新的基于 WebAssembly EH 的支持。我们的 setjmp-longjmp 支持使用相同的机制。因此,在将异常和 setjmp-longjmp 结合使用时,应使用相同类型的 EH 和 setjmp-longjmp 支持。
例如,要将基于 JavaScript 的 EH 和 setjmp-longjmp 支持结合使用
em++ -fexceptions test.cpp -o test.js
-sSUPPORT_LONGJMP
默认值为 emscripten
或 wasm
(具体取决于异常模式),默认情况下已启用,因此你无需显式传递它。
要将 WebAssembly EH 和 setjmp-longjmp 支持结合使用
em++ -fwasm-exceptions -sSUPPORT_LONGJMP=wasm test.cpp -o test.js
在同时使用基于 WebAssembly EH 的异常支持和 setjmp-longjmp 时,存在一项特定限制。你不能在 C++ catch
子句中调用 setjmp
。例如,以下代码将在编译时出错
try {
...
catch (int n) {
setjmp(buf); // Doesn't work
}
在 try
子句中调用 setjmp
是可以的。在 catch
子句中调用另一个调用 setjmp
的用户函数也是可以的。
try {
setjmp(buf); // Works
catch (int n) {
...
}
try {
...
} catch (int n) {
function_that_calls_setjmp(); // Works
}