Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debu…
Browse files Browse the repository at this point in the history
…gger
  • Loading branch information
eusebiu committed Mar 18, 2011
2 parents 24e63b6 + 6046fdc commit 0e1152b
Show file tree
Hide file tree
Showing 9 changed files with 497 additions and 509 deletions.
2 changes: 1 addition & 1 deletion ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs
Expand Up @@ -120,7 +120,7 @@ public void ComputeDominance(CancellationToken cancellationToken = default(Cance
b => b.Successors,
b => {
if (b != EntryPoint) {
ControlFlowNode newIdom = b.Predecessors.First(block => block.Visited);
ControlFlowNode newIdom = b.Predecessors.First(block => block.Visited && block != b);
// for all other predecessors p of b
foreach (ControlFlowNode p in b.Predecessors) {
if (p != b && p.ImmediateDominator != null) {
Expand Down
3 changes: 2 additions & 1 deletion ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
Expand Up @@ -18,7 +18,8 @@ public void RemoveGotos(ILBlock method)
foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) {
ILNode previousChild = null;
foreach (ILNode child in node.GetChildren()) {
Debug.Assert(!parent.ContainsKey(child));
if (parent.ContainsKey(child))
throw new Exception("The following expression is linked from several locations: " + child.ToString());
parent[child] = node;
if (previousChild != null)
nextSibling[previousChild] = child;
Expand Down
270 changes: 168 additions & 102 deletions ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

Large diffs are not rendered by default.

76 changes: 54 additions & 22 deletions ICSharpCode.Decompiler/ILAst/ILInlining.cs
Expand Up @@ -48,41 +48,66 @@ void AnalyzeMethod()
}
}

public void InlineAllVariables()
public bool InlineAllVariables()
{
bool modified = false;
ILInlining i = new ILInlining(method);
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>())
i.InlineAllInBlock(block);
modified |= i.InlineAllInBlock(block);
return modified;
}

public void InlineAllInBlock(ILBlock block)
public bool InlineAllInBlock(ILBlock block)
{
bool modified = false;
List<ILNode> body = block.Body;
for(int i = 0; i < body.Count - 1;) {
ILVariable locVar;
ILExpression expr;
if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(block, i, aggressive: false)) {
if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(block.Body, i, aggressive: false)) {
modified = true;
i = Math.Max(0, i - 1); // Go back one step
} else {
i++;
}
}
foreach(ILBasicBlock bb in body.OfType<ILBasicBlock>()) {
modified |= InlineAllInBasicBlock(bb);
}
return modified;
}

public bool InlineAllInBasicBlock(ILBasicBlock bb)
{
bool modified = false;
List<ILNode> body = bb.Body;
for(int i = 0; i < body.Count - 1;) {
ILVariable locVar;
ILExpression expr;
if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(bb.Body, i, aggressive: false)) {
modified = true;
i = Math.Max(0, i - 1); // Go back one step
} else {
i++;
}
}
return modified;
}

/// <summary>
/// Inlines instructions before pos into block.Body[pos].
/// </summary>
/// <returns>The number of instructions that were inlined.</returns>
public int InlineInto(ILBlock block, int pos, bool aggressive)
public int InlineInto(List<ILNode> body, int pos, bool aggressive)
{
if (pos >= block.Body.Count)
if (pos >= body.Count)
return 0;
int count = 0;
while (--pos >= 0) {
ILExpression expr = block.Body[pos] as ILExpression;
ILExpression expr = body[pos] as ILExpression;
if (expr == null || expr.Code != ILCode.Stloc)
break;
if (InlineOneIfPossible(block, pos, aggressive))
if (InlineOneIfPossible(body, pos, aggressive))
count++;
else
break;
Expand All @@ -97,10 +122,10 @@ public int InlineInto(ILBlock block, int pos, bool aggressive)
/// <remarks>
/// After the operation, pos will point to the new combined instruction.
/// </remarks>
public bool InlineIfPossible(ILBlock block, ref int pos)
public bool InlineIfPossible(List<ILNode> body, ref int pos)
{
if (InlineOneIfPossible(block, pos, true)) {
pos -= InlineInto(block, pos, false);
if (InlineOneIfPossible(body, pos, true)) {
pos -= InlineInto(body, pos, false);
return true;
}
return false;
Expand All @@ -109,28 +134,28 @@ public bool InlineIfPossible(ILBlock block, ref int pos)
/// <summary>
/// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
/// </summary>
public bool InlineOneIfPossible(ILBlock block, int pos, bool aggressive)
public bool InlineOneIfPossible(List<ILNode> body, int pos, bool aggressive)
{
ILVariable v;
ILExpression inlinedExpression;
if (block.Body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) {
if (InlineIfPossible(v, inlinedExpression, block.Body.ElementAtOrDefault(pos+1), aggressive)) {
if (body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) {
if (InlineIfPossible(v, inlinedExpression, body.ElementAtOrDefault(pos+1), aggressive)) {
// Assign the ranges of the stloc instruction:
inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges);
inlinedExpression.ILRanges.AddRange(((ILExpression)body[pos]).ILRanges);
// Remove the stloc instruction:
block.Body.RemoveAt(pos);
body.RemoveAt(pos);
return true;
} else if (numLdloc.GetOrDefault(v) == 0 && numLdloca.GetOrDefault(v) == 0) {
// The variable is never loaded
if (inlinedExpression.HasNoSideEffects()) {
// Remove completely
block.Body.RemoveAt(pos);
body.RemoveAt(pos);
return true;
} else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) {
// Assign the ranges of the stloc instruction:
inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges);
inlinedExpression.ILRanges.AddRange(((ILExpression)body[pos]).ILRanges);
// Remove the stloc, but keep the inner expression
block.Body[pos] = inlinedExpression;
body[pos] = inlinedExpression;
return true;
}
}
Expand All @@ -155,7 +180,7 @@ bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next,
ILExpression parent;
int pos;
if (FindLoadInNext(next as ILExpression, v, inlinedExpression, out parent, out pos) == true) {
if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent))
if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression))
return false;

// Assign the ranges of the ldloc instruction:
Expand All @@ -168,8 +193,15 @@ bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next,
return false;
}

bool NonAggressiveInlineInto(ILExpression next, ILExpression parent)
bool NonAggressiveInlineInto(ILExpression next, ILExpression parent, ILExpression inlinedExpression)
{
switch (inlinedExpression.Code) {
case ILCode.InitArray:
case ILCode.InitCollection:
case ILCode.DefaultValue:
return true;
}

switch (next.Code) {
case ILCode.Ret:
return parent.Code == ILCode.Ret;
Expand Down Expand Up @@ -300,7 +332,7 @@ public void CopyPropagation()
// if we un-inlined stuff; we need to update the usage counters
AnalyzeMethod();
}
InlineInto(block, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i]
InlineInto(block.Body, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i]
i -= uninlinedArgs.Length + 1;
}
}
Expand Down
149 changes: 61 additions & 88 deletions ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
Expand Up @@ -12,25 +12,16 @@ namespace ICSharpCode.Decompiler.ILAst
/// <summary>
/// IL AST transformation that introduces array, object and collection initializers.
/// </summary>
public class InitializerPeepholeTransforms
public class Initializers
{
readonly ILBlock method;

#region Array Initializers

public InitializerPeepholeTransforms(ILBlock method)
{
this.method = method;
}

public void TransformArrayInitializers(ILBlock block, ref int i)
public static bool TransformArrayInitializers(List<ILNode> body, ILExpression expr, int pos)
{
ILVariable v, v2, v3;
ILExpression newarrExpr;
TypeReference arrayType;
ILExpression lengthExpr;
int arrayLength;
if (block.Body[i].Match(ILCode.Stloc, out v, out newarrExpr) &&
if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
newarrExpr.Match(ILCode.Newarr, out arrayType, out lengthExpr) &&
lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
arrayLength > 0)
Expand All @@ -39,7 +30,7 @@ public void TransformArrayInitializers(ILBlock block, ref int i)
ILExpression methodArg1;
ILExpression methodArg2;
FieldDefinition field;
if (block.Body.ElementAtOrDefault(i + 1).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
if (body.ElementAtOrDefault(pos + 1).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
methodRef.Name == "InitializeArray" &&
methodArg1.Match(ILCode.Ldloc, out v2) &&
Expand All @@ -49,59 +40,41 @@ public void TransformArrayInitializers(ILBlock block, ref int i)
{
ILExpression[] newArr = new ILExpression[arrayLength];
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType), field.InitialValue, newArr)) {
block.Body[i] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
block.Body.RemoveAt(i + 1);
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1;
return;
body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
body.RemoveAt(pos + 1);
return true;
}
}

const int maxConsecutiveDefaultValueExpressions = 10;
List<ILExpression> operands = new List<ILExpression>();
int numberOfInstructionsToRemove = 0;
for (int j = i + 1; j < block.Body.Count; j++) {
ILExpression expr = block.Body[j] as ILExpression;
int pos;
if (expr != null &&
IsStoreToArray(expr.Code) &&
expr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
for (int j = pos + 1; j < body.Count; j++) {
ILExpression nextExpr = body[j] as ILExpression;
int arrayPos;
if (nextExpr != null &&
nextExpr.Code.IsStoreToArray() &&
nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
v == v3 &&
expr.Arguments[1].Match(ILCode.Ldc_I4, out pos) &&
pos >= operands.Count &&
pos <= operands.Count + maxConsecutiveDefaultValueExpressions)
nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
arrayPos >= operands.Count &&
arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions)
{
while (operands.Count < pos)
while (operands.Count < arrayPos)
operands.Add(new ILExpression(ILCode.DefaultValue, arrayType));
operands.Add(expr.Arguments[2]);
operands.Add(nextExpr.Arguments[2]);
numberOfInstructionsToRemove++;
} else {
break;
}
}
if (operands.Count == arrayLength) {
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands);
block.Body.RemoveRange(i + 1, numberOfInstructionsToRemove);
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1;
}
}
}

static bool IsStoreToArray(ILCode code)
{
switch (code) {
case ILCode.Stelem_Any:
case ILCode.Stelem_I:
case ILCode.Stelem_I1:
case ILCode.Stelem_I2:
case ILCode.Stelem_I4:
case ILCode.Stelem_I8:
case ILCode.Stelem_R4:
case ILCode.Stelem_R8:
case ILCode.Stelem_Ref:
expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands);
body.RemoveRange(pos + 1, numberOfInstructionsToRemove);
return true;
default:
return false;
}
}
return false;
}

