From ae10f4eee04f08a6fbc3b0ea01ba4dbde032b30d Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Wed, 19 Nov 2025 21:22:01 +0100 Subject: [PATCH] Static specialization done --- ASTPlayground/MainForm.pas | 7 +- ASTPlayground/UserLib.json | 299 ++++++----------------- Src/AST/Myc.Ast.Compiler.Specializer.pas | 28 ++- 3 files changed, 99 insertions(+), 235 deletions(-) diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index bc12b1e..990b709 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -1158,10 +1158,9 @@ end; procedure TForm1.FailingUpvalueButtonClick(Sender: TObject); var - mainBlock: IAstNode; resultValue: TDataValue; begin - mainBlock := + FCurrUnboundAst := TAst.Block( [ TAst.VarDecl(TAst.Identifier('a'), TAst.Constant(10)), @@ -1186,10 +1185,12 @@ begin ] ); + UpdateScript; + Memo1.Lines.Clear; Memo1.Lines.Add('--- Executing Corrected Upvalue Test ---'); - resultValue := ExecuteAst(mainBlock); + resultValue := ExecuteAst(FCurrUnboundAst); var res := resultValue.AsScalar.Value.AsInt64; if res = 15 then diff --git a/ASTPlayground/UserLib.json b/ASTPlayground/UserLib.json index eeba53d..2022c27 100644 --- a/ASTPlayground/UserLib.json +++ b/ASTPlayground/UserLib.json @@ -16,24 +16,34 @@ } ], "Body": { - "NodeType": "BinaryExpr", - "Operator": "+", - "Left": { - "NodeType": "BinaryExpr", - "Operator": "+", - "Left": { - "NodeType": "Identifier", - "Name": "a" - }, - "Right": { - "NodeType": "Identifier", - "Name": "b" - } - }, - "Right": { + "NodeType": "FunctionCall", + "Callee": { "NodeType": "Identifier", - "Name": "c" - } + "Name": "+" + }, + "Arguments": [ + { + "NodeType": "FunctionCall", + "Callee": { + "NodeType": "Identifier", + "Name": "+" + }, + "Arguments": [ + { + "NodeType": "Identifier", + "Name": "a" + }, + { + "NodeType": "Identifier", + "Name": "b" + } + ] + }, + { + "NodeType": "Identifier", + "Name": "c" + } + ] } }, "repeat": { @@ -74,22 +84,27 @@ "Body": { "NodeType": "IfExpr", "Condition": { - "NodeType": "BinaryExpr", - "Operator": ">", - "Left": { + "NodeType": "FunctionCall", + "Callee": { "NodeType": "Identifier", - "Name": "counter" + "Name": ">" }, - "Right": { - "NodeType": "Constant", - "Value": { - "Kind": "Scalar", + "Arguments": [ + { + "NodeType": "Identifier", + "Name": "counter" + }, + { + "NodeType": "Constant", "Value": { - "Kind": "Ordinal", - "Value": 0 + "Kind": "Scalar", + "Value": { + "Kind": "Ordinal", + "Value": 0 + } } } - } + ] }, "ThenBranch": { "NodeType": "Block", @@ -105,22 +120,27 @@ "NodeType": "Recur", "Arguments": [ { - "NodeType": "BinaryExpr", - "Operator": "-", - "Left": { + "NodeType": "FunctionCall", + "Callee": { "NodeType": "Identifier", - "Name": "counter" + "Name": "-" }, - "Right": { - "NodeType": "Constant", - "Value": { - "Kind": "Scalar", + "Arguments": [ + { + "NodeType": "Identifier", + "Name": "counter" + }, + { + "NodeType": "Constant", "Value": { - "Kind": "Ordinal", - "Value": 1 + "Kind": "Scalar", + "Value": { + "Kind": "Ordinal", + "Value": 1 + } } } - } + ] } ] } @@ -128,8 +148,7 @@ }, "ElseBranch": { "NodeType": "Block", - "Expressions": [ - ] + "Expressions": [] } } } @@ -483,8 +502,21 @@ "Name": "series" }, "Index": { - "NodeType": "Identifier", - "Name": "len" + "NodeType": "FunctionCall", + "Callee": { + "NodeType": "Identifier", + "Name": "-" + }, + "Arguments": [ + { + "NodeType": "Identifier", + "Name": "count" + }, + { + "NodeType": "Identifier", + "Name": "len" + } + ] } } ] @@ -632,185 +664,6 @@ } } }, - { - "NodeType": "VarDecl", - "Identifier": { - "NodeType": "Identifier", - "Name": "sum-product" - }, - "Initializer": { - "NodeType": "LambdaExpr", - "Parameters": [ - { - "NodeType": "Identifier", - "Name": "xs" - }, - { - "NodeType": "Identifier", - "Name": "ys" - } - ], - "Body": { - "NodeType": "Block", - "Expressions": [ - { - "NodeType": "VarDecl", - "Identifier": { - "NodeType": "Identifier", - "Name": "loop" - }, - "Initializer": { - "NodeType": "LambdaExpr", - "Parameters": [ - { - "NodeType": "Identifier", - "Name": "i" - }, - { - "NodeType": "Identifier", - "Name": "acc" - } - ], - "Body": { - "NodeType": "IfExpr", - "Condition": { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "=" - }, - "Arguments": [ - { - "NodeType": "Identifier", - "Name": "i" - }, - { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "series-count" - }, - "Arguments": [ - { - "NodeType": "Identifier", - "Name": "xs" - } - ] - } - ] - }, - "ThenBranch": { - "NodeType": "Identifier", - "Name": "acc" - }, - "ElseBranch": { - "NodeType": "Recur", - "Arguments": [ - { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "+" - }, - "Arguments": [ - { - "NodeType": "Identifier", - "Name": "i" - }, - { - "NodeType": "Constant", - "Value": { - "Kind": "Scalar", - "Value": { - "Kind": "Ordinal", - "Value": 1 - } - } - } - ] - }, - { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "+" - }, - "Arguments": [ - { - "NodeType": "Identifier", - "Name": "acc" - }, - { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "*" - }, - "Arguments": [ - { - "NodeType": "Indexer", - "Base": { - "NodeType": "Identifier", - "Name": "xs" - }, - "Index": { - "NodeType": "Identifier", - "Name": "i" - } - }, - { - "NodeType": "Indexer", - "Base": { - "NodeType": "Identifier", - "Name": "ys" - }, - "Index": { - "NodeType": "Identifier", - "Name": "i" - } - } - ] - } - ] - } - ] - } - } - } - }, - { - "NodeType": "FunctionCall", - "Callee": { - "NodeType": "Identifier", - "Name": "loop" - }, - "Arguments": [ - { - "NodeType": "Constant", - "Value": { - "Kind": "Scalar", - "Value": { - "Kind": "Ordinal", - "Value": 0 - } - } - }, - { - "NodeType": "Constant", - "Value": { - "Kind": "Scalar", - "Value": { - "Kind": "Ordinal", - "Value": 0 - } - } - } - ] - } - ] - } - } - }, { "NodeType": "VarDecl", "Identifier": { @@ -1035,7 +888,7 @@ }, { "NodeType": "Identifier", - "Name": "sum-y" + "Name": "sum-x" } ] } diff --git a/Src/AST/Myc.Ast.Compiler.Specializer.pas b/Src/AST/Myc.Ast.Compiler.Specializer.pas index df8d4e6..d6f4a29 100644 --- a/Src/AST/Myc.Ast.Compiler.Specializer.pas +++ b/Src/AST/Myc.Ast.Compiler.Specializer.pas @@ -25,8 +25,6 @@ type TStaticSpecializer = class(TAstTransformer, IAstSpecializer) private FEnvironment: IEnvironment; - FMonomorphCache: TMonomorphCache; - FFunctionRegistry: IFunctionDefinitionRegistry; function GetStaticRtlFunction(const AName: string; const AArgTypes: TArray): TSpecializedMethod; @@ -53,9 +51,6 @@ begin inherited Create; Assert(Assigned(AEnvironment)); FEnvironment := AEnvironment; - FMonomorphCache := AEnvironment.MonomorphCache; - FFunctionRegistry := AEnvironment.FunctionRegistry; // Get registry - Assert(Assigned(FFunctionRegistry)); end; class function TStaticSpecializer.Specialize( @@ -139,7 +134,7 @@ begin // 4. Check the Environment (Instance) Cache key := TMonoCacheKey.Create(calleeIdent.Address, argTypes); - if FMonomorphCache.TryGetValue(key, specializedMethod) then + if FEnvironment.MonomorphCache.TryGetValue(key, specializedMethod) then begin // 4a. Cache Hit (Environment): Found user-defined or previously specialized fn Result := @@ -158,7 +153,7 @@ begin if Assigned(specializedMethod.Target) then begin // 5a. Cache Hit (RTL): Found a native, static RTL function - FMonomorphCache.Add(key, specializedMethod); + FEnvironment.MonomorphCache.Add(key, specializedMethod); Result := TAst.FunctionCall( @@ -172,10 +167,25 @@ begin end; // 6. Cache Miss (User Code) - funcDef := FFunctionRegistry.Resolve(calleeIdent.Address); + funcDef := FEnvironment.FunctionRegistry.Resolve(calleeIdent.Address); if (funcDef <> nil) then begin + // Cannot specialize closures or functions with nested closures + // that might depend on the local environment being detached. + // We check if it's a lambda expression node (which it usually is) + if funcDef.Kind = akLambdaExpression then + begin + var lambdaDef := funcDef.AsLambdaExpression; + if (Length(lambdaDef.Upvalues) > 0) or (lambdaDef.HasNestedLambdas) then + begin + // This function relies on local scope context. We cannot lift it + // to a static compilation unit safely. Fallback to dynamic dispatch. + Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); + exit; + end; + end; + // 6a. Compile func with KNOWN TYPES var compiled := FEnvironment.Compile(funcDef, argTypes); @@ -183,7 +193,7 @@ begin // Get the return type from the *full function type* returned by Compile var returnType := compiled.StaticType.Signatures[0].ReturnType; specializedMethod := TSpecializedMethod.Create(compiled.Func, returnType); - FMonomorphCache.Add(key, specializedMethod); + FEnvironment.MonomorphCache.Add(key, specializedMethod); // 6e. Return the new node Result :=