Browse Source

Rename ExpressionTreeType to DelegateType and use ILFunction.DelegateType instead of the NewObj(LdNull, ILFunction) pattern in DelegateConstruction and ExpressionTrees

pull/988/head
Siegfried Pammer 8 years ago
parent
commit
25eecb90e1
  1. 4
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 18
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  4. 14
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  5. 274
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

4
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -420,10 +420,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -420,10 +420,6 @@ namespace ICSharpCode.Decompiler.CSharp
case OpCode.LdVirtFtn:
method = ((LdVirtFtn)func).Method;
break;
case OpCode.ILFunction:
method = ((ILFunction)func).Method;
return expressionBuilder.TranslateFunction(inst.Method.DeclaringType, (ILFunction)func)
.WithILInstruction(inst);
default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
}

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1422,7 +1422,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1422,7 +1422,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitILFunction(ILFunction function, TranslationContext context)
{
return TranslateFunction(function.ExpressionTreeType, function)
return TranslateFunction(function.DelegateType, function)
.WithILInstruction(function);
}

18
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -62,12 +62,12 @@ namespace ICSharpCode.Decompiler.IL @@ -62,12 +62,12 @@ namespace ICSharpCode.Decompiler.IL
public IType AsyncReturnType;
/// <summary>
/// If this is an expression tree, returns Expression{T}, otherwise null.
/// If this is an expression tree or delegate, returns the expression tree type Expression{T} or T.
/// T is the delegate type that matches the signature of this method.
/// </summary>
public IType ExpressionTreeType;
public IType DelegateType;
public bool IsExpressionTree => ExpressionTreeType != null;
public bool IsExpressionTree => DelegateType != null && DelegateType.FullName == "System.Linq.Expressions.Expression" && DelegateType.TypeParameterCount == 1;
public readonly IType ReturnType;
@ -78,8 +78,8 @@ namespace ICSharpCode.Decompiler.IL @@ -78,8 +78,8 @@ namespace ICSharpCode.Decompiler.IL
this.Body = body;
this.Method = method;
this.CecilMethod = cecilMethod;
this.ReturnType = Method.ReturnType;
this.Parameters = Method.Parameters;
this.ReturnType = Method?.ReturnType;
this.Parameters = Method?.Parameters;
this.Variables = new ILVariableCollection(this);
}
@ -113,6 +113,14 @@ namespace ICSharpCode.Decompiler.IL @@ -113,6 +113,14 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' ');
Method.WriteTo(output);
}
if (IsExpressionTree) {
output.Write(".ET");
}
if (DelegateType != null) {
output.Write("[");
DelegateType.WriteTo(output);
output.Write("]");
}
output.WriteLine(" {");
output.Indent();

14
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -44,13 +44,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -44,13 +44,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var call in block.Instructions[i].Descendants.OfType<NewObj>()) {
ILFunction f = TransformDelegateConstruction(call, out ILInstruction target);
if (f != null) {
f.AddILRange(call.Arguments[0].ILRange);
f.AddILRange(call.Arguments[1].ILRange);
call.Arguments[0].ReplaceWith(new LdNull());
call.Arguments[1].ReplaceWith(f);
if (target is IInstructionWithVariableOperand && !target.MatchLdThis())
targetsToReplace.Add((IInstructionWithVariableOperand)target);
}
call.ReplaceWith(f);
if (target is IInstructionWithVariableOperand && !target.MatchLdThis())
targetsToReplace.Add((IInstructionWithVariableOperand)target);
}
}
if (block.Instructions[i].MatchStLoc(out ILVariable targetVariable, out ILInstruction value)) {
var newObj = value as NewObj;
@ -144,6 +141,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -144,6 +141,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var ilReader = new ILReader(localTypeSystem);
ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols;
var function = ilReader.ReadIL(methodDefinition.Body, context.CancellationToken);
function.DelegateType = value.Method.DeclaringType;
function.CheckInvariant(ILPhase.Normal);
var contextPrefix = targetMethod.Name;
@ -158,6 +156,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -158,6 +156,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
// handle nested lambdas
((IILTransform)new DelegateConstruction()).Run(function, nestedContext);
function.AddILRange(target.ILRange);
function.AddILRange(value.Arguments[1].ILRange);
return function;
}
return null;

