Java für WebAssembly

Guten Abend.

Ich habe mich ein bisschen mit WebAssembly auseinandergesetzt und habe ein kleines Tool programmiert das Java classen in entsprechende wasm Dateien konvertiert. WebAssembly ist ziemlich ähnlich zu dem Java bytecode, beide basieren auf einem Kellerautomat (Stack Machine). Einige Befehle werden allerdings leider nicht unterstützt. Z.B. gibt es kein GOTO, und es gibt bisher keine Möglichkeit frames zu pop-en. Deshalb kann man das „Exception-Handling“ nur schwer realisieren, wenn dann mit zusätzlichen Checks was die Performance vermindern würde. Aber WebAssembly wird sich weiterentwickeln und die Ergebnisse bis jetzt sind schon atemberaubend.
Ein weiteres Problem ist der Speicher. Es gibt Pläne für WebAssembly den JavaScript Heap benutzbar zu machen womit die Java Programme sehr einfach auf wasm portierbar wären. Aber für den anderen Fall habe ich aus Neugier einen Garbage Collector mit C programmiert. Der ist so ähnlich wie der aus Hot-Spot JVM. Da wo der Heap auf Generationen unterteilt wird. Den finde ich sehr spannend. Habe einen aufwendigen Test mit einer schönen Visuellen Darstellung dafür programmiert:


Da dieser in C programmiert ist kann man ihn mit emscripten nach WebAssembly portieren. Das werde ich demnächst versuchen. Das Projekt ist hier zu finden:

2 Likes

Kurz: Ich finds super.

Eines Tages kommt hoffentlich JavaScript dorthin wo es hin gehört… in die Vergessenheit.

3 Likes

Ich möchte aber JavaScript verteidigen. Ursprünglich wollte der Erfinder von JavaScript die Programmiersprache Lisp in den Browser bringen. Lisp ist eine geniale Sprache. Bei Java z.B. hört die reflection bei bytecode auf. Man kann nicht einfach innerhalb der Sprache auf eine einfache Weise eine Methode um zusätzliche Befehle erweitern. Bei Lisp dagegen ist es der Bestandteil der Sprache. Das ist genial: man kann durch den Code iterieren, neuen Code generieren usw. Mal ein Beispiel:
Hello world Programm in Lisp:

(print "hello world")

Um auf den Code selbst zuzugreifen schreibt man ein Apostroph vor dem Block:

