@@ -42,13 +42,15 @@ namespace FastExpressionCompiler.LightExpression
4242 using static FastExpressionCompiler.LightExpression.Expression;
4343 using PE = FastExpressionCompiler.LightExpression.ParameterExpression;
4444 using FastExpressionCompiler.LightExpression.ImTools;
45+ using FastExpressionCompiler.LightExpression.ILDecoder;
4546 using static FastExpressionCompiler.LightExpression.ImTools.SmallMap4;
4647#else
4748namespace FastExpressionCompiler
4849{
4950 using static System.Linq.Expressions.Expression;
5051 using PE = System.Linq.Expressions.ParameterExpression;
5152 using FastExpressionCompiler.ImTools;
53+ using FastExpressionCompiler.ILDecoder;
5254 using static FastExpressionCompiler.ImTools.SmallMap4;
5355#endif
5456 using System;
@@ -104,6 +106,8 @@ public interface IDelegateDebugInfo
104106 string ExpressionString { get; }
105107 /// <summary>The equivalent C# code of the lambda expression</summary>
106108 string CSharpString { get; }
109+ /// <summary>Delegate IL op-codes and tokens</summary>
110+ string ILString { get; }
107111
108112 // todo: @feature add the debug info to the nested lambdas
109113 // /// <summary>Total nested lambda counting</summary>
@@ -514,19 +518,17 @@ internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Exp
514518 var collectResult = TryCollectInfo(ref closureInfo, bodyExpr, paramExprs, null, ref closureInfo.NestedLambdas, flags);
515519 if (collectResult == Result.OK)
516520 {
521+ var constantsAndNestedLambdas = (closureInfo.Status & ClosureStatus.HasClosure) != 0
522+ ? closureInfo.GetArrayOfConstantsAndNestedLambdas()
523+ : null;
524+
517525 ArrayClosure closure;
518- if ((flags & CompilerFlags.EnableDelegateDebugInfo) == 0)
519- {
520- closure = (closureInfo.Status & ClosureStatus.HasClosure) == 0
521- ? EmptyArrayClosure
522- : new ArrayClosure(closureInfo.GetArrayOfConstantsAndNestedLambdas());
523- }
526+ var hasDebugInfo = (flags & CompilerFlags.EnableDelegateDebugInfo) != 0;
527+ if (!hasDebugInfo)
528+ closure = constantsAndNestedLambdas == null ? EmptyArrayClosure : new ArrayClosure(constantsAndNestedLambdas);
524529 else
525- { // todo: @feature add the debug info to the nested lambdas!
530+ {
526531 var debugExpr = Lambda(delegateType, bodyExpr, paramExprs?.ToReadOnlyList() ?? Tools.Empty<PE>());
527- var constantsAndNestedLambdas = (closureInfo.Status & ClosureStatus.HasClosure) == 0
528- ? null
529- : closureInfo.GetArrayOfConstantsAndNestedLambdas();
530532 closure = new DebugArrayClosure(constantsAndNestedLambdas, debugExpr);
531533 }
532534
@@ -548,6 +550,8 @@ internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Exp
548550 {
549551 il.Demit(OpCodes.Ret);
550552 compiledDelegate = dynMethod.CreateDelegate(delegateType, closure);
553+ if (hasDebugInfo)
554+ ((DebugArrayClosure)closure).ILString = compiledDelegate.Method.ToILString().ToString();
551555 }
552556
553557 DynamicMethodHacks.FreePooledILGenerator(dynMethod, il);
@@ -1007,6 +1011,9 @@ public sealed class DebugArrayClosure : ArrayClosure, IDelegateDebugInfo
10071011
10081012 private readonly Lazy<string> _csharpString;
10091013 public string CSharpString => _csharpString.Value;
1014+
1015+ public string ILString { get; internal set; }
1016+
10101017 public DebugArrayClosure(object[] constantsAndNestedLambdas, LambdaExpression expr)
10111018 : base(constantsAndNestedLambdas)
10121019 {
@@ -1804,7 +1811,7 @@ private static bool FindAlreadyCompiledNestedLambdaInfoInLambdas(
18041811 return false;
18051812 }
18061813
1807- private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, NestedLambdaInfo nestedLambdaInfo, CompilerFlags setup )
1814+ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, NestedLambdaInfo nestedLambdaInfo, CompilerFlags flags )
18081815 {
18091816 // 1. Try to compile nested lambda in place
18101817 // 2. Check that parameters used in compiled lambda are passed or closed by outer lambda
@@ -1829,28 +1836,34 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
18291836 nestedClosureInfo.NestedLambdas = nestedLambdaInfo.NestedLambdas;
18301837 nestedClosureInfo.NonPassedParameters = nestedLambdaInfo.NonPassedParameters;
18311838
1832- var nestedConstsAndLambdas = nestedClosureInfo.GetArrayOfConstantsAndNestedLambdas();
1839+ var constantsAndNestedLambdas = (nestedClosureInfo.Status & ClosureStatus.HasClosure) != 0
1840+ ? nestedClosureInfo.GetArrayOfConstantsAndNestedLambdas()
1841+ : null;
18331842
18341843 ArrayClosure nestedLambdaClosure = null;
18351844 var hasNonPassedParameters = nestedLambdaInfo.NonPassedParameters.Count != 0;
18361845 if (!hasNonPassedParameters)
1837- nestedLambdaClosure = (nestedClosureInfo.Status & ClosureStatus.HasClosure) == 0
1838- ? EmptyArrayClosure
1839- : new ArrayClosure(nestedConstsAndLambdas);
1846+ {
1847+ var hasDebugInfo = (flags & CompilerFlags.EnableDelegateDebugInfo) != 0;
1848+ if (!hasDebugInfo)
1849+ nestedLambdaClosure = constantsAndNestedLambdas == null ? EmptyArrayClosure : new ArrayClosure(constantsAndNestedLambdas);
1850+ else
1851+ nestedLambdaClosure = new DebugArrayClosure(constantsAndNestedLambdas, nestedLambdaExpr);
1852+ }
18401853
18411854 var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(nestedLambdaParamExprs);
18421855
18431856 var method = new DynamicMethod(string.Empty, nestedReturnType, closurePlusParamTypes, typeof(ArrayClosure), true);
18441857 var il = DynamicMethodHacks.RentPooledOrNewILGenerator(method, nestedReturnType, closurePlusParamTypes);
18451858
1846- if (nestedConstsAndLambdas != null)
1859+ if (constantsAndNestedLambdas != null)
18471860 EmittingVisitor.EmitLoadConstantsAndNestedLambdasIntoVars(il, ref nestedClosureInfo);
18481861
18491862 var parent = nestedReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.LambdaCall;
18501863 if (nestedReturnType.IsByRef)
18511864 parent |= ParentFlags.ReturnByRef;
18521865
1853- var emitOk = EmittingVisitor.TryEmit(nestedLambdaBody, nestedLambdaParamExprs, il, ref nestedClosureInfo, setup , parent);
1866+ var emitOk = EmittingVisitor.TryEmit(nestedLambdaBody, nestedLambdaParamExprs, il, ref nestedClosureInfo, flags , parent);
18541867 if (emitOk)
18551868 {
18561869 il.Demit(OpCodes.Ret);
@@ -1862,8 +1875,8 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
18621875 : method.CreateDelegate(Tools.GetFuncOrActionType(closurePlusParamTypes, nestedReturnType), null);
18631876
18641877 nestedLambdaInfo.Lambda = !hasNonPassedParameters ? nestedLambda
1865- : nestedConstsAndLambdas == null ? new NestedLambdaForNonPassedParams(nestedLambda)
1866- : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, nestedConstsAndLambdas );
1878+ : constantsAndNestedLambdas == null ? new NestedLambdaForNonPassedParams(nestedLambda)
1879+ : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, constantsAndNestedLambdas );
18671880 }
18681881 DynamicMethodHacks.FreePooledILGenerator(method, il);
18691882 FreePooledClosureTypeAndParamTypes(closurePlusParamTypes);
0 commit comments