Emscripten kann verwendet werden, um fast jeden portablen C++/C-Code nach JavaScript zu kompilieren.
Dieser Abschnitt erläutert, welche Arten von Code nicht portabel (oder schwieriger zu portieren) sind und welcher Code zwar kompiliert werden kann, aber langsam läuft. Entwickler können diese Informationen nutzen, um den Aufwand für die Portierung und das Umschreiben von Code abzuschätzen.
Multithreading hängt von SharedArrayBuffer ab, was sich noch in der Standardisierung und Implementierung durch die Browser befindet. Emscripten verfügt über eine funktionierende Unterstützung für Threads, die Sie in Entwickler-Browsern ausprobieren können, indem Sie die entsprechenden Einstellungen vornehmen.
SIMD befindet sich ebenfalls im Prozess der Standardisierung und Implementierung.
Die folgenden Arten von Code müssten umgeschrieben werden, um mit Emscripten zu funktionieren. (Während es theoretisch möglich wäre, dass Emscripten diese Probleme mittels Emulation umgeht, wäre dies sehr langsam.)
Code, der auf einer Big-Endian-Architektur basiert. Mit Emscripten kompilierter Code benötigt derzeit einen Little-Endian-Host zur Ausführung, was auf 99 % der mit dem Internet verbundenen Rechner zutrifft. Dies liegt daran, dass JavaScript Typed Arrays (die für die Speicherdarstellung verwendet werden) der Byte-Reihenfolge des Hosts folgen und LLVM wissen muss, welche Endianness als Ziel dienen soll.
Code, der Low-Level-Funktionen der nativen Umgebung nutzt, zum Beispiel native Stack-Manipulation in Verbindung mit setjmp/longjmp (wir unterstützen korrektes setjmp/longjmp, d. h. das Springen im Stack nach unten, aber nicht das Springen nach oben in einen bereits aufgelösten Stack, was undefiniertes Verhalten darstellt).
Code, der Register oder den Stack scannt. Dies wird nicht funktionieren, da eine Variable in einem Register oder auf dem Stack in einer lokalen JavaScript-Variable gehalten werden kann (welche nicht gescannt werden kann).
Hinweis
Code dieser Art wird unter Umständen für konservative Garbage Collection verwendet. Sie können ein konservatives Scanning durchführen, wenn kein anderer Code auf dem Stack liegt, z. B. aus einer Iteration der Haupt-Ereignisschleife heraus. Andere Lösungen umfassen den SpillPointers-Pass in Binaryen.
Code mit architekturspezifischem Inline-Assembly (wie ein asm() mit x86-Code) ist nicht portabel. Dieser Code müsste durch portables C oder C++ ersetzt werden. Manchmal enthält eine Codebasis sowohl portablen Code als auch optionales Inline-Assembly als Optimierung, sodass Sie eventuell eine Option zum Deaktivieren des Inline-Assemblys finden.
Hinweis
Das Verständnis dieser Probleme kann bei der Optimierung von Code hilfreich sein.
Die folgenden Arten von Code lassen sich kompilieren, laufen aber möglicherweise nicht so schnell wie erwartet
In asm.js (aber nicht in WebAssembly): 64-Bit int-Variablen. Mathematische Operationen (+, -, *, /) sind langsam, da sie emuliert werden (bitweise Operationen sind einigermaßen schnell). JavaScript hat keinen nativen 64-Bit int-Typ, daher ist dies unvermeidlich.
C++ Exceptions. In JavaScript führt solcher Code im Allgemeinen dazu, dass die JavaScript-Engine verschiedene Optimierungen deaktiviert. Aus diesem Grund sind Exceptions in -O1 und höher standardmäßig deaktiviert. Um sie wieder zu aktivieren, führen Sie emcc mit -sDISABLE_EXCEPTION_CATCHING=0 aus (siehe src/settings.js).
setjmp verhindert zudem das Relooping in seiner Umgebung, was uns zwingt, den Kontrollfluss mit einem weniger effizienten Ansatz zu emulieren.
Code, der sich auf das x86-Alignment-Verhalten verlässt. x86 erlaubt nicht-ausgerichtete Lese- und Schreibvorgänge (sodass Sie beispielsweise einen 16-Bit-Wert von einer ungeraden Adresse lesen können), andere Architekturen jedoch nicht (32-Bit ARM wird SIGILL auslösen). Bei asm.js werden Lasten und Speicherungen auf ausgerichtete Offsets erzwungen; bei WebAssembly funktionieren nicht-ausgerichtete Lasten und Speicherungen, können aber je nach zugrunde liegender CPU langsam sein. Wenn Sie Ihren Code mit SAFE_HEAP=1 erstellen, erhalten Sie eine eindeutige Laufzeit-Exception, siehe Debugging.