Skip to content

Commit cd22406

Browse files
author
chaowlert
committed
GlobalReference
1 parent 524210d commit cd22406

File tree

4 files changed

+109
-34
lines changed

4 files changed

+109
-34
lines changed

ExpressionDebugger/DebugInfoInjector.cs

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Linq;
88
using System.Linq.Expressions;
99
using System.Reflection;
10+
using System.Reflection.Emit;
1011
using System.Runtime.CompilerServices;
1112

1213
namespace ExpressionDebugger
@@ -35,7 +36,7 @@ public DebugInfoInjector(string filename)
3536

3637
public DebugInfoInjector(TextWriter writer)
3738
{
38-
_document = Expression.SymbolDocument("unnamed.cs");
39+
_document = null;
3940
_writer = writer;
4041
}
4142

@@ -631,9 +632,11 @@ Expression VisitConditionalBlock(ConditionalExpression node, bool shouldReturn,
631632
Outdent();
632633
}
633634
}
634-
return Expression.Block(
635-
debug,
636-
Expression.Condition(test, ifTrue, ifFalse));
635+
636+
Expression condition = Expression.Condition(test, ifTrue, ifFalse, typeof(void));
637+
if (debug != null)
638+
condition = Expression.Block(debug, condition);
639+
return condition;
637640
}
638641

639642
protected override Expression VisitConditional(ConditionalExpression node)
@@ -645,7 +648,6 @@ protected override Expression VisitConstant(ConstantExpression node)
645648
{
646649
var value = node.Value;
647650

648-
Type t;
649651
if (value == null)
650652
Write("null");
651653
else if (value is string)
@@ -654,17 +656,59 @@ protected override Expression VisitConstant(ConstantExpression node)
654656
Write($"\'{value}\'");
655657
else if (value is bool)
656658
Write(value.ToString().ToLower());
657-
else if ((t = value as Type) != null)
659+
else if (value is Type t)
658660
Write($"typeof({Translate(t)})");
659661
else
660662
{
661-
var type = value.GetType();
663+
Type type = value.GetType();
662664
if (type.GetTypeInfo().IsPrimitive || type == typeof(decimal))
663665
Write(value.ToString());
664666
else
665667
Write("valueof(", Translate(type), ", \"", value.ToString(), "\")");
666668
}
667-
return node;
669+
670+
if (_document == null || CanEmitConstant(value, node.Type))
671+
return node;
672+
673+
var i = GlobalReference.GetIndex(value);
674+
return Expression.Convert(
675+
Expression.Call(
676+
typeof(GlobalReference).GetMethod(nameof(GlobalReference.GetObject)),
677+
Expression.Constant(i)),
678+
node.Type);
679+
}
680+
681+
private static bool CanEmitConstant(object value, Type type)
682+
{
683+
if (value == null
684+
|| type.GetTypeInfo().IsPrimitive
685+
|| type == typeof(string)
686+
|| type == typeof(decimal))
687+
return true;
688+
689+
if (value is Type t)
690+
return ShouldLdtoken(t);
691+
692+
if (value is MethodBase mb)
693+
return ShouldLdtoken(mb);
694+
695+
return false;
696+
}
697+
698+
private static bool ShouldLdtoken(Type t)
699+
{
700+
return t is TypeBuilder
701+
|| t.IsGenericParameter
702+
|| t.IsVisible;
703+
}
704+
705+
private static bool ShouldLdtoken(MethodBase mb)
706+
{
707+
if (mb is DynamicMethod)
708+
return false;
709+
710+
Type dt = mb.DeclaringType;
711+
return dt == null || ShouldLdtoken(dt);
668712
}
669713

670714
protected override Expression VisitDefault(DefaultExpression node)
@@ -683,30 +727,26 @@ static Expression Update(DynamicExpression node, IEnumerable<Expression> args)
683727

