Resolved cyclic dependencies between environment and compiler stages
This commit is contained in:
@@ -39,6 +39,7 @@ uses
|
|||||||
FMX.ListView.Appearances,
|
FMX.ListView.Appearances,
|
||||||
FMX.ListView.Adapters.Base,
|
FMX.ListView.Adapters.Base,
|
||||||
FMX.ListView,
|
FMX.ListView,
|
||||||
|
Myc.Ast.Compiler.Specializer,
|
||||||
Myc.Ast.Environment,
|
Myc.Ast.Environment,
|
||||||
FMX.ListBox; // Added Environment
|
FMX.ListBox; // Added Environment
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,18 @@ uses
|
|||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Types,
|
Myc.Ast.Types,
|
||||||
Myc.Ast.Compiler.Binder.Upvalues,
|
Myc.Ast.Compiler.Binder.Upvalues,
|
||||||
Myc.Ast,
|
Myc.Ast;
|
||||||
Myc.Ast.Environment;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
IAstBinder = interface(IAstVisitor)
|
IAstBinder = interface(IAstVisitor)
|
||||||
function Execute(const RootNode: IAstNode; out Layout: IScopeLayout): IAstNode;
|
function Execute(const RootNode: IAstNode; out Layout: IScopeLayout): IAstNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
IFunctionDefinitionRegistry = interface
|
||||||
|
procedure Register(const Address: TResolvedAddress; const ADef: IFunctionDefinition);
|
||||||
|
function Resolve(const Address: TResolvedAddress): IFunctionDefinition;
|
||||||
|
end;
|
||||||
|
|
||||||
TAstBinder = class(TAstTransformer, IAstBinder)
|
TAstBinder = class(TAstTransformer, IAstBinder)
|
||||||
private
|
private
|
||||||
type
|
type
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ uses
|
|||||||
Myc.Ast.Visitor,
|
Myc.Ast.Visitor,
|
||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Types,
|
Myc.Ast.Types,
|
||||||
Myc.Ast,
|
Myc.Ast;
|
||||||
Myc.Ast.Environment;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
IAstMacroExpander = interface(IAstVisitor)
|
IAstMacroExpander = interface(IAstVisitor)
|
||||||
@@ -56,6 +55,16 @@ type
|
|||||||
): IAstNode;
|
): IAstNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
IMacroRegistry = interface
|
||||||
|
{$region 'private'}
|
||||||
|
function GetParent: IMacroRegistry;
|
||||||
|
{$endregion}
|
||||||
|
procedure Define(const Node: IMacroDefinitionNode);
|
||||||
|
function Find(const Name: string): IMacroDefinitionNode;
|
||||||
|
function CreateChildRegistry: IMacroRegistry;
|
||||||
|
property Parent: IMacroRegistry read GetParent;
|
||||||
|
end;
|
||||||
|
|
||||||
// Handles the expansion of macro calls within the AST.
|
// Handles the expansion of macro calls within the AST.
|
||||||
TMacroExpander = class(TAstTransformer, IAstMacroExpander)
|
TMacroExpander = class(TAstTransformer, IAstMacroExpander)
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -5,27 +5,55 @@ interface
|
|||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
System.Generics.Collections,
|
System.Generics.Collections,
|
||||||
|
System.Generics.Defaults,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
Myc.Ast,
|
Myc.Ast,
|
||||||
Myc.Ast.Types,
|
Myc.Ast.Types,
|
||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Visitor,
|
Myc.Ast.Visitor,
|
||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Environment,
|
Myc.Ast.RTL,
|
||||||
Myc.Ast.RTL;
|
Myc.Ast.Compiler.Binder;
|
||||||
|
|
||||||
type
|
type
|
||||||
IAstSpecializer = interface(IAstVisitor)
|
IAstSpecializer = interface(IAstVisitor)
|
||||||
function Execute(const RootNode: IAstNode): IAstNode;
|
function Execute(const RootNode: IAstNode): IAstNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// --- Monomorphization Cache Definitions ---
|
||||||
|
|
||||||
|
TMonoCacheKey = record
|
||||||
|
public
|
||||||
|
Address: TResolvedAddress;
|
||||||
|
ArgTypes: TArray<IStaticType>;
|
||||||
|
Func: TDataValue.TFunc;
|
||||||
|
constructor Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
||||||
|
end;
|
||||||
|
|
||||||
|
IMonomorphCache = interface
|
||||||
|
function TryGetFunction(const Key: TMonoCacheKey; out Func: TSpecializedMethod): Boolean;
|
||||||
|
procedure Add(const Key: TMonoCacheKey; const Func: TSpecializedMethod);
|
||||||
|
end;
|
||||||
|
|
||||||
|
TCompiledFunction = record
|
||||||
|
public
|
||||||
|
Func: TDataValue.TFunc;
|
||||||
|
StaticType: IStaticType;
|
||||||
|
IsPure: Boolean;
|
||||||
|
constructor Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
||||||
|
end;
|
||||||
|
|
||||||
// This transformer runs *after* TypeChecker.
|
// This transformer runs *after* TypeChecker.
|
||||||
// It specializes all statically resolvable function calls (RTL and user-defined)
|
// It specializes all statically resolvable function calls (RTL and user-defined)
|
||||||
// by replacing them with nodes that have a direct StaticTarget.
|
// by replacing them with nodes that have a direct StaticTarget.
|
||||||
// It propagates Purity information but does NOT perform Constant Folding yet.
|
// It propagates Purity information but does NOT perform Constant Folding yet.
|
||||||
TStaticSpecializer = class(TAstTransformer, IAstSpecializer)
|
TStaticSpecializer = class(TAstTransformer, IAstSpecializer)
|
||||||
|
type
|
||||||
|
TCompileFunc = reference to function(const Node: IFunctionDefinition; const ArgTypes: TArray<IStaticType>): TCompiledFunction;
|
||||||
private
|
private
|
||||||
FEnvironment: IEnvironment;
|
FMonomorphCache: IMonomorphCache;
|
||||||
|
FFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
|
FCompileFunc: TCompileFunc;
|
||||||
|
|
||||||
function GetStaticRtlFunction(const AName: string; const AArgTypes: TArray<IStaticType>): TSpecializedMethod;
|
function GetStaticRtlFunction(const AName: string; const AArgTypes: TArray<IStaticType>): TSpecializedMethod;
|
||||||
|
|
||||||
@@ -33,26 +61,48 @@ type
|
|||||||
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
|
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(const AEnvironment: IEnvironment);
|
constructor Create(
|
||||||
|
const AMonomorphCache: IMonomorphCache;
|
||||||
|
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
|
const ACompileFunc: TCompileFunc
|
||||||
|
);
|
||||||
function Execute(const RootNode: IAstNode): IAstNode;
|
function Execute(const RootNode: IAstNode): IAstNode;
|
||||||
|
|
||||||
class function Specialize(const AEnvironment: IEnvironment; const RootNode: IAstNode): IAstNode; static;
|
class function Specialize(
|
||||||
|
const RootNode: IAstNode;
|
||||||
|
const AMonomorphCache: IMonomorphCache;
|
||||||
|
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
|
const ACompileFunc: TCompileFunc
|
||||||
|
): IAstNode; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Hash;
|
||||||
|
|
||||||
{ TStaticSpecializer }
|
{ TStaticSpecializer }
|
||||||
|
|
||||||
constructor TStaticSpecializer.Create(const AEnvironment: IEnvironment);
|
constructor TStaticSpecializer.Create(
|
||||||
|
const AMonomorphCache: IMonomorphCache;
|
||||||
|
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
|
const ACompileFunc: TCompileFunc
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
Assert(Assigned(AEnvironment));
|
FMonomorphCache := AMonomorphCache;
|
||||||
FEnvironment := AEnvironment;
|
FFunctionRegistry := AFunctionRegistry;
|
||||||
|
FCompileFunc := ACompileFunc;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TStaticSpecializer.Specialize(const AEnvironment: IEnvironment; const RootNode: IAstNode): IAstNode;
|
class function TStaticSpecializer.Specialize(
|
||||||
|
const RootNode: IAstNode;
|
||||||
|
const AMonomorphCache: IMonomorphCache;
|
||||||
|
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
|
const ACompileFunc: TCompileFunc
|
||||||
|
): IAstNode;
|
||||||
begin
|
begin
|
||||||
var specializer := TStaticSpecializer.Create(AEnvironment) as IAstSpecializer;
|
var specializer := TStaticSpecializer.Create(AMonomorphCache, AFunctionRegistry, ACompileFunc) as IAstSpecializer;
|
||||||
Result := specializer.Execute(RootNode);
|
Result := specializer.Execute(RootNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -125,7 +175,7 @@ begin
|
|||||||
// 4. Check the Environment (Instance) Cache
|
// 4. Check the Environment (Instance) Cache
|
||||||
key := TMonoCacheKey.Create(calleeIdent.Address, argTypes);
|
key := TMonoCacheKey.Create(calleeIdent.Address, argTypes);
|
||||||
|
|
||||||
if FEnvironment.MonomorphCache.TryGetValue(key, specializedMethod) then
|
if FMonomorphCache.TryGetFunction(key, specializedMethod) then
|
||||||
begin
|
begin
|
||||||
// 4a. Cache Hit (Environment)
|
// 4a. Cache Hit (Environment)
|
||||||
// Propagate IsPure flag from cache to AST node
|
// Propagate IsPure flag from cache to AST node
|
||||||
@@ -146,7 +196,7 @@ begin
|
|||||||
if Assigned(specializedMethod.Target) then
|
if Assigned(specializedMethod.Target) then
|
||||||
begin
|
begin
|
||||||
// 5a. Cache Hit (RTL)
|
// 5a. Cache Hit (RTL)
|
||||||
FEnvironment.MonomorphCache.Add(key, specializedMethod);
|
FMonomorphCache.Add(key, specializedMethod);
|
||||||
|
|
||||||
// Propagate IsPure flag from RTL definition to AST node
|
// Propagate IsPure flag from RTL definition to AST node
|
||||||
Result :=
|
Result :=
|
||||||
@@ -162,7 +212,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// 6. Cache Miss (User Code)
|
// 6. Cache Miss (User Code)
|
||||||
funcDef := FEnvironment.FunctionRegistry.Resolve(calleeIdent.Address);
|
funcDef := FFunctionRegistry.Resolve(calleeIdent.Address);
|
||||||
|
|
||||||
if (funcDef <> nil) then
|
if (funcDef <> nil) then
|
||||||
begin
|
begin
|
||||||
@@ -179,13 +229,13 @@ begin
|
|||||||
|
|
||||||
// 6a. Compile func with KNOWN TYPES
|
// 6a. Compile func with KNOWN TYPES
|
||||||
// This recursively triggers Bind -> Check -> Specialize -> Purity Inference for the callee body!
|
// This recursively triggers Bind -> Check -> Specialize -> Purity Inference for the callee body!
|
||||||
var compiled := FEnvironment.Compile(funcDef, argTypes);
|
var compiled := FCompileFunc(funcDef, argTypes);
|
||||||
|
|
||||||
// 6b. Store in cache
|
// 6b. Store in cache
|
||||||
// Get the return type from the *full function type* returned by Compile
|
// Get the return type from the *full function type* returned by Compile
|
||||||
var returnType := compiled.StaticType.Signatures[0].ReturnType;
|
var returnType := compiled.StaticType.Signatures[0].ReturnType;
|
||||||
specializedMethod := TSpecializedMethod.Create(compiled.Func, returnType, compiled.IsPure);
|
specializedMethod := TSpecializedMethod.Create(compiled.Func, returnType, compiled.IsPure);
|
||||||
FEnvironment.MonomorphCache.Add(key, specializedMethod);
|
FMonomorphCache.Add(key, specializedMethod);
|
||||||
|
|
||||||
// 6c. Return the new node
|
// 6c. Return the new node
|
||||||
// Propagate the inferred IsPure flag to the AST node
|
// Propagate the inferred IsPure flag to the AST node
|
||||||
@@ -200,4 +250,21 @@ begin
|
|||||||
Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil);
|
Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TMonoCacheKey }
|
||||||
|
|
||||||
|
constructor TMonoCacheKey.Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
||||||
|
begin
|
||||||
|
Address := AAddress;
|
||||||
|
ArgTypes := AArgTypes;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCompiledFunction }
|
||||||
|
|
||||||
|
constructor TCompiledFunction.Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
||||||
|
begin
|
||||||
|
Func := AFunc;
|
||||||
|
StaticType := AStaticType;
|
||||||
|
IsPure := AIsPure;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+111
-182
@@ -12,63 +12,27 @@ uses
|
|||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.RTL,
|
Myc.Ast.RTL,
|
||||||
Myc.Ast.Types;
|
Myc.Ast.Types,
|
||||||
|
Myc.Ast.Compiler.Macros,
|
||||||
|
Myc.Ast.Compiler.Binder,
|
||||||
|
Myc.Ast.Compiler.TypeChecker,
|
||||||
|
Myc.Ast.Compiler.Specializer,
|
||||||
|
Myc.Ast.Compiler.TCO,
|
||||||
|
Myc.Ast.Analysis.Purity;
|
||||||
|
|
||||||
type
|
type
|
||||||
IMacroRegistry = interface;
|
|
||||||
IEnvironment = interface;
|
IEnvironment = interface;
|
||||||
IExecutionStrategy = interface;
|
IExecutionStrategy = interface;
|
||||||
IFunctionDefinitionRegistry = interface;
|
|
||||||
|
|
||||||
// --- Monomorphization Cache Definitions ---
|
|
||||||
|
|
||||||
TMonoCacheKey = record
|
|
||||||
public
|
|
||||||
Address: TResolvedAddress;
|
|
||||||
ArgTypes: TArray<IStaticType>;
|
|
||||||
constructor Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
|
||||||
end;
|
|
||||||
|
|
||||||
TMonoCacheKeyComparer = class(TEqualityComparer<TMonoCacheKey>)
|
|
||||||
public
|
|
||||||
function Equals(const Left, Right: TMonoCacheKey): Boolean; override;
|
|
||||||
function GetHashCode(const Value: TMonoCacheKey): Integer; override;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TMonomorphCache = TDictionary<TMonoCacheKey, TSpecializedMethod>;
|
|
||||||
|
|
||||||
TCompiledFunction = record
|
|
||||||
public
|
|
||||||
Func: TDataValue.TFunc;
|
|
||||||
StaticType: IStaticType;
|
|
||||||
IsPure: Boolean;
|
|
||||||
constructor Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
|
||||||
end;
|
|
||||||
|
|
||||||
IExecutionStrategy = interface
|
IExecutionStrategy = interface
|
||||||
function CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
function CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
IMacroRegistry = interface
|
|
||||||
{$region 'private'}
|
|
||||||
function GetParent: IMacroRegistry;
|
|
||||||
{$endregion}
|
|
||||||
procedure Define(const Node: IMacroDefinitionNode);
|
|
||||||
function Find(const Name: string): IMacroDefinitionNode;
|
|
||||||
function CreateChildRegistry: IMacroRegistry;
|
|
||||||
property Parent: IMacroRegistry read GetParent;
|
|
||||||
end;
|
|
||||||
|
|
||||||
IFunctionDefinitionRegistry = interface
|
|
||||||
procedure Register(const Address: TResolvedAddress; const ADef: IFunctionDefinition);
|
|
||||||
function Resolve(const Address: TResolvedAddress): IFunctionDefinition;
|
|
||||||
end;
|
|
||||||
|
|
||||||
IEnvironment = interface
|
IEnvironment = interface
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetRootScope: IExecutionScope;
|
function GetRootScope: IExecutionScope;
|
||||||
function GetMacroRegistry: IMacroRegistry;
|
function GetMacroRegistry: IMacroRegistry;
|
||||||
function GetMonomorphCache: TMonomorphCache;
|
function GetMonomorphCache: IMonomorphCache;
|
||||||
function GetFunctionRegistry: IFunctionDefinitionRegistry;
|
function GetFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
|
|
||||||
@@ -94,7 +58,7 @@ type
|
|||||||
|
|
||||||
property RootScope: IExecutionScope read GetRootScope;
|
property RootScope: IExecutionScope read GetRootScope;
|
||||||
property MacroRegistry: IMacroRegistry read GetMacroRegistry;
|
property MacroRegistry: IMacroRegistry read GetMacroRegistry;
|
||||||
property MonomorphCache: TMonomorphCache read GetMonomorphCache;
|
property MonomorphCache: IMonomorphCache read GetMonomorphCache;
|
||||||
property FunctionRegistry: IFunctionDefinitionRegistry read GetFunctionRegistry;
|
property FunctionRegistry: IFunctionDefinitionRegistry read GetFunctionRegistry;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -139,79 +103,25 @@ implementation
|
|||||||
uses
|
uses
|
||||||
System.Hash,
|
System.Hash,
|
||||||
Myc.Ast.Evaluator,
|
Myc.Ast.Evaluator,
|
||||||
Myc.Ast.Debugger,
|
Myc.Ast.Debugger;
|
||||||
Myc.Ast.Compiler.Macros,
|
|
||||||
Myc.Ast.Compiler.Binder,
|
|
||||||
Myc.Ast.Compiler.TypeChecker,
|
|
||||||
Myc.Ast.Compiler.Specializer,
|
|
||||||
Myc.Ast.Compiler.TCO,
|
|
||||||
Myc.Ast.Analysis.Purity;
|
|
||||||
|
|
||||||
{ TMonoCacheKey }
|
|
||||||
|
|
||||||
constructor TMonoCacheKey.Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
|
||||||
begin
|
|
||||||
Address := AAddress;
|
|
||||||
ArgTypes := AArgTypes;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TMonoCacheKeyComparer }
|
|
||||||
|
|
||||||
function TMonoCacheKeyComparer.Equals(const Left, Right: TMonoCacheKey): Boolean;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
if not (Left.Address = Right.Address) then
|
|
||||||
exit(False);
|
|
||||||
|
|
||||||
if Length(Left.ArgTypes) <> Length(Right.ArgTypes) then
|
|
||||||
exit(False);
|
|
||||||
|
|
||||||
for i := 0 to High(Left.ArgTypes) do
|
|
||||||
begin
|
|
||||||
if not Left.ArgTypes[i].IsEqual(Right.ArgTypes[i]) then
|
|
||||||
exit(False);
|
|
||||||
end;
|
|
||||||
|
|
||||||
Result := True;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TMonoCacheKeyComparer.GetHashCode(const Value: TMonoCacheKey): Integer;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
hash: Integer;
|
|
||||||
typeHash: Integer;
|
|
||||||
adr: TResolvedAddress;
|
|
||||||
begin
|
|
||||||
adr := Value.Address;
|
|
||||||
|
|
||||||
hash := THashBobJenkins.GetHashValue(adr.Kind, SizeOf(TAddressKind), 0);
|
|
||||||
hash := THashBobJenkins.GetHashValue(adr.ScopeDepth, SizeOf(Integer), hash);
|
|
||||||
hash := THashBobJenkins.GetHashValue(adr.SlotIndex, SizeOf(Integer), hash);
|
|
||||||
|
|
||||||
for i := 0 to High(Value.ArgTypes) do
|
|
||||||
begin
|
|
||||||
if Assigned(Value.ArgTypes[i]) then
|
|
||||||
typeHash := Value.ArgTypes[i].GetHashCode
|
|
||||||
else
|
|
||||||
typeHash := 0;
|
|
||||||
|
|
||||||
hash := THashBobJenkins.GetHashValue(typeHash, SizeOf(Integer), hash);
|
|
||||||
end;
|
|
||||||
|
|
||||||
Result := hash;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TCompiledFunction }
|
|
||||||
|
|
||||||
constructor TCompiledFunction.Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
|
||||||
begin
|
|
||||||
Func := AFunc;
|
|
||||||
StaticType := AStaticType;
|
|
||||||
IsPure := AIsPure;
|
|
||||||
end;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TMonoCacheKeyComparer = class(TEqualityComparer<TMonoCacheKey>)
|
||||||
|
public
|
||||||
|
function Equals(const Left, Right: TMonoCacheKey): Boolean; override;
|
||||||
|
function GetHashCode(const Value: TMonoCacheKey): Integer; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TMonomorphCache = class(TInterfacedObject, IMonomorphCache)
|
||||||
|
private
|
||||||
|
FMonomorphCache: TDictionary<TMonoCacheKey, TSpecializedMethod>;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
function TryGetFunction(const Key: TMonoCacheKey; out Func: TSpecializedMethod): Boolean;
|
||||||
|
procedure Add(const Key: TMonoCacheKey; const Func: TSpecializedMethod);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TStandardExecutionStrategy }
|
{ TStandardExecutionStrategy }
|
||||||
TStandardExecutionStrategy = class(TInterfacedObject, IExecutionStrategy)
|
TStandardExecutionStrategy = class(TInterfacedObject, IExecutionStrategy)
|
||||||
public
|
public
|
||||||
@@ -244,11 +154,11 @@ type
|
|||||||
FRootScope: IExecutionScope;
|
FRootScope: IExecutionScope;
|
||||||
FMacroRegistry: IMacroRegistry;
|
FMacroRegistry: IMacroRegistry;
|
||||||
FExecutionStrategy: IExecutionStrategy;
|
FExecutionStrategy: IExecutionStrategy;
|
||||||
FMonomorphCache: TMonomorphCache;
|
FMonomorphCache: IMonomorphCache;
|
||||||
FFunctionRegistry: IFunctionDefinitionRegistry;
|
FFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
function GetRootScope: IExecutionScope;
|
function GetRootScope: IExecutionScope;
|
||||||
function GetMacroRegistry: IMacroRegistry;
|
function GetMacroRegistry: IMacroRegistry;
|
||||||
function GetMonomorphCache: TMonomorphCache;
|
function GetMonomorphCache: IMonomorphCache;
|
||||||
function GetFunctionRegistry: IFunctionDefinitionRegistry;
|
function GetFunctionRegistry: IFunctionDefinitionRegistry;
|
||||||
public
|
public
|
||||||
constructor Create(
|
constructor Create(
|
||||||
@@ -256,8 +166,6 @@ type
|
|||||||
const AMacroRegistry: IMacroRegistry;
|
const AMacroRegistry: IMacroRegistry;
|
||||||
const AExecutionStrategy: IExecutionStrategy
|
const AExecutionStrategy: IExecutionStrategy
|
||||||
);
|
);
|
||||||
destructor Destroy; override;
|
|
||||||
|
|
||||||
function CreateEnvironment: IEnvironment;
|
function CreateEnvironment: IEnvironment;
|
||||||
|
|
||||||
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||||
@@ -415,17 +323,11 @@ begin
|
|||||||
FRootScope := ARootScope;
|
FRootScope := ARootScope;
|
||||||
FMacroRegistry := AMacroRegistry;
|
FMacroRegistry := AMacroRegistry;
|
||||||
FExecutionStrategy := AExecutionStrategy;
|
FExecutionStrategy := AExecutionStrategy;
|
||||||
FMonomorphCache := TMonomorphCache.Create(TMonoCacheKeyComparer.Create);
|
FMonomorphCache := TMonomorphCache.Create;
|
||||||
FFunctionRegistry := TFunctionDefinitionRegistry.Create;
|
FFunctionRegistry := TFunctionDefinitionRegistry.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TEnvironment.Destroy;
|
function TEnvironment.GetMonomorphCache: IMonomorphCache;
|
||||||
begin
|
|
||||||
FMonomorphCache.Free;
|
|
||||||
inherited Destroy;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TEnvironment.GetMonomorphCache: TMonomorphCache;
|
|
||||||
begin
|
begin
|
||||||
Result := FMonomorphCache;
|
Result := FMonomorphCache;
|
||||||
end;
|
end;
|
||||||
@@ -464,60 +366,9 @@ function TEnvironment.Compile(
|
|||||||
const Params: TArray<IIdentifierNode>;
|
const Params: TArray<IIdentifierNode>;
|
||||||
const ArgTypes: TArray<IStaticType>
|
const ArgTypes: TArray<IStaticType>
|
||||||
): TCompiledFunction;
|
): TCompiledFunction;
|
||||||
var
|
|
||||||
layout: IScopeLayout;
|
|
||||||
descriptor: IScopeDescriptor;
|
|
||||||
funcType: IStaticType;
|
|
||||||
finalFunc: TDataValue.TFunc;
|
|
||||||
|
|
||||||
typedNode: IAstNode;
|
|
||||||
specialized: IAstNode;
|
|
||||||
tcoOptimized: IAstNode;
|
|
||||||
isPure: Boolean;
|
|
||||||
begin
|
begin
|
||||||
// 0. Wrap in Lambda to create an isolatable compilation unit (scope)
|
// Wrap in Lambda to create an isolatable compilation unit (scope)
|
||||||
var prg := TAst.LambdaExpr(Params, Node);
|
Result := Compile(TAst.LambdaExpr(Params, Node).AsLambdaExpression, ArgTypes);
|
||||||
|
|
||||||
// 1. Expand Macros
|
|
||||||
var expanded := ExpandMacros(prg);
|
|
||||||
|
|
||||||
// 2. Bind & Check Types
|
|
||||||
typedNode := Bind(expanded, layout, ArgTypes);
|
|
||||||
|
|
||||||
// Retrieve the descriptor from the typed lambda node
|
|
||||||
// (The TypeChecker baked it into the new LambdaExpressionNode)
|
|
||||||
descriptor := typedNode.AsLambdaExpression.Descriptor;
|
|
||||||
Assert(Assigned(descriptor), 'Compiler Logic Error: Descriptor missing after type checking.');
|
|
||||||
|
|
||||||
funcType := typedNode.AsTypedNode.StaticType;
|
|
||||||
|
|
||||||
// 3. Specialize
|
|
||||||
specialized := Specialize(typedNode);
|
|
||||||
|
|
||||||
// 4. Optimize (TCO)
|
|
||||||
tcoOptimized := TAstTCO.Optimize(specialized);
|
|
||||||
|
|
||||||
// 5. Purity Inference
|
|
||||||
// Check the body of the optimized lambda for purity.
|
|
||||||
// Note: tcoOptimized is a LambdaExpressionNode. Its body is what we check.
|
|
||||||
isPure := TPurityAnalyzer.IsPure(tcoOptimized.AsLambdaExpression.Body);
|
|
||||||
|
|
||||||
// 6. Create Evaluator
|
|
||||||
var visitor := FExecutionStrategy.CreateVisitor(descriptor.CreateScope(FRootScope));
|
|
||||||
|
|
||||||
// Execute the AST to get the TFunc (Closure)
|
|
||||||
var closure := tcoOptimized.Accept(visitor).AsMethod();
|
|
||||||
|
|
||||||
// Wrap TCO handling for the final result
|
|
||||||
finalFunc :=
|
|
||||||
function(const Args: TArray<TDataValue>): TDataValue
|
|
||||||
begin
|
|
||||||
Result := closure(Args);
|
|
||||||
TEvaluatorVisitor.HandleTCO(Result);
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Pass IsPure flag to the compiled function record
|
|
||||||
Result := TCompiledFunction.Create(finalFunc, funcType, isPure);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEnvironment.Compile(const Node: IFunctionDefinition; const ArgTypes: TArray<IStaticType>): TCompiledFunction;
|
function TEnvironment.Compile(const Node: IFunctionDefinition; const ArgTypes: TArray<IStaticType>): TCompiledFunction;
|
||||||
@@ -600,7 +451,85 @@ end;
|
|||||||
|
|
||||||
function TEnvironment.Specialize(const Node: IAstNode): IAstNode;
|
function TEnvironment.Specialize(const Node: IAstNode): IAstNode;
|
||||||
begin
|
begin
|
||||||
Result := TStaticSpecializer.Specialize(Self, Node);
|
Result :=
|
||||||
|
TStaticSpecializer.Specialize(
|
||||||
|
Node,
|
||||||
|
FMonomorphCache,
|
||||||
|
FFunctionRegistry,
|
||||||
|
function(const Node: IFunctionDefinition; const ArgTypes: TArray<IStaticType>): TCompiledFunction
|
||||||
|
begin
|
||||||
|
Result := Compile(Node, ArgTypes);
|
||||||
|
end
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TMonoCacheKeyComparer }
|
||||||
|
|
||||||
|
function TMonoCacheKeyComparer.Equals(const Left, Right: TMonoCacheKey): Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if not (Left.Address = Right.Address) then
|
||||||
|
exit(False);
|
||||||
|
|
||||||
|
if Length(Left.ArgTypes) <> Length(Right.ArgTypes) then
|
||||||
|
exit(False);
|
||||||
|
|
||||||
|
for i := 0 to High(Left.ArgTypes) do
|
||||||
|
begin
|
||||||
|
if not Left.ArgTypes[i].IsEqual(Right.ArgTypes[i]) then
|
||||||
|
exit(False);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMonoCacheKeyComparer.GetHashCode(const Value: TMonoCacheKey): Integer;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
hash: Integer;
|
||||||
|
typeHash: Integer;
|
||||||
|
adr: TResolvedAddress;
|
||||||
|
begin
|
||||||
|
adr := Value.Address;
|
||||||
|
|
||||||
|
hash := THashBobJenkins.GetHashValue(adr.Kind, SizeOf(TAddressKind), 0);
|
||||||
|
hash := THashBobJenkins.GetHashValue(adr.ScopeDepth, SizeOf(Integer), hash);
|
||||||
|
hash := THashBobJenkins.GetHashValue(adr.SlotIndex, SizeOf(Integer), hash);
|
||||||
|
|
||||||
|
for i := 0 to High(Value.ArgTypes) do
|
||||||
|
begin
|
||||||
|
if Assigned(Value.ArgTypes[i]) then
|
||||||
|
typeHash := Value.ArgTypes[i].GetHashCode
|
||||||
|
else
|
||||||
|
typeHash := 0;
|
||||||
|
|
||||||
|
hash := THashBobJenkins.GetHashValue(typeHash, SizeOf(Integer), hash);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := hash;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TMonomorphCache.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FMonomorphCache := TDictionary<TMonoCacheKey, TSpecializedMethod>.Create(TMonoCacheKeyComparer.Create);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TMonomorphCache.Destroy;
|
||||||
|
begin
|
||||||
|
FMonomorphCache.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMonomorphCache.Add(const Key: TMonoCacheKey; const Func: TSpecializedMethod);
|
||||||
|
begin
|
||||||
|
FMonomorphCache.Add(Key, Func);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMonomorphCache.TryGetFunction(const Key: TMonoCacheKey; out Func: TSpecializedMethod): Boolean;
|
||||||
|
begin
|
||||||
|
Result := FMonomorphCache.TryGetValue(Key, Func);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
Reference in New Issue
Block a user