[bcl] Remove NET_4_5 defines from class libs.
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Rewrite / Decompile.cs
1 //
2 // Decompile.cs
3 //
4 // Authors:
5 //      Chris Bacon (chrisbacon76@gmail.com)
6 //
7 // Copyright (C) 2010 Chris Bacon
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28
29 using System;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Text;
33 using Mono.CodeContracts.Rewrite.Ast;
34 using Mono.Cecil;
35 using Mono.Cecil.Cil;
36
37 namespace Mono.CodeContracts.Rewrite {
38
39         class Decompile {
40
41                 public Decompile (ModuleDefinition module, MethodDefinition method)
42                 {
43                         this.method = 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);
48                 }
49
50                 private MethodInfo methodInfo;
51                 private MethodDefinition method;
52                 private Stack<Expr> exprs;
53                 private ExprGen gen;
54
55                 public Dictionary<Expr, Instruction> Instructions { get; private set; }
56
57                 public Expr Go (bool failQuietly = true)
58                 {
59                         Instruction unknownInst = null;
60                         var insts = this.method.Body.Instructions;
61                         foreach (Instruction inst in insts) {
62                                 if (failQuietly) {
63                                         if (unknownInst == null) {
64                                                 try {
65                                                         Expr expr = this.ProcessInst (inst);
66                                                         this.Instructions.Add (expr, inst);
67                                                         this.exprs.Push (expr);
68                                                 } catch (NotSupportedException) {
69                                                         unknownInst = inst;
70                                                 }
71                                         } else {
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);
77                                                         }
78                                                 }
79                                         }
80                                 } else {
81                                         Expr expr = this.ProcessInst (inst);
82                                         this.Instructions.Add (expr, inst);
83                                         this.exprs.Push (expr);
84                                 }
85                         }
86
87                         Expr decompiled = new ExprBlock (this.methodInfo, this.exprs.Reverse ().ToArray ());
88                         return decompiled;
89                 }
90
91                 private Expr ProcessInst (Instruction inst)
92                 {
93                         var opcode = inst.OpCode.Code;
94                         switch (opcode) {
95                         case Code.Nop:
96                                 return this.gen.Nop ();
97                         case Code.Ldarg_0:
98                         case Code.Ldarg_1:
99                         case Code.Ldarg_2:
100                         case Code.Ldarg_3:
101                                 return this.gen.LoadArg ((int) (opcode - Code.Ldarg_0));
102                         case Code.Ldarg_S:
103                                 return this.gen.LoadArg ((ParameterDefinition) inst.Operand);
104                         case Code.Ldnull:
105                                 return this.gen.LoadConstant (null);
106                         case Code.Ldc_I4_M1:
107                         case Code.Ldc_I4_0:
108                         case Code.Ldc_I4_1:
109                         case Code.Ldc_I4_2:
110                         case Code.Ldc_I4_3:
111                         case Code.Ldc_I4_4:
112                         case Code.Ldc_I4_5:
113                         case Code.Ldc_I4_6:
114                         case Code.Ldc_I4_7:
115                         case Code.Ldc_I4_8:
116                                 return this.gen.LoadConstant ((int) (opcode - Code.Ldc_I4_0));
117                         case Code.Ldc_I4_S:
118                                 return this.gen.LoadConstant ((int) (sbyte) inst.Operand);
119                         case Code.Ldc_I4:
120                                 return this.gen.LoadConstant ((int) inst.Operand);
121                         case Code.Ldc_R4:
122                         case Code.Ldc_R8:
123                         case Code.Ldstr:
124                                 return this.gen.LoadConstant(inst.Operand);
125                         case Code.Clt:
126                         case Code.Clt_Un:
127                         case Code.Cgt:
128                         case Code.Cgt_Un:
129                         case Code.Ceq:
130                         case Code.Add:
131                         case Code.Sub:
132                                 return this.ProcessBinaryOp (opcode);
133                         case Code.Call:
134                                 return this.ProcessCall ((MethodReference) inst.Operand);
135                         case Code.Ret:
136                                 return this.gen.Return ();
137                         case Code.Conv_I4:
138                                 return this.ProcessConv (TypeCode.Int32);
139                         case Code.Conv_I8:
140                                 return this.ProcessConv (TypeCode.Int64);
141                         default:
142                                 throw new NotSupportedException ("Cannot handle opcode: " + inst.OpCode);
143                         }
144                 }
145
146                 private Expr ProcessBinaryOp (Code opcode)
147                 {
148                         Expr right = this.exprs.Pop ();
149                         Expr left = this.exprs.Pop ();
150                         switch (opcode) {
151                         case Code.Ceq:
152                                 return this.gen.CompareEqual (left, right);
153                         case Code.Clt:
154                                 return this.gen.CompareLessThan (left, right, Sn.Signed);
155                         case Code.Clt_Un:
156                                 return this.gen.CompareLessThan (left, right, Sn.Unsigned);
157                         case Code.Cgt:
158                                 return this.gen.CompareGreaterThan (left, right, Sn.Signed);
159                         case Code.Cgt_Un:
160                                 return this.gen.CompareGreaterThan (left, right, Sn.Unsigned);
161                         case Code.Add:
162                                 return this.gen.Add (left, right, Sn.None, false);
163                         case Code.Sub:
164                                 return this.gen.Sub (left, right, Sn.None, false);
165                         default:
166                                 throw new NotSupportedException ("Unknown binary opcode: " + opcode);
167                         }
168                 }
169
170                 private Expr ProcessCall (MethodReference method)
171                 {
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;
177                         }
178                         return this.gen.Call(method, parameterExprs);
179                 }
180
181                 private Expr ProcessConv (TypeCode convToType)
182                 {
183                         Expr exprToConvert = this.exprs.Pop ();
184                         return this.gen.Conv(exprToConvert, convToType);
185                 }
186
187         }
188 }