684728
protected override Expression VisitDynamic(DynamicExpression node)
685729
{
686-
var convert = node.Binder as ConvertBinder;
687-
if (convert != null)
730+
if (node.Binder is ConvertBinder convert)
688731
{
689732
Write("(", Translate(convert.Type), ")");
690733
var expr = VisitGroup(node.Arguments[0], ExpressionType.Convert);
691-
return Update(node, new[] {expr}.Concat(node.Arguments.Skip(1)));
734+
return Update(node, new[] { expr }.Concat(node.Arguments.Skip(1)));
692735
}
693-
var getMember = node.Binder as GetMemberBinder;
694-
if (getMember != null)
736+
if (node.Binder is GetMemberBinder getMember)
695737
{
696738
var expr = VisitGroup(node.Arguments[0], ExpressionType.MemberAccess);
697739
Write(".", getMember.Name);
698740
return Update(node, new[] { expr }.Concat(node.Arguments.Skip(1)));
699741
}
700-
var setMember = node.Binder as SetMemberBinder;
701-
if (setMember != null)
742+
if (node.Binder is SetMemberBinder setMember)
702743
{
703744
var expr = VisitGroup(node.Arguments[0], ExpressionType.MemberAccess);
704745
Write(".", setMember.Name, " = ");
705746
var value = VisitGroup(node.Arguments[1], ExpressionType.Assign);
706747
return Update(node, new[] { expr, value }.Concat(node.Arguments.Skip(2)));
707748
}
708-
var deleteMember = node.Binder as DeleteMemberBinder;
709-
if (deleteMember != null)
749+
if (node.Binder is DeleteMemberBinder deleteMember)
710750
{
711751
var expr = VisitGroup(node.Arguments[0], ExpressionType.MemberAccess);
712752
Write(".", deleteMember.Name, " = null");
@@ -733,8 +773,7 @@ protected override Expression VisitDynamic(DynamicExpression node)
733773
Write(" = null");
734774
return Update(node, new[] { expr }.Concat(args));
735775
}
736-
var invokeMember = node.Binder as InvokeMemberBinder;
737-
if (invokeMember != null)
776+
if (node.Binder is InvokeMemberBinder invokeMember)
738777
{
739778
var expr = VisitGroup(node.Arguments[0], ExpressionType.MemberAccess);
740779
Write(".", invokeMember.Name);
@@ -754,14 +793,12 @@ protected override Expression VisitDynamic(DynamicExpression node)
754793
var args = VisitArguments("(", node.Arguments.Skip(1).ToList(), Visit, ")");
755794
return Update(node, new[] { expr }.Concat(args));
756795
}
757-
var unary = node.Binder as UnaryOperationBinder;
758-
if (unary != null)
796+
if (node.Binder is UnaryOperationBinder unary)
759797
{
760798
var expr = VisitUnary(node.Arguments[0], unary.Operation);
761799
return Update(node, new[] { expr }.Concat(node.Arguments.Skip(1)));
762800
}
763-
var binary = node.Binder as BinaryOperationBinder;
764-
if (binary != null)
801+
if (node.Binder is BinaryOperationBinder binary)
765802
{
766803
var left = VisitGroup(node.Arguments[0], node.NodeType);
767804
Write(" ", Translate(binary.Operation), " ");
@@ -1013,9 +1050,8 @@ protected override Expression VisitLoop(LoopExpression node)
10131050
if (node.Body.NodeType == ExpressionType.Conditional)
10141051
{
10151052
var condExpr = (ConditionalExpression) node.Body;
1016-
var @break = condExpr.IfFalse as GotoExpression;
10171053

1018-
if (@break != null && @break.Target == node.BreakLabel)
1054+
if (condExpr.IfFalse is GotoExpression @break && @break.Target == node.BreakLabel)
10191055
{
10201056
WriteNextLine("while (");
10211057
var position = GetPosition();
@@ -1025,11 +1061,13 @@ protected override Expression VisitLoop(LoopExpression node)
10251061
Indent();
10261062
body = VisitBody(condExpr.IfTrue);
10271063
Outdent();
1064+
1065+
Expression condition = Expression.Condition(test, body, @break, typeof(void));
1066+
if (debug != null)
1067+
condition = Expression.Block(debug, condition);
10281068
return Expression.Loop(
1029-
Expression.Block(
1030-
debug,
1031-
Expression.Condition(test, body, @break)),
1032-
node.BreakLabel,
1069+
condition,
1070+
node.BreakLabel,
10331071
node.ContinueLabel);
10341072
}
10351073
}

ExpressionDebugger/ExpressionDebugger.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net40;net45;netstandard1.3</TargetFrameworks>
4+
<TargetFrameworks>net45</TargetFrameworks>
55
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
66
<Authors>Chaowlert Chaisrichalermpol</Authors>
77
<Description>Step into debugging and generate readable script from linq expressions</Description>
@@ -12,6 +12,7 @@
1212
<SignAssembly>True</SignAssembly>
1313
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
1414
<AssemblyOriginatorKeyFile>ExpressionDebugger.snk</AssemblyOriginatorKeyFile>
15+
<Version>1.0.1</Version>
1516
</PropertyGroup>
1617

1718
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">

ExpressionDebugger/ExpressionExtensions.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@ public static string ToScript(this Expression node)
3030
/// <returns>Generated method</returns>
3131
public static T CompileWithDebugInfo<T>(this Expression<T> node, string filename = null)
3232
{
33+
return (T)(object)CompileWithDebugInfo((LambdaExpression)node, filename);
34+
}
35+
36+
public static Delegate CompileWithDebugInfo(this LambdaExpression node, string filename = null)
37+
{
3338
#if NETSTANDARD1_3
3439
return node.Compile();
3540
#else
41+
3642
if (filename == null)
3743
filename = Path.GetTempFileName();
38-
var name = "m_" + Guid.NewGuid().ToString("N");
39-
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run);
44+
var assemblyName = "m_" + Guid.NewGuid().ToString("N");
45+
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run);
4046

4147
var daType = typeof(DebuggableAttribute);
4248
var daCtor = daType.GetConstructor(new[] { typeof(DebuggableAttribute.DebuggingModes) });
@@ -45,7 +51,7 @@ public static T CompileWithDebugInfo<T>(this Expression<T> node, string filename
4551
DebuggableAttribute.DebuggingModes.Default });
4652
asm.SetCustomAttribute(daBuilder);
4753

