|
|
|
@ -183,31 +183,74 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -183,31 +183,74 @@ namespace ICSharpCode.Decompiler.ILAst
|
|
|
|
|
ILExpression parent; |
|
|
|
|
int pos; |
|
|
|
|
if (FindLoadInNext(next as ILExpression, v, inlinedExpression, out parent, out pos) == true) { |
|
|
|
|
if (ldloc == 0) |
|
|
|
|
{ |
|
|
|
|
if (ldloc == 0) { |
|
|
|
|
if (!IsGeneratedValueTypeTemporary((ILExpression)next, parent, pos, v)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
else if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression)) |
|
|
|
|
} else { |
|
|
|
|
if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Assign the ranges of the ldloc instruction:
|
|
|
|
|
inlinedExpression.ILRanges.AddRange(parent.Arguments[pos].ILRanges); |
|
|
|
|
|
|
|
|
|
if (ldloc == 0) { |
|
|
|
|
// it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof' so that the types
|
|
|
|
|
// comes out correctly
|
|
|
|
|
parent.Arguments[pos] = new ILExpression(ILCode.AddressOf, null, inlinedExpression); |
|
|
|
|
} else { |
|
|
|
|
parent.Arguments[pos] = inlinedExpression; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Is this a temporary variable generated by the C# compiler for instance method calls on immutable value type values
|
|
|
|
|
/// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="next">The next top-level expression</param>
|
|
|
|
|
/// <param name="parent">The direct parent of the load within 'next'</param>
|
|
|
|
|
/// <param name="pos">Index of the load within 'parent'</param>
|
|
|
|
|
/// <param name="v">The variable being inlined.</param>
|
|
|
|
|
bool IsGeneratedValueTypeTemporary(ILExpression next, ILExpression parent, int pos, ILVariable v) |
|
|
|
|
{ |
|
|
|
|
return pos == 0 && v.Type != null && v.Type.IsValueType && next.Code == ILCode.Stloc |
|
|
|
|
&& (parent.Code == ILCode.Call || parent.Code == ILCode.Callvirt) && ((MethodReference)parent.Operand).HasThis; |
|
|
|
|
if (pos == 0 && v.Type != null && v.Type.IsValueType) { |
|
|
|
|
// inline the compiler-generated variable that are used when accessing a member on a value type:
|
|
|
|
|
switch (parent.Code) { |
|
|
|
|
case ILCode.Call: |
|
|
|
|
case ILCode.CallGetter: |
|
|
|
|
case ILCode.CallSetter: |
|
|
|
|
case ILCode.Callvirt: |
|
|
|
|
case ILCode.CallvirtGetter: |
|
|
|
|
case ILCode.CallvirtSetter: |
|
|
|
|
MethodReference mr = (MethodReference)parent.Operand; |
|
|
|
|
return mr.HasThis; |
|
|
|
|
case ILCode.Stfld: |
|
|
|
|
case ILCode.Ldfld: |
|
|
|
|
case ILCode.Ldflda: |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Determines whether a variable should be inlined in non-aggressive mode, even though it is not a generated variable.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="next">The next top-level expression</param>
|
|
|
|
|
/// <param name="parent">The direct parent of the load within 'next'</param>
|
|
|
|
|
bool NonAggressiveInlineInto(ILExpression next, ILExpression parent) |
|
|
|
|
{ |
|
|
|
|
switch (next.Code) { |
|
|
|
|
case ILCode.Ret: |
|
|
|
|
case ILCode.Brtrue: |
|
|
|
|
return parent == next; |
|
|
|
|
case ILCode.Switch: |
|
|
|
|
return parent == next || (parent.Code == ILCode.Sub && parent == next.Arguments[0]); |
|
|
|
|
default: |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool NonAggressiveInlineInto(ILExpression next, ILExpression parent, ILExpression inlinedExpression) |
|
|
|
|