Emscripten は、ほぼすべての *移植可能な* C++/C コードを JavaScript にコンパイルするために使用できます。
このセクションでは、移植できない (または移植がより困難な) コードの種類と、コンパイルできるが実行速度が遅くなるコードについて説明します。開発者は、この情報を使用して、コードの移植と書き換えの労力を評価できます。
マルチスレッドは SharedArrayBuffer に依存しており、これはまだ標準化とブラウザによる実装の途中です。 Emscripten にはスレッドの動作サポートがあり、適切な設定を行うことで開発用ブラウザで試すことができます。
SIMD も標準化と実装の過程にあります。
次の種類のコードは、Emscripten で動作させるために書き換える必要があります。(理論的には、Emscripten がエミュレーションを使用してこれらの問題を回避することは可能ですが、非常に遅くなるでしょう。)
ビッグエンディアンアーキテクチャに依存するコード。Emscripten でコンパイルされたコードは、現在、リトルエンディアンのホスト上で実行する必要があります。これは、インターネットに接続されているマシンの 99% を占めています。これは、JavaScript の型付き配列 (メモリのビューに使用) がホストのバイト順序に従い、LLVM がターゲットとするエンディアンを知る必要があるためです。
ネイティブ環境の低レベル機能を使用するコード。たとえば、setjmp
/longjmp
と組み合わせてネイティブスタック操作を行うコード (適切な setjmp
/longjmp
、つまり、スタックを下方向にジャンプすることはサポートしますが、巻き戻されたスタックまでジャンプすることは、未定義の動作であるためサポートしません)。
レジスタまたはスタックをスキャンするコード。レジスタ内またはスタック上の変数は JavaScript のローカル変数に保持される場合があるため、スキャンできないため、これは機能しません。
注意
このタイプのコードは、保守的なガベージコレクションに使用される場合があります。スタックに他のコードがない場合、例えばメインイベントループの反復処理から、保守的なスキャンを実行できます。他の解決策には、Binaryen の SpillPointers パスが含まれます。
アーキテクチャ固有のインラインアセンブリ (x86 コードを含む asm()
など) は移植できません。そのコードは、移植可能な C または C++ に置き換える必要があります。場合によっては、コードベースに移植可能なコードと、最適化としてオプションのインラインアセンブリの両方があるため、インラインアセンブリを無効にするオプションが見つかる場合があります。
注意
これらの問題を理解することは、コードを最適化する際に役立ちます。
次の種類のコードはコンパイルされますが、期待どおりに高速に実行されない可能性があります
asm.js (ただし WebAssembly ではない) では、64 ビットの int
変数。数学演算 (+、-、*、/) は、エミュレートされるため遅くなります (ビット単位演算は比較的高速です)。JavaScript にはネイティブの 64 ビット int
型がないため、これは避けられません。
C++ 例外。JavaScript では、このようなコードは一般的に JavaScript エンジンにさまざまな最適化をオフにさせます。そのため、例外は -O1
以上ではデフォルトでオフになっています。それらを再度有効にするには、-sDISABLE_EXCEPTION_CATCHING=0
を指定して *emcc* を実行します ( src/settings.js を参照してください)。
setjmp
は、その周りの 再ループ も妨げ、効率の低いアプローチを使用して制御フローをエミュレートすることを強制します。
x86 アライメント動作に依存するコード。x86 では、アライメントされていない読み取りと書き込みが許可されます (たとえば、偶数でないアドレスから 16 ビット値を読み取ることができます) が、他のアーキテクチャでは許可されていません (32 ビット ARM は SIGILL
を発生させます)。asm.js の場合、ロードとストアは強制的にアライメントされたオフセットになります。WebAssembly の場合、アライメントされていないロードとストアは機能しますが、基盤となる CPU によっては遅くなる可能性があります。コードを SAFE_HEAP=1
でビルドすると、明確な実行時例外が発生します。 デバッグ を参照してください。