mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
Merge pull request #4090 from icsharpcode/infer-type
Extend InferType() to every ILInstruction
This commit is contained in:
@@ -6,12 +6,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
|
||||
{
|
||||
public unsafe static int Seq(int a, int b, int c)
|
||||
{
|
||||
byte* num = stackalloc byte[12];
|
||||
*(int*)num = a;
|
||||
*(int*)num = 99;
|
||||
((int*)num)[1] = b;
|
||||
((int*)num)[2] = c;
|
||||
Span<int> span = new Span<int>(num, 3);
|
||||
byte* ptr = stackalloc byte[12];
|
||||
*(int*)ptr = a;
|
||||
*(int*)ptr = 99;
|
||||
((int*)ptr)[1] = b;
|
||||
((int*)ptr)[2] = c;
|
||||
Span<int> span = new Span<int>(ptr, 3);
|
||||
return span[0] + span[1] + span[2];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,21 +274,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
// rather than be reconstructed as 'stackalloc int[4] { 1, v, 3 }' (too few elements).
|
||||
public unsafe string PartialReinterpret(int v)
|
||||
{
|
||||
#if OPT
|
||||
byte* num = stackalloc byte[16];
|
||||
*(int*)num = 1;
|
||||
((int*)num)[1] = v;
|
||||
((int*)num)[2] = 3;
|
||||
long num2 = 0L;
|
||||
return UseBytePointer(num, &num2);
|
||||
#else
|
||||
byte* ptr = stackalloc byte[16];
|
||||
*(int*)ptr = 1;
|
||||
((int*)ptr)[1] = v;
|
||||
((int*)ptr)[2] = 3;
|
||||
long num = 0L;
|
||||
return UseBytePointer(ptr, &num);
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe static string UseBytePointer(byte* ptr, long* length)
|
||||
@@ -298,15 +289,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public unsafe string NegativeOffsets(int a, int b, int c)
|
||||
{
|
||||
#if OPT
|
||||
byte* num = stackalloc byte[12];
|
||||
*(int*)num = 1;
|
||||
*((int*)num - 1) = 2;
|
||||
*((int*)num - 2) = 3;
|
||||
int* ptr = (int*)num;
|
||||
Console.WriteLine(*ptr);
|
||||
return UsePointer((byte*)ptr);
|
||||
#else
|
||||
byte* ptr = stackalloc byte[12];
|
||||
*(int*)ptr = 1;
|
||||
*((int*)ptr - 1) = 2;
|
||||
@@ -314,7 +296,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
int* ptr2 = (int*)ptr;
|
||||
Console.WriteLine(*ptr2);
|
||||
return UsePointer((byte*)ptr2);
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe string UsePointer(byte* ptr)
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool GetBool()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Done()
|
||||
{
|
||||
}
|
||||
@@ -69,6 +74,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool GetBool()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Done()
|
||||
{
|
||||
}
|
||||
@@ -169,6 +179,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
GetMyClass()?[GetInt()].Done();
|
||||
}
|
||||
|
||||
public void CallGetBool()
|
||||
{
|
||||
GetMyClass()?.GetBool();
|
||||
GetMyClass()?.Field?.GetBool();
|
||||
GetMyClass()?.Field.GetBool();
|
||||
GetMyClass()?.Property?.GetBool();
|
||||
GetMyClass()?.Property.GetBool();
|
||||
GetMyClass()?.Method(GetInt())?.GetBool();
|
||||
GetMyClass()?.Method(GetInt()).GetBool();
|
||||
GetMyClass()?[GetInt()]?.GetBool();
|
||||
GetMyClass()?[GetInt()].GetBool();
|
||||
}
|
||||
|
||||
public void CallDoneStruct()
|
||||
{
|
||||
GetMyStruct()?.Done();
|
||||
@@ -181,6 +204,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
GetMyStruct()?[GetInt()]?.Done();
|
||||
}
|
||||
|
||||
public void CallGetBoolStruct()
|
||||
{
|
||||
GetMyStruct()?.GetBool();
|
||||
GetMyStruct()?.Field?.GetBool();
|
||||
GetMyStruct()?.Field.GetBool();
|
||||
GetMyStruct()?.Property1?.GetBool();
|
||||
GetMyStruct()?.Property2.GetBool();
|
||||
GetMyStruct()?.Method1(GetInt())?.GetBool();
|
||||
GetMyStruct()?.Method2(GetInt()).GetBool();
|
||||
GetMyStruct()?[GetInt()]?.GetBool();
|
||||
}
|
||||
|
||||
public void RequiredParentheses()
|
||||
{
|
||||
(GetMyClass()?.Field).Done();
|
||||
|
||||
@@ -803,7 +803,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
.WithRR(new TypeOfResolveResult(compilation.FindType(KnownTypeCode.Type), inst.Type));
|
||||
return new MemberReferenceExpression(typeofExpr, "TypeHandle")
|
||||
.WithILInstruction(inst)
|
||||
.WithRR(new TypeOfResolveResult(compilation.FindType(new TopLevelTypeName("System", "RuntimeTypeHandle")), inst.Type));
|
||||
.WithRR(new TypeOfResolveResult(compilation.FindType(KnownTypeCode.RuntimeTypeHandle), inst.Type));
|
||||
}
|
||||
|
||||
protected internal override TranslatedExpression VisitBitNot(BitNot inst, TranslationContext context)
|
||||
@@ -3554,7 +3554,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
{
|
||||
return new UndocumentedExpression { UndocumentedExpressionType = UndocumentedExpressionType.ArgListAccess }
|
||||
.WithILInstruction(inst)
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(new TopLevelTypeName("System", "RuntimeArgumentHandle"))));
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(KnownTypeCode.RuntimeArgumentHandle)));
|
||||
}
|
||||
|
||||
protected internal override TranslatedExpression VisitMakeRefAny(MakeRefAny inst, TranslationContext context)
|
||||
@@ -3569,7 +3569,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
Arguments = { arg.Detach() }
|
||||
}
|
||||
.WithILInstruction(inst)
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(new TopLevelTypeName("System", "TypedReference"))));
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(KnownTypeCode.TypedReference)));
|
||||
}
|
||||
|
||||
protected internal override TranslatedExpression VisitRefAnyType(RefAnyType inst, TranslationContext context)
|
||||
@@ -3579,7 +3579,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
Arguments = { Translate(inst.Argument).Expression.Detach() }
|
||||
}, "TypeHandle")
|
||||
.WithILInstruction(inst)
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(new TopLevelTypeName("System", "RuntimeTypeHandle"))));
|
||||
.WithRR(new TypeResolveResult(compilation.FindType(KnownTypeCode.RuntimeTypeHandle)));
|
||||
}
|
||||
|
||||
protected internal override TranslatedExpression VisitRefAnyValue(RefAnyValue inst, TranslationContext context)
|
||||
|
||||
@@ -177,4 +177,12 @@
|
||||
<Compile Remove="Properties\DecompilerVersionInfo.template.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="IL\Instructions.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Instructions.tt</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
ILInstruction filter;
|
||||
if (eh.Kind == System.Reflection.Metadata.ExceptionRegionKind.Filter)
|
||||
{
|
||||
var filterBlock = new BlockContainer(expectedResultType: StackType.I4);
|
||||
var filterBlock = new BlockContainer(expectedResultType: compilation.FindType(KnownTypeCode.Int32));
|
||||
filterBlock.AddILRange(new Interval(eh.FilterOffset, eh.HandlerOffset));
|
||||
handlerContainers.Add(filterBlock.StartILOffset, filterBlock);
|
||||
filter = filterBlock;
|
||||
@@ -191,7 +191,9 @@ namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
// assign the finally/filter container
|
||||
leave.TargetContainer = containerStack.Peek();
|
||||
leave.Value = ILReader.Cast(leave.Value, leave.TargetContainer.ExpectedResultType, null, leave.StartILOffset);
|
||||
leave.Value = ILReader.Cast(leave.Value,
|
||||
leave.TargetContainer.ResultType,
|
||||
null, leave.StartILOffset);
|
||||
}
|
||||
break;
|
||||
case BlockContainer container:
|
||||
|
||||
@@ -158,11 +158,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
FinalizeInlineMoveNext(function);
|
||||
if (methodType == AsyncMethodType.AsyncEnumerable || methodType == AsyncMethodType.AsyncEnumerator)
|
||||
{
|
||||
((BlockContainer)function.Body).ExpectedResultType = StackType.Void;
|
||||
((BlockContainer)function.Body).ExpectedResultType = context.TypeSystem.FindType(KnownTypeCode.Void);
|
||||
}
|
||||
else
|
||||
{
|
||||
((BlockContainer)function.Body).ExpectedResultType = underlyingReturnType.GetStackType();
|
||||
((BlockContainer)function.Body).ExpectedResultType = underlyingReturnType;
|
||||
}
|
||||
|
||||
// Re-run control flow simplification over the newly constructed set of gotos,
|
||||
|
||||
@@ -440,7 +440,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
&& trueBlock.Instructions[0].MatchIfInstruction(out var nestedCondition, out var nestedTrueInst))
|
||||
{
|
||||
context.Step("Combine 'if (cond1 && cond2)' in then-branch", ifInst);
|
||||
ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, nestedCondition);
|
||||
ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, nestedCondition, context.TypeSystem);
|
||||
ifInst.TrueInst = nestedTrueInst;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,10 +162,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
for (int i = 0; i < container.Blocks.Count; i++)
|
||||
{
|
||||
var block = container.Blocks[i];
|
||||
if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock))
|
||||
if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock)
|
||||
&& v.Type is ArrayType arrayType)
|
||||
{
|
||||
context.Step("NullSafeArrayToPointerPattern", block);
|
||||
ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), null);
|
||||
ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), arrayType.ElementType, null);
|
||||
if (p.StackType != StackType.Ref)
|
||||
{
|
||||
arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None);
|
||||
@@ -180,16 +181,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
{
|
||||
context.Step("CustomRefPinPattern", block);
|
||||
ILInstruction gpr;
|
||||
if (context.Settings.PatternBasedFixedStatement)
|
||||
if (context.Settings.PatternBasedFixedStatement
|
||||
&& callGPR.Method.ReturnType is ByReferenceType brt)
|
||||
{
|
||||
gpr = new GetPinnableReference(ldlocMem, callGPR.Method);
|
||||
gpr = new GetPinnableReference(ldlocMem, brt.ElementType, callGPR.Method);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr = new IfInstruction(
|
||||
condition: new Comp(ComparisonKind.Inequality, Sign.None, ldlocMem, new LdNull()),
|
||||
trueInst: callGPR,
|
||||
falseInst: new Conv(new LdcI4(0), PrimitiveType.Ref, checkForOverflow: false, inputSign: Sign.None)
|
||||
falseInst: new Conv(new LdcI4(0), PrimitiveType.Ref, checkForOverflow: false, inputSign: Sign.None),
|
||||
resultType: callGPR.Method.ReturnType
|
||||
);
|
||||
}
|
||||
block.Instructions[block.Instructions.Count - 2] = new StLoc(v, gpr)
|
||||
@@ -818,7 +821,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
newVar.HasGeneratedName = oldVar.HasGeneratedName;
|
||||
oldVar.Function.Variables.Add(newVar);
|
||||
pinnedRegion.Variable = newVar;
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, arrayToPointer.Method).WithILRange(arrayToPointer);
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, arrayToPointer.Type, arrayToPointer.Method).WithILRange(arrayToPointer);
|
||||
conv.ReplaceWith(new LdLoc(newVar).WithILRange(conv));
|
||||
}
|
||||
|
||||
@@ -895,7 +898,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
newVar.HasGeneratedName = pinnedRegion.Variable.HasGeneratedName;
|
||||
pinnedRegion.Variable.Function.Variables.Add(newVar);
|
||||
pinnedRegion.Variable = newVar;
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, context.TypeSystem.FindType(KnownTypeCode.Char), null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -948,7 +951,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
|
||||
body.Blocks.RemoveRange(1, body.Blocks.Count - 1);
|
||||
body.Blocks[0].Instructions.Add(new Branch(targetBlock));
|
||||
}
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
|
||||
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, context.TypeSystem.FindType(KnownTypeCode.Char), null);
|
||||
|
||||
ILVariable otherVar;
|
||||
ILInstruction otherVarInit;
|
||||
|
||||
@@ -190,14 +190,16 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.reader = body.GetILReader();
|
||||
this.currentStack = ImmutableStack<ILVariable>.Empty;
|
||||
this.expressionStack.Clear();
|
||||
IType methodReturnType;
|
||||
if (isRuntimeAsync)
|
||||
{
|
||||
this.methodReturnStackType = TaskType.UnpackAnyTask(compilation, method.ReturnType).GetStackType();
|
||||
methodReturnType = TaskType.UnpackAnyTask(compilation, method.ReturnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.methodReturnStackType = method.ReturnType.GetStackType();
|
||||
methodReturnType = method.ReturnType;
|
||||
}
|
||||
this.methodReturnStackType = methodReturnType.GetStackType();
|
||||
InitParameterVariables();
|
||||
localVariables = InitLocalVariables();
|
||||
foreach (var v in localVariables)
|
||||
@@ -205,7 +207,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
v.InitialValueIsInitialized = body.LocalVariablesInitialized;
|
||||
v.UsesInitialValue = true;
|
||||
}
|
||||
this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType);
|
||||
this.mainContainer = new BlockContainer(expectedResultType: methodReturnType);
|
||||
this.blocksByOffset.Clear();
|
||||
this.importQueue.Clear();
|
||||
this.isBranchTarget = new BitSet(reader.Length);
|
||||
@@ -2128,10 +2130,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
// (note: if the variable is merged across control-flow branches,
|
||||
// we'll reset the type to be based on the StackType)
|
||||
IType type = inst.InferType(compilation);
|
||||
if (type.GetStackType() != inst.ResultType)
|
||||
{
|
||||
type = compilation.FindType(inst.ResultType);
|
||||
}
|
||||
Debug.Assert(type.GetStackType() == inst.ResultType);
|
||||
var v = new ILVariable(VariableKind.StackSlot, type, inst.ResultType);
|
||||
v.HasGeneratedName = true;
|
||||
currentStack = currentStack.Push(v);
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
/// <summary>
|
||||
/// Infers the C# type an instruction expects of the child in <paramref name="childIndex"/>,
|
||||
/// i.e. the counterpart to <see cref="InferType"/>: that one asks what a value is, this one
|
||||
/// i.e. the counterpart to <see cref="ILInstruction.InferType"/>: that one asks what a value is, this one
|
||||
/// asks what the position it flows into says it should be.
|
||||
///
|
||||
/// Returns SpecialType.UnknownType where the position names nothing.
|
||||
@@ -202,130 +202,5 @@ namespace ICSharpCode.Decompiler.IL
|
||||
return SpecialType.UnknownType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Infers the C# type for an IL instruction.
|
||||
///
|
||||
/// Returns SpecialType.UnknownType for unsupported instructions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For instructions with StackType.O that produce a value type, or
|
||||
/// instructions with StackType.Ref, we should aim to return the actual type
|
||||
/// instead of SpecialType.UnknownType.
|
||||
///
|
||||
/// If not returning UnknownType, must return a type that can store
|
||||
/// the result of the instruction without loss of information.
|
||||
/// </remarks>
|
||||
public static IType InferType(this ILInstruction inst, ICompilation compilation)
|
||||
{
|
||||
Debug.Assert(compilation != null);
|
||||
switch (inst)
|
||||
{
|
||||
case NewObj newObj:
|
||||
return newObj.Method.DeclaringType ?? SpecialType.UnknownType;
|
||||
case NewArr newArr:
|
||||
return new ArrayType(compilation, newArr.Type, newArr.Indices.Count);
|
||||
case Call call:
|
||||
return call.Method.ReturnType;
|
||||
case CallVirt callVirt:
|
||||
return callVirt.Method.ReturnType;
|
||||
case CallIndirect calli:
|
||||
return calli.FunctionPointerType.ReturnType;
|
||||
case UserDefinedLogicOperator logicOp:
|
||||
return logicOp.Method.ReturnType;
|
||||
case LdObj ldobj:
|
||||
return ldobj.Type;
|
||||
case StObj stobj:
|
||||
return stobj.Type;
|
||||
case LdLoc ldloc:
|
||||
return ldloc.Variable.Type;
|
||||
case StLoc stloc:
|
||||
return stloc.Variable.Type;
|
||||
case LdLoca ldloca:
|
||||
return new ByReferenceType(ldloca.Variable.Type);
|
||||
case LdFlda ldflda:
|
||||
return new ByReferenceType(ldflda.Field.Type);
|
||||
case LdsFlda ldsflda:
|
||||
return new ByReferenceType(ldsflda.Field.Type);
|
||||
case LdElema ldelema:
|
||||
if (ldelema.Array.InferType(compilation) is ArrayType arrayType)
|
||||
{
|
||||
if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type))
|
||||
{
|
||||
return new ByReferenceType(arrayType.ElementType);
|
||||
}
|
||||
}
|
||||
return new ByReferenceType(ldelema.Type);
|
||||
case Comp comp:
|
||||
switch (comp.LiftingKind)
|
||||
{
|
||||
case ComparisonLiftingKind.None:
|
||||
case ComparisonLiftingKind.CSharp:
|
||||
return compilation.FindType(KnownTypeCode.Boolean);
|
||||
case ComparisonLiftingKind.ThreeValuedLogic:
|
||||
return NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean));
|
||||
default:
|
||||
return SpecialType.UnknownType;
|
||||
}
|
||||
case BinaryNumericInstruction bni:
|
||||
if (bni.IsLifted)
|
||||
return SpecialType.UnknownType;
|
||||
switch (bni.Operator)
|
||||
{
|
||||
case BinaryNumericOperator.BitAnd:
|
||||
case BinaryNumericOperator.BitOr:
|
||||
case BinaryNumericOperator.BitXor:
|
||||
var left = bni.Left.InferType(compilation);
|
||||
var right = bni.Right.InferType(compilation);
|
||||
if (left.Equals(right) && (left.IsCSharpPrimitiveIntegerType() || left.IsCSharpNativeIntegerType() || left.IsKnownType(KnownTypeCode.Boolean)))
|
||||
return left;
|
||||
else
|
||||
return SpecialType.UnknownType;
|
||||
default:
|
||||
return SpecialType.UnknownType;
|
||||
}
|
||||
case LdLen ldLen:
|
||||
if (compilation == null)
|
||||
return SpecialType.UnknownType;
|
||||
// Mirrors ExpressionBuilder.VisitLdLen, which picks Array.Length or
|
||||
// Array.LongLength based on the result type alone.
|
||||
return compilation.FindType(ldLen.ResultType == StackType.I4 ? KnownTypeCode.Int32 : KnownTypeCode.Int64);
|
||||
case DefaultValue defaultValue:
|
||||
return defaultValue.Type;
|
||||
case ILFunction func when func.DelegateType != null:
|
||||
return func.DelegateType;
|
||||
case IfInstruction ifInst:
|
||||
// For structs and byrefs, we don't want to return Unknown as a fallback to
|
||||
// to FindType(StackType) wouldn't work. Valid IL should have the same
|
||||
// type on both branches so we just return the first that works.
|
||||
var thenType = ifInst.TrueInst.InferType(compilation);
|
||||
if (thenType.CannotBeReconstructedFromStackType())
|
||||
{
|
||||
return thenType;
|
||||
}
|
||||
var elseType = ifInst.FalseInst.InferType(compilation);
|
||||
if (elseType.CannotBeReconstructedFromStackType())
|
||||
{
|
||||
return elseType;
|
||||
}
|
||||
if (thenType.Equals(elseType))
|
||||
{
|
||||
return thenType;
|
||||
}
|
||||
return SpecialType.UnknownType;
|
||||
case SwitchInstruction switchInst:
|
||||
foreach (var section in switchInst.Sections)
|
||||
{
|
||||
var bodyType = section.Body.InferType(compilation);
|
||||
if (bodyType.CannotBeReconstructedFromStackType())
|
||||
{
|
||||
return bodyType;
|
||||
}
|
||||
}
|
||||
return SpecialType.UnknownType;
|
||||
default:
|
||||
return SpecialType.UnknownType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +540,8 @@ namespace ICSharpCode.Decompiler.IL.Patterns
|
||||
protected PatternInstruction(OpCode opCode) : base(opCode)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Unknown; } }
|
||||
public override StackType ResultType => (SpecialType.UnknownType).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.UnknownType;
|
||||
}
|
||||
}
|
||||
namespace ICSharpCode.Decompiler.IL
|
||||
@@ -738,7 +739,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public Nop() : base(OpCode.Nop)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitNop(this);
|
||||
@@ -819,7 +821,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.CloneVariables();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return DelegateType?.GetStackType() ?? StackType.O; } }
|
||||
public override StackType ResultType => (DelegateType ?? SpecialType.UnknownType).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => DelegateType ?? SpecialType.UnknownType;
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitILFunction(this);
|
||||
@@ -844,7 +847,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// <summary>A container of IL blocks.</summary>
|
||||
public sealed partial class BlockContainer : ILInstruction
|
||||
{
|
||||
public override StackType ResultType { get { return this.ExpectedResultType; } }
|
||||
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitBlockContainer(this);
|
||||
@@ -900,7 +903,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Init = init;
|
||||
this.Body = body;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
ILVariable variable;
|
||||
public ILVariable Variable {
|
||||
get { return variable; }
|
||||
@@ -1083,7 +1087,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitNumericCompoundAssign(this);
|
||||
@@ -1142,7 +1147,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// <summary>Common instruction for dynamic compound assignments.</summary>
|
||||
public sealed partial class DynamicCompoundAssign : CompoundAssignmentInstruction
|
||||
{
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
|
||||
@@ -1204,7 +1210,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public Arglist() : base(OpCode.Arglist)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.RuntimeArgumentHandle);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitArglist(this);
|
||||
@@ -1229,7 +1236,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// <summary>Unconditional branch. <c>goto target;</c></summary>
|
||||
public sealed partial class Branch : SimpleInstruction
|
||||
{
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
|
||||
@@ -1313,7 +1321,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Value = this.value.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitLeave(this);
|
||||
@@ -1612,7 +1621,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Body = this.body.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitSwitchSection(this);
|
||||
@@ -1767,6 +1777,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
base.Disconnected();
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitTryCatchHandler(this);
|
||||
@@ -1913,7 +1925,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Body = this.body.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return onExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
|
||||
@@ -2057,7 +2070,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Body = this.body.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayWriteLocals | resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
|
||||
@@ -2101,7 +2115,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public DebugBreak() : base(OpCode.DebugBreak)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.SideEffect;
|
||||
@@ -2234,7 +2249,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public Ckfinite(ILInstruction argument) : base(OpCode.Ckfinite, argument)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -2329,7 +2345,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
base.Disconnected();
|
||||
}
|
||||
|
||||
public override StackType ResultType { get { return variable.StackType; } }
|
||||
public override StackType ResultType => variable.StackType;
|
||||
public override IType InferType(ICompilation compilation) => variable.Type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayReadLocals;
|
||||
@@ -2380,7 +2397,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
this.variable = variable ?? throw new ArgumentNullException(nameof(variable));
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(variable.Type);
|
||||
ILVariable variable;
|
||||
public ILVariable Variable {
|
||||
get { return variable; }
|
||||
@@ -2538,7 +2556,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Value = this.value.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return variable.StackType; } }
|
||||
public override StackType ResultType => variable.StackType;
|
||||
public override IType InferType(ICompilation compilation) => variable.Type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayWriteLocals | value.Flags;
|
||||
@@ -2637,7 +2656,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Value = this.value.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(type);
|
||||
IType type;
|
||||
/// <summary>Returns the type operand.</summary>
|
||||
public IType Type {
|
||||
@@ -2690,7 +2710,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public ThreeValuedBoolAnd(ILInstruction left, ILInstruction right) : base(OpCode.ThreeValuedBoolAnd, left, right)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitThreeValuedBoolAnd(this);
|
||||
@@ -2718,7 +2738,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public ThreeValuedBoolOr(ILInstruction left, ILInstruction right) : base(OpCode.ThreeValuedBoolOr, left, right)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitThreeValuedBoolOr(this);
|
||||
@@ -2784,10 +2804,26 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
|
||||
public sealed partial class NullableRewrap : UnaryInstruction
|
||||
{
|
||||
public NullableRewrap(ILInstruction argument) : base(OpCode.NullableRewrap, argument)
|
||||
public NullableRewrap(ILInstruction argument, IType type) : base(OpCode.NullableRewrap, argument)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
IType type;
|
||||
/// <summary>Returns the type operand.</summary>
|
||||
public IType Type {
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
output.Write(OpCode);
|
||||
output.Write(' ');
|
||||
type.WriteTo(output);
|
||||
output.Write('(');
|
||||
Argument.WriteTo(output, options);
|
||||
output.Write(')');
|
||||
}
|
||||
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitNullableRewrap(this);
|
||||
@@ -2803,7 +2839,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
protected internal override bool PerformMatch(ILInstruction? other, ref Patterns.Match match)
|
||||
{
|
||||
var o = other as NullableRewrap;
|
||||
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
|
||||
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2817,7 +2853,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly string Value;
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.String);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -2854,7 +2891,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly string Value;
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => new ParameterizedType(compilation.FindType(KnownTypeCode.ReadOnlySpanOfT), compilation.FindType(KnownTypeCode.Boolean));
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -2891,7 +2929,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly int Value;
|
||||
public override StackType ResultType { get { return StackType.I4; } }
|
||||
public override StackType ResultType => StackType.I4;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Int32);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -2928,7 +2967,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly long Value;
|
||||
public override StackType ResultType { get { return StackType.I8; } }
|
||||
public override StackType ResultType => StackType.I8;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Int64);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -2965,7 +3005,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly float Value;
|
||||
public override StackType ResultType { get { return StackType.F4; } }
|
||||
public override StackType ResultType => StackType.F4;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Single);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3002,7 +3043,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly double Value;
|
||||
public override StackType ResultType { get { return StackType.F8; } }
|
||||
public override StackType ResultType => StackType.F8;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Double);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3039,7 +3081,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.Value = value;
|
||||
}
|
||||
public readonly decimal Value;
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Decimal);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3074,7 +3117,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public LdNull() : base(OpCode.LdNull)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Object);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitLdNull(this);
|
||||
@@ -3106,7 +3150,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IMethod method;
|
||||
/// <summary>Returns the method operand.</summary>
|
||||
public IMethod Method => method;
|
||||
public override StackType ResultType { get { return StackType.I; } }
|
||||
public override StackType ResultType => StackType.I;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.IntPtr);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3148,7 +3193,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IMethod method;
|
||||
/// <summary>Returns the method operand.</summary>
|
||||
public IMethod Method => method;
|
||||
public override StackType ResultType { get { return StackType.I; } }
|
||||
public override StackType ResultType => StackType.I;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.IntPtr);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -3209,7 +3255,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IMethod method;
|
||||
/// <summary>Returns the method operand.</summary>
|
||||
public IMethod Method => method;
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -3268,7 +3315,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.RuntimeTypeHandle);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3307,7 +3355,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IMember member;
|
||||
/// <summary>Returns the token operand.</summary>
|
||||
public IMember Member { get { return member; } }
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(member is IField ? KnownTypeCode.RuntimeFieldHandle : KnownTypeCode.RuntimeMethodHandle);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -3342,7 +3391,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public LocAlloc(ILInstruction argument) : base(OpCode.LocAlloc, argument)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.I; } }
|
||||
public override StackType ResultType => StackType.I;
|
||||
public override IType InferType(ICompilation compilation) => new PointerType(compilation.FindType(KnownTypeCode.Void));
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -3386,7 +3436,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -3524,7 +3575,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public bool IsVolatile { get; set; }
|
||||
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
|
||||
public byte UnalignedPrefix { get; set; }
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return destAddress.Flags | sourceAddress.Flags | size.Flags | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
|
||||
@@ -3675,7 +3727,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public bool IsVolatile { get; set; }
|
||||
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
|
||||
public byte UnalignedPrefix { get; set; }
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return address.Flags | value.Flags | size.Flags | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
|
||||
@@ -3791,7 +3844,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IField @field;
|
||||
/// <summary>Returns the field operand.</summary>
|
||||
public IField Field { get { return @field; } }
|
||||
public override StackType ResultType { get { return target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref; } }
|
||||
public override StackType ResultType => target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => target.ResultType.IsIntegerType() ? new PointerType(field.Type) : new ByReferenceType(field.Type);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return target.Flags | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);
|
||||
@@ -3841,7 +3895,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
this.@field = @field;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(field.Type);
|
||||
readonly IField @field;
|
||||
/// <summary>Returns the field operand.</summary>
|
||||
public IField Field { get { return @field; } }
|
||||
@@ -3886,7 +3941,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -3940,7 +3996,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Object);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -4040,7 +4097,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public bool IsVolatile { get; set; }
|
||||
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
|
||||
public byte UnalignedPrefix { get; set; }
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return target.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
|
||||
@@ -4154,7 +4212,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(this.type);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return target.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
|
||||
@@ -4287,7 +4346,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public bool IsVolatile { get; set; }
|
||||
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
|
||||
public byte UnalignedPrefix { get; set; }
|
||||
public override StackType ResultType { get { return UnalignedPrefix == 0 ? type.GetStackType() : StackType.Void; } }
|
||||
public override StackType ResultType => UnalignedPrefix == 0 ? type.GetStackType() : StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => UnalignedPrefix == 0 ? type : compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
|
||||
@@ -4354,7 +4414,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Object);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -4399,7 +4460,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(this.type);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -4453,7 +4515,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
|
||||
@@ -4500,7 +4563,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public NewObj(IMethod method) : base(OpCode.NewObj, method)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return Method.DeclaringType.GetStackType(); } }
|
||||
public override StackType ResultType => (Method.DeclaringType).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => Method.DeclaringType;
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitNewObj(this);
|
||||
@@ -4570,7 +4634,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Indices.AddRange(this.Indices.Select(arg => (ILInstruction)arg.Clone()));
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.Obj;
|
||||
public override IType InferType(ICompilation compilation) => new ArrayType(compilation, this.Type, this.Indices.Count);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow;
|
||||
@@ -4632,7 +4697,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -4667,7 +4733,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return this.resultType; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
|
||||
@@ -4704,7 +4771,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public Rethrow() : base(OpCode.Rethrow)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
|
||||
@@ -4748,7 +4816,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.I4; } }
|
||||
public override StackType ResultType => StackType.I4;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Int32);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -4938,7 +5007,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
public bool WithSystemIndex;
|
||||
public bool DelayExceptions; // NullReferenceException/IndexOutOfBoundsException only occurs when the reference is dereferenced
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(this.Type);
|
||||
/// <summary>Gets whether the 'readonly' prefix was applied to this instruction.</summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
@@ -5063,7 +5133,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Indices.AddRange(this.Indices.Select(arg => (ILInstruction)arg.Clone()));
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(this.Type);
|
||||
/// <summary>Gets whether the 'readonly' prefix was applied to this instruction.</summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
@@ -5120,9 +5191,10 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// </summary>
|
||||
public sealed partial class GetPinnableReference : ILInstruction, IInstructionWithMethodOperand
|
||||
{
|
||||
public GetPinnableReference(ILInstruction argument, IMethod? method) : base(OpCode.GetPinnableReference)
|
||||
public GetPinnableReference(ILInstruction argument, IType type, IMethod? method) : base(OpCode.GetPinnableReference)
|
||||
{
|
||||
this.Argument = argument;
|
||||
this.type = type;
|
||||
this.method = method;
|
||||
}
|
||||
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true);
|
||||
@@ -5175,7 +5247,14 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Argument = this.argument.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
IType type;
|
||||
/// <summary>Returns the type operand.</summary>
|
||||
public IType Type {
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(this.Type);
|
||||
readonly IMethod? method;
|
||||
/// <summary>Returns the method operand.</summary>
|
||||
public IMethod? Method => method;
|
||||
@@ -5192,6 +5271,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
output.Write(OpCode);
|
||||
output.Write(' ');
|
||||
type.WriteTo(output);
|
||||
if (method != null)
|
||||
{
|
||||
output.Write(' ');
|
||||
@@ -5216,7 +5297,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
protected internal override bool PerformMatch(ILInstruction? other, ref Patterns.Match match)
|
||||
{
|
||||
var o = other as GetPinnableReference;
|
||||
return o != null && this.argument.PerformMatch(o.argument, ref match) && object.Equals(method, o.method);
|
||||
return o != null && this.argument.PerformMatch(o.argument, ref match) && type.Equals(o.type) && object.Equals(method, o.method);
|
||||
}
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
@@ -5280,7 +5361,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Argument = this.argument.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.I4; } }
|
||||
public override StackType ResultType => StackType.I4;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Int32);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return argument.Flags;
|
||||
@@ -5325,7 +5407,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return type.GetStackType(); } }
|
||||
public override StackType ResultType => (this.type).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => this.type;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -5368,7 +5451,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
readonly IMethod method;
|
||||
/// <summary>Returns the method operand.</summary>
|
||||
public IMethod Method => method;
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => (method.ReturnType).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => method.ReturnType;
|
||||
public static readonly SlotInfo LeftSlot = new SlotInfo("Left", canInlineInto: true);
|
||||
ILInstruction left = null!;
|
||||
public ILInstruction Left {
|
||||
@@ -6581,7 +6665,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.SubPatterns.AddRange(this.SubPatterns.Select(arg => (ILInstruction)arg.Clone()));
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.I4; } }
|
||||
public override StackType ResultType => StackType.I4;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Boolean);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayWriteLocals | testedOperand.Flags | SubPatterns.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.SideEffect | InstructionFlags.MayThrow | InstructionFlags.ControlFlow;
|
||||
@@ -6632,7 +6717,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.TypedReference);
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -6670,7 +6756,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public RefAnyType(ILInstruction argument) : base(OpCode.RefAnyType, argument)
|
||||
{
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.O; } }
|
||||
public override StackType ResultType => StackType.VT;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.RuntimeTypeHandle);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitRefAnyType(this);
|
||||
@@ -6705,7 +6792,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return type; }
|
||||
set { type = value; InvalidateFlags(); }
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Ref; } }
|
||||
public override StackType ResultType => StackType.Ref;
|
||||
public override IType InferType(ICompilation compilation) => new ByReferenceType(type);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return base.ComputeFlags() | InstructionFlags.MayThrow;
|
||||
@@ -6803,7 +6891,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Value = this.value.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.MayBranch | InstructionFlags.SideEffect | value.Flags;
|
||||
@@ -6899,7 +6988,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
clone.Value = this.value.Clone();
|
||||
return clone;
|
||||
}
|
||||
public override StackType ResultType { get { return GetResultMethod?.ReturnType.GetStackType() ?? StackType.Unknown; } }
|
||||
public override StackType ResultType => (GetResultMethod?.ReturnType ?? SpecialType.UnknownType).GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => GetResultMethod?.ReturnType ?? SpecialType.UnknownType;
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return InstructionFlags.SideEffect | value.Flags;
|
||||
@@ -6941,7 +7031,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// <summary>Deconstruction statement</summary>
|
||||
public sealed partial class DeconstructInstruction : ILInstruction
|
||||
{
|
||||
public override StackType ResultType { get { return StackType.Void; } }
|
||||
public override StackType ResultType => StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
public override void AcceptVisitor(ILVisitor visitor)
|
||||
{
|
||||
visitor.VisitDeconstructInstruction(this);
|
||||
@@ -8568,15 +8659,17 @@ namespace ICSharpCode.Decompiler.IL
|
||||
right = default(ILInstruction);
|
||||
return false;
|
||||
}
|
||||
public bool MatchNullableRewrap([NotNullWhen(true)] out ILInstruction? argument)
|
||||
public bool MatchNullableRewrap([NotNullWhen(true)] out ILInstruction? argument, [NotNullWhen(true)] out IType? type)
|
||||
{
|
||||
var inst = this as NullableRewrap;
|
||||
if (inst != null)
|
||||
{
|
||||
argument = inst.Argument;
|
||||
type = inst.Type;
|
||||
return true;
|
||||
}
|
||||
argument = default(ILInstruction);
|
||||
type = default(IType);
|
||||
return false;
|
||||
}
|
||||
public bool MatchLdStr([NotNullWhen(true)] out string? value)
|
||||
@@ -8989,16 +9082,18 @@ namespace ICSharpCode.Decompiler.IL
|
||||
array = default(ILInstruction);
|
||||
return false;
|
||||
}
|
||||
public bool MatchGetPinnableReference([NotNullWhen(true)] out ILInstruction? argument, out IMethod? method)
|
||||
public bool MatchGetPinnableReference([NotNullWhen(true)] out ILInstruction? argument, [NotNullWhen(true)] out IType? type, out IMethod? method)
|
||||
{
|
||||
var inst = this as GetPinnableReference;
|
||||
if (inst != null)
|
||||
{
|
||||
argument = inst.Argument;
|
||||
type = inst.Type;
|
||||
method = inst.Method;
|
||||
return true;
|
||||
}
|
||||
argument = default(ILInstruction);
|
||||
type = default(IType);
|
||||
method = default(IMethod?);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
new OpCode("CallInstruction", "Instruction with a list of arguments.",
|
||||
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
|
||||
CustomConstructor, CustomWriteTo, MayThrow, SideEffect),
|
||||
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" },
|
||||
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("SpecialType.UnknownType")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" },
|
||||
new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.",
|
||||
AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))),
|
||||
new OpCode("DynamicInstruction", "Instruction representing a dynamic call site.",
|
||||
@@ -53,10 +53,10 @@
|
||||
CustomChildren(new [] {
|
||||
new ChildInfo("body"),
|
||||
new ChildInfo("localFunctions") { IsCollection = true, Type = "ILFunction" }
|
||||
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("DelegateType?.GetStackType() ?? StackType.O")
|
||||
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("DelegateType ?? SpecialType.UnknownType")
|
||||
),
|
||||
new OpCode("BlockContainer", "A container of IL blocks.",
|
||||
ResultType("this.ExpectedResultType"), CustomConstructor, CustomVariableName("container"),
|
||||
CustomConstructor, CustomVariableName("container"),
|
||||
MatchCondition("Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match)")),
|
||||
new OpCode("Block", "A block of IL instructions.",
|
||||
CustomConstructor, CustomVariableName("block"),
|
||||
@@ -64,7 +64,7 @@
|
||||
MatchCondition("Patterns.ListMatch.DoMatch(this.Instructions, o.Instructions, ref match)"),
|
||||
MatchCondition("this.FinalInstruction.PerformMatch(o.FinalInstruction, ref match)")),
|
||||
new OpCode("PinnedRegion", "A region where a pinned variable is used (initial representation of future fixed statement).",
|
||||
ResultType("Void"),
|
||||
VoidResult,
|
||||
HasVariableOperand("Store"),
|
||||
CustomChildren(new []{
|
||||
new ChildInfo("init") { CanInlineInto = true },
|
||||
@@ -76,7 +76,7 @@
|
||||
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")),
|
||||
new OpCode("numeric.compound", "Common instruction for numeric compound assignments.",
|
||||
CustomClassName("NumericCompoundAssign"), BaseClass("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
|
||||
MayThrow, HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo,
|
||||
MayThrow, HasTypeOperand, ResultType("this.type"), CustomWriteTo,
|
||||
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator"),
|
||||
MatchCondition("this.EvalMode == o.EvalMode"),
|
||||
MatchCondition("this.TargetKind == o.TargetKind"),
|
||||
@@ -92,13 +92,13 @@
|
||||
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
|
||||
new OpCode("dynamic.compound", "Common instruction for dynamic compound assignments.",
|
||||
CustomClassName("DynamicCompoundAssign"), BaseClass("CompoundAssignmentInstruction"),
|
||||
MayThrow, SideEffect, CustomWriteTo, CustomConstructor, ResultType("O"),
|
||||
MayThrow, SideEffect, CustomWriteTo, CustomConstructor, ResultType("SpecialType.Dynamic", "O"),
|
||||
MatchCondition("this.EvalMode == o.EvalMode"),
|
||||
MatchCondition("this.TargetKind == o.TargetKind"),
|
||||
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
|
||||
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
|
||||
new OpCode("bit.not", "Bitwise NOT", Unary, CustomConstructor, MatchCondition("IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType")),
|
||||
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
|
||||
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("RuntimeArgumentHandle", "VT")),
|
||||
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
|
||||
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch,
|
||||
MatchCondition("this.TargetBlock == o.TargetBlock")),
|
||||
@@ -123,7 +123,7 @@
|
||||
MatchCondition("IsLifted == o.IsLifted && Value.PerformMatch(o.Value, ref match) && Patterns.ListMatch.DoMatch(this.Sections, o.Sections, ref match)")),
|
||||
new OpCode("switch.section", "Switch section within a switch statement",
|
||||
CustomClassName("SwitchSection"), CustomChildren(new [] { new ChildInfo("body") }),
|
||||
CustomConstructor, CustomComputeFlags, CustomWriteTo, ResultType("Void"),
|
||||
CustomConstructor, CustomComputeFlags, CustomWriteTo, VoidResult,
|
||||
MatchCondition("this.Labels.SetEquals(o.Labels) && this.HasNullLabel == o.HasNullLabel")),
|
||||
new OpCode("try.catch", "Try-catch statement.",
|
||||
BaseClass("TryInstruction"), CustomConstructor, CustomComputeFlags, CustomWriteTo,
|
||||
@@ -133,7 +133,8 @@
|
||||
CustomChildren(new [] {
|
||||
new ChildInfo("filter"),
|
||||
new ChildInfo("body"),
|
||||
}), HasVariableOperand("Store", generateCheckInvariant: false), CustomWriteTo, CustomComputeFlags),
|
||||
}), HasVariableOperand("Store", generateCheckInvariant: false),
|
||||
CustomWriteTo, CustomComputeFlags, VoidResult),
|
||||
new OpCode("try.finally", "Try-finally statement",
|
||||
BaseClass("TryInstruction"), CustomConstructor, CustomWriteTo, CustomComputeFlags,
|
||||
MatchCondition("TryBlock.PerformMatch(o.TryBlock, ref match) && finallyBlock.PerformMatch(o.finallyBlock, ref match)")),
|
||||
@@ -145,12 +146,12 @@
|
||||
CustomChildren(new [] {
|
||||
new ArgumentInfo("onExpression") { ExpectedTypes = new[] { "O" }},
|
||||
new ChildInfo("body")
|
||||
}), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")),
|
||||
}), CustomWriteTo, ControlFlow, SideEffect, VoidResult),
|
||||
new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), HasVariableOperand("Store"),
|
||||
CustomChildren(new [] {
|
||||
new ArgumentInfo("resourceExpression") { ExpectedTypes = new[] { "O" }},
|
||||
new ChildInfo("body")
|
||||
}), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")),
|
||||
}), CustomWriteTo, ControlFlow, SideEffect, VoidResult),
|
||||
new OpCode("debug.break", "Breakpoint instruction",
|
||||
NoArguments, VoidResult, SideEffect),
|
||||
new OpCode("comp", "Comparison. The inputs must be both integers; or both floats; or both object references. "
|
||||
@@ -174,19 +175,19 @@
|
||||
Unary, CustomConstructor,
|
||||
MatchCondition("CheckForOverflow == o.CheckForOverflow && Kind == o.Kind && InputSign == o.InputSign && TargetType == o.TargetType && IsLifted == o.IsLifted")),
|
||||
new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)",
|
||||
CustomClassName("LdLoc"), NoArguments, HasVariableOperand("Load"), ResultType("variable.StackType")),
|
||||
CustomClassName("LdLoc"), NoArguments, HasVariableOperand("Load"), ResultType("variable.Type", "variable.StackType")),
|
||||
new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)",
|
||||
CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand("Address")),
|
||||
CustomClassName("LdLoca"), NoArguments, ResultType("new ByReferenceType(variable.Type)", "Ref"), HasVariableOperand("Address")),
|
||||
new OpCode("stloc", "Stores a value into a local variable. (IL: starg/stloc)" + Environment.NewLine
|
||||
+ "Evaluates to the value that was stored (for byte/short variables: evaluates to the truncated value, sign/zero extended back to I4 based on variable.Type.GetSign())",
|
||||
CustomClassName("StLoc"), HasVariableOperand("Store", generateCheckInvariant: false), CustomArguments(("value", null)),
|
||||
ResultType("variable.StackType")),
|
||||
ResultType("variable.Type", "variable.StackType")),
|
||||
new OpCode("addressof", "Stores the value into an anonymous temporary variable, and returns the address of that variable.",
|
||||
CustomClassName("AddressOf"), CustomArguments(("value", null)), ResultType("Ref"), HasTypeOperand),
|
||||
CustomClassName("AddressOf"), CustomArguments(("value", null)), ResultType("new ByReferenceType(type)", "Ref"), HasTypeOperand),
|
||||
new OpCode("3vl.bool.and", "Three valued logic and. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.and(), does not have short-circuiting behavior.",
|
||||
CustomClassName("ThreeValuedBoolAnd"), Binary, ResultType("O")),
|
||||
CustomClassName("ThreeValuedBoolAnd"), Binary),
|
||||
new OpCode("3vl.bool.or", "Three valued logic or. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.or(), does not have short-circuiting behavior.",
|
||||
CustomClassName("ThreeValuedBoolOr"), Binary, ResultType("O")),
|
||||
CustomClassName("ThreeValuedBoolOr"), Binary),
|
||||
new OpCode("nullable.unwrap", "The input operand must be one of:" + Environment.NewLine
|
||||
+ " 1. a nullable value type" + Environment.NewLine
|
||||
+ " 2. a reference type" + Environment.NewLine
|
||||
@@ -200,114 +201,132 @@
|
||||
+ "If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type)."
|
||||
+ "If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,"
|
||||
+ "the nullable.rewrap instruction evaluates to null.",
|
||||
Unary, CustomComputeFlags),
|
||||
Unary, CustomComputeFlags, HasTypeOperand),
|
||||
|
||||
new OpCode("ldstr", "Loads a constant string.",
|
||||
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
|
||||
CustomClassName("LdStr"), LoadConstant("string"), ResultType("String", "Obj")),
|
||||
new OpCode("ldstr.utf8", "Loads a constant byte string (as ReadOnlySpan<byte>).",
|
||||
CustomClassName("LdStrUtf8"), LoadConstant("string"), ResultType("O")),
|
||||
CustomClassName("LdStrUtf8"), LoadConstant("string"),
|
||||
ResultType("new ParameterizedType(compilation.FindType(KnownTypeCode.ReadOnlySpanOfT), compilation.FindType(KnownTypeCode.Boolean))", "VT")),
|
||||
new OpCode("ldc.i4", "Loads a constant 32-bit integer.",
|
||||
LoadConstant("int"), ResultType("I4")),
|
||||
LoadConstant("int"), ResultType("Int32", "I4")),
|
||||
new OpCode("ldc.i8", "Loads a constant 64-bit integer.",
|
||||
LoadConstant("long"), ResultType("I8")),
|
||||
LoadConstant("long"), ResultType("Int64", "I8")),
|
||||
new OpCode("ldc.f4", "Loads a constant 32-bit floating-point number.",
|
||||
LoadConstant("float"), ResultType("F4")),
|
||||
LoadConstant("float"), ResultType("Single", "F4")),
|
||||
new OpCode("ldc.f8", "Loads a constant 64-bit floating-point number.",
|
||||
LoadConstant("double"), ResultType("F8")),
|
||||
LoadConstant("double"), ResultType("Double", "F8")),
|
||||
new OpCode("ldc.decimal", "Loads a constant decimal.",
|
||||
LoadConstant("decimal"), ResultType("O")),
|
||||
LoadConstant("decimal"), ResultType("Decimal", "O")),
|
||||
new OpCode("ldnull", "Loads the null reference.",
|
||||
CustomClassName("LdNull"), NoArguments, ResultType("O")),
|
||||
CustomClassName("LdNull"), NoArguments, ResultType("Object", "Obj")),
|
||||
new OpCode("ldftn", "Load method pointer",
|
||||
CustomClassName("LdFtn"), NoArguments, HasMethodOperand(), ResultType("I")),
|
||||
CustomClassName("LdFtn"), NoArguments, HasMethodOperand(), ResultType("IntPtr", "I")),
|
||||
new OpCode("ldvirtftn", "Load method pointer",
|
||||
CustomClassName("LdVirtFtn"), Unary, HasMethodOperand(), MayThrow, ResultType("I")),
|
||||
CustomClassName("LdVirtFtn"), Unary, HasMethodOperand(), MayThrow, ResultType("IntPtr", "I")),
|
||||
new OpCode("ldvirtdelegate", "Virtual delegate construction",
|
||||
CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand(),
|
||||
MayThrow, ResultType("O")),
|
||||
MayThrow, ResultType("this.type", "Obj")),
|
||||
new OpCode("ldtypetoken", "Loads runtime representation of metadata token",
|
||||
CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")),
|
||||
CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("RuntimeTypeHandle", "VT")),
|
||||
new OpCode("ldmembertoken", "Loads runtime representation of metadata token",
|
||||
CustomClassName("LdMemberToken"), NoArguments, HasMemberOperand, ResultType("O")),
|
||||
CustomClassName("LdMemberToken"), NoArguments, HasMemberOperand,
|
||||
ResultType("compilation.FindType(member is IField ? KnownTypeCode.RuntimeFieldHandle : KnownTypeCode.RuntimeMethodHandle)", "VT")),
|
||||
new OpCode("localloc", "Allocates space in the stack frame",
|
||||
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
|
||||
ResultType("new PointerType(compilation.FindType(KnownTypeCode.Void))", "I"),
|
||||
CustomClassName("LocAlloc"), Unary, MayThrow),
|
||||
new OpCode("localloc.span", "Allocates space in the stack frame and wraps it in a Span",
|
||||
CustomClassName("LocAllocSpan"), Unary, HasTypeOperand, ResultType("O"), MayThrow),
|
||||
CustomClassName("LocAllocSpan"), Unary, HasTypeOperand, ResultType("this.type", "VT"), MayThrow),
|
||||
new OpCode("cpblk", "memcpy(destAddress, sourceAddress, size);",
|
||||
CustomArguments(("destAddress", new[] { "I", "Ref" }), ("sourceAddress", new[] { "I", "Ref" }), ("size", new[] { "I4" })),
|
||||
MayThrow, MemoryAccess,
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, ResultType("Void")),
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult),
|
||||
new OpCode("initblk", "memset(address, value, size)",
|
||||
CustomArguments(("address", new[] { "I", "Ref" }), ("value", new[] { "I4" }), ("size", new[] { "I4" })),
|
||||
MayThrow, MemoryAccess,
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, ResultType("Void")),
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult),
|
||||
|
||||
new OpCode("ldflda", "Load address of instance field",
|
||||
CustomClassName("LdFlda"), CustomArguments(("target", null)), MayThrowIfNotDelayed, HasFieldOperand,
|
||||
ResultType("target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref")),
|
||||
ResultType(
|
||||
"target.ResultType.IsIntegerType() ? new PointerType(field.Type) : new ByReferenceType(field.Type)",
|
||||
"target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref")),
|
||||
new OpCode("ldsflda", "Load static field address",
|
||||
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),
|
||||
CustomClassName("LdsFlda"), NoArguments, ResultType("new ByReferenceType(field.Type)", "Ref"), HasFieldOperand),
|
||||
|
||||
new OpCode("castclass", "Casts an object to a class.",
|
||||
CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")),
|
||||
CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("this.type")),
|
||||
new OpCode("isinst", "Test if object is instance of class or interface.",
|
||||
CustomClassName("IsInst"), Unary, HasTypeOperand, ResultType("O")),
|
||||
CustomClassName("IsInst"), Unary, HasTypeOperand, ResultType("Object", "Obj")),
|
||||
new OpCode("ldobj", "Indirect load (ref/pointer dereference).",
|
||||
CustomClassName("LdObj"), CustomArguments(("target", new[] { "Ref", "I" })), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
|
||||
new OpCode("ldobj.if.ref", "If argument is a ref to a reference type, loads the object reference, stores it in a temporary, and evaluates to the address of that temporary (address.of(ldobj(arg))). Otherwise, returns the argument ref as-is.<para>This instruction represents the memory-load semantics of callvirt with a generic type as receiver (where the IL always takes a ref, but only methods on value types expect one, for method on reference types there's an implicit ldobj, which this instruction makes explicit in order to preserve the order-of-evaluation).</para>",
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("this.type")),
|
||||
new OpCode("ldobj.if.ref", "If argument is a ref to a reference type, loads the object reference, stores it in a temporary, " +
|
||||
"and evaluates to the address of that temporary (address.of(ldobj(arg))). Otherwise, returns the argument ref as-is.<para>" +
|
||||
"This instruction represents the memory-load semantics of callvirt with a generic type as receiver (where the IL always takes " +
|
||||
"a ref, but only methods on value types expect one, for method on reference types there's an implicit ldobj, which this "+
|
||||
"instruction makes explicit in order to preserve the order-of-evaluation).</para>",
|
||||
CustomClassName("LdObjIfRef"), CustomArguments(("target", new[] { "Ref", "I" })), HasTypeOperand, MemoryAccess,
|
||||
MayThrow, ResultType("Ref")),
|
||||
MayThrow, ResultType("new ByReferenceType(this.type)", "Ref")),
|
||||
new OpCode("stobj", "Indirect store (store to ref/pointer)." + Environment.NewLine
|
||||
+ "Evaluates to the value that was stored (when using type byte/short: evaluates to the truncated value, sign/zero extended back to I4 based on type.GetSign())",
|
||||
CustomClassName("StObj"), CustomArguments(("target", new[] { "Ref", "I" }), ("value", new[] { "type.GetStackType()" })), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
|
||||
+ "Evaluates to the value that was stored (when using type byte/short: evaluates to the truncated value, "
|
||||
+ "sign/zero extended back to I4 based on type.GetSign())",
|
||||
CustomClassName("StObj"),
|
||||
CustomArguments(("target", new[] { "Ref", "I" }), ("value", new[] { "type.GetStackType()" })),
|
||||
HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
|
||||
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
|
||||
ResultType("UnalignedPrefix == 0 ? type.GetStackType() : StackType.Void"),
|
||||
ResultType("UnalignedPrefix == 0 ? type : compilation.FindType(KnownTypeCode.Void)",
|
||||
"UnalignedPrefix == 0 ? type.GetStackType() : StackType.Void"),
|
||||
CustomInvariant("CheckTargetSlot();")),
|
||||
|
||||
new OpCode("box", "Boxes a value.",
|
||||
Unary, HasTypeOperand, ResultType("O")),
|
||||
Unary, HasTypeOperand, ResultType("Object", "Obj")),
|
||||
new OpCode("unbox", "Compute address inside box.",
|
||||
Unary, HasTypeOperand, MayThrow, ResultType("Ref")),
|
||||
Unary, HasTypeOperand, MayThrow, ResultType("new ByReferenceType(this.type)", "Ref")),
|
||||
new OpCode("unbox.any", "Unbox a value.",
|
||||
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("type.GetStackType()")),
|
||||
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("this.type")),
|
||||
new OpCode("newobj", "Creates an object instance and calls the constructor.",
|
||||
CustomClassName("NewObj"), Call, ResultType("Method.DeclaringType.GetStackType()")),
|
||||
CustomClassName("NewObj"), Call, ResultType("Method.DeclaringType")),
|
||||
new OpCode("newarr", "Creates an array instance.",
|
||||
CustomClassName("NewArr"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("indices") { IsCollection = true } }, true), MayThrow, ResultType("O")),
|
||||
CustomClassName("NewArr"), HasTypeOperand,
|
||||
CustomChildren(new [] { new ArgumentInfo("indices") { IsCollection = true } }, true),
|
||||
MayThrow, ResultType("new ArrayType(compilation, this.Type, this.Indices.Count)", "Obj")),
|
||||
new OpCode("default.value", "Returns the default value for a type.",
|
||||
NoArguments, HasTypeOperand, ResultType("type.GetStackType()")),
|
||||
NoArguments, HasTypeOperand, ResultType("this.type")),
|
||||
new OpCode("throw", "Throws an exception.",
|
||||
Unary, MayThrow, HasFlag("InstructionFlags.EndPointUnreachable"), ResultType("this.resultType")),
|
||||
Unary, MayThrow, VoidResult, HasFlag("InstructionFlags.EndPointUnreachable")),
|
||||
new OpCode("rethrow", "Rethrows the current exception.",
|
||||
NoArguments, MayThrow, UnconditionalBranch),
|
||||
new OpCode("sizeof", "Gets the size of a type in bytes.",
|
||||
CustomClassName("SizeOf"), NoArguments, HasTypeOperand, ResultType("I4")),
|
||||
CustomClassName("SizeOf"), NoArguments, HasTypeOperand, ResultType("Int32", "I4")),
|
||||
|
||||
new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.",
|
||||
CustomClassName("LdLen"), CustomArguments(("array", new[] { "O" })), CustomConstructor, CustomWriteTo, MayThrow),
|
||||
new OpCode("ldelema", "Load address of array element.",
|
||||
CustomClassName("LdElema"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true),
|
||||
BoolFlag("WithSystemIndex"),
|
||||
MayThrowIfNotDelayed, ResultType("Ref"), SupportsReadonlyPrefix),
|
||||
MayThrowIfNotDelayed, ResultType("new ByReferenceType(this.Type)", "Ref"), SupportsReadonlyPrefix),
|
||||
new OpCode("ldelema.inlinearray", "Load address of inline array element.",
|
||||
CustomClassName("LdElemaInlineArray"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true),
|
||||
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix),
|
||||
MayThrow, ResultType("new ByReferenceType(this.Type)", "Ref"), SupportsReadonlyPrefix),
|
||||
new OpCode("get.pinnable.reference", "Retrieves a pinnable reference for the input object." + Environment.NewLine
|
||||
+ "The input must be an object reference (O)." + Environment.NewLine
|
||||
+ "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine
|
||||
+ "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine,
|
||||
CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand(nullable: true)),
|
||||
CustomArguments(("argument", new[] { "O" })),
|
||||
HasTypeOperand,
|
||||
ResultType("new ByReferenceType(this.Type)", "Ref"), HasMethodOperand(nullable: true)),
|
||||
new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
|
||||
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),
|
||||
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("Int32", "I4")),
|
||||
|
||||
new OpCode("expression.tree.cast", "ILAst representation of Expression.Convert.",
|
||||
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"),
|
||||
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo,
|
||||
ResultType("this.type"),
|
||||
MatchCondition("this.IsChecked == o.IsChecked")),
|
||||
|
||||
new OpCode("user.logic.operator", "Use of user-defined && or || operator.",
|
||||
CustomClassName("UserDefinedLogicOperator"),
|
||||
HasMethodOperand(), ResultType("O"),
|
||||
HasMethodOperand(), ResultType("method.ReturnType"),
|
||||
CustomChildren(new []{
|
||||
new ChildInfo("left") { CanInlineInto = true },
|
||||
new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left
|
||||
@@ -352,14 +371,15 @@
|
||||
CustomChildren(new []{
|
||||
new ChildInfo("testedOperand") { CanInlineInto = true },
|
||||
new ChildInfo("subPatterns") { IsCollection = true }
|
||||
}), ResultType("I4"), CustomWriteTo, SideEffect, MayThrow, ControlFlow, CustomInvariant("AdditionalInvariants();")),
|
||||
}), ResultType("Boolean", "I4"), CustomWriteTo, SideEffect, MayThrow, ControlFlow, CustomInvariant("AdditionalInvariants();")),
|
||||
|
||||
new OpCode("mkrefany", "Push a typed reference of type class onto the stack.",
|
||||
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")),
|
||||
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("TypedReference", "VT")),
|
||||
new OpCode("refanytype", "Push the type token stored in a typed reference.",
|
||||
CustomClassName("RefAnyType"), Unary, ResultType("O")),
|
||||
CustomClassName("RefAnyType"), Unary, ResultType("RuntimeTypeHandle", "VT")),
|
||||
new OpCode("refanyval", "Push the address stored in a typed reference.",
|
||||
CustomClassName("RefAnyValue"), Unary, HasTypeOperand, MayThrow, ResultType("Ref")),
|
||||
CustomClassName("RefAnyValue"), Unary, HasTypeOperand, MayThrow,
|
||||
ResultType("new ByReferenceType(type)", "Ref")),
|
||||
|
||||
new OpCode("yield.return", "Yield an element from an iterator.",
|
||||
MayBranch, // yield return may end up returning if the consumer disposes the iterator
|
||||
@@ -368,10 +388,10 @@
|
||||
// note: "yield break" is always represented using a "leave" instruction
|
||||
new OpCode("await", "C# await operator.",
|
||||
SideEffect, // other code can run with arbitrary side effects while we're waiting
|
||||
CustomArguments(("value", null)), ResultType("GetResultMethod?.ReturnType.GetStackType() ?? StackType.Unknown")),
|
||||
CustomArguments(("value", null)), ResultType("GetResultMethod?.ReturnType ?? SpecialType.UnknownType")),
|
||||
|
||||
new OpCode("deconstruct", "Deconstruction statement",
|
||||
CustomClassName("DeconstructInstruction"), CustomConstructor, ResultType("Void"), CustomWriteTo),
|
||||
CustomClassName("DeconstructInstruction"), CustomConstructor, VoidResult, CustomWriteTo),
|
||||
new OpCode("deconstruct.result", "Represents a deconstructed value",
|
||||
CustomClassName("DeconstructResultInstruction"), CustomConstructor, CustomInvariant("AdditionalInvariants();"),
|
||||
Unary, CustomWriteTo),
|
||||
@@ -715,24 +735,28 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
// ResultType trait: the instruction has the specified result type.
|
||||
static Action<OpCode> ResultType(string type)
|
||||
static Action<OpCode> ResultType(string type, string stackType = null)
|
||||
{
|
||||
if (!type.Contains("."))
|
||||
type = "StackType." + type;
|
||||
if (!type.Contains(".") && !type.Contains("("))
|
||||
type = "compilation.FindType(KnownTypeCode." + type + ")";
|
||||
if (stackType != null && !stackType.Contains("."))
|
||||
stackType = "StackType." + stackType;
|
||||
stackType ??= "(" + type + ").GetStackType()";
|
||||
return opCode => {
|
||||
opCode.Members.Add("public override StackType ResultType { get { return " + type + "; } }");
|
||||
opCode.Members.Add("public override StackType ResultType => " + stackType + ";");
|
||||
opCode.Members.Add("public override IType InferType(ICompilation compilation) => " + type + ";");
|
||||
};
|
||||
}
|
||||
|
||||
// VoidResult trait: the instruction has no result and is not usable as an argument
|
||||
static Action<OpCode> VoidResult = ResultType("Void");
|
||||
static Action<OpCode> VoidResult = ResultType("Void", "Void");
|
||||
|
||||
// ResultTypeParam trait: the instruction takes its result type as ctor parameter
|
||||
static Action<OpCode> ResultTypeParam = opCode => {
|
||||
opCode.ConstructorParameters.Add("StackType resultType");
|
||||
opCode.ConstructorBody.Add("this.resultType = resultType;");
|
||||
opCode.Members.Add("StackType resultType;");
|
||||
opCode.Members.Add("public override StackType ResultType { get { return resultType; } }");
|
||||
opCode.Members.Add("public override StackType ResultType => resultType;");
|
||||
};
|
||||
|
||||
// MayThrow trait: the instruction may throw exceptions
|
||||
|
||||
@@ -78,6 +78,14 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
readonly StackType resultType;
|
||||
|
||||
/// <summary>
|
||||
/// Result type of this instruction. If not null, InferType() will return this type.
|
||||
/// Can be used to store an improved C# type for the result of this instruction,
|
||||
/// e.g. `bit.or.i4(bool1, bool2)` can use CSharpResultType = bool after the
|
||||
/// ExpressionTransform has determined that the result is always 0 or 1.
|
||||
/// </summary>
|
||||
public IType? CSharpResultType { get; set; }
|
||||
|
||||
public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
|
||||
: this(op, left, right, left.ResultType, right.ResultType, checkForOverflow, sign)
|
||||
{
|
||||
@@ -123,12 +131,22 @@ namespace ICSharpCode.Decompiler.IL
|
||||
return StackType.Unknown;
|
||||
}
|
||||
|
||||
public StackType UnderlyingResultType { get => resultType; }
|
||||
public StackType UnderlyingResultType => resultType;
|
||||
|
||||
public sealed override StackType ResultType {
|
||||
get => IsLifted ? StackType.O : resultType;
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
if (CSharpResultType != null)
|
||||
return CSharpResultType;
|
||||
IType type = compilation.FindType(UnderlyingResultType);
|
||||
if (IsLifted)
|
||||
return NullableType.Create(compilation, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
@@ -142,14 +160,14 @@ namespace ICSharpCode.Decompiler.IL
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
var flags = base.ComputeFlags();
|
||||
if (CheckForOverflow || (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem))
|
||||
if (CheckForOverflow || Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem)
|
||||
flags |= InstructionFlags.MayThrow;
|
||||
return flags;
|
||||
}
|
||||
|
||||
public override InstructionFlags DirectFlags {
|
||||
get {
|
||||
if (CheckForOverflow || (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem))
|
||||
if (CheckForOverflow || Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem)
|
||||
return base.DirectFlags | InstructionFlags.MayThrow;
|
||||
return base.DirectFlags;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,11 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
return finalInstruction.InferType(compilation);
|
||||
}
|
||||
|
||||
internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved)
|
||||
{
|
||||
switch (Kind)
|
||||
|
||||
@@ -44,7 +44,11 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public readonly InstructionCollection<Block> Blocks;
|
||||
|
||||
public ContainerKind Kind { get; set; }
|
||||
public StackType ExpectedResultType { get; set; }
|
||||
IType? expectedResultType; // null means void
|
||||
public IType? ExpectedResultType {
|
||||
get => expectedResultType;
|
||||
set => expectedResultType = value;
|
||||
}
|
||||
|
||||
int leaveCount;
|
||||
|
||||
@@ -80,16 +84,16 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
public BlockContainer(ContainerKind kind = ContainerKind.Normal, StackType expectedResultType = StackType.Void) : base(OpCode.BlockContainer)
|
||||
public BlockContainer(ContainerKind kind = ContainerKind.Normal, IType? expectedResultType = null) : base(OpCode.BlockContainer)
|
||||
{
|
||||
this.Kind = kind;
|
||||
this.Blocks = new InstructionCollection<Block>(this, 0);
|
||||
this.ExpectedResultType = expectedResultType;
|
||||
this.expectedResultType = expectedResultType;
|
||||
}
|
||||
|
||||
public override ILInstruction Clone()
|
||||
{
|
||||
BlockContainer clone = new BlockContainer(this.Kind, this.ExpectedResultType);
|
||||
BlockContainer clone = new BlockContainer(this.Kind, this.expectedResultType);
|
||||
clone.AddILRange(this);
|
||||
clone.Blocks.AddRange(this.Blocks.Select(block => (Block)block.Clone()));
|
||||
// Adjust branch instructions to point to the new container
|
||||
@@ -236,6 +240,20 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
if (expectedResultType != null)
|
||||
return expectedResultType.GetStackType();
|
||||
else
|
||||
return StackType.Void;
|
||||
}
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
return expectedResultType ?? compilation.FindType(StackType.Void);
|
||||
}
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
InstructionFlags flags = InstructionFlags.ControlFlow;
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => FunctionPointerType.ReturnType.GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => FunctionPointerType.ReturnType;
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
|
||||
@@ -87,14 +87,9 @@ namespace ICSharpCode.Decompiler.IL
|
||||
return Method.Parameters[argumentIndex - firstParamIndex];
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
if (OpCode == OpCode.NewObj)
|
||||
return Method.DeclaringType.GetStackType();
|
||||
else
|
||||
return Method.ReturnType.GetStackType();
|
||||
}
|
||||
}
|
||||
// Note: NewObj is overriding ResultType+InferType.
|
||||
public override StackType ResultType => Method.ReturnType.GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => Method.ReturnType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expected stack type for passing the this pointer in a method call.
|
||||
|
||||
@@ -161,6 +161,20 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => LiftingKind == ComparisonLiftingKind.ThreeValuedLogic ? StackType.O : StackType.I4;
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
IType boolType = compilation.FindType(KnownTypeCode.Boolean);
|
||||
if (LiftingKind == ComparisonLiftingKind.ThreeValuedLogic)
|
||||
{
|
||||
return NullableType.Create(compilation, boolType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return boolType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLifted => LiftingKind != ComparisonLiftingKind.None;
|
||||
public StackType UnderlyingResultType => StackType.I4;
|
||||
|
||||
|
||||
@@ -336,6 +336,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => Method.ReturnType.GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => Method.ReturnType;
|
||||
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
|
||||
@@ -307,7 +307,25 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get => IsLifted ? StackType.O : TargetType.GetStackType();
|
||||
get => IsLifted ? StackType.VT : TargetType.GetStackType();
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
var ktc = TargetType.ToKnownTypeCode();
|
||||
IType type;
|
||||
if (ktc != KnownTypeCode.None)
|
||||
{
|
||||
type = compilation.FindType(ktc);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = compilation.FindType(TargetType.GetStackType());
|
||||
}
|
||||
if (IsLifted)
|
||||
return NullableType.Create(compilation, type);
|
||||
else
|
||||
return type;
|
||||
}
|
||||
|
||||
public StackType UnderlyingResultType {
|
||||
|
||||
@@ -256,17 +256,14 @@ namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (stobj.Target.InferType(typeSystem) is ByReferenceType brt)
|
||||
expectedType = brt.ElementType;
|
||||
else
|
||||
{
|
||||
// Pointer targets do not infer a ByReferenceType. stobj.Type cannot stand
|
||||
// in for the element type: it comes from the store opcode, which is
|
||||
// sign-agnostic, so a uint* and an int* both report int32 and a byte*
|
||||
// reports sbyte. Recover the declared type instead, and only fall back to
|
||||
// the store where the target is not a pointer at all.
|
||||
expectedType = GetPointerElementType(stobj.Target, typeSystem) ?? stobj.Type;
|
||||
}
|
||||
// stobj.Type comes from the store opcode and is sign-agnostic (an int* and a
|
||||
// uint* target both store int32), so for pointer targets the element type of
|
||||
// the target's inferred type must be used instead.
|
||||
expectedType = stobj.Target.InferType(typeSystem) switch {
|
||||
ByReferenceType brt => brt.ElementType,
|
||||
PointerType ptr => ptr.ElementType,
|
||||
_ => stobj.Type
|
||||
};
|
||||
value = stobj.Value;
|
||||
return true;
|
||||
default:
|
||||
@@ -274,28 +271,6 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The element type of a pointer-typed target. A pointer passing through a stack slot
|
||||
/// is typed IntPtr there, so the declared type has to be taken from the definition the
|
||||
/// slot was filled from. Returns null if the target is not a pointer.
|
||||
/// </summary>
|
||||
static IType GetPointerElementType(ILInstruction target, ICompilation typeSystem)
|
||||
{
|
||||
// Bounded because a definition chain could be cyclic in invalid IL.
|
||||
for (int step = 0; step < 4; step++)
|
||||
{
|
||||
if (target.InferType(typeSystem) is PointerType pointerType)
|
||||
return pointerType.ElementType;
|
||||
if (!target.MatchLdLoc(out var v) || !v.IsSingleDefinition
|
||||
|| v.StoreInstructions.Count != 1 || !(v.StoreInstructions[0] is StLoc store))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
target = store.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
|
||||
@@ -28,14 +28,18 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public int Index { get; }
|
||||
|
||||
public override StackType ResultType { get; }
|
||||
public IType Type { get; }
|
||||
|
||||
public DeconstructResultInstruction(int index, StackType resultType, ILInstruction argument)
|
||||
public DeconstructResultInstruction(int index, IType type, StackType resultType, ILInstruction argument)
|
||||
: base(OpCode.DeconstructResultInstruction, argument)
|
||||
{
|
||||
Debug.Assert(index >= 0);
|
||||
Index = index;
|
||||
Type = type;
|
||||
ResultType = resultType;
|
||||
Debug.Assert(type.GetStackType() == resultType);
|
||||
}
|
||||
public override IType InferType(ICompilation compilation) => Type;
|
||||
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
|
||||
@@ -156,6 +156,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
public override StackType ResultType => type.GetStackType();
|
||||
|
||||
public override IType InferType(ICompilation compilation) => type;
|
||||
|
||||
public bool IsChecked => (BinderFlags & CSharpBinderFlags.CheckedContext) != 0;
|
||||
|
||||
public bool IsExplicit => (BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0;
|
||||
@@ -223,6 +225,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
index += ArgumentInfoOffset;
|
||||
@@ -256,6 +260,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -292,6 +297,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -330,6 +336,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -362,6 +369,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -402,6 +410,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => Type.GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => Type;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -440,6 +449,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -482,6 +492,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
@@ -541,6 +552,18 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
switch (Operation)
|
||||
{
|
||||
case ExpressionType.IsFalse:
|
||||
case ExpressionType.IsTrue:
|
||||
return compilation.FindType(KnownTypeCode.Boolean);
|
||||
default:
|
||||
return SpecialType.Dynamic;
|
||||
}
|
||||
}
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
switch (index)
|
||||
@@ -575,6 +598,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => SpecialType.Dynamic;
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
@@ -608,6 +632,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
public override StackType ResultType => StackType.I4;
|
||||
|
||||
public override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Boolean);
|
||||
|
||||
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
|
||||
{
|
||||
return default(CSharpArgumentInfo);
|
||||
|
||||
@@ -102,6 +102,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
child.CheckInvariant(phase, compilation);
|
||||
}
|
||||
Debug.Assert((this.DirectFlags & ~this.Flags) == 0, "All DirectFlags must also appear in this.Flags");
|
||||
var inferredType = this.InferType(compilation);
|
||||
Debug.Assert(inferredType.GetStackType() == this.ResultType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,19 +218,26 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// </summary>
|
||||
public abstract StackType ResultType { get; }
|
||||
|
||||
/* Not sure if it's a good idea to offer this on all instructions --
|
||||
* e.g. ldloc for a local of type `int?` would return StackType.O (because it's not a lifted operation),
|
||||
* even though the underlying type is int = StackType.I4.
|
||||
/// <summary>
|
||||
/// Gets the underlying result type of the value produced by this instruction.
|
||||
///
|
||||
/// If this is a lifted operation, the ResultType will be `StackType.O` (because Nullable{T} is a struct),
|
||||
/// and UnderlyingResultType will be result type of the corresponding non-lifted operation.
|
||||
///
|
||||
/// If this is not a lifted operation, the underlying result type is equal to the result type.
|
||||
/// Gets a possible C# type that could be used to store the result of this instruction.
|
||||
/// </summary>
|
||||
public virtual StackType UnderlyingResultType { get => ResultType; }
|
||||
*/
|
||||
/// <remarks>
|
||||
/// Post-condition: this.InferType().GetStackType() == this.ResultType.
|
||||
///
|
||||
/// This must be a type suitable for use a local variable (i.e. `ldnull` uses `object`, not `NullType`).
|
||||
///
|
||||
/// If this function returns a small integer type, the instruction is guaranteed to
|
||||
/// evaluate to a value that fits into that type (when the I4 evaluation result is
|
||||
/// interpreted as int/uint depending on the small integer type's sign).
|
||||
///
|
||||
/// For instructions producing an non-nullable value type, this function must return that
|
||||
/// exact type.
|
||||
/// For nullable value types, this function may return `int?` when actually the instruction
|
||||
/// produces a nullable I4, which might end up being a `bool?` expression in C#.
|
||||
/// Similarly, for reference types, this function may return `object` when actually the C#
|
||||
/// type is a more specific reference type.
|
||||
/// </remarks>
|
||||
public abstract IType InferType(ICompilation compilation);
|
||||
|
||||
internal static StackType CommonResultType(StackType a, StackType b)
|
||||
{
|
||||
|
||||
@@ -38,46 +38,60 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// </remarks>
|
||||
partial class IfInstruction : ILInstruction
|
||||
{
|
||||
public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction? falseInst = null) : base(OpCode.IfInstruction)
|
||||
// null means void
|
||||
readonly IType? resultType;
|
||||
|
||||
public IfInstruction(ILInstruction condition, ILInstruction trueInst,
|
||||
ILInstruction? falseInst = null, IType? resultType = null) : base(OpCode.IfInstruction)
|
||||
{
|
||||
this.Condition = condition;
|
||||
this.TrueInst = trueInst;
|
||||
this.FalseInst = falseInst ?? new Nop();
|
||||
falseInst ??= new Nop();
|
||||
this.FalseInst = falseInst;
|
||||
this.resultType = resultType;
|
||||
Debug.Assert(condition.ResultType == StackType.I4);
|
||||
Debug.Assert(trueInst.ResultType == this.ResultType
|
||||
|| trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
Debug.Assert(falseInst.ResultType == this.ResultType
|
||||
|| falseInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
}
|
||||
|
||||
public static IfInstruction LogicAnd(ILInstruction lhs, ILInstruction rhs)
|
||||
public static IfInstruction LogicAnd(ILInstruction lhs, ILInstruction rhs, ICompilation compilation)
|
||||
{
|
||||
return new IfInstruction(lhs, rhs, new LdcI4(0));
|
||||
Debug.Assert(lhs.ResultType == StackType.I4);
|
||||
Debug.Assert(rhs.ResultType == StackType.I4);
|
||||
return new IfInstruction(lhs, rhs, new LdcI4(0), rhs.InferType(compilation));
|
||||
}
|
||||
|
||||
public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction? rhs)
|
||||
public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction rhs, ICompilation compilation)
|
||||
{
|
||||
return new IfInstruction(lhs, new LdcI4(1), rhs);
|
||||
return new IfInstruction(lhs, new LdcI4(1), rhs, rhs.InferType(compilation));
|
||||
}
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
Debug.Assert(condition.ResultType == StackType.I4);
|
||||
Debug.Assert(trueInst.ResultType == falseInst.ResultType
|
||||
|| trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable)
|
||||
Debug.Assert(trueInst.ResultType == this.ResultType
|
||||
|| trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
Debug.Assert(falseInst.ResultType == this.ResultType
|
||||
|| falseInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
if (trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable))
|
||||
return falseInst.ResultType;
|
||||
else
|
||||
return trueInst.ResultType;
|
||||
if (resultType != null)
|
||||
return resultType.GetStackType();
|
||||
return StackType.Void;
|
||||
}
|
||||
}
|
||||
|
||||
public override InstructionFlags DirectFlags {
|
||||
get {
|
||||
return InstructionFlags.ControlFlow;
|
||||
}
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
if (resultType != null)
|
||||
return resultType;
|
||||
return compilation.FindType(KnownTypeCode.Void);
|
||||
}
|
||||
public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow;
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
|
||||
namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of LdLen.
|
||||
/// </summary>
|
||||
public sealed partial class LdLen
|
||||
{
|
||||
readonly StackType resultType;
|
||||
@@ -39,6 +38,11 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return resultType; }
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
return compilation.FindType(resultType);
|
||||
}
|
||||
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace ICSharpCode.Decompiler.IL
|
||||
bool ILiftableInstruction.IsLifted => true;
|
||||
StackType ILiftableInstruction.UnderlyingResultType => StackType.I4;
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean));
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
@@ -43,6 +46,9 @@ namespace ICSharpCode.Decompiler.IL
|
||||
bool ILiftableInstruction.IsLifted => true;
|
||||
StackType ILiftableInstruction.UnderlyingResultType => StackType.I4;
|
||||
|
||||
public override StackType ResultType => StackType.O;
|
||||
public override IType InferType(ICompilation compilation) => NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean));
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
|
||||
@@ -56,28 +56,28 @@ namespace ICSharpCode.Decompiler.IL
|
||||
partial class NullCoalescingInstruction
|
||||
{
|
||||
public readonly NullCoalescingKind Kind;
|
||||
public IType Type { get; }
|
||||
public StackType UnderlyingResultType = StackType.O;
|
||||
|
||||
public NullCoalescingInstruction(NullCoalescingKind kind, ILInstruction valueInst, ILInstruction fallbackInst) : base(OpCode.NullCoalescingInstruction)
|
||||
public NullCoalescingInstruction(IType type, NullCoalescingKind kind, ILInstruction valueInst, ILInstruction fallbackInst) : base(OpCode.NullCoalescingInstruction)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Kind = kind;
|
||||
this.ValueInst = valueInst;
|
||||
this.FallbackInst = fallbackInst;
|
||||
Debug.Assert(type.GetStackType() == fallbackInst.ResultType || fallbackInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
}
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
base.CheckInvariant(phase, compilation);
|
||||
Debug.Assert(valueInst.ResultType == StackType.O); // lhs is reference type or nullable type
|
||||
Debug.Assert(fallbackInst.ResultType == StackType.O || Kind == NullCoalescingKind.NullableWithValueFallback);
|
||||
Debug.Assert(fallbackInst.ResultType == StackType.O || Kind == NullCoalescingKind.NullableWithValueFallback || fallbackInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
Debug.Assert(ResultType == UnderlyingResultType || Kind == NullCoalescingKind.Nullable);
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
return fallbackInst.ResultType;
|
||||
}
|
||||
}
|
||||
public override StackType ResultType => Type.GetStackType();
|
||||
public override IType InferType(ICompilation compilation) => Type;
|
||||
|
||||
public override InstructionFlags DirectFlags {
|
||||
get {
|
||||
|
||||
@@ -65,10 +65,12 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// RefOutput can only be used if RefInput is also used.
|
||||
/// </summary>
|
||||
public bool RefOutput { get => ResultType == StackType.Ref; }
|
||||
public IType Type { get; }
|
||||
|
||||
public NullableUnwrap(StackType unwrappedType, ILInstruction argument, bool refInput = false)
|
||||
public NullableUnwrap(IType type, StackType unwrappedType, ILInstruction argument, bool refInput = false)
|
||||
: base(OpCode.NullableUnwrap, argument)
|
||||
{
|
||||
this.Type = type;
|
||||
this.ResultType = unwrappedType;
|
||||
this.RefInput = refInput;
|
||||
if (unwrappedType == StackType.Ref)
|
||||
@@ -105,6 +107,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
|
||||
public override StackType ResultType { get; }
|
||||
public override IType InferType(ICompilation compilation) => Type;
|
||||
}
|
||||
|
||||
partial class NullableRewrap
|
||||
@@ -131,9 +134,10 @@ namespace ICSharpCode.Decompiler.IL
|
||||
if (Argument.ResultType == StackType.Void)
|
||||
return StackType.Void;
|
||||
else
|
||||
return StackType.O;
|
||||
return StackType.VT;
|
||||
}
|
||||
}
|
||||
public override IType InferType(ICompilation compilation) => Type;
|
||||
|
||||
internal override bool PrepareExtract(int childIndex, ExtractionContext ctx)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
|
||||
namespace ICSharpCode.Decompiler.IL
|
||||
{
|
||||
/// <summary>
|
||||
@@ -73,6 +75,11 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return ExpectedResultType; }
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
return compilation.FindType(ExpectedResultType);
|
||||
}
|
||||
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
@@ -101,6 +108,11 @@ namespace ICSharpCode.Decompiler.IL
|
||||
get { return ExpectedResultType; }
|
||||
}
|
||||
|
||||
public override IType InferType(ICompilation compilation)
|
||||
{
|
||||
return compilation.FindType(ExpectedResultType);
|
||||
}
|
||||
|
||||
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
|
||||
{
|
||||
WriteILRange(output, options);
|
||||
|
||||
@@ -143,11 +143,12 @@ namespace ICSharpCode.Decompiler.IL
|
||||
return clone;
|
||||
}
|
||||
|
||||
StackType resultType = StackType.Void;
|
||||
IType? resultType = null;
|
||||
|
||||
public override StackType ResultType => resultType;
|
||||
public override StackType ResultType => resultType?.GetStackType() ?? StackType.Void;
|
||||
public override IType InferType(ICompilation compilation) => resultType ?? compilation.FindType(KnownTypeCode.Void);
|
||||
|
||||
public void SetResultType(StackType resultType)
|
||||
public void SetResultType(IType resultType)
|
||||
{
|
||||
this.resultType = resultType;
|
||||
}
|
||||
@@ -166,7 +167,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
Debug.Assert(!section.Labels.IsEmpty || section.HasNullLabel);
|
||||
Debug.Assert(!section.Labels.Overlaps(sets));
|
||||
Debug.Assert(section.Body.ResultType == this.ResultType);
|
||||
Debug.Assert(section.Body.ResultType == this.ResultType || section.Body.HasDirectFlag(InstructionFlags.EndPointUnreachable));
|
||||
sets = sets.UnionWith(section.Labels);
|
||||
}
|
||||
Debug.Assert(sets.SetEquals(LongSet.Universe), "switch does not handle all possible cases");
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace ICSharpCode.Decompiler.IL
|
||||
this.TryBlock = tryBlock;
|
||||
}
|
||||
|
||||
public sealed override StackType ResultType => StackType.Void;
|
||||
public sealed override IType InferType(ICompilation compilation) => compilation.FindType(KnownTypeCode.Void);
|
||||
|
||||
ILInstruction tryBlock = null!;
|
||||
public ILInstruction TryBlock {
|
||||
get { return this.tryBlock; }
|
||||
@@ -81,10 +84,6 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get { return StackType.Void; }
|
||||
}
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
var flags = TryBlock.Flags;
|
||||
@@ -149,10 +148,6 @@ namespace ICSharpCode.Decompiler.IL
|
||||
Debug.Assert(this.IsDescendantOf(variable.Function!));
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get { return StackType.Void; }
|
||||
}
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
return filter.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.MayWriteLocals;
|
||||
@@ -227,12 +222,6 @@ namespace ICSharpCode.Decompiler.IL
|
||||
finallyBlock.WriteTo(output, options);
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
return TryBlock.ResultType;
|
||||
}
|
||||
}
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
// if the endpoint of either the try or the finally is unreachable, the endpoint of the try-finally will be unreachable
|
||||
@@ -324,10 +313,6 @@ namespace ICSharpCode.Decompiler.IL
|
||||
faultBlock.WriteTo(output, options);
|
||||
}
|
||||
|
||||
public override StackType ResultType {
|
||||
get { return TryBlock.ResultType; }
|
||||
}
|
||||
|
||||
protected override InstructionFlags ComputeFlags()
|
||||
{
|
||||
// The endpoint of the try-fault is unreachable iff the try endpoint is unreachable
|
||||
@@ -386,9 +371,4 @@ namespace ICSharpCode.Decompiler.IL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Throw
|
||||
{
|
||||
internal StackType resultType = StackType.Void;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,8 @@ namespace ICSharpCode.Decompiler.IL
|
||||
public bool IsLifted { get; }
|
||||
public StackType UnderlyingResultType { get; }
|
||||
|
||||
public override StackType ResultType {
|
||||
get {
|
||||
return Argument.ResultType;
|
||||
}
|
||||
}
|
||||
public override StackType ResultType => Argument.ResultType;
|
||||
public override IType InferType(ICompilation compilation) => Argument.InferType(compilation);
|
||||
|
||||
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
|
||||
{
|
||||
|
||||
@@ -67,9 +67,17 @@ namespace ICSharpCode.Decompiler.IL
|
||||
F8,
|
||||
/// <summary>Another stack type. Includes objects, value types, ...</summary>
|
||||
O,
|
||||
/// <summary>A managed pointer</summary>
|
||||
// TODO: delete O and turn Obj/VT into separate enumerators.
|
||||
/// <summary>Reference type: class type, boxed value type, etc.</summary>
|
||||
Obj = O,
|
||||
/// <summary>
|
||||
/// A value type other than the primitive types listed above.
|
||||
/// This includes unconstrained generic types which might be value types at runtime.
|
||||
/// </summary>
|
||||
VT = O,
|
||||
/// <summary>A managed pointer (C# `ref T`, C++/CLI `interior_ptr<T>`)</summary>
|
||||
Ref,
|
||||
/// <summary>Represents the lack of a stack slot</summary>
|
||||
Void
|
||||
Void,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// leave (elseValue)
|
||||
// =>
|
||||
// leave (if (cond) value else elseValue)
|
||||
IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leaveElse.Value);
|
||||
IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leaveElse.Value, leave.TargetContainer.ExpectedResultType);
|
||||
value.AddILRange(ifInst);
|
||||
Leave combinedLeave = new Leave(leave.TargetContainer, value);
|
||||
combinedLeave.AddILRange(leaveElse);
|
||||
|
||||
@@ -1147,7 +1147,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
var receiver = nested.Receiver!;
|
||||
match.SubPatterns.Add(BuildPatternMatch(nested, receiver,
|
||||
new DeconstructResultInstruction(i, receiver.StackType, new LdLoc(matchVariable))));
|
||||
new DeconstructResultInstruction(i, receiver.Type, receiver.StackType, new LdLoc(matchVariable))));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1156,7 +1156,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
match.SubPatterns.Add(
|
||||
new MatchInstruction(
|
||||
result,
|
||||
new DeconstructResultInstruction(i, result.StackType, new LdLoc(matchVariable))
|
||||
new DeconstructResultInstruction(i, result.Type, result.StackType, new LdLoc(matchVariable))
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1188,7 +1188,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
if (TupleType.GetTupleElementTypes(nested.Variable.Type).IsDefaultOrEmpty)
|
||||
nested.Variable.Type = nested.Type;
|
||||
match.SubPatterns.Add(BuildTuplePatternMatch(nested, nested.Variable,
|
||||
new DeconstructResultInstruction(i, nested.Variable.StackType, new LdLoc(matchVariable))));
|
||||
new DeconstructResultInstruction(i, node.Type.ElementTypes[i], nested.Variable.StackType, new LdLoc(matchVariable))));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1207,7 +1207,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
match.SubPatterns.Add(
|
||||
new MatchInstruction(
|
||||
result,
|
||||
new DeconstructResultInstruction(i, result.StackType, new LdLoc(matchVariable))
|
||||
new DeconstructResultInstruction(i, node.Type.ElementTypes[i], result.StackType, new LdLoc(matchVariable))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
var falseStore = new StLoc(v, falseValue).WithILRange(falseValue);
|
||||
var trueBlock = new Block { Instructions = { trueStore } }.WithILRange(trueStore);
|
||||
var falseBlock = new Block { Instructions = { falseStore } }.WithILRange(falseStore);
|
||||
var expanded = new IfInstruction(condition, trueBlock, falseBlock);
|
||||
var expanded = new IfInstruction(condition, trueBlock, falseBlock, context.TypeSystem.FindType(KnownTypeCode.Void));
|
||||
expanded.AddILRange(ifInst);
|
||||
expanded.AddILRange(stloc);
|
||||
stloc.ReplaceWith(expanded);
|
||||
|
||||
@@ -294,7 +294,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
context.Step("call Nullable{T}.GetValueOrDefault(a, b) -> a ?? b", inst);
|
||||
var ldObj = new LdObj(nullableValue, inst.Method.DeclaringType);
|
||||
var replacement = new NullCoalescingInstruction(NullCoalescingKind.NullableWithValueFallback, ldObj, fallback) {
|
||||
var replacement = new NullCoalescingInstruction(
|
||||
NullableType.GetUnderlyingType(inst.Method.DeclaringType),
|
||||
NullCoalescingKind.NullableWithValueFallback, ldObj, fallback) {
|
||||
UnderlyingResultType = fallback.ResultType
|
||||
};
|
||||
inst.ReplaceWith(replacement.WithILRange(inst));
|
||||
@@ -603,7 +605,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2))
|
||||
{
|
||||
context.Step("conditional operator", inst);
|
||||
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1);
|
||||
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1, v.Type);
|
||||
newIf.AddILRange(inst);
|
||||
var stLoc = new StLoc(v, newIf);
|
||||
inst.ReplaceWith(stLoc);
|
||||
@@ -621,7 +623,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
Debug.Assert(container.Kind == ContainerKind.Switch);
|
||||
Debug.Assert(container.ResultType == StackType.Void);
|
||||
var defaultSection = switchInst.GetDefaultSection();
|
||||
StackType resultType = StackType.Void;
|
||||
BlockContainer leaveTarget = null;
|
||||
ILVariable resultVariable = null;
|
||||
foreach (var section in switchInst.Sections)
|
||||
@@ -650,7 +651,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
return;
|
||||
leaveTarget ??= leave.TargetContainer;
|
||||
Debug.Assert(leaveTarget == leave.TargetContainer);
|
||||
resultType = leave.Value.ResultType;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -666,7 +666,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
resultVariable ??= v;
|
||||
if (resultVariable != v)
|
||||
return;
|
||||
resultType = resultVariable.StackType;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -676,8 +675,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// Exactly one of resultVariable/leaveTarget must be null
|
||||
if ((resultVariable == null) == (leaveTarget == null))
|
||||
return;
|
||||
IType resultType = resultVariable?.Type ?? leaveTarget?.ExpectedResultType;
|
||||
// C# has no ref-returning switch expression: an arm cannot be `0 => ref x`.
|
||||
if (resultType == StackType.Ref)
|
||||
if (resultType.Kind == TypeKind.ByReference)
|
||||
return;
|
||||
if (switchInst.Value is StringToInt str2int)
|
||||
{
|
||||
@@ -699,7 +699,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
if (block.Instructions[0] is Throw t)
|
||||
{
|
||||
t.resultType = resultType;
|
||||
section.Body = t;
|
||||
}
|
||||
else if (block.Instructions[0] is Leave leave)
|
||||
@@ -864,8 +863,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
}
|
||||
break;
|
||||
case BinaryNumericOperator.BitAnd:
|
||||
if (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
|
||||
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean))
|
||||
{
|
||||
IType leftType = inst.Left.InferType(context.TypeSystem);
|
||||
IType rightType = inst.Right.InferType(context.TypeSystem);
|
||||
DetectImprovedTypeForForBitOp(inst, leftType, rightType);
|
||||
if (leftType.IsKnownType(KnownTypeCode.Boolean)
|
||||
&& rightType.IsKnownType(KnownTypeCode.Boolean))
|
||||
{
|
||||
if (new NullableLiftingTransform(context).Run(inst))
|
||||
{
|
||||
@@ -873,6 +876,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BinaryNumericOperator.BitOr:
|
||||
case BinaryNumericOperator.BitXor:
|
||||
{
|
||||
IType leftType = inst.Left.InferType(context.TypeSystem);
|
||||
IType rightType = inst.Right.InferType(context.TypeSystem);
|
||||
DetectImprovedTypeForForBitOp(inst, leftType, rightType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MatchExpectedShiftSize(ILInstruction rhs)
|
||||
@@ -895,6 +907,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
}
|
||||
}
|
||||
|
||||
// Given bit.or(a, b), promotes the "known to be bool/short" information from the operands to bit.or
|
||||
void DetectImprovedTypeForForBitOp(BinaryNumericInstruction inst, IType leftType, IType rightType)
|
||||
{
|
||||
if (leftType.Equals(rightType) && (leftType.IsCSharpPrimitiveIntegerType() || leftType.IsCSharpNativeIntegerType() || leftType.IsKnownType(KnownTypeCode.Boolean)))
|
||||
{
|
||||
if (!leftType.Equals(inst.CSharpResultType))
|
||||
{
|
||||
context.Step("DetectImprovedTypeForForBitOp", inst);
|
||||
inst.CSharpResultType = leftType;
|
||||
context.EndStep(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected internal override void VisitTryCatchHandler(TryCatchHandler inst)
|
||||
{
|
||||
base.VisitTryCatchHandler(inst);
|
||||
|
||||
@@ -223,11 +223,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
if (swap)
|
||||
{
|
||||
condition.Condition = IfInstruction.LogicAnd(Comp.LogicNot(inst.Condition), condition.Condition);
|
||||
condition.Condition = IfInstruction.LogicAnd(Comp.LogicNot(inst.Condition), condition.Condition, context.TypeSystem);
|
||||
}
|
||||
else
|
||||
{
|
||||
condition.Condition = IfInstruction.LogicAnd(inst.Condition, condition.Condition);
|
||||
condition.Condition = IfInstruction.LogicAnd(inst.Condition, condition.Condition, context.TypeSystem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,11 +433,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
break;
|
||||
if (forCondition == null)
|
||||
{
|
||||
forCondition = new IfInstruction(condition, whileCondition.TrueInst, whileCondition.FalseInst);
|
||||
forCondition = new IfInstruction(condition, whileCondition.TrueInst, whileCondition.FalseInst,
|
||||
whileCondition.InferType(context.TypeSystem));
|
||||
}
|
||||
else
|
||||
{
|
||||
forCondition.Condition = IfInstruction.LogicAnd(forCondition.Condition, condition);
|
||||
forCondition.Condition = IfInstruction.LogicAnd(forCondition.Condition, condition, context.TypeSystem);
|
||||
}
|
||||
numberOfConditions++;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue))
|
||||
{
|
||||
context.Step("NullCoalescingTransform: simple (reference types)", stloc);
|
||||
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
|
||||
stloc.Value = new NullCoalescingInstruction(stloc.Variable.Type, NullCoalescingKind.Ref, stloc.Value, fallbackValue);
|
||||
block.Instructions.RemoveAt(pos + 1); // remove if instruction
|
||||
ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context);
|
||||
return true;
|
||||
@@ -85,7 +85,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
&& useOfTemporary.MatchLdLoc(temporary))
|
||||
{
|
||||
context.Step("NullCoalescingTransform: with temporary variable (reference types)", stloc);
|
||||
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
|
||||
stloc.Value = new NullCoalescingInstruction(stloc.Variable.Type, NullCoalescingKind.Ref, stloc.Value, fallbackValue);
|
||||
block.Instructions.RemoveAt(pos + 1); // remove if instruction
|
||||
ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context);
|
||||
return true;
|
||||
@@ -99,8 +99,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
if (context.Settings.ThrowExpressions && trueInst is Throw throwInst)
|
||||
{
|
||||
context.Step("NullCoalescingTransform (reference types + throw expression)", stloc);
|
||||
throwInst.resultType = StackType.O;
|
||||
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, throwInst);
|
||||
stloc.Value = new NullCoalescingInstruction(stloc.Variable.Type, NullCoalescingKind.Ref, stloc.Value, throwInst);
|
||||
block.Instructions.RemoveAt(pos + 1); // remove if instruction
|
||||
ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context);
|
||||
return true;
|
||||
@@ -156,7 +155,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
var paramLoadChildIndex = paramLoad.ChildIndex;
|
||||
var throwInstParent = throwInst.Parent;
|
||||
var throwInstChildIndex = throwInst.ChildIndex;
|
||||
var expressionWithThrow = new NullCoalescingInstruction(NullCoalescingKind.Ref, paramLoad, throwInst);
|
||||
var expressionWithThrow = new NullCoalescingInstruction(paramLoad.Variable.Type, NullCoalescingKind.Ref, paramLoad, throwInst);
|
||||
var result = ILInlining.FindLoadInNext(block.Instructions[pos + 1], paramLoad.Variable, expressionWithThrow,
|
||||
InliningOptions.None);
|
||||
if (result.Type != ILInlining.FindResultType.Found || result.LoadInst is not LdLoc firstUse)
|
||||
@@ -173,7 +172,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
|
||||
var temp = function.RegisterVariable(VariableKind.StackSlot, paramLoad.Variable.Type);
|
||||
firstUse.Variable = temp;
|
||||
throwInst.resultType = StackType.O;
|
||||
var stloc = new StLoc(temp, expressionWithThrow);
|
||||
stloc.AddILRange(guard);
|
||||
block.Instructions[pos] = stloc;
|
||||
@@ -230,18 +228,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
return false;
|
||||
var throwInstParent = throwInst.Parent;
|
||||
var throwInstChildIndex = throwInst.ChildIndex;
|
||||
var underlyingType = NullableType.GetUnderlyingType(call.Method.DeclaringType);
|
||||
var nullCoalescingWithThrow = new NullCoalescingInstruction(
|
||||
underlyingType,
|
||||
NullCoalescingKind.NullableWithValueFallback,
|
||||
stloc.Value,
|
||||
throwInst);
|
||||
var resultType = NullableType.GetUnderlyingType(call.Method.DeclaringType).GetStackType();
|
||||
var resultType = underlyingType.GetStackType();
|
||||
nullCoalescingWithThrow.UnderlyingResultType = resultType;
|
||||
var result = ILInlining.FindLoadInNext(block.Instructions[pos + 2], v, nullCoalescingWithThrow, InliningOptions.None);
|
||||
if (result.Type == ILInlining.FindResultType.Found
|
||||
&& NullableLiftingTransform.MatchGetValueOrDefault(result.LoadInst.Parent, v))
|
||||
{
|
||||
context.Step("NullCoalescingTransform (value types + throw expression)", stloc);
|
||||
throwInst.resultType = resultType;
|
||||
result.LoadInst.Parent.ReplaceWith(nullCoalescingWithThrow);
|
||||
block.Instructions.RemoveRange(pos, 2); // remove store(s) and if instruction
|
||||
return true;
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
nonNullInst = arg;
|
||||
removedRewrapOrNullableCtor = true;
|
||||
}
|
||||
else if (nonNullInst.MatchNullableRewrap(out arg))
|
||||
else if (nonNullInst.MatchNullableRewrap(out arg, out _))
|
||||
{
|
||||
nonNullInst = arg;
|
||||
removedRewrapOrNullableCtor = true;
|
||||
@@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// testedVar != null ? testedVar.AccessChain : null
|
||||
// => testedVar?.AccessChain
|
||||
IntroduceUnwrap(testedVar, varLoad, mode);
|
||||
var result = new NullableRewrap(nonNullInst);
|
||||
var result = new NullableRewrap(nonNullInst, returnType);
|
||||
context.EndStep(result);
|
||||
return result;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// testedVar != null ? testedVar.AccessChain : default(T?)
|
||||
// => testedVar?.AccessChain
|
||||
IntroduceUnwrap(testedVar, varLoad, mode);
|
||||
var result = new NullableRewrap(nonNullInst);
|
||||
var result = new NullableRewrap(nonNullInst, type);
|
||||
context.EndStep(result);
|
||||
return result;
|
||||
}
|
||||
@@ -154,8 +154,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// Span<T> is excluded because it cannot be wrapped in Nullable<T> for the ?. / ?? form)
|
||||
IntroduceUnwrap(testedVar, varLoad, mode);
|
||||
var result = new NullCoalescingInstruction(
|
||||
nullInst.InferType(context.TypeSystem),
|
||||
NullCoalescingKind.NullableWithValueFallback,
|
||||
new NullableRewrap(nonNullInst),
|
||||
new NullableRewrap(nonNullInst, NullableType.Create(context.TypeSystem, returnType)),
|
||||
nullInst
|
||||
) {
|
||||
UnderlyingResultType = nullInst.ResultType
|
||||
@@ -231,7 +232,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
if (body == null || body.Instructions.Count != 1)
|
||||
return;
|
||||
var bodyInst = body.Instructions[0];
|
||||
if (bodyInst.MatchNullableRewrap(out var arg))
|
||||
if (bodyInst.MatchNullableRewrap(out var arg, out _))
|
||||
{
|
||||
bodyInst = arg;
|
||||
}
|
||||
@@ -241,9 +242,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// if (testedVar != null) { testedVar.AccessChain(); }
|
||||
// => testedVar?.AccessChain();
|
||||
IntroduceUnwrap(testedVar, varLoad, mode);
|
||||
var replacement = new NullableRewrap(
|
||||
bodyInst
|
||||
).WithILRange(ifInst);
|
||||
var returnType = bodyInst.InferType(context.TypeSystem);
|
||||
if (returnType.Kind != TypeKind.Void)
|
||||
{
|
||||
returnType = NullableType.Create(context.TypeSystem, returnType);
|
||||
}
|
||||
var replacement = new NullableRewrap(bodyInst, returnType).WithILRange(ifInst);
|
||||
ifInst.ReplaceWith(replacement);
|
||||
context.EndStep(replacement);
|
||||
}
|
||||
@@ -404,17 +408,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
case Mode.ReferenceType:
|
||||
case Mode.UnconstrainedType:
|
||||
// Wrap varLoad in nullable.unwrap:
|
||||
replacement = new NullableUnwrap(varLoad.ResultType, varLoad, refInput: varLoad.ResultType == StackType.Ref);
|
||||
replacement = new NullableUnwrap(varLoad.InferType(context.TypeSystem), varLoad.ResultType, varLoad, refInput: varLoad.ResultType == StackType.Ref);
|
||||
break;
|
||||
case Mode.NullableByValue:
|
||||
Debug.Assert(NullableLiftingTransform.MatchGetValueOrDefault(varLoad, testedVar));
|
||||
replacement = new NullableUnwrap(
|
||||
varLoad.InferType(context.TypeSystem),
|
||||
varLoad.ResultType,
|
||||
new LdLoc(testedVar).WithILRange(varLoad.Children[0])
|
||||
).WithILRange(varLoad);
|
||||
break;
|
||||
case Mode.NullableByReference:
|
||||
replacement = new NullableUnwrap(
|
||||
varLoad.InferType(context.TypeSystem),
|
||||
varLoad.ResultType,
|
||||
new LdLoc(testedVar).WithILRange(varLoad.Children[0]),
|
||||
refInput: true
|
||||
|
||||
@@ -771,7 +771,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
// v.HasValue ? ldloc v : fallback
|
||||
// => v ?? fallback
|
||||
context.Step("v.HasValue ? v : fallback => v ?? fallback", trueInst);
|
||||
return new NullCoalescingInstruction(NullCoalescingKind.Nullable, trueInst, falseInst) {
|
||||
return new NullCoalescingInstruction(nullableVars[0].Type, NullCoalescingKind.Nullable, trueInst, falseInst) {
|
||||
UnderlyingResultType = NullableType.GetUnderlyingType(nullableVars[0].Type).GetStackType()
|
||||
};
|
||||
}
|
||||
@@ -822,7 +822,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
}
|
||||
if (isNullCoalescingWithNonNullableFallback)
|
||||
{
|
||||
lifted = new NullCoalescingInstruction(NullCoalescingKind.NullableWithValueFallback, lifted, falseInst) {
|
||||
lifted = new NullCoalescingInstruction(utype, NullCoalescingKind.NullableWithValueFallback, lifted, falseInst) {
|
||||
UnderlyingResultType = exprToLift.ResultType
|
||||
};
|
||||
}
|
||||
@@ -830,7 +830,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
// Normal lifting, but the falseInst isn't `default(utype?)`
|
||||
// => use the `??` operator to provide the fallback value.
|
||||
lifted = new NullCoalescingInstruction(NullCoalescingKind.Nullable, lifted, falseInst) {
|
||||
lifted = new NullCoalescingInstruction(NullableType.Create(context.TypeSystem, utype), NullCoalescingKind.Nullable, lifted, falseInst) {
|
||||
UnderlyingResultType = exprToLift.ResultType
|
||||
};
|
||||
}
|
||||
|
||||
@@ -80,30 +80,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to infer IType of stack slots that are of StackType.Ref:
|
||||
foreach (var v in function.Variables)
|
||||
{
|
||||
if (v.Kind == VariableKind.StackSlot && v.StackType == StackType.Ref && v.AddressCount == 0)
|
||||
{
|
||||
IType newType = null;
|
||||
// Multiple store are possible in case of (c ? ref a : ref b) += 1, for example.
|
||||
foreach (var stloc in v.StoreInstructions.OfType<StLoc>())
|
||||
{
|
||||
var inferredType = stloc.Value.InferType(context.TypeSystem);
|
||||
// cancel, if types of values do not match exactly
|
||||
if (newType != null && !newType.Equals(inferredType))
|
||||
{
|
||||
newType = SpecialType.UnknownType;
|
||||
break;
|
||||
}
|
||||
newType = inferredType;
|
||||
}
|
||||
// Only overwrite existing type, if a "better" type was found.
|
||||
if (newType != null && newType != SpecialType.UnknownType)
|
||||
v.Type = newType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ResetUsesInitialValueFlag(ILFunction function, ILTransformContext context)
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
lambdaStack.Push(function);
|
||||
var convertedBody = bodyInstruction();
|
||||
lambdaStack.Pop();
|
||||
container.ExpectedResultType = convertedBody.ResultType;
|
||||
container.ExpectedResultType = type;
|
||||
container.Blocks.Add(new Block() { Instructions = { new Leave(container, convertedBody) } });
|
||||
// Replace all other usages of the parameter variable
|
||||
foreach (var mapping in parameterMapping)
|
||||
@@ -752,7 +752,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
targetType = fallbackInstType;
|
||||
}
|
||||
return (() => new NullCoalescingInstruction(kind, trueInst(), fallbackInst()) {
|
||||
return (() => new NullCoalescingInstruction(targetType, kind, trueInst(), fallbackInst()) {
|
||||
UnderlyingResultType = trueInstTypeNonNullable.GetStackType()
|
||||
}, targetType);
|
||||
}
|
||||
@@ -820,7 +820,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
return (null, SpecialType.UnknownType);
|
||||
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(trueInstType, falseInstType))
|
||||
return (null, SpecialType.UnknownType);
|
||||
return (() => new IfInstruction(condition(), trueInst(), falseInst()), trueInstType);
|
||||
return (() => new IfInstruction(condition(), trueInst(), falseInst(), trueInstType), trueInstType);
|
||||
}
|
||||
|
||||
(Func<ILInstruction>, IType) ConvertConstant(CallInstruction invocation)
|
||||
@@ -1008,7 +1008,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
{
|
||||
case 2:
|
||||
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean);
|
||||
return (() => and ? IfInstruction.LogicAnd(left(), right()) : IfInstruction.LogicOr(left(), right()), resultType);
|
||||
return (() => and ? IfInstruction.LogicAnd(left(), right(), context.TypeSystem) : IfInstruction.LogicOr(left(), right(), context.TypeSystem), resultType);
|
||||
case 3:
|
||||
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method))
|
||||
return (null, SpecialType.UnknownType);
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
||||
return false;
|
||||
disposeInvocation = disposeBlock.Instructions[0];
|
||||
}
|
||||
else if (checkInst.MatchNullableRewrap(out disposeInst))
|
||||
else if (checkInst.MatchNullableRewrap(out disposeInst, out _))
|
||||
{
|
||||
disposeInvocation = disposeInst;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
|
||||
/// <summary><c>System.Index</c></summary>
|
||||
Index,
|
||||
/// <summary><c>System.Range</c></summary>
|
||||
Range
|
||||
Range,
|
||||
/// <summary><c>System.RuntimeArgumentHandle</c></summary>
|
||||
RuntimeArgumentHandle,
|
||||
/// <summary><c>System.RuntimeTypeHandle</c></summary>
|
||||
RuntimeTypeHandle,
|
||||
/// <summary><c>System.RuntimeFieldHandle</c></summary>
|
||||
RuntimeFieldHandle,
|
||||
/// <summary><c>System.RuntimeMethodHandle</c></summary>
|
||||
RuntimeMethodHandle,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -163,7 +171,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
|
||||
[Serializable]
|
||||
public sealed class KnownTypeReference : ITypeReference
|
||||
{
|
||||
internal const int KnownTypeCodeCount = (int)KnownTypeCode.Range + 1;
|
||||
internal const int KnownTypeCodeCount = (int)KnownTypeCode.RuntimeMethodHandle + 1;
|
||||
|
||||
static readonly KnownTypeReference?[] knownTypeReferences = new KnownTypeReference?[KnownTypeCodeCount] {
|
||||
null, // None
|
||||
@@ -229,6 +237,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
|
||||
new KnownTypeReference(KnownTypeCode.IAsyncEnumeratorOfT, TypeKind.Interface, "System.Collections.Generic", "IAsyncEnumerator", 1),
|
||||
new KnownTypeReference(KnownTypeCode.Index, TypeKind.Struct, "System", "Index", 0),
|
||||
new KnownTypeReference(KnownTypeCode.Range, TypeKind.Struct, "System", "Range", 0),
|
||||
new KnownTypeReference(KnownTypeCode.RuntimeArgumentHandle, TypeKind.Struct, "System", "RuntimeArgumentHandle", 0),
|
||||
new KnownTypeReference(KnownTypeCode.RuntimeTypeHandle, TypeKind.Struct, "System", "RuntimeTypeHandle", 0),
|
||||
new KnownTypeReference(KnownTypeCode.RuntimeFieldHandle, TypeKind.Struct, "System", "RuntimeFieldHandle", 0),
|
||||
new KnownTypeReference(KnownTypeCode.RuntimeMethodHandle, TypeKind.Struct, "System", "RuntimeMethodHandle", 0),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
|
||||
case StackType.Unknown:
|
||||
return SpecialType.UnknownType;
|
||||
case StackType.Ref:
|
||||
return new ByReferenceType(SpecialType.UnknownType);
|
||||
return new ByReferenceType(compilation.FindType(KnownTypeCode.Byte));
|
||||
default:
|
||||
return compilation.FindType(stackType.ToKnownTypeCode(sign));
|
||||
}
|
||||
|
||||
@@ -310,8 +310,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
|
||||
case KnownTypeCode.IntPtr:
|
||||
case KnownTypeCode.UIntPtr:
|
||||
case KnownTypeCode.TypedReference:
|
||||
//case KnownTypeCode.ArgIterator:
|
||||
//case KnownTypeCode.RuntimeArgumentHandle:
|
||||
//case KnownTypeCode.ArgIterator:
|
||||
case KnownTypeCode.RuntimeArgumentHandle:
|
||||
return true;
|
||||
}
|
||||
if (type.Kind == TypeKind.Struct)
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace ICSharpCode.ILSpy.AppEnv
|
||||
public override void Fail(string? message)
|
||||
=> Fail(message, null);
|
||||
|
||||
[DebuggerStepThrough] // make the 'Debug' button jump directly to the failing assertion, not here.
|
||||
public override void Fail(string? message, string? detailMessage)
|
||||
{
|
||||
Debug.WriteLine("Assertion failed: " + message);
|
||||
|
||||
Reference in New Issue
Block a user