C setjmp-longjmp 支援

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

基於 JavaScript 的 setjmp-longjmp 支援

在此模式下,Emscripten 使用 JavaScript 模擬 setjmp-longjmp。此選項透過將 -sSUPPORT_LONGJMP=emscripten 新增至命令列來設定,但目前預設為啟用。

請注意,此選項在程式碼大小方面可能具有相對較高的負擔,但它將在所有支援 WebAssembly 的 JavaScript 引擎上運作,即使它們尚未支援新的 WebAssembly 例外處理提案

基於 WebAssembly 例外處理的 setjmp-longjmp 支援

或者,您可以使用WebAssembly 例外處理提案選擇加入新的支援。若要啟用它,請在編譯時間和連結時間傳遞 -sSUPPORT_LONGJMP=wasm

此選項利用一個新功能,該功能為 WebAssembly 帶來了用於擲回和捕捉例外的內建指令。因此,與基於 JavaScript 的實作相比,它可以減少程式碼大小和效能負擔。此選項目前在一些主要的 Web 瀏覽器中受支援,但可能並非所有 WebAssembly 引擎都支援

同時使用例外和 setjmp-longjmp

我們還有兩種例外處理支援:基於 JavaScript 的支援和新的基於 WebAssembly EH 的支援。我們的 setjmp-longjmp 支援使用相同的機制。因此,當同時使用例外和 setjmp-longjmp 時,應使用相同類型的 EH 和 setjmp-longjmp 支援。

例如,若要同時使用基於 JavaScript 的 EH 和 setjmp-longjmp 支援

em++ -fexceptions test.cpp -o test.js

-sSUPPORT_LONGJMP(預設為 emscriptenwasm,具體取決於例外模式)預設為啟用,因此您不需要明確傳遞它。

若要同時使用 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
}