Files
TerminalBasic/docs/tbvm-design.md
Chili Palmer 1ce371b96b Leitbild und Performance-Anforderungen verankern
- README: Leitbild Re-Imagination (Stufe 1 originalgetreu, Stufe 2
  additive Anreicherung fuer CLI-/TUI-Tool-Entwicklung)
- PLAN: Leitplanken (Online-Doku als Primaerquelle, Performance als
  Anforderung: Instant-Compile, Projekt-Build in Sekunden, Executable
  ohne Toolchain), Stufe-2-Ideenspeicher, Benchmark-Aufgaben in Phase 2
- tbvm-design: Performance-Abschnitt (Single-Pass, inkrementell,
  typisierte Opcodes, Slot-Aufloesung zur Compilezeit, Messlatten)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 16:45:59 +02:00

119 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TBVM — Designentwurf
Eigene Stack-basierte Bytecode-VM (Entscheidung siehe PLAN.md, 0.2).
Die VM ist in `tbdos` (IDE) und in von `tbdosc` erzeugte Executables
eingebettet — identischer Code, identisches Verhalten, schneller Turnaround.
## Werte-Modell
Tagged Enum, kein NaN-Boxing (Einfachheit und Debugbarkeit vor Mikro-
performance):
```rust
enum Value {
Int(i16), // INTEGER
Long(i32), // LONG
Single(f32), // SINGLE
Double(f64), // DOUBLE
Currency(i64), // CURRENCY, Festkomma ×10 000
Str(Rc<str>), // STRING (immutabel geteilt; Copy-on-Write bei MID$-Anweisung)
// Arrays und TYPE-Instanzen leben im Heap-Bereich der VM,
// Variablen-Slots referenzieren sie per Handle (Rc<RefCell<…>>).
}
```
- Kein GC nötig: der Dialekt kennt keine Zyklen (keine Objektreferenzen in
TYPEs, keine Closures) → `Rc` genügt.
- Feste Strings (`STRING * n`) und TYPE-Records werden als eigene
Speicherobjekte mit fester Zeichen-/Elementstruktur geführt.
## Bytecode
- Stack-Maschine, Opcodes 1 Byte + Operanden variabler Länge (u8/u16/u32,
little-endian).
- **Modul-Struktur:** Konstantenpool (Strings, Zahlen), Typtabelle
(TYPE-Layouts), Prozedurtabelle (Signatur, Locals-Anzahl, Code-Offset),
globale Slots, DATA-Segment (für READ/RESTORE), Zeilentabelle.
- **Zeilentabelle:** Abbildung Code-Offset → (Moduldatei, Zeile). Grundlage
für `ERL`, Fehlermeldungen, Breakpoints und Einzelschritt.
- **Aufrufkonventionen:**
- SUB/FUNCTION: eigener Frame (Locals-Slots, Operandenstack-Basis);
BYREF-Parameter als Referenz-Slots (Handle auf Variablen-Slot).
- GOSUB: **kein** Frame — Rücksprungadresse auf separatem GOSUB-Stack im
aktuellen Frame (RETURN prüft diesen zuerst).
- **Fehlerbehandlung:** Pro Frame ein Handler-Zustand (`ON ERROR GOTO x`).
Laufzeitfehler → VM sucht aktiven Handler im aktuellen Modulkontext
(Vorbild: Handler sind modul-/prozedurlokal, TODO: exakte Scoping-Regel
testen), setzt `ERR`/`ERL`, springt. `RESUME` nutzt gemerkten
Anweisungs-Offset.
## Ausführungsmodell / Unterbrechbarkeit
- Die Interpreterschleife läuft in **Ticks**: nach jeder Anweisung (Grenze
aus der Zeilentabelle) prüft sie ein Flag-Set: Breakpoint? Einzelschritt?
Strg+Untbr? Ereignis-Queue nicht leer und Zustellung erlaubt?
- Ereigniszustellung (Forms, Timer) erfolgt kooperativ: nur an
Zustellpunkten (`DOEVENTS`, `SLEEP`, blockierende Eingabe, Ende einer
Ereignisprozedur) — wie im Vorbild.
- Die VM ist eine gewöhnliche zustandsbehaftete Struktur, `step()`-basiert;
die einbettende Schleife (IDE-Debugger oder Runner) treibt sie. Kein
eigener Thread nötig; Terminal-Events werden zwischen Ticks gepollt.
## `.tbc`-Container (Entwurf)
```
Magic "TBC\0" · Formatversion u16 · Flags
Abschnittstabelle: [ (Kennung, Offset, Länge) ]
Abschnitte: CONSTS, TYPES, PROCS, CODE, DATA, LINES, FORMS (serialisierte .FRM-Beschreibungen)
```
Serialisierung mit einfachem eigenem Writer/Reader (kein serde nötig,
Format bleibt stabil und dokumentiert).
## Eigenständige Executables
`tbdosc build --exe` kopiert den vorkompilierten Runner (dieselbe
tb-vm/tb-runtime/tb-ui-Bibliothek wie die IDE) und hängt das `.tbc` als
Ressource an (Anhängen ans Binary + Fußzeile mit Offset/Magic; portabel für
alle drei Plattformen). Alternative — `include_bytes!` + Cargo-Build beim
Nutzer — verworfen: erfordert Rust-Toolchain beim Anwender.
## Performance
**Compiler (Instant-Compile, Anforderung siehe PLAN.md):**
- Single-Pass pro Modul: Lexen, Parsen und Codegen in einem Durchlauf;
Vorwärtsreferenzen (Prozeduren, Labels) über Fixup-Listen statt zweitem
Pass. Die Sprache ist dafür gemacht — das Vorbild kompilierte auf
1992er-Hardware gefühlt sofort.
- Modulweise inkrementell: `.BAS`/`.FRM` werden unabhängig zu Bytecode-
Einheiten übersetzt und beim Build nur zusammengebunden; die IDE
recompiliert nur geänderte Module (Hash über Quelltext).
- Keine Optimierungspasses. Erlaubt sind nur Gratis-Optimierungen im
Codegen (Konstantenfaltung im Ausdruck, Peephole beim Emit).
- Budget als Test verankern (Phase 2): Benchmark-Projekt (~50k Zeilen)
muss unter 1 s kompilieren (Release-Build der Toolchain, Referenzrechner);
einzelnes Modul < 50 ms.
**VM-Ausführung:**
- Alle Namen werden zur Compilezeit aufgelöst: Variablen/Parameter sind
Slot-Indizes, Prozeduren Tabellenindizes — zur Laufzeit keine
Hash-Lookups.
- Statische Typen des Dialekts ausnutzen: typisierte Opcodes
(`ADD_I16`, `ADD_F64`, `CONCAT` …) statt generischem Dispatch über
`Value`-Tags in heißen Pfaden.
- Dichte Opcodes, `match`-Dispatch in einer engen Schleife; Tick-Prüfung
(Events/Breakpoints) nur an Anweisungsgrenzen über ein einzelnes
Flag-Wort, nicht pro Opcode.
- Strings immutabel via `Rc<str>` (Kopien sind Pointer-Kopien);
Konstantenpool dedupliziert.
- Messlatte (Phase 2, Benchmarks in `benches/`): typische
Schleifen-/String-Lasten mindestens ~100× schneller als das Vorbild auf
Originalhardware; Richtwert grob Lua-Interpreter-Klasse, gemessen und
dokumentiert statt geraten.
## Offene Punkte
- Opcode-Satz konkret ausformulieren (mit Phase 2)
- Zahlenkonvertierungs-Matrix (implizite Casts, Rundung, Überlauf) als Tabelle
- Verhalten von `STOP`/`CONT` im Runner (ohne IDE): Abbruch mit Meldung?