@@ -102,19 +102,21 @@ public interface IDelegateDebugInfo
102
102
{
103
103
/// <summary>The lambda expression object that was compiled to the delegate</summary>
104
104
LambdaExpression Expression { get; }
105
+
105
106
/// <summary>The lambda expression construction syntax C# code</summary>
106
107
string ExpressionString { get; }
108
+
107
109
/// <summary>The equivalent C# code of the lambda expression</summary>
108
110
string CSharpString { get; }
109
- /// <summary>Delegate IL op-codes and tokens</summary>
110
- string ILString { get; }
111
111
112
- // todo: @feature add the debug info to the nested lambdas
113
- // /// <summary>Total nested lambda counting</summary>
114
- // ushort NestedLambdaCount { get; } // todo: @wip count nested lambdas and expressions
112
+ /// <summary>Delegate IL op-codes</summary>
113
+ ILInstruction[] ILInstructions { get; }
114
+
115
+ /// <summary>Delegate IL op-codes</summary>
116
+ string ILString { get; }
115
117
116
- // /// <summary>Nested lambda compiled counting, should be less or equal to `NestedLambdaCount` so that the same lambda compiled only once .</summary>
117
- // ushort NestedLambdaCompiledTimesCount { get; }
118
+ /// <summary>Enumerates all nested lambdas in the closure object, if any .</summary>
119
+ IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas();
118
120
}
119
121
120
122
/// <summary>Compiles expression to delegate ~20 times faster than Expression.Compile.
@@ -489,6 +491,8 @@ private static Delegate CompileNoArgsNew(NewExpression newExpr, Type delegateTyp
489
491
var closure = !hasDebugInfo ? EmptyArrayClosure : new DebugArrayClosure(null, Lambda(newExpr, Tools.Empty<PE>()));
490
492
var dlg = method.CreateDelegate(delegateType, closure);
491
493
DynamicMethodHacks.FreePooledILGenerator(method, il);
494
+ if (hasDebugInfo)
495
+ ((DebugArrayClosure)closure).ILInstructions = ILReaderFactory.CreateILReader(dlg.Method).ToArray();
492
496
return dlg;
493
497
}
494
498
@@ -553,7 +557,7 @@ internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Exp
553
557
il.Demit(OpCodes.Ret);
554
558
compiledDelegate = dynMethod.CreateDelegate(delegateType, closure);
555
559
if (hasDebugInfo)
556
- ((DebugArrayClosure)closure).ILString = compiledDelegate.Method.ToILString().ToString ();
560
+ ((DebugArrayClosure)closure).ILInstructions = ILReaderFactory.CreateILReader( compiledDelegate.Method).ToArray ();
557
561
}
558
562
559
563
DynamicMethodHacks.FreePooledILGenerator(dynMethod, il);
@@ -1003,71 +1007,69 @@ public class ArrayClosure
1003
1007
public ArrayClosure(object[] constantsAndNestedLambdas) => ConstantsAndNestedLambdas = constantsAndNestedLambdas;
1004
1008
}
1005
1009
1010
+ // todo: @rename to DiagInfoClosure
1006
1011
[RequiresUnreferencedCode(Trimming.Message)]
1007
1012
public sealed class DebugArrayClosure : ArrayClosure, IDelegateDebugInfo
1008
1013
{
1009
1014
public LambdaExpression Expression { get; internal set; }
1010
1015
1011
- private readonly Lazy<string> _expressionString;
1012
- public string ExpressionString => _expressionString.Value;
1013
-
1014
- private readonly Lazy<string> _csharpString;
1015
- public string CSharpString => _csharpString.Value;
1016
-
1017
- public string ILString { get; internal set; }
1018
-
1019
- public DebugArrayClosure(object[] constantsAndNestedLambdas, LambdaExpression expr)
1020
- : base(constantsAndNestedLambdas)
1016
+ private string _expressionString;
1017
+ public string ExpressionString
1021
1018
{
1022
- Expression = expr;
1023
- _expressionString = new Lazy<string>(() => Expression?.ToExpressionString() ?? "<expression is not available>");
1024
- _csharpString = new Lazy<string>(() => Expression?.ToCSharpString() ?? "<expression is not available>");
1019
+ get
1020
+ {
1021
+ if (_expressionString != null)
1022
+ return _expressionString;
1023
+ var expr = Expression;
1024
+ return expr == null
1025
+ ? "<Expression is not set to the DebugArrayClosure>"
1026
+ : (_expressionString = expr.ToExpressionString());
1027
+ }
1025
1028
}
1026
- }
1027
-
1028
- public static bool TryGetDebugClosureNestedLambdaOrConstant(this Delegate parentLambda, out object item, int itemIndex = 0)
1029
- {
1030
- var target = parentLambda.Target;
1031
- if (target is ExpressionCompiler.DebugArrayClosure t)
1029
+ private string _csharpString;
1030
+ public string CSharpString
1032
1031
{
1033
- var closureItems = t.ConstantsAndNestedLambdas;
1034
- if (itemIndex < closureItems.Length)
1032
+ get
1035
1033
{
1036
- item = closureItems[itemIndex];
1037
- return true;
1034
+ if (_csharpString != null)
1035
+ return _csharpString;
1036
+ var expr = Expression;
1037
+ return expr == null
1038
+ ? "<Expression is not set to the DebugArrayClosure>"
1039
+ : (_csharpString = expr.ToCSharpString());
1038
1040
}
1039
1041
}
1040
- item = null;
1041
- return false;
1042
- }
1043
1042
1044
- public static bool TryGetDebugClosureNestedLambda(this Delegate parentLambda, int itemIndex, out Delegate d)
1045
- {
1046
- var target = parentLambda.Target ;
1047
- if (target is ExpressionCompiler.DebugArrayClosure t)
1043
+ public ILInstruction[] ILInstructions { get; internal set; }
1044
+
1045
+ private string _ilString ;
1046
+ public string ILString
1048
1047
{
1049
- var closureItems = t.ConstantsAndNestedLambdas;
1050
- if (itemIndex < closureItems.Length)
1048
+ get
1051
1049
{
1052
- var nestedLambda = closureItems[itemIndex];
1053
- d = (Delegate)(nestedLambda is NestedLambdaForNonPassedParams n ? n.NestedLambda : nestedLambda);
1054
- return true;
1050
+ if (_ilString != null)
1051
+ return _ilString;
1052
+ var ilInstructions = ILInstructions;
1053
+ return ilInstructions == null
1054
+ ? "<ILInstructions are not set to the DebugArrayClosure>"
1055
+ : (_ilString = ILInstructions.ToILString().ToString());
1055
1056
}
1056
1057
}
1057
- d = null;
1058
- return false;
1059
- }
1060
1058
1061
- public static IEnumerable<object> EnumerateDebugConstantsAndNestedLambdas(this Delegate parentLambda)
1062
- {
1063
- var target = parentLambda.Target;
1064
- if (target is ExpressionCompiler.DebugArrayClosure t)
1059
+ public DebugArrayClosure(object[] constantsAndNestedLambdas, LambdaExpression expr)
1060
+ : base(constantsAndNestedLambdas) =>
1061
+ Expression = expr;
1062
+
1063
+ // <inheritdoc />
1064
+ public IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas()
1065
1065
{
1066
- foreach (var item in t.ConstantsAndNestedLambdas)
1067
- if (item is NestedLambdaForNonPassedParams nestedLambda)
1068
- yield return nestedLambda.NestedLambda;
1069
- else
1070
- yield return item;
1066
+ if (ConstantsAndNestedLambdas != null)
1067
+ foreach (var item in ConstantsAndNestedLambdas)
1068
+ {
1069
+ var dlg = (item is NestedLambdaForNonPassedParams nestedLambda ? nestedLambda.NestedLambda : item) as Delegate;
1070
+ if (dlg != null && dlg.Target is IDelegateDebugInfo delegateDebugInfo)
1071
+ yield return delegateDebugInfo;
1072
+ }
1071
1073
}
1072
1074
}
1073
1075
@@ -1844,9 +1846,9 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
1844
1846
1845
1847
ArrayClosure nestedLambdaClosure = null;
1846
1848
var hasNonPassedParameters = nestedLambdaInfo.NonPassedParameters.Count != 0;
1849
+ var hasDebugInfo = (flags & CompilerFlags.EnableDelegateDebugInfo) != 0;
1847
1850
if (!hasNonPassedParameters)
1848
1851
{
1849
- var hasDebugInfo = (flags & CompilerFlags.EnableDelegateDebugInfo) != 0;
1850
1852
if (!hasDebugInfo)
1851
1853
nestedLambdaClosure = constantsAndNestedLambdas == null ? EmptyArrayClosure : new ArrayClosure(constantsAndNestedLambdas);
1852
1854
else
@@ -1876,9 +1878,14 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
1876
1878
? method.CreateDelegate(nestedLambdaExpr.Type, nestedLambdaClosure)
1877
1879
: method.CreateDelegate(Tools.GetFuncOrActionType(closurePlusParamTypes, nestedReturnType), null);
1878
1880
1879
- nestedLambdaInfo.Lambda = !hasNonPassedParameters ? nestedLambda
1880
- : constantsAndNestedLambdas == null ? new NestedLambdaForNonPassedParams(nestedLambda)
1881
- : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, constantsAndNestedLambdas);
1881
+ nestedLambdaInfo.Lambda = !hasNonPassedParameters
1882
+ ? nestedLambda
1883
+ : constantsAndNestedLambdas == null
1884
+ ? new NestedLambdaForNonPassedParams(nestedLambda)
1885
+ : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, constantsAndNestedLambdas);
1886
+
1887
+ if (nestedLambdaClosure is DebugArrayClosure debugInfoClosure)
1888
+ debugInfoClosure.ILInstructions = ILReaderFactory.CreateILReader(nestedLambda).ToArray();
1882
1889
}
1883
1890
DynamicMethodHacks.FreePooledILGenerator(method, il);
1884
1891
FreePooledClosureTypeAndParamTypes(closurePlusParamTypes);
0 commit comments