Browse Source

Use custom enum to store OpCodes (so that we can add "virtual" opcodes)

pull/37/head
David Srbecký 15 years ago
parent
commit
a03d029d30
  1. 2
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 13
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 5
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 76
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  5. 15
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 17
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  7. 423
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  8. 6
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 15
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs
  10. 478
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs
  11. 118
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs

2
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -148,7 +148,7 @@ namespace Decompiler
} }
} else { } else {
// Base type // Base type
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != "System.Object") {
astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole); astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole);
} }
foreach (var i in typeDef.Interfaces) foreach (var i in typeDef.Interfaces)

13
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -8,7 +8,6 @@ using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Decompiler.ControlFlow; using Decompiler.ControlFlow;
namespace Decompiler namespace Decompiler
@ -80,7 +79,7 @@ namespace Decompiler
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>(); Dictionary<string, int> typeNames = new Dictionary<string, int>();
foreach(ILVariable varDef in astBuilder.Variables) { foreach(ILVariable varDef in astBuilder.Variables) {
if (varDef.Type.FullName == Constants.Int32 && intNames.Count > 0) { if (varDef.Type.FullName == "System.Int32" && intNames.Count > 0) {
varDef.Name = intNames[0]; varDef.Name = intNames[0];
intNames.RemoveAt(0); intNames.RemoveAt(0);
} else { } else {
@ -243,7 +242,7 @@ namespace Decompiler
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
TypeReference arg1Type = args.Count >= 1 ? expr.Arguments[0].InferredType : null; TypeReference arg1Type = args.Count >= 1 ? expr.Arguments[0].InferredType : null;
switch(expr.OpCode.Code) { switch((Code)expr.Code) {
case Code.Brfalse: case Code.Brfalse:
if (arg1Type == typeSystem.Boolean) if (arg1Type == typeSystem.Boolean)
return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
@ -328,7 +327,7 @@ namespace Decompiler
if (byteCode.Operand != null) { if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
} }
return new IdentifierExpression(byteCode.OpCode.Name).Invoke(args); return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args);
} }
} }
@ -361,7 +360,7 @@ namespace Decompiler
{ {
// throw new NotImplementedException(); // throw new NotImplementedException();
OpCode opCode = byteCode.OpCode; ILCode opCode = byteCode.Code;
object operand = byteCode.Operand; object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
ILExpression operandAsByteCode = operand as ILExpression; ILExpression operandAsByteCode = operand as ILExpression;
@ -375,7 +374,7 @@ namespace Decompiler
branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)); branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
} }
switch(opCode.Code) { switch((Code)opCode) {
#region Arithmetic #region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -655,7 +654,7 @@ namespace Decompiler
case Code.Refanytype: throw new NotImplementedException(); case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException(); case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: { case Code.Ret: {
if (methodDef.ReturnType.FullName != Constants.Void) { if (methodDef.ReturnType.FullName != "System.Void") {
arg1 = Convert(arg1, methodDef.ReturnType); arg1 = Convert(arg1, methodDef.ReturnType);
return new Ast.ReturnStatement { Expression = arg1 }; return new Ast.ReturnStatement { Expression = arg1 };
} else { } else {

5
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -89,11 +89,9 @@
<Compile Include="ILAst\ILAstBuilder.cs" /> <Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" /> <Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" /> <Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" /> <Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="Options.cs" /> <Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" /> <Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -114,7 +112,6 @@
<Folder Include="Ast\Transforms" /> <Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" /> <Folder Include="Disassembler" />
<Folder Include="ILAst" /> <Folder Include="ILAst" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

76
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -4,9 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Decompiler.Rocks;
namespace Decompiler namespace Decompiler
{ {
@ -33,7 +31,7 @@ namespace Decompiler
public ILLabel Label; // Non-null only if needed public ILLabel Label; // Non-null only if needed
public int Offset; public int Offset;
public int EndOffset; public int EndOffset;
public OpCode OpCode; public ILCode Code;
public object Operand; public object Operand;
public int? PopCount; // Null means pop all public int? PopCount; // Null means pop all
public int PushCount; public int PushCount;
@ -59,7 +57,7 @@ namespace Decompiler
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}:{1} {2} {3}", this.Name, this.Label != null ? " *" : "", this.OpCode, this.Operand); sb.AppendFormat("{0}:{1} {2} {3}", this.Name, this.Label != null ? " *" : "", this.Code.GetName(), this.Operand);
if (this.StackBefore != null) { if (this.StackBefore != null) {
sb.Append(" StackBefore = {"); sb.Append(" StackBefore = {");
bool first = true; bool first = true;
@ -116,13 +114,13 @@ namespace Decompiler
// Create temporary structure for the stack analysis // Create temporary structure for the stack analysis
List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count); List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count);
foreach(Instruction inst in methodDef.Body.Instructions) { foreach(Instruction inst in methodDef.Body.Instructions) {
OpCode opCode = inst.OpCode; ILCode code = (ILCode)inst.OpCode.Code;
object operand = inst.Operand; object operand = inst.Operand;
MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body); ILCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body);
ByteCode byteCode = new ByteCode() { ByteCode byteCode = new ByteCode() {
Offset = inst.Offset, Offset = inst.Offset,
EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize, EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
OpCode = opCode, Code = code,
Operand = operand, Operand = operand,
PopCount = inst.GetPopCount(), PopCount = inst.GetPopCount(),
PushCount = inst.GetPushCount() PushCount = inst.GetPushCount()
@ -173,27 +171,25 @@ namespace Decompiler
// Apply the state to any successors // Apply the state to any successors
List<ByteCode> branchTargets = new List<ByteCode>(); List<ByteCode> branchTargets = new List<ByteCode>();
if (byteCode.OpCode.CanFallThough()) { if (byteCode.Code.CanFallThough()) {
branchTargets.Add(byteCode.Next); branchTargets.Add(byteCode.Next);
} }
if (byteCode.OpCode.IsBranch()) { if (byteCode.Operand is Instruction[]) {
if (byteCode.Operand is Instruction[]) { foreach(Instruction inst in (Instruction[])byteCode.Operand) {
foreach(Instruction inst in (Instruction[])byteCode.Operand) { ByteCode target = instrToByteCode[inst];
ByteCode target = instrToByteCode[inst];
branchTargets.Add(target);
// The target of a branch must have label
if (target.Label == null) {
target.Label = new ILLabel() { Name = target.Name };
}
}
} else {
ByteCode target = instrToByteCode[(Instruction)byteCode.Operand];
branchTargets.Add(target); branchTargets.Add(target);
// The target of a branch must have label // The target of a branch must have label
if (target.Label == null) { if (target.Label == null) {
target.Label = new ILLabel() { Name = target.Name }; target.Label = new ILLabel() { Name = target.Name };
} }
} }
} else if (byteCode.Operand is Instruction) {
ByteCode target = instrToByteCode[(Instruction)byteCode.Operand];
branchTargets.Add(target);
// The target of a branch must have label
if (target.Label == null) {
target.Label = new ILLabel() { Name = target.Name };
}
} }
foreach (ByteCode branchTarget in branchTargets) { foreach (ByteCode branchTarget in branchTargets) {
if (branchTarget.StackBefore == null) { if (branchTarget.StackBefore == null) {
@ -255,12 +251,12 @@ namespace Decompiler
int[] numReads = new int[Variables.Count]; int[] numReads = new int[Variables.Count];
int[] numWrites = new int[Variables.Count]; int[] numWrites = new int[Variables.Count];
foreach(ByteCode byteCode in body) { foreach(ByteCode byteCode in body) {
if (byteCode.OpCode == OpCodes.Ldloc) { if (byteCode.Code == ILCode.Ldloc) {
int index = ((VariableDefinition)byteCode.Operand).Index; int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = Variables[index]; byteCode.Operand = Variables[index];
numReads[index]++; numReads[index]++;
} }
if (byteCode.OpCode == OpCodes.Stloc) { if (byteCode.Code == ILCode.Stloc) {
int index = ((VariableDefinition)byteCode.Operand).Index; int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = Variables[index]; byteCode.Operand = Variables[index];
numWrites[index]++; numWrites[index]++;
@ -361,12 +357,7 @@ namespace Decompiler
// Convert stack-based IL code to ILAst tree // Convert stack-based IL code to ILAst tree
foreach(ByteCode byteCode in body) { foreach(ByteCode byteCode in body) {
OpCode opCode = byteCode.OpCode; ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
object operand = byteCode.Operand;
MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);
ILExpression expr = new ILExpression(opCode, operand);
expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset }); expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset });
// Label for this instruction // Label for this instruction
@ -379,10 +370,10 @@ namespace Decompiler
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
StackSlot slot = byteCode.StackBefore[i]; StackSlot slot = byteCode.StackBefore[i];
if (slot.PushedBy != null) { if (slot.PushedBy != null) {
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, slot.LoadFrom); ILExpression ldExpr = new ILExpression(ILCode.Ldloc, slot.LoadFrom);
expr.Arguments.Add(ldExpr); expr.Arguments.Add(ldExpr);
} else { } else {
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true }); ILExpression ldExpr = new ILExpression(ILCode.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true });
expr.Arguments.Add(ldExpr); expr.Arguments.Add(ldExpr);
} }
} }
@ -391,12 +382,12 @@ namespace Decompiler
if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
ast.Add(expr); ast.Add(expr);
} else if (byteCode.StoreTo.Count == 1) { } else if (byteCode.StoreTo.Count == 1) {
ast.Add(new ILExpression(OpCodes.Stloc, byteCode.StoreTo[0], expr)); ast.Add(new ILExpression(ILCode.Stloc, byteCode.StoreTo[0], expr));
} else { } else {
ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true }; ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true };
ast.Add(new ILExpression(OpCodes.Stloc, tmpVar, expr)); ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr));
foreach(ILVariable storeTo in byteCode.StoreTo) { foreach(ILVariable storeTo in byteCode.StoreTo) {
ast.Add(new ILExpression(OpCodes.Stloc, storeTo, new ILExpression(OpCodes.Ldloc, tmpVar))); ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar)));
} }
} }
} }
@ -408,10 +399,10 @@ namespace Decompiler
ILExpression currExpr = ast[i] as ILExpression; ILExpression currExpr = ast[i] as ILExpression;
ILExpression nextExpr = ast[i + 1] as ILExpression; ILExpression nextExpr = ast[i + 1] as ILExpression;
if (currExpr != null && nextExpr != null && currExpr.OpCode.Code == Code.Stloc) { if (currExpr != null && nextExpr != null && currExpr.Code == ILCode.Stloc) {
// If the next expression is generated stloc, look inside // If the next expression is generated stloc, look inside
if (nextExpr.OpCode.Code == Code.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) { if (nextExpr.Code == ILCode.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) {
nextExpr = nextExpr.Arguments[0]; nextExpr = nextExpr.Arguments[0];
} }
@ -421,7 +412,7 @@ namespace Decompiler
// We are moving the expression evaluation past the other aguments. // We are moving the expression evaluation past the other aguments.
// It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value // It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value
if (arg.OpCode.Code == Code.Ldloc) { if (arg.Code == ILCode.Ldloc) {
bool canInline; bool canInline;
allowInline.TryGetValue((ILVariable)arg.Operand, out canInline); allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
if (arg.Operand == currExpr.Operand && canInline) { if (arg.Operand == currExpr.Operand && canInline) {
@ -443,4 +434,17 @@ namespace Decompiler
return ast; return ast;
} }
} }
public static class ILAstBuilderExtensionMethods
{
public static List<T> CutRange<T>(this List<T> list, int start, int count)
{
List<T> ret = new List<T>(count);
for (int i = 0; i < count; i++) {
ret.Add(list[start + i]);
}
list.RemoveRange(start, count);
return ret;
}
}
} }

