5 // Chris Bacon (chrisbacon76@gmail.com)
7 // Copyright (C) 2010 Chris Bacon
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
33 using Mono.CodeContracts.Rewrite.Ast;
37 namespace Mono.CodeContracts.Rewrite {
41 public Decompile (ModuleDefinition module, MethodDefinition method)
44 this.exprs = new Stack<Expr> ();
45 this.Instructions = new Dictionary<Expr, Instruction> ();
46 this.methodInfo = new MethodInfo (module, method);
47 this.gen = new ExprGen (this.methodInfo);
50 private MethodInfo methodInfo;
51 private MethodDefinition method;
52 private Stack<Expr> exprs;
55 public Dictionary<Expr, Instruction> Instructions { get; private set; }
57 public Expr Go (bool failQuietly = true)
59 Instruction unknownInst = null;
60 var insts = this.method.Body.Instructions;
61 foreach (Instruction inst in insts) {
63 if (unknownInst == null) {
65 Expr expr = this.ProcessInst (inst);
66 this.Instructions.Add (expr, inst);
67 this.exprs.Push (expr);
68 } catch (NotSupportedException) {
72 // Met unknown instruction, so check that there are no more contracts
73 if (inst.OpCode.OperandType == OperandType.InlineMethod) {
74 MethodReference method = (MethodReference) inst.Operand;
75 if (method.DeclaringType.FullName == "System.Diagnostics.Contracts.Contract") {
76 throw new NotSupportedException ("Unknown instruction in contract: " + unknownInst);
81 Expr expr = this.ProcessInst (inst);
82 this.Instructions.Add (expr, inst);
83 this.exprs.Push (expr);
87 Expr decompiled = new ExprBlock (this.methodInfo, this.exprs.Reverse ().ToArray ());
91 private Expr ProcessInst (Instruction inst)
93 var opcode = inst.OpCode.Code;
96 return this.gen.Nop ();
101 return this.gen.LoadArg ((int) (opcode - Code.Ldarg_0));
103 return this.gen.LoadArg ((ParameterDefinition) inst.Operand);
105 return this.gen.LoadConstant (null);
116 return this.gen.LoadConstant ((int) (opcode - Code.Ldc_I4_0));
118 return this.gen.LoadConstant ((int) (sbyte) inst.Operand);
120 return this.gen.LoadConstant ((int) inst.Operand);
124 return this.gen.LoadConstant(inst.Operand);
132 return this.ProcessBinaryOp (opcode);
134 return this.ProcessCall ((MethodReference) inst.Operand);
136 return this.gen.Return ();
138 return this.ProcessConv (TypeCode.Int32);
140 return this.ProcessConv (TypeCode.Int64);
142 throw new NotSupportedException ("Cannot handle opcode: " + inst.OpCode);
146 private Expr ProcessBinaryOp (Code opcode)
148 Expr right = this.exprs.Pop ();
149 Expr left = this.exprs.Pop ();
152 return this.gen.CompareEqual (left, right);
154 return this.gen.CompareLessThan (left, right, Sn.Signed);
156 return this.gen.CompareLessThan (left, right, Sn.Unsigned);
158 return this.gen.CompareGreaterThan (left, right, Sn.Signed);
160 return this.gen.CompareGreaterThan (left, right, Sn.Unsigned);
162 return this.gen.Add (left, right, Sn.None, false);
164 return this.gen.Sub (left, right, Sn.None, false);
166 throw new NotSupportedException ("Unknown binary opcode: " + opcode);
170 private Expr ProcessCall (MethodReference method)
172 int paramCount = method.Parameters.Count;
173 Expr [] parameterExprs = new Expr [paramCount];
174 for (int i = 0; i < paramCount; i++) {
175 Expr parameter = this.exprs.Pop ();
176 parameterExprs [paramCount - i - 1] = parameter;
178 return this.gen.Call(method, parameterExprs);
181 private Expr ProcessConv (TypeCode convToType)
183 Expr exprToConvert = this.exprs.Pop ();
184 return this.gen.Conv(exprToConvert, convToType);