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例外処理提案をまだサポートしていない場合でも、WebAssemblyをサポートするすべてのJavaScriptエンジンで動作します。
または、WebAssembly例外処理提案を使用して、新しいサポートをオプトインできます。これを有効にするには、コンパイル時とリンク時の両方で-sSUPPORT_LONGJMP=wasmを渡します。
このオプションは、例外をスローおよびキャッチするための組み込み命令をWebAssemblyに導入する新機能を利用します。その結果、JavaScriptベースの実装と比較して、コードサイズとパフォーマンスのオーバーヘッドを削減できます。このオプションは現在、いくつかの主要なWebブラウザーでサポートされていますが、まだすべてのWebAssemblyエンジンでサポートされていない可能性があります。
また、例外処理サポートには、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
}