15
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -4,7 +4,6 @@ using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Decompiler.Rocks;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {
@ -76,7 +75,7 @@ namespace Decompiler.ControlFlow
{ {
// Remve no-ops // Remve no-ops
// TODO: Assign the no-op range to someting // TODO: Assign the no-op range to someting
block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).OpCode == OpCodes.Nop)).ToList(); block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).Code == ILCode.Nop)).ToList();
List<ILNode> moveableBlocks = new List<ILNode>(); List<ILNode> moveableBlocks = new List<ILNode>();
@ -96,8 +95,8 @@ namespace Decompiler.ControlFlow
if ((currNode is ILLabel && !(lastNode is ILLabel)) || if ((currNode is ILLabel && !(lastNode is ILLabel)) ||
lastNode is ILTryCatchBlock || lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock || currNode is ILTryCatchBlock ||
(lastNode is ILExpression) && ((ILExpression)lastNode).OpCode.IsBranch() || (lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() ||
(currNode is ILExpression) && ((ILExpression)currNode).OpCode.IsBranch()) (currNode is ILExpression) && ((ILExpression)currNode).IsBranch())
{ {
ILBlock lastBlock = moveableBlock; ILBlock lastBlock = moveableBlock;
moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) }; moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
@ -105,9 +104,9 @@ namespace Decompiler.ControlFlow
// Explicit branch from one block to other // Explicit branch from one block to other
// (unless the last expression was unconditional branch) // (unless the last expression was unconditional branch)
if (!(lastNode is ILExpression) || ((ILExpression)lastNode).OpCode.CanFallThough()) { if (!(lastNode is ILExpression) || ((ILExpression)lastNode).Code.CanFallThough()) {
ILLabel blockLabel = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder }; ILLabel blockLabel = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder };
lastBlock.Body.Add(new ILExpression(OpCodes.Br, blockLabel)); lastBlock.Body.Add(new ILExpression(ILCode.Br, blockLabel));
moveableBlock.Body.Add(blockLabel); moveableBlock.Body.Add(blockLabel);
} }
} }
@ -466,7 +465,7 @@ namespace Decompiler.ControlFlow
if (block != null) { if (block != null) {
List<ILNode> flatBody = new List<ILNode>(); List<ILNode> flatBody = new List<ILNode>();
if (block.EntryPoint != null) { if (block.EntryPoint != null) {
flatBody.Add(new ILExpression(OpCodes.Br, block.EntryPoint)); flatBody.Add(new ILExpression(ILCode.Br, block.EntryPoint));
block.EntryPoint = null; block.EntryPoint = null;
} }
foreach (ILNode child in block.Body) { foreach (ILNode child in block.Body) {
@ -496,7 +495,7 @@ namespace Decompiler.ControlFlow
for (int i = 0; i < block.Body.Count; i++) { for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression; ILExpression expr = block.Body[i] as ILExpression;
// Uncoditional branch // Uncoditional branch
if (expr != null && (expr.OpCode == OpCodes.Br || expr.OpCode == OpCodes.Br_S)) { if (expr != null && (expr.Code == ILCode.Br)) {
// Check that branch is followed by its label (allow multiple labels) // Check that branch is followed by its label (allow multiple labels)
for (int j = i + 1; j < block.Body.Count; j++) { for (int j = i + 1; j < block.Body.Count; j++) {
ILLabel label = block.Body[j] as ILLabel; ILLabel label = block.Body[j] as ILLabel;

17
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -160,7 +160,7 @@ namespace Decompiler
public class ILExpression : ILNode public class ILExpression : ILNode
{ {
public OpCode OpCode { get; set; } public ILCode Code { get; set; }
public object Operand { get; set; } public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; } public List<ILExpression> Arguments { get; set; }
// Mapping to the original instructions (useful for debugging) // Mapping to the original instructions (useful for debugging)
@ -168,14 +168,19 @@ namespace Decompiler
public TypeReference InferredType { get; set; } public TypeReference InferredType { get; set; }
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) public ILExpression(ILCode code, object operand, params ILExpression[] args)
{ {
this.OpCode = opCode; this.Code = code;
this.Operand = operand; this.Operand = operand;
this.Arguments = new List<ILExpression>(args); this.Arguments = new List<ILExpression>(args);
this.ILRanges = new List<ILRange>(1); this.ILRanges = new List<ILRange>(1);
} }
public bool IsBranch()
{
return this.Operand is ILLabel || this.Operand is ILLabel[];
}
public IEnumerable<ILLabel> GetBranchTargets() public IEnumerable<ILLabel> GetBranchTargets()
{ {
if (this.Operand is ILLabel) { if (this.Operand is ILLabel) {
@ -216,12 +221,12 @@ namespace Decompiler
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) { if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {
if (OpCode == OpCodes.Stloc && this.InferredType == null) { if (Code == ILCode.Stloc && this.InferredType == null) {
output.Write(((ILVariable)Operand).Name); output.Write(((ILVariable)Operand).Name);
output.Write(" = "); output.Write(" = ");
Arguments.First().WriteTo(output); Arguments.First().WriteTo(output);
return; return;
} else if (OpCode == OpCodes.Ldloc) { } else if (Code == ILCode.Ldloc) {
output.Write(((ILVariable)Operand).Name); output.Write(((ILVariable)Operand).Name);
if (this.InferredType != null) { if (this.InferredType != null) {
output.Write(':'); output.Write(':');
@ -231,7 +236,7 @@ namespace Decompiler
} }
} }
output.Write(OpCode.Name); output.Write(Code.GetName());
if (this.InferredType != null) { if (this.InferredType != null) {
output.Write(':'); output.Write(':');
this.InferredType.WriteTo(output, true, true); this.InferredType.WriteTo(output, true, true);

423
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -0,0 +1,423 @@
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2010 Jb Evain
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public enum ILCode
{
// For convenience, the start is exactly identical to Mono.Cecil.Cil.Code
// The macro instructions should never be used and are therefore prepended by __
Nop,
Break,
__Ldarg_0,
__Ldarg_1,
__Ldarg_2,
__Ldarg_3,
__Ldloc_0,
__Ldloc_1,
__Ldloc_2,
__Ldloc_3,
__Stloc_0,
__Stloc_1,
__Stloc_2,
__Stloc_3,
__Ldarg_S,
__Ldarga_S,
__Starg_S,
__Ldloc_S,
__Ldloca_S,
__Stloc_S,
Ldnull,
__Ldc_I4_M1,
__Ldc_I4_0,
__Ldc_I4_1,
__Ldc_I4_2,
__Ldc_I4_3,
__Ldc_I4_4,
__Ldc_I4_5,
__Ldc_I4_6,
__Ldc_I4_7,
__Ldc_I4_8,
__Ldc_I4_S,
Ldc_I4,
Ldc_I8,
Ldc_R4,
Ldc_R8,
Dup,
Pop,
Jmp,
Call,
Calli,
Ret,
__Br_S,
__Brfalse_S,
__Brtrue_S,
__Beq_S,
__Bge_S,
__Bgt_S,
__Ble_S,
__Blt_S,
__Bne_Un_S,
__Bge_Un_S,
__Bgt_Un_S,
__Ble_Un_S,
__Blt_Un_S,
Br,
Brfalse,
Brtrue,
Beq,
Bge,
Bgt,
Ble,
Blt,
Bne_Un,
Bge_Un,
Bgt_Un,
Ble_Un,
Blt_Un,
Switch,
Ldind_I1,
Ldind_U1,
Ldind_I2,
Ldind_U2,
Ldind_I4,
Ldind_U4,
Ldind_I8,
Ldind_I,
Ldind_R4,
Ldind_R8,
Ldind_Ref,
Stind_Ref,
Stind_I1,
Stind_I2,
Stind_I4,
Stind_I8,
Stind_R4,
Stind_R8,
Add,
Sub,
Mul,
Div,
Div_Un,
Rem,
Rem_Un,
And,
Or,
Xor,
Shl,
Shr,
Shr_Un,
Neg,
Not,
Conv_I1,
Conv_I2,
Conv_I4,
Conv_I8,
Conv_R4,
Conv_R8,
Conv_U4,
Conv_U8,
Callvirt,
Cpobj,
Ldobj,
Ldstr,
Newobj,
Castclass,
Isinst,
Conv_R_Un,
Unbox,
Throw,
Ldfld,
Ldflda,
Stfld,
Ldsfld,
Ldsflda,
Stsfld,
Stobj,
Conv_Ovf_I1_Un,
Conv_Ovf_I2_Un,
Conv_Ovf_I4_Un,
Conv_Ovf_I8_Un,
Conv_Ovf_U1_Un,
Conv_Ovf_U2_Un,
Conv_Ovf_U4_Un,
Conv_Ovf_U8_Un,
Conv_Ovf_I_Un,
Conv_Ovf_U_Un,
Box,
Newarr,
Ldlen,
Ldelema,
Ldelem_I1,
Ldelem_U1,
Ldelem_I2,
Ldelem_U2,
Ldelem_I4,
Ldelem_U4,
Ldelem_I8,
Ldelem_I,
Ldelem_R4,
Ldelem_R8,
Ldelem_Ref,
Stelem_I,
Stelem_I1,
Stelem_I2,
Stelem_I4,
Stelem_I8,
Stelem_R4,
Stelem_R8,
Stelem_Ref,
Ldelem_Any,
Stelem_Any,
Unbox_Any,
Conv_Ovf_I1,
Conv_Ovf_U1,
Conv_Ovf_I2,
Conv_Ovf_U2,
Conv_Ovf_I4,
Conv_Ovf_U4,
Conv_Ovf_I8,
Conv_Ovf_U8,
Refanyval,
Ckfinite,
Mkrefany,
Ldtoken,
Conv_U2,
Conv_U1,
Conv_I,
Conv_Ovf_I,
Conv_Ovf_U,
Add_Ovf,
Add_Ovf_Un,
Mul_Ovf,
Mul_Ovf_Un,
Sub_Ovf,
Sub_Ovf_Un,
Endfinally,
Leave,
__Leave_S,
Stind_I,
Conv_U,
Arglist,
Ceq,
Cgt,
Cgt_Un,
Clt,
Clt_Un,
Ldftn,
Ldvirtftn,
Ldarg,
Ldarga,
Starg,
Ldloc,
Ldloca,
Stloc,
Localloc,
Endfilter,
Unaligned,
Volatile,
Tail,
Initobj,
Constrained,
Cpblk,
Initblk,
No,
Rethrow,
Sizeof,
Refanytype,
Readonly,
// Virtual codes - defined for convenience
}
public static class ILCodeUtil
{
public static string GetName(this ILCode code)
{
return code.ToString().ToLowerInvariant().Replace('_','.');
}
public static bool CanFallThough(this ILCode code)
{
switch(code) {
case ILCode.Br:
case ILCode.__Br_S:
case ILCode.Leave:
case ILCode.__Leave_S:
case ILCode.Ret:
case ILCode.Endfilter:
case ILCode.Endfinally:
case ILCode.Throw:
case ILCode.Rethrow:
return false;
default:
return true;
}
}
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:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
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 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.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == "System.Void") {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
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;
}
}
public static ParameterDefinition GetParameter (this MethodBody self, int index)
{
var method = self.Method;
if (method.HasThis) {
if (index == 0)
return self.ThisParameter;
index--;
}
var parameters = method.Parameters;
if (index < 0 || index >= parameters.Count)
return null;
return parameters [index];
}
}
}

6
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -40,7 +40,7 @@ namespace Decompiler
ILExpression expr = child as ILExpression; ILExpression expr = child as ILExpression;
if (expr != null) { if (expr != null) {
ILVariable v = expr.Operand as ILVariable; ILVariable v = expr.Operand as ILVariable;
if (v != null && v.IsGenerated && v.Type == null && expr.OpCode == OpCodes.Stloc) { if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc) {
// don't deal with this node or its children yet, // don't deal with this node or its children yet,
// wait for the expected type to be inferred first // wait for the expected type to be inferred first
storedToGeneratedVariables.Add(expr); storedToGeneratedVariables.Add(expr);
@ -70,7 +70,7 @@ namespace Decompiler
TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{ {
switch (expr.OpCode.Code) { switch ((Code)expr.Code) {
#region Variable load/store #region Variable load/store
case Code.Stloc: case Code.Stloc:
if (forceInferChildren) if (forceInferChildren)
@ -387,7 +387,7 @@ namespace Decompiler
case Code.Dup: case Code.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType); return InferTypeForExpression(expr.Arguments.Single(), expectedType);
default: default:
Debug.WriteLine("Type Inference: Can't handle " + expr.OpCode.Name); Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
return null; return null;
} }
} }

15
ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs

@ -1,15 +0,0 @@
// 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;
namespace Decompiler
{
public class Constants
{
public const string Object = "System.Object";
public const string Int32 = "System.Int32";
public const string Boolean = "System.Boolean";
public const string Void = "System.Void";
}
}

478
ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs

@ -1,478 +0,0 @@
//
// MethodBodyRocks.cs
//
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2010 Jb Evain
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using Mono.Cecil.Cil;
namespace Mono.Cecil.Rocks {
#if INSIDE_ROCKS
public
#endif
static class MethodBodyRocks {
public static ParameterDefinition GetParameter (this MethodBody self, int index)
{
var method = self.Method;
if (method.HasThis) {
if (index == 0)
return self.ThisParameter;
index--;
}
var parameters = method.Parameters;
if (index < 0 || index >= parameters.Count)
return null;
return parameters [index];
}
public static void SimplifyMacros (this MethodBody self)
{
if (self == null)
throw new ArgumentNullException ("self");
foreach (var instruction in self.Instructions) {
if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
continue;
switch (instruction.OpCode.Code) {
case Code.Ldarg_0:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0));
break;
case Code.Ldarg_1:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1));
break;
case Code.Ldarg_2:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2));
break;
case Code.Ldarg_3:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3));
break;
case Code.Ldloc_0:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]);
break;
case Code.Ldloc_1:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]);
break;
case Code.Ldloc_2:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]);
break;
case Code.Ldloc_3:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]);
break;
case Code.Stloc_0:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]);
break;
case Code.Stloc_1:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]);
break;
case Code.Stloc_2:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]);
break;
case Code.Stloc_3:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]);
break;
case Code.Ldarg_S:
instruction.OpCode = OpCodes.Ldarg;
break;
case Code.Ldarga_S:
instruction.OpCode = OpCodes.Ldarga;
break;
case Code.Starg_S:
instruction.OpCode = OpCodes.Starg;
break;
case Code.Ldloc_S:
instruction.OpCode = OpCodes.Ldloc;
break;
case Code.Ldloca_S:
instruction.OpCode = OpCodes.Ldloca;
break;
case Code.Stloc_S:
instruction.OpCode = OpCodes.Stloc;
break;
case Code.Ldc_I4_M1:
ExpandMacro (instruction, OpCodes.Ldc_I4, -1);
break;
case Code.Ldc_I4_0:
ExpandMacro (instruction, OpCodes.Ldc_I4, 0);
break;
case Code.Ldc_I4_1:
ExpandMacro (instruction, OpCodes.Ldc_I4, 1);
break;
case Code.Ldc_I4_2:
ExpandMacro (instruction, OpCodes.Ldc_I4, 2);
break;
case Code.Ldc_I4_3:
ExpandMacro (instruction, OpCodes.Ldc_I4, 3);
break;
case Code.Ldc_I4_4:
ExpandMacro (instruction, OpCodes.Ldc_I4, 4);
break;
case Code.Ldc_I4_5:
ExpandMacro (instruction, OpCodes.Ldc_I4, 5);
break;
case Code.Ldc_I4_6:
ExpandMacro (instruction, OpCodes.Ldc_I4, 6);
break;
case Code.Ldc_I4_7:
ExpandMacro (instruction, OpCodes.Ldc_I4, 7);
break;
case Code.Ldc_I4_8:
ExpandMacro (instruction, OpCodes.Ldc_I4, 8);
break;
case Code.Ldc_I4_S:
ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand);
break;
case Code.Br_S:
instruction.OpCode = OpCodes.Br;
break;
case Code.Brfalse_S:
instruction.OpCode = OpCodes.Brfalse;
break;
case Code.Brtrue_S:
instruction.OpCode = OpCodes.Brtrue;
break;
case Code.Beq_S:
instruction.OpCode = OpCodes.Beq;
break;
case Code.Bge_S:
instruction.OpCode = OpCodes.Bge;
break;
case Code.Bgt_S:
instruction.OpCode = OpCodes.Bgt;
break;
case Code.Ble_S:
instruction.OpCode = OpCodes.Ble;
break;
case Code.Blt_S:
instruction.OpCode = OpCodes.Blt;
break;
case Code.Bne_Un_S:
instruction.OpCode = OpCodes.Bne_Un;
break;
case Code.Bge_Un_S:
instruction.OpCode = OpCodes.Bge_Un;
break;
case Code.Bgt_Un_S:
instruction.OpCode = OpCodes.Bgt_Un;
break;
case Code.Ble_Un_S:
instruction.OpCode = OpCodes.Ble_Un;
break;
case Code.Blt_Un_S:
instruction.OpCode = OpCodes.Blt_Un;
break;
case Code.Leave_S:
instruction.OpCode = OpCodes.Leave;
break;
}
}
}
public static void ExpandMacro(ref OpCode opCode, ref object operand, MethodBody methodBody)
{
if (opCode.OpCodeType != OpCodeType.Macro)
return;
switch (opCode.Code) {
case Code.Ldarg_0: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(0); break;
case Code.Ldarg_1: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(1); break;
case Code.Ldarg_2: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(2); break;
case Code.Ldarg_3: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(3); break;
case Code.Ldloc_0: opCode = OpCodes.Ldloc; operand = methodBody.Variables[0]; break;
case Code.Ldloc_1: opCode = OpCodes.Ldloc; operand = methodBody.Variables[1]; break;
case Code.Ldloc_2: opCode = OpCodes.Ldloc; operand = methodBody.Variables[2]; break;
case Code.Ldloc_3: opCode = OpCodes.Ldloc; operand = methodBody.Variables[3]; break;
case Code.Stloc_0: opCode = OpCodes.Stloc; operand = methodBody.Variables[0]; break;
case Code.Stloc_1: opCode = OpCodes.Stloc; operand = methodBody.Variables[1]; break;
case Code.Stloc_2: opCode = OpCodes.Stloc; operand = methodBody.Variables[2]; break;
case Code.Stloc_3: opCode = OpCodes.Stloc; operand = methodBody.Variables[3]; break;
case Code.Ldarg_S: opCode = OpCodes.Ldarg; break;
case Code.Ldarga_S: opCode = OpCodes.Ldarga; break;
case Code.Starg_S: opCode = OpCodes.Starg; break;
case Code.Ldloc_S: opCode = OpCodes.Ldloc; break;
case Code.Ldloca_S: opCode = OpCodes.Ldloca; break;
case Code.Stloc_S: opCode = OpCodes.Stloc; break;
case Code.Ldc_I4_M1: opCode = OpCodes.Ldc_I4; operand = -1; break;
case Code.Ldc_I4_0: opCode = OpCodes.Ldc_I4; operand = 0; break;
case Code.Ldc_I4_1: opCode = OpCodes.Ldc_I4; operand = 1; break;
case Code.Ldc_I4_2: opCode = OpCodes.Ldc_I4; operand = 2; break;
case Code.Ldc_I4_3: opCode = OpCodes.Ldc_I4; operand = 3; break;
case Code.Ldc_I4_4: opCode = OpCodes.Ldc_I4; operand = 4; break;
case Code.Ldc_I4_5: opCode = OpCodes.Ldc_I4; operand = 5; break;
case Code.Ldc_I4_6: opCode = OpCodes.Ldc_I4; operand = 6; break;
case Code.Ldc_I4_7: opCode = OpCodes.Ldc_I4; operand = 7; break;
case Code.Ldc_I4_8: opCode = OpCodes.Ldc_I4; operand = 8; break;
case Code.Ldc_I4_S: opCode = OpCodes.Ldc_I4; operand = (int) (sbyte) operand; break;
case Code.Br_S: opCode = OpCodes.Br; break;
case Code.Brfalse_S: opCode = OpCodes.Brfalse; break;
case Code.Brtrue_S: opCode = OpCodes.Brtrue; break;
case Code.Beq_S: opCode = OpCodes.Beq; break;
case Code.Bge_S: opCode = OpCodes.Bge; break;
case Code.Bgt_S: opCode = OpCodes.Bgt; break;
case Code.Ble_S: opCode = OpCodes.Ble; break;
case Code.Blt_S: opCode = OpCodes.Blt; break;
case Code.Bne_Un_S: opCode = OpCodes.Bne_Un; break;
case Code.Bge_Un_S: opCode = OpCodes.Bge_Un; break;
case Code.Bgt_Un_S: opCode = OpCodes.Bgt_Un; break;
case Code.Ble_Un_S: opCode = OpCodes.Ble_Un; break;
case Code.Blt_Un_S: opCode = OpCodes.Blt_Un; break;
case Code.Leave_S: opCode = OpCodes.Leave; break;
}
}
static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
{
instruction.OpCode = opcode;
instruction.Operand = operand;
}
static void MakeMacro (Instruction instruction, OpCode opcode)
{
instruction.OpCode = opcode;
instruction.Operand = null;
}
public static void OptimizeMacros (this MethodBody self)
{
if (self == null)
throw new ArgumentNullException ("self");
var method = self.Method;
foreach (var instruction in self.Instructions) {
int index;
switch (instruction.OpCode.Code) {
case Code.Ldarg:
index = ((ParameterDefinition) instruction.Operand).Index;
if (index == -1 && instruction.Operand == self.ThisParameter)
index = 0;
else if (method.HasThis)
index++;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Ldarg_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldarg_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldarg_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldarg_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand);
break;
}
break;
case Code.Ldloc:
index = ((VariableDefinition) instruction.Operand).Index;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Ldloc_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldloc_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldloc_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldloc_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand);
break;
}
break;
case Code.Stloc:
index = ((VariableDefinition) instruction.Operand).Index;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Stloc_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Stloc_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Stloc_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Stloc_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand);
break;
}
break;
case Code.Ldarga:
index = ((ParameterDefinition) instruction.Operand).Index;
if (index == -1 && instruction.Operand == self.ThisParameter)
index = 0;
else if (method.HasThis)
index++;
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand);
break;
case Code.Ldloca:
if (((VariableDefinition) instruction.Operand).Index < 256)
ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand);
break;
case Code.Ldc_I4:
int i = (int) instruction.Operand;
switch (i) {
case -1:
MakeMacro (instruction, OpCodes.Ldc_I4_M1);
break;
case 0:
MakeMacro (instruction, OpCodes.Ldc_I4_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldc_I4_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldc_I4_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldc_I4_3);
break;
case 4:
MakeMacro (instruction, OpCodes.Ldc_I4_4);
break;
case 5:
MakeMacro (instruction, OpCodes.Ldc_I4_5);
break;
case 6:
MakeMacro (instruction, OpCodes.Ldc_I4_6);
break;
case 7:
MakeMacro (instruction, OpCodes.Ldc_I4_7);
break;
case 8:
MakeMacro (instruction, OpCodes.Ldc_I4_8);
break;
default:
if (i >= -128 && i < 128)
ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i);
break;
}
break;
}
}
OptimizeBranches (self);
}
static void OptimizeBranches (MethodBody body)
{
ComputeOffsets (body);
foreach (var instruction in body.Instructions) {
if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
continue;
if (OptimizeBranch (instruction))
ComputeOffsets (body);
}
}
static bool OptimizeBranch (Instruction instruction)
{
var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
if (!(offset >= -128 && offset <= 127))
return false;
switch (instruction.OpCode.Code) {
case Code.Br:
instruction.OpCode = OpCodes.Br_S;
break;
case Code.Brfalse:
instruction.OpCode = OpCodes.Brfalse_S;
break;
case Code.Brtrue:
instruction.OpCode = OpCodes.Brtrue_S;
break;
case Code.Beq:
instruction.OpCode = OpCodes.Beq_S;
break;
case Code.Bge:
instruction.OpCode = OpCodes.Bge_S;
break;
case Code.Bgt:
instruction.OpCode = OpCodes.Bgt_S;
break;
case Code.Ble:
instruction.OpCode = OpCodes.Ble_S;
break;
case Code.Blt:
instruction.OpCode = OpCodes.Blt_S;
break;
case Code.Bne_Un:
instruction.OpCode = OpCodes.Bne_Un_S;
break;
case Code.Bge_Un:
instruction.OpCode = OpCodes.Bge_Un_S;
break;
case Code.Bgt_Un:
instruction.OpCode = OpCodes.Bgt_Un_S;
break;
case Code.Ble_Un:
instruction.OpCode = OpCodes.Ble_Un_S;
break;
case Code.Blt_Un:
instruction.OpCode = OpCodes.Blt_Un_S;
break;
case Code.Leave:
instruction.OpCode = OpCodes.Leave_S;
break;
}
return true;
}
static void ComputeOffsets (MethodBody body)
{
var offset = 0;
foreach (var instruction in body.Instructions) {
instruction.Offset = offset;
offset += instruction.GetSize ();
}
}
}
}

118
ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs

@ -1,118 +0,0 @@
/*
* Created by SharpDevelop.
* User: User
* Date: 05/02/2011
* Time: 10:10
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler.Rocks
{
static class MyRocks
{
public static List<T> CutRange<T>(this List<T> list, int start, int count)
{
List<T> ret = new List<T>(count);
for (int i = 0; i < count; i++) {
ret.Add(list[start + i]);
}
list.RemoveRange(start, count);
return ret;
}
public static bool CanFallThough(this OpCode opCode)
{
switch(opCode.FlowControl) {
case FlowControl.Branch: return false;
case FlowControl.Cond_Branch: return true;
case FlowControl.Next: return true;
case FlowControl.Call: return true;
case FlowControl.Return: return false;
case FlowControl.Throw: return false;
case FlowControl.Meta: return true;
default: throw new NotImplementedException();
}
}
public static bool IsBranch(this OpCode opCode)
{
return opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch;
}
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:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
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 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.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
}
}
Loading…
Cancel
Save