static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, ILExpression[] output)
Expand Down Expand Up @@ -165,50 +138,50 @@ static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, IL
return false;
}
}
#endregion

#region Collection Initilializers
public void TransformCollectionInitializers(ILBlock block, ref int i)
public static bool TransformCollectionInitializers(List<ILNode> body, ILExpression expr, int pos)
{
ILVariable v;
ILExpression expr;
if (!block.Body[i].Match(ILCode.Stloc, out v, out expr) || expr.Code != ILCode.Newobj)
return;
MethodReference ctor = (MethodReference)expr.Operand;
TypeDefinition td = ctor.DeclaringType.Resolve();
if (td == null || !td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections"))
return;
// This is a collection: we can convert Add() calls into a collection initializer
ILExpression collectionInitializer = new ILExpression(ILCode.InitCollection, null, expr);
for (int j = i + 1; j < block.Body.Count; j++) {
MethodReference addMethod;
List<ILExpression> args;
if (!block.Body[j].Match(ILCode.Callvirt, out addMethod, out args))
break;
if (addMethod.Name != "Add" || !addMethod.HasThis || args.Count < 2 || args[0].Code != ILCode.Ldloc || args[0].Operand != v)
break;
collectionInitializer.Arguments.Add((ILExpression)block.Body[j]);
}
// ensure we added at least one additional arg to the collection initializer:
if (collectionInitializer.Arguments.Count == 1)
return;
ILInlining inline = new ILInlining(method);
ILExpression followingExpr = block.Body.ElementAtOrDefault(i + collectionInitializer.Arguments.Count) as ILExpression;
if (inline.CanInlineInto(followingExpr, v, collectionInitializer)) {
block.Body.RemoveRange(i + 1, collectionInitializer.Arguments.Count - 1);
((ILExpression)block.Body[i]).Arguments[0] = collectionInitializer;
ILVariable v, v2;
ILExpression newObjExpr;
MethodReference ctor;
List<ILExpression> ctorArgs;
if (expr.Match(ILCode.Stloc, out v, out newObjExpr) &&
newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))
{
TypeDefinition td = ctor.DeclaringType.Resolve();
if (td == null || !td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections"))
return false;

// Change add methods into InitCollectionAddMethod:
for (int j = 1; j < collectionInitializer.Arguments.Count; j++) {
collectionInitializer.Arguments[j].Arguments.RemoveAt(0);
collectionInitializer.Arguments[j].Code = ILCode.InitCollectionAddMethod;
// This is a collection: we can convert Add() calls into a collection initializer
ILExpression collectionInitializer = new ILExpression(ILCode.InitCollection, null, newObjExpr);
bool anyAdded = false;
while(pos + 1 < body.Count) {
ILExpression nextExpr = body[pos + 1] as ILExpression;
MethodReference addMethod;
List<ILExpression> args;
if (nextExpr.Match(ILCode.Callvirt, out addMethod, out args) &&
addMethod.Name == "Add" &&
addMethod.HasThis &&
args.Count == 2 &&
args[0].Match(ILCode.Ldloc, out v2) &&
v == v2)
{
nextExpr.Code = ILCode.InitCollectionAddMethod;
nextExpr.Arguments.RemoveAt(0);
collectionInitializer.Arguments.Add(nextExpr);
body.RemoveAt(pos + 1);
anyAdded = true;
} else {
break;
}
}
// ensure we added at least one additional arg to the collection initializer:
if (anyAdded) {
expr.Arguments[0] = collectionInitializer;
return true;
}

inline = new ILInlining(method); // refresh variable usage info
if (inline.InlineIfPossible(block, ref i))
i++; // retry transformations on the new combined instruction
}
return false;
}
#endregion
}
}

0 comments on commit 0e1152b

Please sign in to comment.