Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 14 years ago
parent
commit
85c6614868
  1. 24
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 13
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 113
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  5. 4
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 21
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  7. 161
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  8. 92
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  9. 103
      ICSharpCode.Decompiler/ILAst/Pattern.cs
  10. 6
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  11. 36
      ICSharpCode.Decompiler/Tests/ArrayInitializers.cs
  12. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  13. 5
      ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs
  14. 4
      ILSpy/ILAstLanguage.cs

24
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -140,7 +140,7 @@ namespace Decompiler @@ -140,7 +140,7 @@ namespace Decompiler
TypeDeclaration astType = new TypeDeclaration();
astType.AddAnnotation(typeDef);
astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = typeDef.Name;
astType.Name = CleanName(typeDef.Name);
if (typeDef.IsEnum) { // NB: Enum is value type
astType.ClassType = ClassType.Enum;
@ -173,7 +173,7 @@ namespace Decompiler @@ -173,7 +173,7 @@ namespace Decompiler
astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole);
} else {
EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
enumMember.Name = field.Name;
enumMember.Name = CleanName(field.Name);
astType.AddChild(enumMember, TypeDeclaration.MemberRole);
}
}
@ -192,6 +192,14 @@ namespace Decompiler @@ -192,6 +192,14 @@ namespace Decompiler
return astType;
}
string CleanName(string name)
{
int pos = name.LastIndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
return name;
}
#region Convert Type Reference
/// <summary>
/// Converts a type reference.
@ -465,7 +473,7 @@ namespace Decompiler @@ -465,7 +473,7 @@ namespace Decompiler
astMethod.AddAnnotation(methodDef);
astMethod.AddAnnotation(methodMapping);
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = methodDef.Name;
astMethod.Name = CleanName(methodDef.Name);
astMethod.TypeParameters.AddRange(MakeTypeParameters(methodDef.GenericParameters));
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
@ -480,7 +488,7 @@ namespace Decompiler @@ -480,7 +488,7 @@ namespace Decompiler
{
return genericParameters.Select(
gp => new TypeParameterDeclaration {
Name = gp.Name,
Name = CleanName(gp.Name),
Variance = gp.IsContravariant ? VarianceModifier.Contravariant : gp.IsCovariant ? VarianceModifier.Covariant : VarianceModifier.Invariant
});
}
@ -505,7 +513,7 @@ namespace Decompiler @@ -505,7 +513,7 @@ namespace Decompiler
// don't show visibility for static ctors
astMethod.Modifiers &= ~Modifiers.VisibilityMask;
}
astMethod.Name = methodDef.DeclaringType.Name;
astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
return astMethod;
@ -516,7 +524,7 @@ namespace Decompiler @@ -516,7 +524,7 @@ namespace Decompiler
PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef);
astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod);
astProp.Name = propDef.Name;
astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
// Create mapping - used in debugger
@ -547,7 +555,7 @@ namespace Decompiler @@ -547,7 +555,7 @@ namespace Decompiler
{
CustomEventDeclaration astEvent = new CustomEventDeclaration();
astEvent.AddAnnotation(eventDef);
astEvent.Name = eventDef.Name;
astEvent.Name = CleanName(eventDef.Name);
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
if (eventDef.AddMethod != null) {
@ -579,7 +587,7 @@ namespace Decompiler @@ -579,7 +587,7 @@ namespace Decompiler
{
FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(fieldDef.Name);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
astField.AddChild(initializer, FieldDeclaration.Roles.Variable);
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);
astField.Modifiers = ConvertModifiers(fieldDef);

13
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -328,10 +328,21 @@ namespace Decompiler @@ -328,10 +328,21 @@ namespace Decompiler
#endregion
#region Arrays
case Code.Newarr:
case (Code)ILCode.InitArray:
{
var ace = new Ast.ArrayCreateExpression();
ace.Type = operandAsTypeRef;
ace.Arguments.Add(arg1);
ComposedType ct = operandAsTypeRef as ComposedType;
if (ct != null) {
// change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
}
if (opCode == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args);
} else {
ace.Arguments.Add(arg1);
}
return ace;
}
case Code.Ldlen:

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -92,10 +92,13 @@ @@ -92,10 +92,13 @@
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ArrayInitializers.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\ILInlining.cs" />
<Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Options.cs" />

113
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
// 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.Collections.Generic;
using System.Linq;
using Mono.Cecil;
namespace Decompiler
{
/// <summary>
/// IL AST transformation that introduces array initializers.
/// </summary>
public class ArrayInitializers
{
public static void Transform(ILBlock method)
{
// TODO: move this somewhere else
// Eliminate 'dups':
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (expr.Arguments[i].Code == ILCode.Dup)
expr.Arguments[i] = expr.Arguments[i].Arguments[0];
}
}
var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand)));
var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
var initializeArrayPattern = new ILCall(
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = block.Body.Count - 1; i >= 0; i--) {
if (!newArrPattern.Match(block.Body[i]))
continue;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (arrayLength == 0)
continue;
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
i -= ILInlining.InlineInto(block, i + 1, method) - 1;
}
continue;
}
}
if (i + 1 + arrayLength > block.Body.Count)
continue;
List<ILExpression> operands = new List<ILExpression>();
for (int j = 0; j < arrayLength; j++) {
ILExpression expr = block.Body[i + 1 + 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 && (int)expr.Arguments[1].Operand == j))
break;
operands.Add(expr.Arguments[2]);
}
if (operands.Count == arrayLength) {
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
ILCode.InitArray, newArrInst.Operand, operands.ToArray());
block.Body.RemoveRange(i + 1, arrayLength);
i -= ILInlining.InlineInto(block, i + 1, method) - 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:
return true;
default:
return false;
}
}
static bool HandleStaticallyInitializedArray(StoreToVariable arg2, ILBlock block, int i, ILExpression newArrInst, int arrayLength)
{
FieldDefinition field = ((ILExpression)block.Body[i + 3]).Arguments[1].Operand as FieldDefinition;
if (field == null || field.InitialValue == null)
return false;
switch (TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference)) {
case TypeCode.Int32:
case TypeCode.UInt32:
if (field.InitialValue.Length == arrayLength * 4) {
ILExpression[] newArr = new ILExpression[arrayLength];
for (int j = 0; j < newArr.Length; j++) {
newArr[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(field.InitialValue, j * 4));
}
block.Body[i] = new ILExpression(ILCode.Stloc, arg2.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr));
block.Body.RemoveRange(i + 1, 3);
return true;
}
break;
}
return false;
}
}
}

