Emscripten

Ein LLVM nach JavaScript Compiler


Titel | Inhalt | Einleitung | Grundlegendes | Arbeitsweise | Der Relooper | Grenzen | Performanz | Fazit | Quellen

LLVM

Die LLVM Compiler Infrastruktur bietet ein modulares Systemdesign, um verschiedene Werkzeuge, wie z.B. Assembler, Compiler und Debugger miteinander verwenden zu können. Der Clang Compiler für die C-Sprachfamilie ist zum Beispiel ein populäres Tool, das diesem Projekt entsprungen ist. LLVM stand früher für Low Level Virtual Machine. Inzwischen sind die vier Buchstaben zum Eigennamen für das Projekt geworden, da es mit einer traditionellen virtuellen Maschine nicht mehr viel gemeinsam hat.

Das Projekt stellt auch die Definition der LLVM assembyl language. Diese sogenannte LLVM intermediate representation (kurz LLVM IR) ist die Abstraktion einer Maschinensprache für moderne Prozessoren. Allgemein kann der Code einer Programmiersprache durch ein Frontend in die LLVM Zwischensprache übersetzt werden. Dann können z.B. Optimierungen ausgeführt werden und ein Backend übersetzt die LLVM IR schließlich in den Maschinencode für die Zielplattform.

Emscripten spielt dabei die Rolle eines Backends, um von einer möglichst großen Menge von Quellsprachen nach JavaScript übersetzen zu können. Außerdem kann Emscripten auch von den Möglichkeiten zur Code-Optimierung profitieren, die die LLVM Werkzeuge bereits mitbringen.


Möglichkeiten

Generell bieten sich zwei Möglichkeiten an, um eine bestimmte Sprache mit Hilfe von Emscripten im Web auszuführen:

  1. Den von einem vorhandenen Frontend erzeugten LLVM Zwischencode direkt nach JavaScript zu übersetzen
  2. Die ganze Laufzeitumgebung, die genutzt wird um die Sprache auszuführen, nach JavaScript zu portieren

Die erste Methode ist die naheliegende und effizientere. Sie kann für viele populäre Sprachen genutzt werden.

Sollte noch kein LLVM Frontend für eine Sprache vorhanden sein, bietet die zweite Methode einen interessanten Ansatz. Wurde die Laufzeitumgebung der Sprache in einer von einem LLVM Frontend unterstützten Sprache geschrieben, lässt sich diese komplett nach JavaScript übersetzen und im Web ausführen. Somit kann der Code direkt im Browser analysiert und in der innerhalb der JavaScript-Engine laufenden Laufzeitumgebung ausgeführt werden. Für Python und Lua wurde so etwas zum Beispiel umgesetzt.


Herausforderungen

Da Emscripten eine maschinennahe Sprache in eine Hochsprache übersetzt, ergeben sich einige ganz eigene Herausforderungen, denen andere Compiler normalerweise nicht gegenüberstehen.

JavaScript-Engines sind für einen natürlichen Codefluss optimiert, wie er in handgeschriebenem Quellcode vorhanden ist. In der LLVM IR existiert dieser nicht mehr, statt Schleifen und Verzweigungen bestimmen Sprünge und Sprungmarken den Programmablauf. Um performantes JavaScript zu erzeugen, muss Emscripten also die ursprünglichen Hochsprachenkonstrukte wiederherstellen können. Andere Ansätze, wie das Google Web Toolkit, stehen nicht vor dieser Problematik, da sie die Hochsprachenkonstrukte direkt übernehmen können. Dafür haben diese aber den Nachteil, nur eine Quellsprache zu unterstützen.

Eine weitere Herausforderung ist es, die Semantik des ursprünglichen Codes genau umzusetzen und dabei trotzdem performantes JavaScript zu erzeugen. Die Operationen, welche die LLVM Zwischensprache bietet, sind nicht alle auch direkt in JavaScript umsetzbar. Setzt man die Addition zweier vorzeichenlosen 8-Bit Ganzzahlen nur mit einer einfachen JavaScript Addition um, wird der Überlauf bei Zahlen größer 255 beispielsweise nicht abgebildet. In JavaScript ist etwas vergleichbares nicht mit einem einzigen Befehl möglich.


Verwendung

Die Installation ist unter Windows, Mac OS X und Linux möglich. Auf dem System werden LLVM, Python und Node.js vorausgesetzt, um das Projekt in vollem Umfang nutzen zu können. Das englischsprachige Tutorial erläutert alle für den Installationsprozess nötigen Schritte auf den verschiedenen Betriebssystemen.

Bestehende C und C++ Projekte mit Emscripten nach JavaScript zu übersetzen soll möglichst einfach sein. Daher werden einige Tools bereitgestellt, um dem Entwickler dies zu erleichtern:

emcc ist als ein Austausch für den gcc-Compiler gedacht. Die Aufrufkonventionen sind größtenteils identisch, so dass man im einfachsten Fall emcc statt des gcc zum Erstellen seiner Projekte verwenden kann. Dabei kümmert es sich um die Erzeugung von LLVM-Bitcode mit clang und llvm-ld und nutzt dabei die von Emscripten mitgelieferten Schnittstellen, etwa für die C-Standardbibliothek. Die Ausgabe kann JavaScript Code, oder bereits in ein einfaches HTML-Dokument eingebettetes JavaScript sein. Für Projekte, die mittels Makefile oder ./configure erstellt werden, bietet Emscripten auch Werkzeuge, welche die Aufrufe dieser Buildtools übernehmen und dabei konfigurieren können. Eine ausführliche Erläuterung zum Erstellen von Projekten findet sich im Wiki.


Titel | Inhalt | Einleitung | Grundlegendes | Arbeitsweise | Der Relooper | Grenzen | Performanz | Fazit | Quellen