(print '(print "hello world"))

usw…

Der Erfinder von JavaScript war also von Lisp begeistert und hat einige coole Features dort eingebaut die man aus Lisp kennt. Z.B. die eval() Funktion.

Bei Java fehlt mir diese Funktionalität sehr. Es ist nicht unbedingt ein eingebautes Feature.

Den Rundumschlag von wasm über JavaScript und Java zu Lisp hab’ ich jetzt nicht ganz nachvollziehen können, aber ich habe so ein implizites „TODO“, mir wasm (und ggf. das Repo) mal genauer anzusehen. Zum letzten Beitrag nur kurz: Es gibt sowas wie Apache Commons BCEL™ – Home , was schon ein paar interessante Möglichkeiten bietet (ich find’ den BCELifier cool).

Ansonsten… kein Erwähnen von JavaScript ohne den obligatorischen Rant von meiner Seite: Ich könnte eine schier endlose Liste von technischen Gründen auf allen Ebenen erstellen, warum JavaScript ist eine schlechte Programmiersprache ist (und ich zögere oft, das überhaupt als „Progerammiersprache“ zu bezeichnen, außer eben in dem Sinne, wie Malbolge auch eine „Programmiersprache“ ist), und Punkte, die daran „gut“ sein sollen würden mir keine einfallen. Definition, Performance, Libraries, Modulsystem, Build-Prozesse, Deployment, … alles hoffnungslos broken…

1 Like

WebAssembly ist im Prinzip wie die Java Technologie ohne OOP. Damit fehlen dort der Garbage Collector und die typischen OOP Befehle wie GETFIELD und PUTFIELD.

Dafür gibt es Befehle „memory.alloc“ und „memory.grow“.

Damit kann eine WebAssembly - Engine viel einfacher entwickelt werden. Allerdings muss die Software sehr sorgfältig entwickelt werden. So wie man das von C kennt. Das tolle ist, dass es trotzdem Plattformunabhängig ist.

Du hast dich mit dem Thema ja genauer beschäftigt, da häng ich meine Frage direkt an: Wird sich WASP in Zukunft in eine OOP Richtung noch bewegen, so dass man es als JVM-alike verwenden können wird, oder bleibt das Ziel C?

Ich hab mir die anderen Java WASP Projekte angeschaut. Eins davon ist sehr ähnlich zu deinem, es konvertiert Java Bytecode zu WebAssembly. Die merken auch an das so Sachen wie Exceptions (noch) nicht gehen.

Könnte man nicht „„einfach““ die ganze JVM auf WASP konvertieren? Die dann wiederum als Zwischenlayer fungiert?

1 Like

Ich finde den Aspekt sehr interessant, dass WebAssembly sehr einfach gestaltet ist. Es wäre meiner Meinung nach besser sozusagen den Kern einfach zu gestalten und die komplexere Sachen wie Garbage Collector auf diesem Kern zu basieren. Bei Java Technologie ist die JVM selbst eine sehr Komplexe software. Somit ist das portieren auf neuartige Platformen sehr umständlich.

Man könnte sicherlich auch die Hotspot JVM nach WebAssembly portieren. Aber z.B. der JIT kompiler, der halt den bytecode in den nativen Code übersetzen kann, dürfte dabei Probleme bereiten. Und ohne den JIT kompiler hat man nur noch den interpretor.

Und da WebAssembly selbst sehr ähnlich zu dem Java Bytecode ist, werden die WebAssembly-Engines sicherlich selbst solche kompiler haben und unterschiedliche automatische Optimisations Algorithmen.

Für Java wäre halt die beste Option einfach einen Garbage Collector zu entwickeln und die Klassen in entsprechende wasm Dateien umzuwandeln.

Allerdings der interpretor für Bytecode macht bei der JVM trotzem Sinn, falls man eine Java-Klasse zur Laufzeit lädt. Und im nächsten Schritt könnte der Übersetzer (Java zu wasm) auch der Bestandteil von so einer WASM - JVM sein. So hat man dann eine vollwertige JVM.

Es gibt auch Pläne wasm auch außerhalb des Browsers einsatzfähig zu machen (WASI). Stellt euch Mal vor, wie einfach dann eine JVM basierend auf wasm auf andere Plattformen portierbar wäre. Wenn einmal das Problem mit GOTO und „Stack unwinding“ gelöst wird…

Alles, was ich hier sage, unter dem Vorbehalt, dass ich mir das noch nicht genau genug angesehen habe, um das gerechtfertigte Gefühl haben zu können, etwas wirklich fundiertes sagen zu können:

Die JVM war auch mal einfach. Das war so Mitte der Neunziger. Auch heute könnte man, nach allem, was ich bisher so in der JVM-Spec gelesen habe, eine ~„grundsätzlich laufende JVM“ in einer Sprache wie Java oder C++ innerhalb von recht kurzer Zeit implementieren (wenige Wochen vielleicht - Classloader und Garbage Collector sind da wohl noch das komplizierteste, aber eine Stack-basierte VM dengelt man ja teilweise schon in einem Studienpraktikum irgendwie hin…).

Wodurch die JVM kompliziert wird ist, neben den verschiedenen Garbage-Collectoren, vermutlich in erster Linie der Hotspot-Teil. Die ganzen Optimierungen, die zur Laufzeit vorgenommen werden, angefangen bei Escape-Analysis, Intrinsics und Inilining, das echten, Ziel-Hardware-spezifischen (!) Code ausspuckt (der auch läuft, und das richtige macht, und ohne Fehler!), und ggf. auch mal ein Methode wieder „un-inlined“, wenn eine weitere Klasse nachgeladen wird, die diese Methode anders implementiert.

Im Moment gibt es sowas ähnliches soweit ich weiß nicht für wasm. Sobald dort auch Ziel-Hardware-spezifische Optimierungen gemacht werden sollen, wird das, was auch immer das macht, auch sehr kompliziert. Aber die Zeit ist nicht stehen geblieben. Sowas wie LLVM bietet ganz andere Möglichkeiten, die Optimierung und die Compilierung zu trennen. Aber … auch das ist ein Punkt recht weit unten auf meiner „Wenn-ich-mal-seeeehr-viel-Zeit-habe-und-seeeehr-motiviert-bin-TODO-Liste“…

Stellt euch Mal vor, wie einfach dann eine JVM basierend auf wasm auf andere Plattformen portierbar wäre.

Stell’ dir mal vor, wie einfach eine Software auf andere Plattformen zu portieren wäre, die alle schon die JVM unterstützen - man bräuchte nichts zu portieren, sondern könnte sie einfach ausführen :astonished: Write once, run anywhere - Wikipedia - mal im Ernst, wäre das nicht einfach nur „Virtual-Machine-ception“?

1 Like

Habe den Garbage Collector intensiv getestet, einige Aspekte verbessert und mit „emscripten“ kompiliert bekommen zu wasm. Die Tests laufen auf dem Browser genau wie auf x86 oder aarch64. Finde ich sehr interessant. Eventuell kann ich demnächst die NEW* Befehle implementieren.

Habe den Garbage Collector in eine separate repo extrahiert:

Kennt ihr das Projekt copy.sh?
Da wird nativer x86 Code nach WebAssembly direkt im Browser compiliert. So kann man sogar Betriebssysteme im Browser ausführen:

https://copy.sh/v86/?profile=windows98