Browse Source

Refactored some peephole transforms; Moved some of the transforms before loop and condition detection

pull/100/head
David Srbecký 14 years ago
parent
commit
b3f1d599f8
  1. 3
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  2. 157
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 76
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  4. 149
      ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
  5. 10
      ICSharpCode.Decompiler/ILAst/PatternMatching.cs
  6. 323
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  7. 3
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

3
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -18,7 +18,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -18,7 +18,8 @@ namespace ICSharpCode.Decompiler.ILAst
foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) {
ILNode previousChild = null;
foreach (ILNode child in node.GetChildren()) {
Debug.Assert(!parent.ContainsKey(child));
// TODO: Add back
// Debug.Assert(!parent.ContainsKey(child));
parent[child] = node;
if (previousChild != null)
nextSibling[previousChild] = child;

157
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -18,34 +18,43 @@ namespace ICSharpCode.Decompiler.ILAst @@ -18,34 +18,43 @@ namespace ICSharpCode.Decompiler.ILAst
YieldReturn,
SplitToMovableBlocks,
TypeInference,
PeepholeOptimizations,
SimplifyShortCircuit,
SimplifyTernaryOperator,
SimplifyNullCoalescing,
MoreSimplifyPasses,
TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj,
TransformArrayInitializers,
TransformCollectionInitializers,
MakeAssignmentExpression,
InlineVariables2,
FindLoops,
FindConditions,
FlattenNestedMovableBlocks,
RemoveRedundantCode2,
GotoRemoval,
DuplicateReturns,
FlattenIfStatements,
InlineVariables2,
PeepholeTransforms,
ReduceIfNesting,
InlineVariables3,
CachedDelegateInitialization,
IntroduceFixedStatements,
TypeInference2,
RemoveRedundantCode3,
None
}
public class ILAstOptimizer
public partial class ILAstOptimizer
{
int nextLabelIndex = 0;
DecompilerContext context;
TypeSystem typeSystem;
ILBlock method;
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{
this.context = context;
this.typeSystem = context.CurrentMethod.Module.TypeSystem;
this.method = method;
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode) return;
RemoveRedundantCode(method);
@ -77,7 +86,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -77,7 +86,6 @@ namespace ICSharpCode.Decompiler.ILAst
// Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.PeepholeOptimizations) return;
AnalyseLabels(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
bool modified;
@ -85,18 +93,48 @@ namespace ICSharpCode.Decompiler.ILAst @@ -85,18 +93,48 @@ namespace ICSharpCode.Decompiler.ILAst
modified = false;
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit) return;
modified |= block.RunPeepholeOptimization(TrySimplifyShortCircuit);
modified |= block.RunOptimization(SimplifyShortCircuit);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator) return;
modified |= block.RunPeepholeOptimization(TrySimplifyTernaryOperator);
modified |= block.RunOptimization(SimplifyTernaryOperator);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing) return;
modified |= block.RunPeepholeOptimization(TrySimplifyNullCoalescing);
modified |= block.RunOptimization(SimplifyNullCoalescing);
if (abortBeforeStep == ILAstOptimizationStep.MoreSimplifyPasses) return;
} while(modified);
}
ILInlining inlining2 = new ILInlining(method);
inlining2.InlineAllVariables();
inlining2.CopyPropagation();
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
// Intentionaly outside the while(modifed) loop,
// I will put it there later after more testing
bool modified = false;
if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return;
modified |= block.RunOptimization(TransformDecimalCtorToConstant);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return;
modified |= block.RunOptimization(SimplifyLdObjAndStObj);
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
modified |= block.RunOptimization(Initializers.TransformArrayInitializers);
modified |= block.RunOptimization(Initializers.TransformArrayInitializers);
if (abortBeforeStep == ILAstOptimizationStep.TransformCollectionInitializers) return;
modified |= block.RunOptimization(Initializers.TransformCollectionInitializers);
if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) return;
modified |= block.RunOptimization(MakeAssignmentExpression);
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
modified |= new ILInlining(method).InlineAllInBlock(block);
}
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
new LoopsAndConditions(context).FindLoops(block);
@ -110,29 +148,42 @@ namespace ICSharpCode.Decompiler.ILAst @@ -110,29 +148,42 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
FlattenBasicBlocks(method);
if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) return;
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return;
RemoveRedundantCode(method);
if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) return;
new GotoRemoval().RemoveGotos(method);
if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return;
DuplicateReturnStatements(method);
if (abortBeforeStep == ILAstOptimizationStep.FlattenIfStatements) return;
FlattenIfStatements(method);
if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) return;
ReduceIfNesting(method);
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3) return;
// The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators
// open up additional inlining possibilities.
new ILInlining(method).InlineAllVariables();
TypeAnalysis.Reset(method);
if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
CachedDelegateInitialization(block, ref i);
}
}
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
IntroduceFixedStatements(block.Body, i);
}
}
if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) return;
TypeAnalysis.Reset(method);
TypeAnalysis.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3) return;
GotoRemoval.RemoveRedundantCode(method);
// ReportUnassignedILRanges(method);
@ -312,9 +363,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -312,9 +363,9 @@ namespace ICSharpCode.Decompiler.ILAst
}
// scope is modified if successful
bool TrySimplifyTernaryOperator(List<ILNode> scope, ILBasicBlock head, int index)
bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos)
{
Debug.Assert(scope.Contains(head));
Debug.Assert(body.Contains(head));
ILExpression condExpr;
ILLabel trueLabel;
@ -336,8 +387,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -336,8 +387,8 @@ namespace ICSharpCode.Decompiler.ILAst
labelToBasicBlock[falseLabel].Match(ILCode.Ret, out unused, out falseExpr, out falseFall))) &&
trueLocVar == falseLocVar &&
trueFall == falseFall &&
scope.Contains(labelToBasicBlock[trueLabel]) &&
scope.Contains(labelToBasicBlock[falseLabel])
body.Contains(labelToBasicBlock[trueLabel]) &&
body.Contains(labelToBasicBlock[falseLabel])
)
{
ILCode opCode = trueLocVar != null ? ILCode.Stloc : ILCode.Ret;
@ -390,7 +441,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -390,7 +441,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Remove the old basic blocks
foreach(ILLabel deleteLabel in new [] { trueLabel, falseLabel }) {
scope.RemoveOrThrow(labelToBasicBlock[deleteLabel]);
body.RemoveOrThrow(labelToBasicBlock[deleteLabel]);
labelGlobalRefCount.RemoveOrThrow(deleteLabel);
labelToBasicBlock.RemoveOrThrow(deleteLabel);
}
@ -400,7 +451,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -400,7 +451,7 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
bool TrySimplifyNullCoalescing(List<ILNode> scope, ILBasicBlock head, int index)
bool SimplifyNullCoalescing(List<ILNode> body, ILBasicBlock head, int pos)
{
// ...
// v = ldloc(leftVar)
@ -442,16 +493,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -442,16 +493,16 @@ namespace ICSharpCode.Decompiler.ILAst
labelGlobalRefCount.GetOrDefault(condBBLabel) == 1 &&
labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
labelGlobalRefCount.GetOrDefault(endBBLabel) == 2 &&
scope.Contains(condBB) &&
scope.Contains(rightBB) &&
scope.Contains(endBB)
body.Contains(condBB) &&
body.Contains(rightBB) &&
body.Contains(endBB)
)
{
head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr));
head.FallthoughGoto = new ILExpression(ILCode.Br, endBBLabel);
foreach(ILLabel deleteLabel in new [] { condBBLabel, rightBBLabel }) {
scope.RemoveOrThrow(labelToBasicBlock[deleteLabel]);
body.RemoveOrThrow(labelToBasicBlock[deleteLabel]);
labelGlobalRefCount.RemoveOrThrow(deleteLabel);
labelToBasicBlock.RemoveOrThrow(deleteLabel);
}
@ -460,10 +511,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -460,10 +511,9 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
// scope is modified if successful
bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head, int index)
bool SimplifyShortCircuit(List<ILNode> body, ILBasicBlock head, int pos)
{
Debug.Assert(scope.Contains(head));
Debug.Assert(body.Contains(head));
ILExpression condExpr;
ILLabel trueLabel;
@ -481,7 +531,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -481,7 +531,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression nextCondExpr;
ILLabel nextTrueLablel;
ILLabel nextFalseLabel;
if (scope.Contains(nextBasicBlock) &&
if (body.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
nextBasicBlock.Match(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
@ -498,7 +548,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -498,7 +548,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Remove the inlined branch from scope
labelGlobalRefCount.RemoveOrThrow(nextBasicBlock.EntryLabel);
labelToBasicBlock.RemoveOrThrow(nextBasicBlock.EntryLabel);
scope.RemoveOrThrow(nextBasicBlock);
body.RemoveOrThrow(nextBasicBlock);
return true;
}
@ -589,7 +639,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -589,7 +639,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// Reduce the nesting of conditions.
/// It should be done on flat data that already had most gotos removed
/// </summary>
void FlattenIfStatements(ILNode node)
void ReduceIfNesting(ILNode node)
{
ILBlock block = node as ILBlock;
if (block != null) {
@ -624,7 +674,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -624,7 +674,7 @@ namespace ICSharpCode.Decompiler.ILAst
// We are changing the number of blocks so we use plain old recursion to get all blocks
foreach(ILNode child in node.GetChildren()) {
if (child != null && !(child is ILExpression))
FlattenIfStatements(child);
ReduceIfNesting(child);
}
}
@ -642,7 +692,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -642,7 +692,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// Perform one pass of a given optimization on this block.
/// This block must consist of only basicblocks.
/// </summary>
public static bool RunPeepholeOptimization(this ILBlock block, Func<List<ILNode>, ILBasicBlock, int, bool> optimization)
public static bool RunOptimization(this ILBlock block, Func<List<ILNode>, ILBasicBlock, int, bool> optimization)
{
bool modified = false;
List<ILNode> body = block.Body;
@ -657,6 +707,23 @@ namespace ICSharpCode.Decompiler.ILAst @@ -657,6 +707,23 @@ namespace ICSharpCode.Decompiler.ILAst
return modified;
}
public static bool RunOptimization(this ILBlock block, Func<List<ILNode>, ILExpression, int, bool> optimization)
{
bool modified = false;
foreach (ILBasicBlock bb in block.Body) {
for (int j = 0; j < bb.Body.Count;) {
ILExpression expr = bb.Body[j] as ILExpression;
if (expr != null && optimization(bb.Body, expr, j)) {
modified = true;
j = Math.Max(0, j - 1); // Go back one step
} else {
j++;
}
}
}
return modified;
}
public static bool CanFallThough(this ILNode node)
{
ILExpression expr = node as ILExpression;
@ -689,6 +756,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -689,6 +756,24 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
public static bool IsStoreToArray(this 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:
return true;
default:
return false;
}
}
/// <summary>
/// Can the expression be used as a statement in C#?
/// </summary>

76
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -48,41 +48,66 @@ namespace ICSharpCode.Decompiler.ILAst @@ -48,41 +48,66 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
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;
@ -97,10 +122,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -97,10 +122,10 @@ namespace ICSharpCode.Decompiler.ILAst
/// <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;
@ -109,28 +134,28 @@ namespace ICSharpCode.Decompiler.ILAst @@ -109,28 +134,28 @@ namespace ICSharpCode.Decompiler.ILAst
/// <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;
}
}
@ -155,7 +180,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -155,7 +180,7 @@ namespace ICSharpCode.Decompiler.ILAst
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:
@ -168,8 +193,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -168,8 +193,15 @@ namespace ICSharpCode.Decompiler.ILAst
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;
@ -300,7 +332,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -300,7 +332,7 @@ namespace ICSharpCode.Decompiler.ILAst
// 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;
}
}