48-
var mod = asm.DefineDynamicModule(name, true);
54+
var mod = asm.DefineDynamicModule(assemblyName, true);
4955
var type = mod.DefineType("Program", TypeAttributes.Public | TypeAttributes.Class);
5056
var meth = type.DefineMethod("Main", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
5157

@@ -59,7 +65,7 @@ public static T CompileWithDebugInfo<T>(this Expression<T> node, string filename
5965

6066
var newtype = type.CreateType();
6167

62-
return (T)(object)Delegate.CreateDelegate(typeof(T), newtype.GetMethod("Main"));
68+
return Delegate.CreateDelegate(node.Type, newtype.GetMethod("Main"));
6369
#endif
6470
}
6571
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Collections.Generic;
2+
3+
namespace ExpressionDebugger
4+
{
5+
public static class GlobalReference
6+
{
7+
private static readonly List<object> _references = new List<object>();
8+
private static readonly Dictionary<object, int> _dict = new Dictionary<object, int>();
9+
10+
public static int GetIndex(object obj)
11+
{
12+
if (_dict.TryGetValue(obj, out var id))
13+
return id;
14+
lock (_references)
15+
{
16+
if (_dict.TryGetValue(obj, out id))
17+
return id;
18+
id = _references.Count;
19+
_references.Add(obj);
20+
_dict[obj] = id;
21+
return id;
22+
}
23+
}
24+
25+
public static object GetObject(int i)
26+
{
27+
return _references[i];
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)