Browse Source

Add DynamicInstruction

pull/1165/head
Siegfried Pammer 7 years ago
parent
commit
84f5e057d3
  1. 17
      ICSharpCode.Decompiler/DecompilerSettings.cs
  2. 1303
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 26
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 463
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  5. 0
      ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

17
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler
expressionTrees = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp4) {
// * dynamic (not supported yet)
dynamicExpressions = false;
// * named and optional arguments (not supported yet)
}
if (languageVersion < CSharp.LanguageVersion.CSharp5) {
@ -172,6 +172,21 @@ namespace ICSharpCode.Decompiler @@ -172,6 +172,21 @@ namespace ICSharpCode.Decompiler
}
}
bool dynamicExpressions = true;
/// <summary>
/// Decompile expressions that use dynamic types.
/// </summary>
public bool DynamicExpressions {
get { return dynamicExpressions; }
set {
if (dynamicExpressions != value) {
dynamicExpressions = value;
OnPropertyChanged();
}
}
}
bool fixedBuffers = true;
/// <summary>

1303
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

26
ICSharpCode.Decompiler/IL/Instructions.tt

@ -33,6 +33,8 @@ @@ -33,6 +33,8 @@
new OpCode("CallInstruction", "Instruction with a list of arguments.",
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
CustomWriteTo, MayThrow, SideEffect),
new OpCode("DynamicInstruction", "Instruction representing a dynamic call site.",
AbstractBaseClass, CustomWriteTo, MayThrow, SideEffect),
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" }
};
@ -260,6 +262,30 @@ @@ -260,6 +262,30 @@
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"),
MatchCondition("this.IsChecked == o.IsChecked")),
new OpCode("dynamic.binary.operator", "ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).",
CustomClassName("DynamicBinaryOperatorInstruction"), BaseClass("DynamicInstruction"), CustomArguments(("left", null), ("right", null)), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.unary.operator", "ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation).",
CustomClassName("DynamicUnaryOperatorInstruction"), BaseClass("DynamicInstruction"), CustomArguments(("operand", null)), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.convert", "ILAst representation of a cast inside a dynamic expression (maps to Binder.Convert).",
CustomClassName("DynamicConvertInstruction"), BaseClass("DynamicInstruction"), HasTypeOperand, MayThrow, CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.getmember", "ILAst representation of a property get method call inside a dynamic expression (maps to Binder.GetMember).",
CustomClassName("DynamicGetMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("target", new[] { "O" })), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.setmember", "ILAst representation of a property set method call inside a dynamic expression (maps to Binder.SetMember).",
CustomClassName("DynamicSetMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("target", new[] { "O" }), ("value", null)), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.getindex", "ILAst representation of an indexer get method call inside a dynamic expression (maps to Binder.GetIndex).",
CustomClassName("DynamicGetIndexInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.setindex", "ILAst representation of an indexer set method call inside a dynamic expression (maps to Binder.SetIndex).",
CustomClassName("DynamicSetIndexInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.invokemember", "ILAst representation of a method call inside a dynamic expression (maps to Binder.InvokeMember).",
CustomClassName("DynamicInvokeMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.invokeconstructor", "ILAst representation of a constuctor invocation inside a dynamic expression (maps to Binder.InvokeConstructor).",
CustomClassName("DynamicInvokeConstructorInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.invoke", "ILAst representation of a delegate invocation inside a dynamic expression (maps to Binder.Invoke).",
CustomClassName("DynamicInvokeInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.isevent", "ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression.",
CustomClassName("DynamicIsEventInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo),
new OpCode("mkrefany", "Push a typed reference of type class onto the stack.",
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")),
new OpCode("refanytype", "Push the type token stored in a typed reference.",

463
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -0,0 +1,463 @@ @@ -0,0 +1,463 @@
// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using ICSharpCode.Decompiler.IL.Patterns;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
[Flags]
public enum CSharpArgumentInfoFlags
{
None = 0,
UseCompileTimeType = 1,
Constant = 2,
NamedArgument = 4,
IsRef = 8,
IsOut = 0x10,
IsStaticType = 0x20
}
[Flags]
public enum CSharpBinderFlags
{
None = 0,
CheckedContext = 1,
InvokeSimpleName = 2,
InvokeSpecialName = 4,
BinaryOperationLogical = 8,
ConvertExplicit = 0x10,
ConvertArrayIndex = 0x20,
ResultIndexed = 0x40,
ValueFromCompoundAssignment = 0x80,
ResultDiscarded = 0x100
}
public struct CSharpArgumentInfo
{
public string Name { get; set; }
public CSharpArgumentInfoFlags Flags { get; set; }
}
partial class DynamicInstruction
{
public CSharpBinderFlags BinderFlags { get; }
public IType CallingContext { get; }
protected DynamicInstruction(OpCode opCode, CSharpBinderFlags binderFlags, IType context)
: base(opCode)
{
BinderFlags = binderFlags;
CallingContext = context;
}
protected void WriteBinderFlags(ITextOutput output, ILAstWritingOptions options)
{
if ((BinderFlags & CSharpBinderFlags.BinaryOperationLogical) != 0)
output.Write(".logic");
if ((BinderFlags & CSharpBinderFlags.CheckedContext) != 0)
output.Write(".checked");
if ((BinderFlags & CSharpBinderFlags.ConvertArrayIndex) != 0)
output.Write(".arrayindex");
if ((BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0)
output.Write(".explicit");
if ((BinderFlags & CSharpBinderFlags.InvokeSimpleName) != 0)
output.Write(".invokesimple");
if ((BinderFlags & CSharpBinderFlags.InvokeSpecialName) != 0)
output.Write(".invokespecial");
if ((BinderFlags & CSharpBinderFlags.ResultDiscarded) != 0)
output.Write(".discard");
if ((BinderFlags & CSharpBinderFlags.ResultIndexed) != 0)
output.Write(".resultindexed");
if ((BinderFlags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0)
output.Write(".compound");
}
}
partial class DynamicConvertInstruction
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
type.WriteTo(output);
output.Write('(');
argument.WriteTo(output, options);
output.Write(')');
}
public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType context, ILInstruction argument)
: base(OpCode.DynamicConvertInstruction, binderFlags, context)
{
Type = type;
Argument = argument;
}
protected internal override bool PerformMatch(ref ListMatch listMatch, ref Match match)
{
return base.PerformMatch(ref listMatch, ref match);
}
public override StackType ResultType => type.GetStackType();
public bool IsChecked => (BinderFlags & CSharpBinderFlags.CheckedContext) != 0;
}
partial class DynamicInvokeMemberInstruction
{
public string Name { get; }
public IReadOnlyList<IType> TypeArguments { get; }
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeMemberInstruction(CSharpBinderFlags binderFlags, string name, IType[] typeArguments, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeMemberInstruction, binderFlags, context)
{
Name = name;
TypeArguments = typeArguments ?? Empty<IType>.Array;
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
if (TypeArguments.Count > 0) {
output.Write('<');
int i = 0;
foreach (var typeArg in TypeArguments) {
if (i > 0)
output.Write(", ");
typeArg.WriteTo(output);
i++;
}
output.Write('>');
}
output.Write('(');
int j = 0;
foreach (var arg in Arguments) {
if (j > 0)
output.Write(", ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicGetMemberInstruction
{
public string Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public DynamicGetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target)
: base(OpCode.DynamicGetMemberInstruction, binderFlags, context)
{
Name = name;
TargetArgumentInfo = targetArgumentInfo;
Target = target;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
output.Write('(');
Target.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicSetMemberInstruction
{
public string Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public CSharpArgumentInfo ValueArgumentInfo { get; }
public DynamicSetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target, CSharpArgumentInfo valueArgumentInfo, ILInstruction value)
: base(OpCode.DynamicSetMemberInstruction, binderFlags, context)
{
Name = name;
TargetArgumentInfo = targetArgumentInfo;
Target = target;
ValueArgumentInfo = valueArgumentInfo;
Value = value;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
output.Write('(');
Target.WriteTo(output, options);
output.Write(", ");
Value.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicGetIndexInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicGetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicGetIndexInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("get_Item");
output.Write('(');
int j = 0;
foreach (var arg in Arguments) {
if (j > 0)
output.Write(", ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicSetIndexInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicSetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicSetIndexInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("set_Item");
output.Write('(');
int j = 0;
foreach (var arg in Arguments) {
if (j > 0)
output.Write(", ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicInvokeConstructorInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeConstructorInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeConstructorInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(".ctor");
output.Write('(');
int j = 0;
foreach (var arg in Arguments) {
if (j > 0)
output.Write(", ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicBinaryOperatorInstruction
{
public CSharpArgumentInfo LeftArgumentInfo { get; }
public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicBinaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicBinaryOperatorInstruction, binderFlags, context)
{
Operation = operation;
LeftArgumentInfo = leftArgumentInfo;
Left = left;
RightArgumentInfo = rightArgumentInfo;
Right = right;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
output.Write('(');
Left.WriteTo(output, options);
output.Write(", ");
Right.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicUnaryOperatorInstruction
{
public CSharpArgumentInfo OperandArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicUnaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo operandArgumentInfo, ILInstruction operand)
: base(OpCode.DynamicUnaryOperatorInstruction, binderFlags, context)
{
Operation = operation;
OperandArgumentInfo = operandArgumentInfo;
Operand = operand;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
output.Write('(');
Operand.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType {
get {
switch (Operation) {
case ExpressionType.IsFalse:
case ExpressionType.IsTrue:
return StackType.I4; // bool
default:
return SpecialType.Dynamic.GetStackType();
}
}
}
}
partial class DynamicInvokeInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write('(');
int j = 0;
foreach (var arg in Arguments) {
if (j > 0)
output.Write(", ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
}
partial class DynamicIsEventInstruction
{
public string Name { get; }
public DynamicIsEventInstruction(CSharpBinderFlags binderFlags, string name, IType context, ILInstruction argument)
: base(OpCode.DynamicIsEventInstruction, binderFlags, context)
{
Name = name;
Argument = argument;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => StackType.I4;
}
}

0
ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs → ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

Loading…
Cancel
Save