149
ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

@ -12,25 +12,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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)
@ -39,7 +30,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -39,7 +30,7 @@ namespace ICSharpCode.Decompiler.ILAst
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) &&
@ -49,59 +40,41 @@ namespace ICSharpCode.Decompiler.ILAst @@ -49,59 +40,41 @@ namespace ICSharpCode.Decompiler.ILAst
{
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)
@ -165,50 +138,50 @@ namespace ICSharpCode.Decompiler.ILAst @@ -165,50 +138,50 @@ namespace ICSharpCode.Decompiler.ILAst
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
}
}

10
ICSharpCode.Decompiler/ILAst/PatternMatching.cs

@ -28,6 +28,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -28,6 +28,16 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool Match<T>(this ILNode node, ILCode code, T operand)
{
ILExpression expr = node as ILExpression;
if (expr != null && expr.Prefixes == null && expr.Code == code) {
Debug.Assert(expr.Arguments.Count == 0);
return operand.Equals(expr.Operand);
}
return false;
}
public static bool Match(this ILNode node, ILCode code, out List<ILExpression> args)
{
ILExpression expr = node as ILExpression;

323
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -11,179 +11,83 @@ using Mono.Cecil; @@ -11,179 +11,83 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler.ILAst
{
public delegate void PeepholeTransform(ILBlock block, ref int i);
/// <summary>
/// Handles peephole transformations on the ILAst.
/// </summary>
public class PeepholeTransforms
public partial class ILAstOptimizer
{
DecompilerContext context;
ILBlock method;
public static void Run(DecompilerContext context, ILBlock method)
static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr, int pos)
{
PeepholeTransforms transforms = new PeepholeTransforms();
transforms.context = context;
transforms.method = method;
InitializerPeepholeTransforms initializerTransforms = new InitializerPeepholeTransforms(method);
PeepholeTransform[] blockTransforms = {
initializerTransforms.TransformArrayInitializers,
initializerTransforms.TransformCollectionInitializers,
transforms.CachedDelegateInitialization,
transforms.MakeAssignmentExpression,
transforms.IntroduceFixedStatements
};
Func<ILExpression, ILExpression>[] exprTransforms = {
HandleDecimalConstants,
SimplifyLdObjAndStObj
};
// Traverse in post order so that nested blocks are transformed first. This is required so that
// patterns on the parent block can assume that all nested blocks are already transformed.
foreach (var node in TreeTraversal.PostOrder<ILNode>(method, c => c != null ? c.GetChildren() : null)) {
ILBlock block = node as ILBlock;
ILExpression expr;
if (block != null) {
// go through the instructions in reverse so that transforms can build up nested structures inside-out
for (int i = block.Body.Count - 1; i >= 0; i--) {
context.CancellationToken.ThrowIfCancellationRequested();
expr = block.Body[i] as ILExpression;
if (expr != null) {
// apply expr transforms to top-level expr in block
bool modified = ApplyExpressionTransforms(ref expr, exprTransforms);
block.Body[i] = expr;
if (modified) {
ILInlining inlining = new ILInlining(method);
if (inlining.InlineIfPossible(block, ref i)) {
i++; // retry all transforms on the new combined instruction
continue;
}
}
}
// apply block transforms
foreach (var t in blockTransforms) {
t(block, ref i);
Debug.Assert(i <= block.Body.Count && i >= 0);
if (i == block.Body.Count) // special case: retry all transforms
break;
}
MethodReference r;
List<ILExpression> args;
if (expr.Match(ILCode.Newobj, out r, out args) &&
r.DeclaringType.Namespace == "System" &&
r.DeclaringType.Name == "Decimal")
{
if (args.Count == 1) {
int val;
if (args[0].Match(ILCode.Ldc_I4, out val)) {
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(val);
expr.InferredType = r.DeclaringType;
expr.Arguments.Clear();
return true;
}
}
expr = node as ILExpression;
if (expr != null) {
// apply expr transforms to all arguments
for (int i = 0; i < expr.Arguments.Count; i++) {
ILExpression arg = expr.Arguments[i];
ApplyExpressionTransforms(ref arg, exprTransforms);
expr.Arguments[i] = arg;
} else if (args.Count == 5) {
int lo, mid, hi, isNegative, scale;
if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) &&
expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) &&
expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) &&
expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) &&
expr.Arguments[4].Match(ILCode.Ldc_I4, out scale))
{
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale);
expr.InferredType = r.DeclaringType;
expr.Arguments.Clear();
return true;
}
}
}
}
static bool ApplyExpressionTransforms(ref ILExpression expr, Func<ILExpression, ILExpression>[] exprTransforms)
{
bool modifiedInAnyIteration = false;
bool modified;
do {
modified = false;
ILExpression oldExpr = expr;
ILCode oldOpCode = oldExpr.Code;
foreach (var t in exprTransforms)
expr = t(expr);
if (expr != oldExpr || oldOpCode != expr.Code) {
modified = true;
modifiedInAnyIteration = true;
}
} while (modified);
return modifiedInAnyIteration;
}
#region HandleDecimalConstants
static ILExpression HandleDecimalConstants(ILExpression expr)
{
if (expr.Code == ILCode.Newobj) {
MethodReference r = (MethodReference)expr.Operand;
if (r.DeclaringType.Name == "Decimal" && r.DeclaringType.Namespace == "System") {
if (expr.Arguments.Count == 1) {
int? val = GetI4Constant(expr.Arguments[0]);
if (val != null) {
expr.Arguments.Clear();
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(val.Value);
expr.InferredType = r.DeclaringType;
}
} else if (expr.Arguments.Count == 5) {
int? lo = GetI4Constant(expr.Arguments[0]);
int? mid = GetI4Constant(expr.Arguments[1]);
int? hi = GetI4Constant(expr.Arguments[2]);
int? isNegative = GetI4Constant(expr.Arguments[3]);
int? scale = GetI4Constant(expr.Arguments[4]);
if (lo != null && mid != null && hi != null && isNegative != null && scale != null) {
expr.Arguments.Clear();
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(lo.Value, mid.Value, hi.Value, isNegative.Value != 0, (byte)scale);
expr.InferredType = r.DeclaringType;
}
}
}
bool modified = false;
foreach(ILExpression arg in expr.Arguments) {
modified |= TransformDecimalCtorToConstant(null, arg, -1);
}
return expr;
}
static int? GetI4Constant(ILExpression expr)
{
if (expr != null && expr.Code == ILCode.Ldc_I4)
return (int)expr.Operand;
else
return null;
return modified;
}
#endregion
#region SimplifyLdObjAndStObj
static ILExpression SimplifyLdObjAndStObj(ILExpression expr)
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
{
if (expr.Code == ILCode.Initobj) {
expr.Code = ILCode.Stobj;
expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
return true;
}
if (expr.Code == ILCode.Stobj) {
switch (expr.Arguments[0].Code) {
case ILCode.Ldelema:
return SimplifyLdObjOrStObj(expr, ILCode.Stelem_Any);
case ILCode.Ldloca:
return SimplifyLdObjOrStObj(expr, ILCode.Stloc);
case ILCode.Ldflda:
return SimplifyLdObjOrStObj(expr, ILCode.Stfld);
case ILCode.Ldsflda:
return SimplifyLdObjOrStObj(expr, ILCode.Stsfld);
ILExpression arg, arg2;
TypeReference type;
ILCode? newCode = null;
if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) {
switch (arg.Code) {
case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;
case ILCode.Ldloca: newCode = ILCode.Stloc; break;
case ILCode.Ldflda: newCode = ILCode.Stfld; break;
case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
}
} else if (expr.Code == ILCode.Ldobj) {
switch (expr.Arguments[0].Code) {
case ILCode.Ldelema:
return SimplifyLdObjOrStObj(expr, ILCode.Ldelem_Any);
case ILCode.Ldloca:
return SimplifyLdObjOrStObj(expr, ILCode.Ldloc);
case ILCode.Ldflda:
return SimplifyLdObjOrStObj(expr, ILCode.Ldfld);
case ILCode.Ldsflda:
return SimplifyLdObjOrStObj(expr, ILCode.Ldsfld);
} else if (expr.Match(ILCode.Ldobj, out type, out arg)) {
switch (arg.Code) {
case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;
case ILCode.Ldloca: newCode = ILCode.Ldloc; break;
case ILCode.Ldflda: newCode = ILCode.Ldfld; break;
case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
}
}
return expr;
}
static ILExpression SimplifyLdObjOrStObj(ILExpression expr, ILCode newCode)
{
ILExpression lda = expr.Arguments[0];
lda.Code = newCode;
if (expr.Code == ILCode.Stobj)
lda.Arguments.Add(expr.Arguments[1]);
lda.ILRanges.AddRange(expr.ILRanges);
return lda;
if (newCode != null) {
arg.Code = newCode.Value;
if (expr.Code == ILCode.Stobj)
arg.Arguments.Add(arg2);
arg.ILRanges.AddRange(expr.ILRanges);
body[pos] = arg;
return true;
}
return false;
}
#endregion
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)
@ -230,7 +134,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -230,7 +134,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field) {
parent.Arguments[j] = newObj;
block.Body.RemoveAt(i);
i -= new ILInlining(method).InlineInto(block, i, aggressive: true);
i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: true);
return;
}
}
@ -240,51 +144,48 @@ namespace ICSharpCode.Decompiler.ILAst @@ -240,51 +144,48 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region MakeAssignmentExpression
void MakeAssignmentExpression(ILBlock block, ref int i)
bool MakeAssignmentExpression(List<ILNode> body, ILExpression expr, int pos)
{
// expr_44 = ...
// stloc(v, expr_44)
// exprVar = ...
// stloc(v, exprVar)
// ->
// expr_44 = stloc(v, ...))
// exprVar = stloc(v, ...))
ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
ILVariable exprVar;
ILExpression initializer;
if (!(block.Body[i].Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated))
return;
ILExpression stloc1 = block.Body.ElementAtOrDefault(i + 1) as ILExpression;
if (!(stloc1 != null && stloc1.Code == ILCode.Stloc && stloc1.Arguments[0].Code == ILCode.Ldloc && stloc1.Arguments[0].Operand == exprVar))
return;
ILInlining inlining;
ILExpression store2 = block.Body.ElementAtOrDefault(i + 2) as ILExpression;
if (StoreCanBeConvertedToAssignment(store2, exprVar)) {
// expr_44 = ...
// stloc(v1, expr_44)
// anystore(v2, expr_44)
// ->
// stloc(v1, anystore(v2, ...))
inlining = new ILInlining(method);
if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1) {
block.Body.RemoveAt(i + 2); // remove store2
block.Body.RemoveAt(i); // remove expr = ...
stloc1.Arguments[0] = store2;
store2.Arguments[store2.Arguments.Count - 1] = initializer;
if (inlining.InlineIfPossible(block, ref i)) {
i++; // retry transformations on the new combined instruction
ILVariable v;
ILExpression stLocArg;
if (expr.Match(ILCode.Stloc, out exprVar, out initializer) &&
exprVar.IsGenerated &&
nextExpr.Match(ILCode.Stloc, out v, out stLocArg) &&
stLocArg.Match(ILCode.Ldloc, exprVar))
{
ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression;
if (StoreCanBeConvertedToAssignment(store2, exprVar)) {
// expr_44 = ...
// stloc(v1, expr_44)
// anystore(v2, expr_44)
// ->
// stloc(v1, anystore(v2, ...))
ILInlining inlining = new ILInlining(method);
if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1) {
body.RemoveAt(pos + 2); // remove store2
body.RemoveAt(pos); // remove expr = ...
nextExpr.Arguments[0] = store2;
store2.Arguments[store2.Arguments.Count - 1] = initializer;
inlining.InlineIfPossible(body, ref pos);
return true;
}
return;
}
body.RemoveAt(pos + 1); // remove stloc
nextExpr.Arguments[0] = initializer;
((ILExpression)body[pos]).Arguments[0] = nextExpr;
return true;
}
block.Body.RemoveAt(i + 1); // remove stloc
stloc1.Arguments[0] = initializer;
((ILExpression)block.Body[i]).Arguments[0] = stloc1;
inlining = new ILInlining(method);
if (inlining.InlineIfPossible(block, ref i)) {
i++; // retry transformations on the new combined instruction
}
return false;
}
bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar)
@ -297,35 +198,35 @@ namespace ICSharpCode.Decompiler.ILAst @@ -297,35 +198,35 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region IntroduceFixedStatements
void IntroduceFixedStatements(ILBlock block, ref int i)
bool IntroduceFixedStatements(List<ILNode> body, int i)
{
ILExpression initValue;
ILVariable pinnedVar;
int initEndPos;
if (!MatchFixedInitializer(block, i, out pinnedVar, out initValue, out initEndPos))
return;
if (!MatchFixedInitializer(body, i, out pinnedVar, out initValue, out initEndPos))
return false;
ILFixedStatement fixedStmt = block.Body.ElementAtOrDefault(initEndPos) as ILFixedStatement;
ILFixedStatement fixedStmt = body.ElementAtOrDefault(initEndPos) as ILFixedStatement;
if (fixedStmt != null) {
ILExpression expr = fixedStmt.BodyBlock.Body.LastOrDefault() as ILExpression;
if (expr != null && expr.Code == ILCode.Stloc && expr.Operand == pinnedVar && IsNullOrZero(expr.Arguments[0])) {
// we found a second initializer for the existing fixed statement
fixedStmt.Initializers.Insert(0, initValue);
block.Body.RemoveRange(i, initEndPos - i);
body.RemoveRange(i, initEndPos - i);
fixedStmt.BodyBlock.Body.RemoveAt(fixedStmt.BodyBlock.Body.Count - 1);
if (pinnedVar.Type.IsByReference)
pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
return;
return true;
}
}
// find where pinnedVar is reset to 0:
int j;
for (j = initEndPos; j < block.Body.Count; j++) {
for (j = initEndPos; j < body.Count; j++) {
ILVariable v2;
ILExpression storedVal;
// stloc(pinned_Var, conv.u(ldc.i4(0)))
if (block.Body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) {
if (body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) {
if (IsNullOrZero(storedVal)) {
break;
}
@ -334,11 +235,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -334,11 +235,13 @@ namespace ICSharpCode.Decompiler.ILAst
// Create fixed statement from i to j
fixedStmt = new ILFixedStatement();
fixedStmt.Initializers.Add(initValue);
fixedStmt.BodyBlock = new ILBlock(block.Body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive)
block.Body.RemoveRange(i + 1, Math.Min(j, block.Body.Count - 1) - i); // from i+1 to j (inclusive)
block.Body[i] = fixedStmt;
fixedStmt.BodyBlock = new ILBlock(body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive)
body.RemoveRange(i + 1, Math.Min(j, body.Count - 1) - i); // from i+1 to j (inclusive)
body[i] = fixedStmt;
if (pinnedVar.Type.IsByReference)
pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
return true;
}
bool IsNullOrZero(ILExpression expr)
@ -348,15 +251,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -348,15 +251,15 @@ namespace ICSharpCode.Decompiler.ILAst
return (expr.Code == ILCode.Ldc_I4 && (int)expr.Operand == 0) || expr.Code == ILCode.Ldnull;
}
bool MatchFixedInitializer(ILBlock block, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos)
bool MatchFixedInitializer(List<ILNode> body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos)
{
if (block.Body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) {
initValue = (ILExpression)block.Body[i];
if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) {
initValue = (ILExpression)body[i];
nextPos = i + 1;
HandleStringFixing(pinnedVar, block.Body, ref nextPos, ref initValue);
HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue);
return true;
}
ILCondition ifStmt = block.Body[i] as ILCondition;
ILCondition ifStmt = body[i] as ILCondition;
ILExpression arrayLoadingExpr;
if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) {
ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand;

3
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -490,8 +490,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -490,8 +490,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_R8:
return typeSystem.Double;
case ILCode.Ldc_Decimal:
Debug.Assert(expr.InferredType != null && expr.InferredType.FullName == "System.Decimal");
return expr.InferredType;
return new TypeReference("System", "Decimal", module, module, true);
case ILCode.Ldtoken:
if (expr.Operand is TypeReference)
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);

Loading…
Cancel
Save