Hier ist der vollständig aktualisierte Projektplan, der die Verwaltung des Caches als Environment-spezifische Aufgabe (statt global) korrekt abbildet.

---

# Monomorphisierung (Revidierter Plan v2)

09.11.2025 19:10

## Motivation

Der aktuelle Compiler ist in seiner Optimierungsfähigkeit limitiert. Der `TAstLowerer`-Pass implementiert eine hartkodierte statische Spezialisierung ausschließlich für vordefinierte Operatoren (z.B. `(+)` -> `TBinaryExpressionNode`). Alle anderen Aufrufe, einschließlich der restlichen RTL (z.B. `Abs`) und sämtlicher benutzerdefinierter Funktionen, werden zur Laufzeit dynamisch über den `vkMethod`-Pfad aufgelöst. Dieser Pfad erfordert das Boxing von Werten in `TDataValue`-Wrapper und einen Scope-Lookup, was einen signifikanten Performance-Overhead darstellt, selbst wenn alle Typen zur Compile-Zeit bekannt wären.

## Ziel

Implementierung einer **hybriden Monomorphisierungsstrategie** zur Compile-Zeit. Das Ziel ist die Eliminierung des `vkMethod`-Overheads für *alle* Aufrufe, deren Callee und Argumenttypen statisch auflösbar sind.

1.  **Statische Spezialisierung:** Aufrufe an bekannte Funktionen (RTL oder User-Code) mit bekannten Argumenttypen werden zur Compile-Zeit an eine hochoptimierte, statisch gebundene Implementierung gemappt.
2.  **Dynamischer Fallback:** Aufrufe, die nicht statisch aufgelöst werden können (z.B. Higher-Order-Functions, bei denen der Callee aus einer Variable stammt), nutzen weiterhin den bestehenden `vkMethod`-Pfad.

Diese Strategie macht die spezialisierten `TBinaryExpressionNode` und `TUnaryExpressionNode` sowie den `TAstLowerer`-Pass obsolet und ersetzt sie durch einen generalisierten und wesentlich leistungsfähigeren Mechanismus.

## Ergebnis & Implementierungsplan

### 1. Erweiterung: `IFunctionCallNode`
Anstatt einen neuen Knotentyp einzuführen, wird der bestehende `IFunctionCallNode` in `Myc.Ast.Nodes` erweitert, um *beide* Aufrufpfade (dynamisch und statisch) zu repräsentieren.

* Er erhält ein neues Property: **`StaticTarget: TDataValue.TFunc`**.
* **Dynamischer Pfad (Default):** Wenn **`StaticTarget = nil`**, wird der Knoten wie bisher über den `vkMethod`-Pfad ausgewertet (dynamischer Dispatch über den `Callee`-Knoten).
* **Statischer Pfad (Optimiert):** Wenn **`StaticTarget <> nil`**, ignoriert der Evaluator den `Callee`-Knoten und ruft stattdessen das **`StaticTarget`** direkt mit den ausgewerteten Argumenten auf.
* Die `TAst.FunctionCall`-Factory in `Myc.Ast.pas` wird um einen optionalen **`AStaticTarget`**-Parameter erweitert.

### 2. Neue Compiler-Phase: `TStaticSpecializer`
Ein neuer `TAstTransformer` namens `TStaticSpecializer` wird implementiert. Er läuft *nach* dem `TTypeChecker` (Phase 3) und *ersetzt* den `TAstLowerer` (Phase 4).

* **Konstruktor:** Der `TStaticSpecializer` erhält im Konstruktor eine Referenz auf den `IEnvironment`-spezifischen Monomorphisierungs-Cache (siehe Punkt 3).
* **`VisitFunctionCall`-Logik:** Dies ist die Kernmethode.
    1.  Sie prüft, ob der `Callee` des `IFunctionCallNode` ein `IIdentifierNode` ist (z.B. `+`, `Abs`, `my-func`).
    2.  Sie prüft, ob *alle* Argumenttypen (`newArgs[i].StaticType`) statisch bekannt sind (d.h. nicht `stUnknown`).
    3.  **Statischer Pfad (Ja):** Der `TStaticSpecializer` fragt den ihm übergebenen **Environment-Cache** nach einer spezialisierten `TDataValue.TFunc` ab. Bei Erfolg **klont** er den `IFunctionCallNode` (via CoW) und setzt dessen **`StaticTarget`**-Property auf die gefundene Funktion.
    4.  **Dynamischer Pfad (Nein):** Der `IFunctionCallNode` wird (ggf. geklont, falls Kindknoten sich änderten) mit **`StaticTarget = nil`** zurückgegeben.

### 3. Der Environment-spezifische Cache
Das **`IEnvironment`** verwaltet einen **Instanz-spezifischen** Cache (z.B. `TDictionary`), der bereits spezialisierte Funktionen vorhält. Dieser Cache ist *nicht* global oder statisch.

* Jede `IEnvironment`-Instanz (z.B. eine für Produktion, eine für Tests) hat ihren eigenen, isolierten Cache, der an ihre `RootScope` und RTL gebunden ist.
* Die `TEnvironment`-Implementierung (in `Myc.Ast.Environment.pas`) wird um dieses `TDictionary`-Feld erweitert.
* Der `TStaticSpecializer` erhält eine Referenz auf diesen Cache bei seiner Erstellung (z.B. über den Konstruktor).
* **Schlüssel:** `(Funktions-ID, TArray<IStaticType>)`.
    * *Funktions-ID*: Ein eindeutiger Bezeichner für den Callee, gebilded aus der `TResolvedAddress`, die innerhalb des  Environments einen eindeutigen Schlüssel darstellt.
* **Wert:** Die spezialisierte `TDataValue.TFunc`.

