.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

578 lines
18 KiB

// 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 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; }
public IType CompileTimeType { get; set; }
public bool HasFlag(CSharpArgumentInfoFlags flag) => (Flags & flag) != 0;
}
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)
{
WriteBinderFlags(BinderFlags, output, options);
}
internal static void WriteBinderFlags(CSharpBinderFlags flags, ITextOutput output, ILAstWritingOptions options)
{
if ((flags & CSharpBinderFlags.BinaryOperationLogical) != 0)
output.Write(".logic");
if ((flags & CSharpBinderFlags.CheckedContext) != 0)
output.Write(".checked");
if ((flags & CSharpBinderFlags.ConvertArrayIndex) != 0)
output.Write(".arrayindex");
if ((flags & CSharpBinderFlags.ConvertExplicit) != 0)
output.Write(".explicit");
if ((flags & CSharpBinderFlags.InvokeSimpleName) != 0)
output.Write(".invokesimple");
if ((flags & CSharpBinderFlags.InvokeSpecialName) != 0)
output.Write(".invokespecial");
if ((flags & CSharpBinderFlags.ResultDiscarded) != 0)
output.Write(".discard");
if ((flags & CSharpBinderFlags.ResultIndexed) != 0)
output.Write(".resultindexed");
if ((flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0)
output.Write(".compound");
}
public abstract CSharpArgumentInfo GetArgumentInfoOfChild(int index);
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, params (ILInstruction, CSharpArgumentInfo)[] arguments)
{
WriteArgumentList(output, options, (IEnumerable<(ILInstruction, CSharpArgumentInfo)>)arguments);
}
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, IEnumerable<(ILInstruction, CSharpArgumentInfo)> arguments)
{
output.Write('(');
int j = 0;
foreach (var (arg, info) in arguments) {
if (j > 0)
output.Write(", ");
output.Write("[flags: ");
output.Write(info.Flags.ToString());
output.Write(", name: " + info.Name + "] ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
}
partial class DynamicConvertInstruction
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(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;
public bool IsExplicit => (BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
return default(CSharpArgumentInfo);
}
}
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)
{
WriteILRange(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('>');
}
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
WriteArgumentList(output, options, (Target, TargetArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index != 0)
throw new ArgumentOutOfRangeException(nameof(index));
return TargetArgumentInfo;
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
WriteArgumentList(output, options, (Target, TargetArgumentInfo), (Value, ValueArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return TargetArgumentInfo;
case 1:
return ValueArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("get_Item");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("set_Item");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(".ctor");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Left, LeftArgumentInfo), (Right, RightArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return LeftArgumentInfo;
case 1:
return RightArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
partial class DynamicLogicOperatorInstruction
{
public CSharpArgumentInfo LeftArgumentInfo { get; }
public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicLogicOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicLogicOperatorInstruction, binderFlags, context)
{
Operation = operation;
LeftArgumentInfo = leftArgumentInfo;
Left = left;
RightArgumentInfo = rightArgumentInfo;
Right = right;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Left, LeftArgumentInfo), (Right, RightArgumentInfo));
}
public override StackType ResultType => StackType.O;
protected override InstructionFlags ComputeFlags()
{
return DirectFlags | Left.Flags
| SemanticHelper.CombineBranches(Right.Flags, InstructionFlags.None);
}
public override InstructionFlags DirectFlags => InstructionFlags.MayThrow | InstructionFlags.SideEffect | InstructionFlags.ControlFlow;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return LeftArgumentInfo;
case 1:
return RightArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Operand, OperandArgumentInfo));
}
public override StackType ResultType {
get {
switch (Operation) {
case ExpressionType.IsFalse:
case ExpressionType.IsTrue:
return StackType.I4; // bool
default:
return StackType.O;
}
}
}
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return OperandArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
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)
{
WriteILRange(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => StackType.I4;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
return default(CSharpArgumentInfo);
}
}
}