6.4 KiB
6.4 KiB
High-Performance Backend (Bytecode VM)
Datum: 21.11.2025 Status: Entwurf / Planungsphase Zielarchitektur: Stack-based Virtual Machine (ähnlich Lua 5.x / Python)
1. Motivation & Architektur-Ziele
- Status Quo: Der aktuelle AST-Evaluator ist mächtig, flexibel und ideal für Debugging, leidet aber unter "Pointer Chasing" (Cache Misses) und Rekursions-Overhead (CPU Stack Frames).
- Ziel: Maximale Ausführungsgeschwindigkeit für typisierte, numerische Operationen bei gleichzeitiger Beibehaltung der vollen Sprachflexibilität (Closures, dynamische Typen).
- Strategie: Implementierung einer linearen Stack-Maschine.
- Compiler: Transformiert den spezialisierten AST in ein flaches Array von Instruktionen.
- VM: Eine "Dispatch Loop", die Instruktionen abarbeitet und Delphi-Funktionen für komplexe Datentypen (Records, Series) als "Fernsteuerung" nutzt.
2. Phasenplan
Phase 1: Das Fundament (Datenstrukturen)
Ziel: Definition der binären Repräsentation des Codes und des Laufzeit-Stacks.
- Task 1.1: Stack-Architektur definieren
- Implementierung von
TStackSlotals Tagged Union (Variant Record). - Größe: Max. 16 Bytes (Alignment-freundlich).
- Typen:
skEmpty,skInt64,skDouble,skBoolean,skPointer(für RefCounted Objekte).
- Implementierung von
- Task 1.2: OpCodes definieren (
TOpCode)- Kategorisierung in: Stack Ops, Arithmetik (Getrennt nach
_Int,_Flt,_Dyn), Flow Control, Calls.
- Kategorisierung in: Stack Ops, Arithmetik (Getrennt nach
- Task 1.3: Instruktions-Format (
TInstruction)- Record mit
OpCode(Byte/Enum) und Argumenten (Arg1,Arg2,Arg3: Integer).
- Record mit
- Task 1.4: Container (
TBytecodeChunk)- Klasse, die
TArray<TInstruction>,TArray<TDataValue>(Constant Pool) und Metadaten (MaxStackSize) hält.
- Klasse, die
Phase 2: Der Compiler (Core Arithmetic)
Ziel: Kompilierung einfacher mathematischer Ausdrücke ohne Kontrollfluss.
- Task 2.1: Compiler-Gerüst (
TBytecodeCompiler)- Implementierung als
TAstVisitor(oderIAstVisitor). - Verwaltung des
TBytecodeChunk. - Verwaltung einer virtuellen "Stack Height" zur Berechnung von
MaxStackSize.
- Implementierung als
- Task 2.2: Konstanten laden
- Visitor für
VisitConstant. - Logik: Konstante im Pool suchen/einfügen
\toopLdConst <Index>emittieren.
- Visitor für
- Task 2.3: Arithmetik & Typ-Spezialisierung
- Visitor für
FunctionCall(Spezialfall: Binäre Operatoren). - Nutzung der
IStaticType-Informationen aus dem AST. - Entscheidunglogik:
- Sind Operanden
Int64?\toopAddInt. - Sind Operanden
Double?\toopAddFlt. - Sonst
\toopAdd(Fallback).
- Sind Operanden
- Visitor für
Phase 3: Die Virtual Machine (The Engine)
Ziel: Ausführung des in Phase 2 generierten Codes.
- Task 3.1: Die VM-Klasse (
TVM)- Aufbau des
OperandStack(Array ofTStackSlot). - Register:
IP(Instruction Pointer),SP(Stack Pointer),BP(Base/Frame Pointer).
- Aufbau des
- Task 3.2: Dispatch Loop
- Implementierung der
Run(Chunk)Methode. - Großes
case Instruction.OpCode of ....
- Implementierung der
- Task 3.3: Implementierung der Core-OpCodes
opLdConst: Kopieren von Constant-Pool auf Stack.opAddInt: Roher Zugriff aufStack[SP].AsInt. (Performance-kritisch!).opAdd: Generischer Pfad (Unboxing, Operation, Boxing).
Phase 4: Variablen & Kontrollfluss
Ziel: Unterstützung von if, lokalen Variablen und einfachen Schleifen (recur).
- Task 4.1: Lokale Variablen
- Mapping im Compiler: AST
SlotIndex\toStack-Relativ-Index. - OpCodes:
opLdLocal <Idx>,opStLocal <Idx>.
- Mapping im Compiler: AST
- Task 4.2: Sprünge (Jumps)
- Compiler: Handling von
VisitIfExpression. - Logik: Emittieren von Platzhalter-Jumps, Patching der Sprungziele nach Generierung des Branches.
- OpCodes:
opJmp,opJmpFalse.
- Compiler: Handling von
- Task 4.3: TCO / Recur
VisitRecurNode: Generierung vonMoveInstruktionen (Argumente an Position der Parameter kopieren) +opJmpzum Start der Funktion.
Phase 5: Funktionen & Closures (Die Kür)
Ziel: First-Class Functions und Upvalue-Handling.
- Task 5.1: Funktions-Prototypen
- Erweiterung
TBytecodeChunkum Sub-Chunks (Prototypen für innere Funktionen).
- Erweiterung
- Task 5.2: Upvalue-Analyse Integration
- Nutzung der Ergebnisse des Binders/UpvalueAnalyzers.
- Compiler muss wissen, welche Variable Stack-Local ist und welche ein Upvalue ist.
- Task 5.3: Closure-Instanziierung
- OpCode:
opClosure <ProtoIdx>. - VM: Erzeugt
TClosureObjekt, sammelt "Capture"-Variablen vom Stack ein (Hoisting) und speichert sie im Closure-Objekt.
- OpCode:
- Task 5.4: Calls (
opCall)- VM: Stack-Frame Management (Sichern von
BP,IPauf dem Call-Stack). - Umschalten des aktiven Chunks.
- VM: Stack-Frame Management (Sichern von
Phase 6: Interop & komplexe Typen
Ziel: Brückenschlag zur existierenden Delphi-Logik.
- Task 6.1: Native Calls (
opCallNative)- Aufruf von RTL-Funktionen via Funktionszeiger.
- Konvertierung
TStackSlot\leftrightarrowArgumente.
- Task 6.2: Records & Series
- OpCodes:
opNewRecord,opSeriesAdd. - VM: Ruft direkt
TScalarRecord.Createetc. auf. Hier wird keine Logik dupliziert, nur delegiert.
- OpCodes:
3. Technische Eckpfeiler
Das Datenmodell (VM Stack)
type
TStackSlot = record
case Kind: TDataValueKind of
vkOrdinal: (AsInt: Int64);
vkFloat: (AsFloat: Double);
vkObj: (AsPtr: Pointer); // IInterface / TObject / String
end;
Die Optimierungs-Strategie
- Binder/TypeChecker: Leisten die Vorarbeit (Auflösung von Namen zu Indizes, Typ-Inferenz).
- Compiler: Entscheidet statisch über OpCodes (
ADD_INTvsADD). - VM: Führt "blind" und schnell aus. Typprüfungen nur im
_DYNPfad oder als Assert.
4. Nächste Schritte (Todo)
- Anlegen der Unit
Myc.Bytecode.Types(Definition OpCodes, Instruction, StackSlot). - Implementierung
TBytecodeCompiler(Skeleton: Nur Constants & Return). - Implementierung
TVM(Skeleton: Stack setup, Dispatch loop für Const/Ret). - Erster Integrationstest:
42kompiliert\toVM führt aus\toResultat 42. - Erweiterung um
BinaryOp(Add/Sub) inkl. Typ-Spezialisierung.