4
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow @@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow
FlattenNestedMovableBlocks,
SimpleGotoRemoval,
RemoveDeadLabels,
HandleArrayInitializers,
TypeInference,
None
}
@ -64,6 +65,9 @@ namespace Decompiler.ControlFlow @@ -64,6 +65,9 @@ namespace Decompiler.ControlFlow
if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
ArrayInitializers.Transform(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method);
}

21
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -207,6 +207,8 @@ namespace Decompiler @@ -207,6 +207,8 @@ namespace Decompiler
public TypeReference ExpectedType { get; set; }
public TypeReference InferredType { get; set; }
public static readonly object AnyOperand = new object();
public ILExpression(ILCode code, object operand, params ILExpression[] args)
{
this.Code = code;
@ -269,6 +271,25 @@ namespace Decompiler @@ -269,6 +271,25 @@ namespace Decompiler
return ranges;
}
public virtual bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && this.Code == expr.Code
&& (this.Operand == AnyOperand || object.Equals(this.Operand, expr.Operand))
&& Match(this.Arguments, expr.Arguments);
}
protected static bool Match(IList<ILExpression> a, IList<ILExpression> b)
{
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Match(b[i]))
return false;
}
return true;
}
public override void WriteTo(ITextOutput output)
{
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {

161
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -257,7 +257,10 @@ namespace Decompiler @@ -257,7 +257,10 @@ namespace Decompiler
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
BrLogicAnd,
BrLogicOr
BrLogicOr,
InitArray, // Array Initializer
Pattern // used for ILAst pattern nodes
}
public static class ILCodeUtil
@ -288,26 +291,26 @@ namespace Decompiler @@ -288,26 +291,26 @@ namespace Decompiler
public static int? GetPopCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop:
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
@ -317,28 +320,28 @@ namespace Decompiler @@ -317,28 +320,28 @@ namespace Decompiler
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null;
case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null;
case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
}
}
public static int GetPushCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
@ -349,59 +352,59 @@ namespace Decompiler @@ -349,59 +352,59 @@ namespace Decompiler
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{
switch (code) {
case ILCode.__Ldarg_0: code = ILCode.Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break;
case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.Ldarga; break;
case ILCode.__Starg_S: code = ILCode.Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break;
case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break;
case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break;
case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break;
case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break;
case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
case ILCode.__Ldarg_0: code = ILCode.Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break;
case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.Ldarga; break;
case ILCode.__Starg_S: code = ILCode.Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break;
case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break;
case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break;
case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break;
case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break;
case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
}
}