274
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.TypeSystem;
@ -150,7 +151,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -150,7 +151,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var functionType = instruction.Method.ReturnType.TypeArguments[0];
var function = new ILFunction(functionType.TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container);
if (isQuotedLambda || lambdaStack.Count == 0)
function.ExpressionTreeType = instruction.Method.ReturnType;
function.DelegateType = instruction.Method.ReturnType;
else
function.DelegateType = functionType;
function.Variables.AddRange(parameterVariablesList);
lambdaStack.Push(function);
var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]);
@ -159,11 +162,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -159,11 +162,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
container.ExpectedResultType = bodyInstruction.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } });
if (!isQuotedLambda && lambdaStack.Count > 0)
return (new NewObj(functionType.GetConstructors().Single()) {
Arguments = { new LdNull(), function }
}, functionType);
return (function, function.ExpressionTreeType);
return (function, function.DelegateType);
}
bool ReadParameters(ILInstruction initializer, IList<IParameter> parameters, IList<ILVariable> parameterVariables, ITypeResolveContext resolveContext)
@ -199,111 +198,140 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -199,111 +198,140 @@ namespace ICSharpCode.Decompiler.IL.Transforms
(ILInstruction, IType) ConvertInstruction(ILInstruction instruction)
{
switch (instruction) {
case CallInstruction invocation:
if (invocation.Method.DeclaringType.FullName != "System.Linq.Expressions.Expression")
return (null, SpecialType.UnknownType);
var result = Convert();
if (result.Item1 != null) {
Debug.Assert(result.Item2 != null, "IType must be non-null!");
Debug.Assert(result.Item1.ResultType == result.Item2.GetStackType(), "StackTypes must match!");
}
return result;
switch (invocation.Method.Name) {
case "Add":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Add, false);
case "AddChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Add, true);
case "And":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitAnd);
case "AndAlso":
return ConvertLogicOperator(invocation, true);
case "ArrayAccess":
case "ArrayIndex":
return ConvertArrayIndex(invocation);
case "ArrayLength":
return ConvertArrayLength(invocation);
case "Call":
return ConvertCall(invocation);
case "Coalesce":
return ConvertCoalesce(invocation);
case "Condition":
return ConvertCondition(invocation);
case "Constant":
return ConvertConstant(invocation);
case "Convert":
return ConvertCast(invocation, false);
case "ConvertChecked":
return ConvertCast(invocation, true);
case "Divide":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Div);
case "Equal":
return ConvertComparison(invocation, ComparisonKind.Equality);
case "ExclusiveOr":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitXor);
case "Field":
return ConvertField(invocation);
case "GreaterThan":
return ConvertComparison(invocation, ComparisonKind.GreaterThan);
case "GreaterThanOrEqual":
return ConvertComparison(invocation, ComparisonKind.GreaterThanOrEqual);
case "Invoke":
return ConvertInvoke(invocation);
case "Lambda":
return ConvertLambda(invocation);
case "LeftShift":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.ShiftLeft);
case "LessThan":
return ConvertComparison(invocation, ComparisonKind.LessThan);
case "LessThanOrEqual":
return ConvertComparison(invocation, ComparisonKind.LessThanOrEqual);
case "ListInit":
return ConvertListInit(invocation);
case "MemberInit":
return ConvertMemberInit(invocation);
case "Modulo":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Rem);
case "Multiply":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Mul, false);
case "MultiplyChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Mul, true);
case "Negate":
return ConvertUnaryNumericOperator(invocation, BinaryNumericOperator.Sub, false);
case "NegateChecked":
return ConvertUnaryNumericOperator(invocation, BinaryNumericOperator.Sub, true);
case "New":
return ConvertNewObject(invocation);
case "NewArrayBounds":
return ConvertNewArrayBounds(invocation);
case "NewArrayInit":
return ConvertNewArrayInit(invocation);
case "Not":
return ConvertNotOperator(invocation);
case "NotEqual":
return ConvertComparison(invocation, ComparisonKind.Inequality);
case "OnesComplement":
return ConvertNotOperator(invocation);
case "Or":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitOr);
case "OrElse":
return ConvertLogicOperator(invocation, false);
case "Property":
return ConvertProperty(invocation);
case "Quote":
if (invocation.Arguments.Count == 1)
return ConvertInstruction(invocation.Arguments.Single());
else
(ILInstruction, IType) Convert() {
switch (instruction) {
case CallInstruction invocation:
if (invocation.Method.DeclaringType.FullName != "System.Linq.Expressions.Expression")
return (null, SpecialType.UnknownType);
switch (invocation.Method.Name) {
case "Add":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Add, false);
case "AddChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Add, true);
case "And":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitAnd);
case "AndAlso":
return ConvertLogicOperator(invocation, true);
case "ArrayAccess":
case "ArrayIndex":
return ConvertArrayIndex(invocation);
case "ArrayLength":
return ConvertArrayLength(invocation);
case "Call":
return ConvertCall(invocation);
case "Coalesce":
return ConvertCoalesce(invocation);
case "Condition":
return ConvertCondition(invocation);
case "Constant":
return ConvertConstant(invocation);
case "Convert":
return ConvertCast(invocation, false);
case "ConvertChecked":
return ConvertCast(invocation, true);
case "Divide":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Div);
case "Equal":
return ConvertComparison(invocation, ComparisonKind.Equality);
case "ExclusiveOr":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitXor);
case "Field":
return ConvertField(invocation);
case "GreaterThan":
return ConvertComparison(invocation, ComparisonKind.GreaterThan);
case "GreaterThanOrEqual":
return ConvertComparison(invocation, ComparisonKind.GreaterThanOrEqual);
case "Invoke":
return ConvertInvoke(invocation);
case "Lambda":
return ConvertLambda(invocation);
case "LeftShift":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.ShiftLeft);
case "LessThan":
return ConvertComparison(invocation, ComparisonKind.LessThan);
case "LessThanOrEqual":
return ConvertComparison(invocation, ComparisonKind.LessThanOrEqual);
case "ListInit":
return ConvertListInit(invocation);
case "MemberInit":
return ConvertMemberInit(invocation);
case "Modulo":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Rem);
case "Multiply":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Mul, false);
case "MultiplyChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Mul, true);
case "Negate":
return ConvertUnaryNumericOperator(invocation, BinaryNumericOperator.Sub, false);
case "NegateChecked":
return ConvertUnaryNumericOperator(invocation, BinaryNumericOperator.Sub, true);
case "New":
return ConvertNewObject(invocation);
case "NewArrayBounds":
return ConvertNewArrayBounds(invocation);
case "NewArrayInit":
return ConvertNewArrayInit(invocation);
case "Not":
return ConvertNotOperator(invocation);
case "NotEqual":
return ConvertComparison(invocation, ComparisonKind.Inequality);
case "OnesComplement":
return ConvertNotOperator(invocation);
case "Or":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.BitOr);
case "OrElse":
return ConvertLogicOperator(invocation, false);
case "Property":
return ConvertProperty(invocation);
case "Quote":
if (invocation.Arguments.Count == 1)
return ConvertInstruction(invocation.Arguments.Single());
else
return (null, SpecialType.UnknownType);
case "RightShift":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.ShiftRight);
case "Subtract":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Sub, false);
case "SubtractChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Sub, true);
case "TypeAs":
return ConvertTypeAs(invocation);
case "TypeIs":
return ConvertTypeIs(invocation);
}
return (null, SpecialType.UnknownType);
case ILFunction function:
if (function.IsExpressionTree) {
function.DelegateType = UnwrapExpressionTree(function.DelegateType);
}
return (function, function.DelegateType);
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (null, SpecialType.UnknownType);
case "RightShift":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.ShiftRight);
case "Subtract":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Sub, false);
case "SubtractChecked":
return ConvertBinaryNumericOperator(invocation, BinaryNumericOperator.Sub, true);
case "TypeAs":
return ConvertTypeAs(invocation);
case "TypeIs":
return ConvertTypeIs(invocation);
}
return (null, SpecialType.UnknownType);
default:
return ConvertValue(instruction, instruction.Parent);
return (new LdLoc(v), v.Type);
}
return (null, SpecialType.UnknownType);
default:
return (null, SpecialType.UnknownType);
}
}
}
IType UnwrapExpressionTree(IType delegateType)
{
if (delegateType is ParameterizedType pt && pt.FullName == "System.Linq.Expressions.Expression" && pt.TypeArguments.Count == 1) {
return pt.TypeArguments[0];
}
return delegateType;
}
(ILInstruction, IType) ConvertArrayIndex(CallInstruction invocation)
@ -534,11 +562,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -534,11 +562,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (value.MatchBox(out var arg, out var boxType)) {
if (boxType.Kind == TypeKind.Enum || boxType.IsKnownType(KnownTypeCode.Boolean))
return (new ExpressionTreeCast(boxType, ConvertValue(arg, invocation).Item1, false), boxType);
value = ConvertValue(arg, invocation).Item1;
return (new ExpressionTreeCast(boxType, ConvertValue(arg, invocation), false), boxType);
value = ConvertValue(arg, invocation);
return (value, type);
}
return ConvertValue(value, invocation);
return (ConvertValue(value, invocation), type);
}
(ILInstruction, IType) ConvertElementInit(CallInstruction invocation)
@ -727,7 +755,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -727,7 +755,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
indices[i] = index;
}
return (new NewArr(type, indices), type);
return (new NewArr(type, indices), new ArrayType(context.TypeSystem.Compilation, type, arguments.Count));
}
(ILInstruction, IType) ConvertNewArrayInit(CallInstruction invocation)
@ -764,10 +792,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -764,10 +792,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (invocation.Arguments.Count) {
case 1:
if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) {
var ctors = type.GetConstructors().ToArray();
if (ctors.Length != 1 || ctors[0].Parameters.Count > 0)
var ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault();
if (ctor == null)
return (null, SpecialType.UnknownType);
return (new NewObj(ctors[0]), type);
return (new NewObj(ctor), type);
}
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) {
return (new NewObj((IMethod)member), member.DeclaringType);
@ -917,27 +945,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -917,27 +945,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
}
(ILInstruction, IType) ConvertValue(ILInstruction value, ILInstruction context)
ILInstruction ConvertValue(ILInstruction value, ILInstruction context)
{
switch (value) {
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (null, SpecialType.UnknownType);
return null;
if (context is CallInstruction parentCall
&& parentCall.Method.FullName == "System.Linq.Expressions.Expression.Call"
&& v.StackType.IsIntegerType())
return (new LdLoca(v), new ByReferenceType(v.Type));
return (new LdLoc(v), v.Type);
return new LdLoca(v);
return null;
} else {
if (ldloc.Variable.Kind != VariableKind.StackSlot)
return (new LdLoc(ldloc.Variable), ldloc.Variable.Type);
return (null, SpecialType.UnknownType);
return new LdLoc(ldloc.Variable);
return null;
}
default:
if (SemanticHelper.IsPure(value.Flags))
return (value.Clone(), value.InferType());
return (value, value.InferType());
return value.Clone();
}
}

Loading…
Cancel
Save