# Analyse der AST-Optimierungen und Spezialisierung *Datum: 23.05.2024* *Tool: `src/bin/ast.rs` mit `--dump`* ## 1. Motivation Diese Analyse untersucht die Effektivität der Rust-Portierung des Optimizers. Ziel war es, die theoretischen Konzepte aus den Design-Dokumenten (wie "Closure Cracking" und "Beta-Reduction") empirisch am lebenden Objekt zu verifizieren. ## 2. Kern-Erkenntnisse ### A. Aggressives Constant Folding (The "Zero-Cost" Promise) Der Optimizer ist extrem aggressiv bei der Vorkalkulation von Werten. Ein komplexer Ausdruck wie: ```lisp (do (def MYPI 3.14) (def radius 10) (* MYPI (* radius radius))) ``` wird im optimierten AST zu einer einzigen Konstante reduziert: `Constant: 314`. **Erstaunlich:** Nicht nur die Arithmetik wird gefaltet, sondern auch die `def`-Bindungen werden komplett eliminiert (Dead Code Elimination), da sie nach dem Inlining nicht mehr benötigt werden. ### B. Beta-Reduction & Lambda-Inlining Aufrufe von Lambda-Literalen werden bereits zur Compile-Zeit "geknackt" (Cracking). * **Beispiel:** `((fn [x] (+ x 1)) 10)` -> `Constant: 11`. * **Verschachtelung:** Selbst bei verschachtelten Lambdas wie `((fn [x] (fn [] x)) 10)` erkennt der Optimizer die Konstante und reduziert den äußeren Aufruf auf ein Lambda, das lediglich `Constant: 10` zurückgibt. ### C. Die Rolle der Spezialisierung (Monomorphisierung) Eine der wichtigsten architektonischen Erkenntnisse war das Verhalten des `Specializer`. Selbst wenn das Tool mit `--no-opt` aufgerufen wird, tauchen im Dump oft spezialisierte Closures auf. * **Grund:** Die Spezialisierung ist in `Environment::link` fest verdrahtet, da sie für die Korrektheit (z. B. Overload-Resolution von Operatoren wie `+`) notwendig ist. * **Effekt:** Ein globaler Aufruf von `f` mit einem `Int` wird zu einem Aufruf einer spezialisierten Version von `f`, die bereits auf `Int` optimiert wurde. Der "echte" Optimizer baut darauf auf und führt dann das Inlining durch. ## 3. Überraschungen & Kuriositäten ### Der Rekursions-Schutz Beim Testen einer rekursiven Funktion `(def f (fn [x] (f x)))` zeigte der Dump ein interessantes Muster: * Der Optimizer führt genau eine Ebene des Inlinings durch, bevor der `inlining_stack` greift. * Im Dump resultiert dies in einem "Callee", der selbst ein Lambda ist, welches wiederum die globale Funktion aufruft. * Dabei tauchten spezialisierte Typen wie `Vector(Any, 1)` oder `Matrix(Any, [1, 1])` auf. Dies sind interne Artefakte der Monomorphisierung, die zeigen, wie das System versucht, Argumentlisten in einheitliche Tupel-Strukturen zu zwingen (Unification). ### String-Folding Der Optimizer beherrscht das Zusammenfügen von Strings via `+` bereits zur Compile-Zeit. * `(+ "Hello, " "Rust!")` wird im AST direkt zu `"Hello, Rust!"`. * Dies ist besonders wertvoll für Makros, die Code-Teile oder Bezeichner generieren. ## 4. Fazit für die Entwicklung Die Pipeline (Expand -> Bind -> Specialize -> Optimize -> TCO) ist robust. Die Entscheidung, die Spezialisierung vor den Optimizer zu schalten, erweist sich als goldrichtig, da der Optimizer so auf einem bereits typsicheren und "aufgecrackten" Baum operieren kann. Das Tool `ast.exe --dump` bleibt das wichtigste Instrument, um sicherzustellen, dass neue Sprachfeatures nicht den "Fast Path" des Compilers verlassen.