🐞Stack-Maschinen-Debugger
Ein eigener Lern-Interpreter führt die Beispielmodule Befehl für Befehl aus. Am Ende wird das Ergebnis mit der echtenWebAssembly.instantiate-Ausführung deines Browsers verglichen.
▶️Ausführen
Programm:
$factorial() (i32) → (i32)if/else · call · Rekursion (Call-Frames)43 Befehle ausgeführt
Schritt 1 / 44 · Tasten ← →
Aufruf $factorial(4): neuer Call-Frame, Parameter liegen in den ersten Locals.
🧾 $factorial (i32) → (i32)
0▶local.get 0 ;; $n
1i32.const 2
2i32.lt_s
3if (result i32)
4i32.const 1
5else
6local.get 0 ;; $n
7local.get 0 ;; $n
8i32.const 1
9i32.sub
10call 0 ;; $factorial
11i32.mul
12end
13end
▶ = nächster Befehl · ✓ = gerade ausgeführt
📚 Operanden-Stack
leer
Oben = zuletzt abgelegt (gelber Rand). Befehle nehmen ihre Operanden von oben.
🏷️ Locals von $factorial
| 0 | $n | Parameter · i32 | 4 |
🗂️ Call-Frames (1)
$factorial(4) · pc 0
🧠 Linearer Speicher (Bytes 0–127)
Dieses Modul hat keinen linearen Speicher.
⚖️ Vergleich mit der echten Engine
| Lern-Interpreter | … läuft |
WebAssembly.instantiate | … |
Zum Ende springen (⏭), um das Ergebnis zu vergleichen.
🧠Was man hier sieht
💡 Operanden-Stack
Befehle haben keine Register-Operanden:
i32.add nimmt die zwei obersten Werte und legt die Summe ab. Der Validator prüft vor der Ausführung, dass Anzahl und Typen an jeder Stelle stimmen.💡 Locals & Call-Frames
Parameter sind die ersten Locals einer Funktion. Jeder
call legt einen neuen Frame an – beifactorial(4) sieht man die Rekursion bis zur Tiefe 4.✅ Strukturierter Kontrollfluss
Es gibt kein freies goto.
br n springt zu einem umschließenden Label: beiblock/if an das Ende, bei loop an den Anfang.⚠️ Linearer Speicher
Ein zusammenhängendes Byte-Array in Seiten à 64 KiB. Jeder Zugriff wird gegen die Größe geprüft – außerhalb gibt es einen Trap statt eines Speicherfehlers im Host.