### 4. Cache-Miss-Strategie (Inlining & User-Code)
Wenn der `TStaticSpecializer` einen statisch auflösbaren Aufruf (z.B. `(my-func 10)`) findet, der noch nicht im **Environment-Cache** ist (Cache Miss):

1.  Er holt den AST-Body der Zielfunktion (z.B. `(+ x x)` aus `(def my-func (fn [x] (+ x x)))`).
2.  Er instanziiert diesen Body, indem er das Wissen über die Argumenttypen (z.B. `x = stOrdinal`) anwendet.
3.  Er lässt diesen neuen, instanziierten AST-Body (`(+ <x:Ordinal> <x:Ordinal>)`) rekursiv durch die relevanten Compiler-Phasen laufen (mindestens `TypeCheck` und `Specialize`).
4.  Der `Specialize`-Pass wandelt den Body (z.B. `(+ <x:Ordinal> <x:Ordinal>)`) rekursiv in einen *neuen* `IFunctionCallNode` um, dessen **`StaticTarget`** auf die RTL-Funktion `@TRtlFunctions.Add_Ordinal_Ordinal` zeigt.
5.  Das Ergebnis (die `TDataValue.TFunc`, die den optimierten Body repräsentiert) wird im **Environment-Cache** gespeichert.
6.  Der ursprüngliche `IFunctionCallNode` `(my-func 10)` wird durch einen Klon ersetzt, dessen **`StaticTarget`** auf die soeben kompilierte Funktion zeigt.

### 5. RTL-Erweiterung
* `Myc.Ast.RTL.Core` wird um statisch typisierte Implementierungen (z.B. `class function Add_Ordinal_Ordinal(A, B: Int64): Int64; static;`) erweitert.
* Die `TRtlRegistry` wird angepasst, um diese statischen Signaturen zu indizieren und als "Bootstrap" für den Monomorphisierungs-Cache bereitzustellen.

### 6. Evaluator-Anpassung (`TEvaluatorVisitor`)
* `VisitFunctionCall` wird modifiziert, um beide Pfade zu behandeln:
    1.  **Statischer Pfad:** `if Assigned(Node.StaticTarget) then`
        * Wertet die Argument-Nodes aus (mit `Assert(arg.IsTyped)`).
        * Marshallt die `TDataValue`-Ergebnisse direkt in die erwarteten nativen Typen.
        * Ruft das **`Node.StaticTarget`** direkt auf.
        * Wrappt das Ergebnis zurück in ein `TDataValue`.
        * Ruft `HandleTCO` auf (falls das **`StaticTarget`** ein `recur` war).
    2.  **Dynamischer Pfad:** `else`
        * Behält die bestehende Logik (`vkMethod`-Lookup) und die TCO-Thunk-Erzeugung bei (`if Node.IsTailCall then ...`).
* `VisitBinaryExpression` und `VisitUnaryExpression` werden entfernt.

### 7. Auswirkungen auf TCO (Tail Call Optimization)
* Die TCO bleibt für `recur` und *dynamische* `fn`-Aufrufe (die `IFunctionCallNode` mit **`StaticTarget = nil`** bleiben) voll funktionsfähig und erzeugt `TThunk`s.
* Ein `IFunctionCallNode` mit gesetztem **`StaticTarget`** (z.B. `(Abs x)`) in einer Tail-Position wird *nicht* per TCO optimiert. Er ist per Definition keine Rekursion. Der `TEvaluatorVisitor` führt ihn direkt aus und beendet damit korrekt die Trampolin-Schleife.

## TODO

* `IFunctionCallNode` in `Myc.Ast.Nodes` um **`StaticTarget: TDataValue.TFunc`** erweitern.
* `TFunctionCallNode` (Implementierungsklasse) um Feld, Konstruktorparameter und Getter erweitern.
* `TAst.FunctionCall`-Factory in `Myc.Ast.pas` um optionalen **`AStaticTarget`**-Parameter erweitern.
* `TAstTransformer.VisitFunctionCall` in `Myc.Ast.Visitor` anpassen, um **`StaticTarget`** bei CoW zu kopieren.
* `TBinaryExpressionNode`, `TUnaryExpressionNode` (und ihre `Visit...`-Methoden) aus allen Units (`Nodes`, `Visitor`, `Dumper`, `Evaluator`, `Lowerer`, `Json`, `Fmx.AstEditor.Node`) entfernen.
* `TAstLowerer` aus dem Kompilierungsprozess in `TEnvironment.Compile` entfernen.
* `Myc.Ast.RTL.Core` um statisch typisierte Funktionsvarianten für alle Operatoren und gängige Funktionen (Abs, Trunc etc.) ergänzen.
* `TRtlRegistry` erweitern, um diese statischen Signaturen zu indizieren.
* **`IEnvironment`** (und Implementierung) um einen Member für den Monomorphisierungs-Cache erweitern.
* `TStaticSpecializer` als neuen `TAstTransformer`-Pass implementieren.
* **`TStaticSpecializer`-Konstruktor** erweitern, um den Cache vom `IEnvironment` entgegenzunehmen.
* `TStaticSpecializer.VisitFunctionCall` mit der Logik für statische/dynamische Pfade implementieren (Klonen des `IFunctionCallNode` mit gesetztem **`StaticTarget`**).
* Monomorphisierungs-Cache (Lookup und "Cache Miss"-Rekursion) im `TStaticSpecializer` implementieren (unter Verwendung des **Environment-Caches**).
* `TEnvironment.Compile` aktualisieren, um den `TStaticSpecializer` anstelle des `TAstLowerer` aufzurufen.
* `TEvaluatorVisitor.VisitFunctionCall` modifizieren, um den statischen Pfad (`if Assigned(Node.StaticTarget)`) zu implementieren.