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例外処理提案をまだサポートしていない場合でも、WebAssemblyをサポートするすべてのJavaScriptエンジンで動作します。

WebAssembly例外処理ベースのsetjmp-longjmpサポート

または、WebAssembly例外処理提案を使用して、新しいサポートをオプトインできます。これを有効にするには、コンパイル時とリンク時の両方で-sSUPPORT_LONGJMP=wasmを渡します。

このオプションは、例外をスローおよびキャッチするための組み込み命令をWebAssemblyに導入する新機能を利用します。その結果、JavaScriptベースの実装と比較して、コードサイズとパフォーマンスのオーバーヘッドを削減できます。このオプションは現在、いくつかの主要なWebブラウザーでサポートされていますが、まだすべてのWebAssemblyエンジンでサポートされていない可能性があります

例外とsetjmp-longjmpの同時使用

また、例外処理サポートには、JavaScriptベースのサポートと新しいWebAssembly EHベースのサポートの2種類があります。setjmp-longjmpサポートは同じメカニズムを使用します。そのため、例外とsetjmp-longjmpを一緒に使用する場合は、同じ種類のEHとsetjmp-longjmpサポートを使用する必要があります。

たとえば、JavaScriptベースのEHとsetjmp-longjmpサポートを一緒に使用するには

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

例外モードに応じて、デフォルトでemscriptenまたはwasmになる-sSUPPORT_LONGJMPはデフォルトで有効になっているため、明示的に渡す必要はありません。

WebAssembly EHとsetjmp-longjmpサポートを一緒に使用するには

em++ -fwasm-exceptions -sSUPPORT_LONGJMP=wasm test.cpp -o test.js

例外とsetjmp-longjmpにWebAssembly EHベースのサポートを同時に使用する場合、1つの特定の制限があります。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
}