// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.ILAst
{
///
/// Performs inlining transformations.
///
public class ILInlining
{
///
/// Inlines instructions before pos into block.Body[pos].
///
/// The number of instructions that were inlined.
public static int InlineInto(ILBlock block, int pos, ILBlock method)
{
int count = 0;
while (--pos >= 0) {
ILExpression expr = block.Body[pos] as ILExpression;
if (expr == null || expr.Code != ILCode.Stloc)
break;
if (InlineIfPossible(block, pos, method))
count++;
else
break;
}
return count;
}
///
/// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
///
public static bool InlineIfPossible(ILBlock block, int pos, ILBlock method)
{
if (InlineIfPossible((ILExpression)block.Body[pos], block.Body.ElementAtOrDefault(pos+1), method)) {
block.Body.RemoveAt(pos);
return true;
}
return false;
}
///
/// Inlines 'expr' into 'next', if possible.
///
public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method)
{
if (expr.Code != ILCode.Stloc)
throw new ArgumentException("expr must be stloc");
// ensure the variable is accessed only a single time
if (method.GetSelfAndChildrenRecursive().Count(e => e != expr && e.Operand == expr.Operand) != 1)
return false;
ILExpression parent;
int pos;
if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) {
parent.Arguments[pos] = expr.Arguments[0];
return true;
}
return false;
}
///
/// Finds the position to inline to.
///
/// true = found; false = cannot continue search; null = not found
static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
{
parent = null;
pos = 0;
if (expr == null)
return false;
for (int i = 0; i < expr.Arguments.Count; i++) {
ILExpression arg = expr.Arguments[i];
if (arg.Code == ILCode.Ldloc && arg.Operand == v) {
parent = expr;
pos = i;
return true;
}
bool? r = FindLoadInNext(arg, v, out parent, out pos);
if (r != null)
return r;
}
return IsWithoutSideEffects(expr.Code) ? (bool?)null : false;
}
static bool IsWithoutSideEffects(ILCode code)
{
return code == ILCode.Ldloc;
}
}
}