92
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
// 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 Decompiler
{
/// <summary>
/// Performs inlining transformations.
/// </summary>
public class ILInlining
{
/// <summary>
/// Inlines instructions before pos into block.Body[pos].
/// </summary>
/// <returns>The number of instructions that were inlined.</returns>
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;
}
/// <summary>
/// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
/// </summary>
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;
}
/// <summary>
/// Inlines 'expr' into 'next', if possible.
/// </summary>
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 only accessed only a single time
if (method.GetSelfAndChildrenRecursive<ILExpression>().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;
}
/// <summary>
/// Finds the position to inline to.
/// </summary>
/// <returns>true = found; false = cannot continue search; null = not found</returns>
static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
{
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;
}
parent = null;
pos = 0;
return IsWithoutSideEffects(expr.Code) ? (bool?)null : false;
}
static bool IsWithoutSideEffects(ILCode code)
{
return code == ILCode.Ldloc;
}
}
}

103
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
// 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 Mono.Cecil;
namespace Decompiler
{
public interface IVariablePattern
{
bool MatchVariable(ILVariable v);
}
public class StoreToVariable : ILExpression, IVariablePattern
{
public bool MustBeGenerated;
public ILExpression LastMatch;
public ILVariable LastVariable {
get {
return LastMatch != null ? LastMatch.Operand as ILVariable : null;
}
}
public StoreToVariable(ILExpression arg) : base(ILCode.Pattern, null, arg)
{
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Stloc && (!MustBeGenerated || ((ILVariable)expr.Operand).IsGenerated) && Match(this.Arguments, expr.Arguments)) {
this.LastMatch = expr;
return true;
} else {
return false;
}
}
bool IVariablePattern.MatchVariable(ILVariable v)
{
return v == LastMatch.Operand;
}
}
public class LoadFromVariable : ILExpression
{
IVariablePattern v;
public LoadFromVariable(IVariablePattern v) : base(ILCode.Pattern, null)
{
this.v = v;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && expr.Code == ILCode.Ldloc && v.MatchVariable(expr.Operand as ILVariable);
}
}
public class AnyILExpression : ILExpression
{
public ILExpression LastMatch;
public AnyILExpression() : base(ILCode.Pattern, null)
{
}
public override bool Match(ILNode other)
{
if (other is ILExpression) {
LastMatch = (ILExpression)other;
return true;
} else {
return false;
}
}
}
public class ILCall : ILExpression
{
string fullClassName;
string methodName;
public ILCall(string fullClassName, string methodName, params ILExpression[] args) : base(ILCode.Pattern, null, args)
{
this.fullClassName = fullClassName;
this.methodName = methodName;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Call) {
MethodReference r = (MethodReference)expr.Operand;
if (r.Name == methodName && r.DeclaringType.FullName == fullClassName)
return Match(this.Arguments, expr.Arguments);
}
return false;
}
}
}

6
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -310,6 +310,12 @@ namespace Decompiler @@ -310,6 +310,12 @@ namespace Decompiler
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
return new ArrayType((TypeReference)expr.Operand);
case ILCode.InitArray:
if (forceInferChildren) {
foreach (ILExpression arg in expr.Arguments)
InferTypeForExpression(arg, (TypeReference)expr.Operand);
}
return new ArrayType((TypeReference)expr.Operand);
case ILCode.Ldlen:
return typeSystem.Int32;
case ILCode.Ldelem_U1:

36
ICSharpCode.Decompiler/Tests/ArrayInitializers.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// 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;
public class ArrayInitializers
{
// Helper methods used to ensure array initializers used within expressions work correctly
static void X(object a, object b)
{
}
static object Y()
{
return null;
}
public static void Array1()
{
X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
}
public static void Array2(int a, int b, int c)
{
X(Y(), new int[] { a, b, c });
}
public static void NestedArray(int a, int b, int c)
{
X(Y(), new int[][] {
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
new int[] { a, b, c },
new int[] { 1, 2, 3, 4, 5, 6 }
});
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArrayInitializers.cs" />
<Compile Include="DelegateConstruction.cs" />
<Compile Include="ExceptionHandling.cs" />
<Compile Include="MultidimensionalArray.cs" />

5
ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs

@ -24,4 +24,9 @@ public static class MultidimensionalArray @@ -24,4 +24,9 @@ public static class MultidimensionalArray
b[5, 3][2] = y;
}
}
public static int[][,] MakeArray()
{
return new int[10][,];
}
}

4
ILSpy/ILAstLanguage.cs

@ -47,6 +47,10 @@ namespace ICSharpCode.ILSpy @@ -47,6 +47,10 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
if (!method.HasBody) {
return;
}
ILAstBuilder astBuilder = new ILAstBuilder();
ILBlock ilMethod = new ILBlock();
ilMethod.Body = astBuilder.Build(method, inlineVariables);

Loading…
Cancel
Save