Browse Source

Updated decompiler to the new Cecil

pull/1/head^2
David Srbecký 15 years ago
parent
commit
44e1258b5f
  1. 2
      .gitignore
  2. 23
      Decompiler.csproj
  3. 16
      Decompiler.sln
  4. 1833
      bin/Debug/output.cs
  5. 3
      lib/NRefactory/Project/NRefactory.csproj
  6. 13
      lib/NRefactory/Project/NRefactory.csproj.user
  7. 15
      src/AstBuilder.cs
  8. 48
      src/AstMetodBodyBuilder.cs
  9. 4
      src/ByteCode.StackBehaviour.cs
  10. 4
      src/ByteCode.Type.cs
  11. 4
      src/ByteCodeExpression.cs
  12. 15
      src/Constants.cs
  13. 3
      src/MainForm.cs
  14. 426
      src/Mono.Cecil.Rocks/MethodBodyRocks.cs

2
.gitignore vendored

@ -0,0 +1,2 @@
bin/
obj/

23
Decompiler.csproj

@ -1,4 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup> <PropertyGroup>
<ProjectGuid>{EE3A3C1A-F9C3-4C75-853D-A9476E518C3A}</ProjectGuid> <ProjectGuid>{EE3A3C1A-F9C3-4C75-853D-A9476E518C3A}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -7,10 +8,14 @@
<RootNamespace>Decompiler</RootNamespace> <RootNamespace>Decompiler</RootNamespace>
<AssemblyName>Decompiler</AssemblyName> <AssemblyName>Decompiler</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType> <DebugType>Full</DebugType>
<Optimize>False</Optimize> <Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
@ -24,6 +29,13 @@
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>x86</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
@ -44,6 +56,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="src" /> <Folder Include="src" />
<Folder Include="src\ControlFlow" /> <Folder Include="src\ControlFlow" />
<Folder Include="src\Mono.Cecil.Rocks" />
<Folder Include="src\Transforms" /> <Folder Include="src\Transforms" />
<Folder Include="src\Transforms\Ast" /> <Folder Include="src\Transforms\Ast" />
<Compile Include="src\AssemblyInfo.cs" /> <Compile Include="src\AssemblyInfo.cs" />
@ -54,6 +67,7 @@
<Compile Include="src\ByteCode.Type.cs" /> <Compile Include="src\ByteCode.Type.cs" />
<Compile Include="src\ByteCodeCollection.cs" /> <Compile Include="src\ByteCodeCollection.cs" />
<Compile Include="src\CilStack.cs" /> <Compile Include="src\CilStack.cs" />
<Compile Include="src\Constants.cs" />
<Compile Include="src\ControlFlow\Node-Optimize.cs" /> <Compile Include="src\ControlFlow\Node-Optimize.cs" />
<Compile Include="src\ControlFlow\Node-Transforms.cs" /> <Compile Include="src\ControlFlow\Node-Transforms.cs" />
<Compile Include="src\ControlFlow\NodeCollection.cs" /> <Compile Include="src\ControlFlow\NodeCollection.cs" />
@ -61,6 +75,7 @@
<Compile Include="src\ControlFlow\Node-Structure.cs" /> <Compile Include="src\ControlFlow\Node-Structure.cs" />
<Compile Include="src\MainForm.cs" /> <Compile Include="src\MainForm.cs" />
<Compile Include="src\MainForm.Designer.cs" /> <Compile Include="src\MainForm.Designer.cs" />
<Compile Include="src\Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="src\Options.cs" /> <Compile Include="src\Options.cs" />
<Compile Include="src\Program.cs" /> <Compile Include="src\Program.cs" />
<Compile Include="src\ByteCode.StackAnalysis.cs" /> <Compile Include="src\ByteCode.StackAnalysis.cs" />
@ -86,8 +101,8 @@
<Link>Reversi.exe</Link> <Link>Reversi.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<ProjectReference Include="lib\cecil-0.6\src\Mono.Cecil\Mono.Cecil.csproj"> <ProjectReference Include="lib\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}</Project> <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="lib\NRefactory\Project\NRefactory.csproj"> <ProjectReference Include="lib\NRefactory\Project\NRefactory.csproj">

16
Decompiler.sln

@ -1,12 +1,12 @@
 
