Browse Source

Use the simple pattern matching for array initializers

pull/100/head
David Srbecký 15 years ago
parent
commit
95ec14a7c5
  1. 111
      ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

111
ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

@ -17,57 +17,72 @@ namespace ICSharpCode.Decompiler.ILAst
readonly ILBlock method; readonly ILBlock method;
#region Array Initializers #region Array Initializers
StoreToVariable newArrPattern;
ILCall initializeArrayPattern;
public InitializerPeepholeTransforms(ILBlock method) public InitializerPeepholeTransforms(ILBlock method)
{ {
this.method = method; this.method = method;
newArrPattern = new StoreToVariable(new ILExpression(
ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand)));
initializeArrayPattern = new ILCall(
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
new LoadFromVariable(newArrPattern), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
} }
public void TransformArrayInitializers(ILBlock block, ref int i) public void TransformArrayInitializers(ILBlock block, ref int i)
{ {
if (!newArrPattern.Match(block.Body[i])) ILVariable v, v2, v3;
return; ILExpression newarrExpr;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; TypeReference arrayType;
int arrayLength = (int)newArrInst.Arguments[0].Operand; ILExpression lengthExpr;
if (arrayLength == 0) int arrayLength;
return; if (block.Body[i].Match(ILCode.Stloc, out v, out newarrExpr) &&
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 1))) { newarrExpr.Match(ILCode.Newarr, out arrayType, out lengthExpr) &&
if (HandleStaticallyInitializedArray(newArrPattern, block, i, newArrInst, arrayLength)) { lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1; arrayLength > 0)
{
MethodReference methodRef;
ILExpression methodArg1;
ILExpression methodArg2;
FieldDefinition field;
if (block.Body.ElementAtOrDefault(i + 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) &&
v == v2 &&
methodArg2.Match(ILCode.Ldtoken, out field) &&
field != null && field.InitialValue != null)
{
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;
}
} }
return;
}
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;
if (expr == null || !IsStoreToArray(expr.Code))
break;
if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable))
break;
if (expr.Arguments[1].Code != ILCode.Ldc_I4)
break;
int pos = (int)expr.Arguments[1].Operand;
const int maxConsecutiveDefaultValueExpressions = 10; const int maxConsecutiveDefaultValueExpressions = 10;
if (pos < operands.Count || pos > operands.Count + maxConsecutiveDefaultValueExpressions) List<ILExpression> operands = new List<ILExpression>();
break; int numberOfInstructionsToRemove = 0;
while (operands.Count < pos) for (int j = i + 1; j < block.Body.Count; j++) {
operands.Add(new ILExpression(ILCode.DefaultValue, newArrInst.Operand)); ILExpression expr = block.Body[j] as ILExpression;
operands.Add(expr.Arguments[2]); int pos;
numberOfInstructionsToRemove++; if (expr != null &&
} IsStoreToArray(expr.Code) &&
if (operands.Count == arrayLength) { expr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( v == v3 &&
ILCode.InitArray, newArrInst.Operand, operands.ToArray()); expr.Arguments[1].Match(ILCode.Ldc_I4, out pos) &&
block.Body.RemoveRange(i + 1, numberOfInstructionsToRemove); pos >= operands.Count &&
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1; pos <= operands.Count + maxConsecutiveDefaultValueExpressions)
{
while (operands.Count < pos)
operands.Add(new ILExpression(ILCode.DefaultValue, arrayType));
operands.Add(expr.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;
}
} }
} }
@ -89,20 +104,6 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
static bool HandleStaticallyInitializedArray(StoreToVariable newArrPattern, ILBlock block, int i, ILExpression newArrInst, int arrayLength)
{
FieldDefinition field = ((ILExpression)block.Body[i + 1]).Arguments[1].Operand as FieldDefinition;
if (field == null || field.InitialValue == null)
return false;
ILExpression[] newArr = new ILExpression[arrayLength];
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference), field.InitialValue, newArr)) {
block.Body[i] = new ILExpression(ILCode.Stloc, newArrPattern.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr));
block.Body.RemoveAt(i + 1);
return true;
}
return false;
}
static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, ILExpression[] output) static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, ILExpression[] output)
{ {
switch (elementType) { switch (elementType) {

Loading…
Cancel
Save