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
}