Microsoft Visual Studio Solution File, Format Version 10.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2008 # Visual Studio 2010
# SharpDevelop 3.0.0.3674 # SharpDevelop 4.0.0.6486
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Decompiler", "Decompiler.csproj", "{EE3A3C1A-F9C3-4C75-853D-A9476E518C3A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Decompiler", "Decompiler.csproj", "{EE3A3C1A-F9C3-4C75-853D-A9476E518C3A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "lib\cecil-0.6\src\Mono.Cecil\Mono.Cecil.csproj", "{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "lib\Mono.Cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -22,9 +22,9 @@ Global
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.Build.0 = Release|Any CPU {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.Build.0 = Release|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}.Release|Any CPU.Build.0 = Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = Release|Any CPU
{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

1833
bin/Debug/output.cs

File diff suppressed because it is too large Load Diff

3
lib/NRefactory/Project/NRefactory.csproj

@ -1,4 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

13
lib/NRefactory/Project/NRefactory.csproj.user

@ -1,13 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<LastOpenVersion>8.0.41115</LastOpenVersion>
<ProjectView>ShowAllFiles</ProjectView>
<ProjectTrust>0</ProjectTrust>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<StartProgram>..\..\..\..\bin\SharpDevelop.exe</StartProgram>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<StartProgram>..\..\..\..\bin\SharpDevelop.exe</StartProgram>
</PropertyGroup>
</Project>

15
src/AstBuilder.cs

@ -1,13 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Linq;
using Microsoft.CSharp;
using Ast = ICSharpCode.NRefactory.Ast; using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.PrettyPrinter; using ICSharpCode.NRefactory.PrettyPrinter;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
@ -261,7 +258,9 @@ namespace Decompiler
} }
// Add constructors // Add constructors
foreach(MethodDefinition methodDef in typeDef.Constructors) { foreach(MethodDefinition methodDef in typeDef.Methods) {
if (!methodDef.IsConstructor) continue;
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration(
methodDef.Name, methodDef.Name,
ConvertModifiers(methodDef), ConvertModifiers(methodDef),
@ -281,7 +280,7 @@ namespace Decompiler
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration();
astMethod.Name = methodDef.Name; astMethod.Name = methodDef.Name;
astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.ReturnType.FullName); astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName);
astMethod.Modifier = ConvertModifiers(methodDef); astMethod.Modifier = ConvertModifiers(methodDef);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
@ -293,12 +292,12 @@ namespace Decompiler
astType.Children.Add(new IdentifierExpression("\r\n")); astType.Children.Add(new IdentifierExpression("\r\n"));
} }
if (astType.Children.Last is IdentifierExpression) { if (astType.Children.LastOrDefault() is IdentifierExpression) {
astType.Children.Last.Remove(); astType.Children.Last.Remove();
} }
} }
IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(ParameterDefinitionCollection paramCol) IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
{ {
foreach(ParameterDefinition paramDef in paramCol) { foreach(ParameterDefinition paramDef in paramCol) {
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression(

48
src/AstMetodBodyBuilder.cs

@ -7,6 +7,7 @@ using ICSharpCode.NRefactory.Ast;
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;
@ -31,7 +32,7 @@ namespace Decompiler
if (methodDef.Body == null) return astBlock; if (methodDef.Body == null) return astBlock;
methodDef.Body.Simplify(); methodDef.Body.SimplifyMacros();
ByteCodeCollection body = new ByteCodeCollection(methodDef); ByteCodeCollection body = new ByteCodeCollection(methodDef);
@ -48,22 +49,37 @@ 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>();
int boolFlagId = 1; int boolFlagId = 1;
foreach(VariableDefinition varDef in methodDef.Body.Variables) { foreach(VariableDefinition varDef in methodDef.Body.Variables) {
if (varDef.VariableType.FullName == Cecil.Constants.Int32 && if (string.IsNullOrEmpty(varDef.Name)) {
varDef.Name.StartsWith("V_") && if (varDef.VariableType.FullName == Constants.Int32 && intNames.Count > 0) {
intNames.Count > 0) varDef.Name = intNames[0];
{ intNames.RemoveAt(0);
varDef.Name = intNames[0]; } else if (varDef.VariableType.FullName == Constants.Boolean) {
intNames.RemoveAt(0); if (boolFlagId == 1) {
} else if (varDef.VariableType.FullName == Cecil.Constants.Boolean && varDef.Name = "flag";
varDef.Name.StartsWith("V_")) { } else {
if (boolFlagId == 1) { varDef.Name = "flag" + boolFlagId;
varDef.Name = "flag"; }
boolFlagId++;
} else { } else {
varDef.Name = "flag" + boolFlagId; string name;
if (varDef.VariableType.IsArray) {
name = "array";
} else {
name = varDef.VariableType.Name;
name = char.ToLower(name[0]) + name.Substring(1);
}
if (!typeNames.ContainsKey(name)) {
typeNames.Add(name, 0);
}
int count = typeNames[name];
if (count > 0) {
name += count.ToString();
}
varDef.Name = name;
} }
boolFlagId++;
} }
localVarTypes[varDef.Name] = varDef.VariableType; localVarTypes[varDef.Name] = varDef.VariableType;
localVarDefined[varDef.Name] = false; localVarDefined[varDef.Name] = false;
@ -511,7 +527,7 @@ namespace Decompiler
case Code.Isinst: throw new NotImplementedException(); case Code.Isinst: throw new NotImplementedException();
case Code.Jmp: throw new NotImplementedException(); case Code.Jmp: throw new NotImplementedException();
case Code.Ldarg: case Code.Ldarg:
if (methodDef.HasThis && ((ParameterDefinition)operand).Sequence == 0) { if (methodDef.HasThis && ((ParameterDefinition)operand).Index == 0) {
return new Ast.ThisReferenceExpression(); return new Ast.ThisReferenceExpression();
} else { } else {
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name);
@ -600,8 +616,8 @@ 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.ReturnType.FullName != Cecil.Constants.Void) { if (methodDef.ReturnType.FullName != Constants.Void) {
arg1 = Convert(arg1, methodDef.ReturnType.ReturnType); arg1 = Convert(arg1, methodDef.ReturnType);
return new Ast.ReturnStatement(arg1); return new Ast.ReturnStatement(arg1);
} else { } else {
return new Ast.ReturnStatement(null); return new Ast.ReturnStatement(null);

4
src/ByteCode.StackBehaviour.cs

@ -55,7 +55,7 @@ namespace Decompiler
} }
case Code.Calli: throw new NotImplementedException(); case Code.Calli: throw new NotImplementedException();
case Code.Ret: case Code.Ret:
if (methodDef.ReturnType.ReturnType.FullName == Constants.Void) { if (methodDef.ReturnType.FullName == Constants.Void) {
return 0; return 0;
} else { } else {
return 1; return 1;
@ -85,7 +85,7 @@ namespace Decompiler
case Code.Call: case Code.Call:
case Code.Callvirt: case Code.Callvirt:
Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand); Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) { if (cecilMethod.ReturnType.FullName == Constants.Void) {
return 0; return 0;
} else { } else {
return 1; return 1;

4
src/ByteCode.Type.cs

@ -199,9 +199,9 @@ namespace Decompiler
case Code.Arglist: throw new NotImplementedException(); case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException(); case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException(); case Code.Break: throw new NotImplementedException();
case Code.Call: return ((MethodReference)operand).ReturnType.ReturnType; case Code.Call: return ((MethodReference)operand).ReturnType;
case Code.Calli: throw new NotImplementedException(); case Code.Calli: throw new NotImplementedException();
case Code.Callvirt: return ((MethodReference)operand).ReturnType.ReturnType; case Code.Callvirt: return ((MethodReference)operand).ReturnType;
case Code.Castclass: throw new NotImplementedException(); case Code.Castclass: throw new NotImplementedException();
case Code.Ckfinite: throw new NotImplementedException(); case Code.Ckfinite: throw new NotImplementedException();
case Code.Constrained: throw new NotImplementedException(); case Code.Constrained: throw new NotImplementedException();

4
src/ByteCodeExpression.cs

@ -77,12 +77,12 @@ namespace Decompiler
public static ByteCodeExpression Ldloc(string name) public static ByteCodeExpression Ldloc(string name)
{ {
return new ByteCodeExpression(OpCodes.Ldloc, new VariableDefinition(name, 0, null, null), true); return new ByteCodeExpression(OpCodes.Ldloc, new VariableDefinition(name, null), true);
} }
public static ByteCodeExpression Stloc(string name) public static ByteCodeExpression Stloc(string name)
{ {
return new ByteCodeExpression(OpCodes.Stloc, new VariableDefinition(name, 0, null, null), false); return new ByteCodeExpression(OpCodes.Stloc, new VariableDefinition(name, null), false);
} }
public ByteCodeExpression(OpCode opCode, object operand, bool returnsValue) public ByteCodeExpression(OpCode opCode, object operand, bool returnsValue)

15
src/Constants.cs

@ -0,0 +1,15 @@
// 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";
}
}

3
src/MainForm.cs

@ -1,7 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Reflection; using System.Reflection;
using System.Windows.Forms; using System.Windows.Forms;
@ -59,7 +58,7 @@ namespace Decompiler
Options.TypeFilter = filter.Text; Options.TypeFilter = filter.Text;
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(filename); AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filename);
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddAssembly(assembly); codeDomBuilder.AddAssembly(assembly);
SourceCode = codeDomBuilder.GenerateCode(); SourceCode = codeDomBuilder.GenerateCode();

426
src/Mono.Cecil.Rocks/MethodBodyRocks.cs

@ -0,0 +1,426 @@
//
// 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;
}
}
}
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 ();
}
}
}
}
Loading…
Cancel
Save