2007-07-19 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Cil / MethodBody.cs
1 //
2 // MethodBody.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2005 Jb Evain
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 namespace Mono.Cecil.Cil {
30
31         using Mono.Cecil;
32
33         public sealed class MethodBody : IVariableDefinitionProvider, IScopeProvider, ICodeVisitable {
34
35                 MethodDefinition m_method;
36                 int m_maxStack;
37                 int m_codeSize;
38                 bool m_initLocals;
39                 int m_localVarToken;
40
41                 InstructionCollection m_instructions;
42                 ExceptionHandlerCollection m_exceptions;
43                 VariableDefinitionCollection m_variables;
44                 ScopeCollection m_scopes;
45
46                 private CilWorker m_cilWorker;
47
48                 public MethodDefinition Method {
49                         get { return m_method; }
50                 }
51
52                 public int MaxStack {
53                         get { return m_maxStack; }
54                         set { m_maxStack = value; }
55                 }
56
57                 public int CodeSize {
58                         get { return m_codeSize; }
59                         set { m_codeSize = value; }
60                 }
61
62                 public bool InitLocals {
63                         get { return m_initLocals; }
64                         set { m_initLocals = value; }
65                 }
66
67                 internal int LocalVarToken {
68                         get { return m_localVarToken; }
69                         set { m_localVarToken = value; }
70                 }
71
72                 public CilWorker CilWorker {
73                         get {
74                                 if (m_cilWorker == null)
75                                         m_cilWorker = new CilWorker (this);
76                                 return m_cilWorker;
77                         }
78                         set { m_cilWorker = value; }
79                 }
80
81                 public InstructionCollection Instructions {
82                         get { return m_instructions; }
83                 }
84
85                 public ExceptionHandlerCollection ExceptionHandlers {
86                         get { return m_exceptions; }
87                 }
88
89                 public VariableDefinitionCollection Variables {
90                         get { return m_variables; }
91                 }
92
93                 public ScopeCollection Scopes {
94                         get { return m_scopes; }
95                 }
96
97                 public MethodBody (MethodDefinition meth)
98                 {
99                         m_method = meth;
100                         m_instructions = new InstructionCollection (this);
101                         m_exceptions = new ExceptionHandlerCollection (this);
102                         m_variables = new VariableDefinitionCollection (this);
103                         m_scopes = new ScopeCollection (this);
104                 }
105
106                 internal static Instruction GetInstruction (MethodBody oldBody, MethodBody newBody, Instruction i)
107                 {
108                         int pos = oldBody.Instructions.IndexOf (i);
109                         if (pos > -1 && pos < newBody.Instructions.Count)
110                                 return newBody.Instructions [pos];
111
112                         return newBody.Instructions.Outside;
113                 }
114
115                 internal static MethodBody Clone (MethodBody body, MethodDefinition parent, ImportContext context)
116                 {
117                         MethodBody nb = new MethodBody (parent);
118                         nb.MaxStack = body.MaxStack;
119                         nb.InitLocals = body.InitLocals;
120                         nb.CodeSize = body.CodeSize;
121
122                         foreach (VariableDefinition var in body.Variables)
123                                 nb.Variables.Add (new VariableDefinition (
124                                         context.Import (var.VariableType)));
125
126                         foreach (Instruction instr in body.Instructions) {
127                                 Instruction ni = new Instruction (instr.OpCode);
128
129                                 switch (instr.OpCode.OperandType) {
130                                 case OperandType.InlineParam :
131                                 case OperandType.ShortInlineParam :
132                                         int param = body.Method.Parameters.IndexOf ((ParameterDefinition) instr.Operand);
133                                         ni.Operand = parent.Parameters [param];
134                                         break;
135                                 case OperandType.InlineVar :
136                                 case OperandType.ShortInlineVar :
137                                         int var = body.Variables.IndexOf ((VariableDefinition) instr.Operand);
138                                         ni.Operand = nb.Variables [var];
139                                         break;
140                                 case OperandType.InlineField :
141                                         ni.Operand = context.Import ((FieldReference) instr.Operand);
142                                         break;
143                                 case OperandType.InlineMethod :
144                                         ni.Operand = context.Import ((MethodReference) instr.Operand);
145                                         break;
146                                 case OperandType.InlineType :
147                                         ni.Operand = context.Import ((TypeReference) instr.Operand);
148                                         break;
149                                 case OperandType.InlineTok :
150                                         if (instr.Operand is TypeReference)
151                                                 ni.Operand = context.Import ((TypeReference) instr.Operand);
152                                         else if (instr.Operand is FieldReference)
153                                                 ni.Operand = context.Import ((FieldReference) instr.Operand);
154                                         else if (instr.Operand is MethodReference)
155                                                 ni.Operand = context.Import ((MethodReference) instr.Operand);
156                                         break;
157                                 case OperandType.ShortInlineBrTarget :
158                                 case OperandType.InlineBrTarget :
159                                         break;
160                                 default :
161                                         ni.Operand = instr.Operand;
162                                         break;
163                                 }
164
165                                 nb.Instructions.Add (ni);
166                         }
167
168                         for (int i = 0; i < body.Instructions.Count; i++) {
169                                 Instruction instr = nb.Instructions [i];
170                                 if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget &&
171                                         instr.OpCode.OperandType != OperandType.InlineBrTarget)
172                                         continue;
173
174                                 instr.Operand = GetInstruction (body, nb, (Instruction) body.Instructions [i].Operand);
175                         }
176
177                         foreach (ExceptionHandler eh in body.ExceptionHandlers) {
178                                 ExceptionHandler neh = new ExceptionHandler (eh.Type);
179                                 neh.TryStart = GetInstruction (body, nb, eh.TryStart);
180                                 neh.TryEnd = GetInstruction (body, nb, eh.TryEnd);
181                                 neh.HandlerStart = GetInstruction (body, nb, eh.HandlerStart);
182                                 neh.HandlerEnd = GetInstruction (body, nb, eh.HandlerEnd);
183
184                                 switch (eh.Type) {
185                                 case ExceptionHandlerType.Catch :
186                                         neh.CatchType = context.Import (eh.CatchType);
187                                         break;
188                                 case ExceptionHandlerType.Filter :
189                                         neh.FilterStart = GetInstruction (body, nb, eh.FilterStart);
190                                         neh.FilterEnd = GetInstruction (body, nb, eh.FilterEnd);
191                                         break;
192                                 }
193
194                                 nb.ExceptionHandlers.Add (neh);
195                         }
196
197                         return nb;
198                 }
199
200                 public void Simplify ()
201                 {
202                         foreach (Instruction i in this.Instructions) {
203                                 if (i.OpCode.OpCodeType != OpCodeType.Macro)
204                                         continue;
205
206                                 switch (i.OpCode.Code) {
207                                 case Code.Ldarg_0 :
208                                         Simplify (i, OpCodes.Ldarg,
209                                                 CodeReader.GetParameter (this, 0));
210                                         break;
211                                 case Code.Ldarg_1 :
212                                         Simplify (i, OpCodes.Ldarg,
213                                                 CodeReader.GetParameter (this, 1));
214                                         break;
215                                 case Code.Ldarg_2 :
216                                         Simplify (i, OpCodes.Ldarg,
217                                                 CodeReader.GetParameter (this, 2));
218                                         break;
219                                 case Code.Ldarg_3 :
220                                         Simplify (i, OpCodes.Ldarg,
221                                                 CodeReader.GetParameter (this, 3));
222                                         break;
223                                 case Code.Ldloc_0 :
224                                         Simplify (i, OpCodes.Ldloc,
225                                                 CodeReader.GetVariable (this, 0));
226                                         break;
227                                 case Code.Ldloc_1 :
228                                         Simplify (i, OpCodes.Ldloc,
229                                                 CodeReader.GetVariable (this, 1));
230                                         break;
231                                 case Code.Ldloc_2 :
232                                         Simplify (i, OpCodes.Ldloc,
233                                                 CodeReader.GetVariable (this, 2));
234                                         break;
235                                 case Code.Ldloc_3 :
236                                         Simplify (i, OpCodes.Ldloc,
237                                                 CodeReader.GetVariable (this, 3));
238                                         break;
239                                 case Code.Stloc_0 :
240                                         Simplify (i, OpCodes.Stloc,
241                                                 CodeReader.GetVariable (this, 0));
242                                         break;
243                                 case Code.Stloc_1 :
244                                         Simplify (i, OpCodes.Stloc,
245                                                 CodeReader.GetVariable (this, 1));
246                                         break;
247                                 case Code.Stloc_2 :
248                                         Simplify (i, OpCodes.Stloc,
249                                                 CodeReader.GetVariable (this, 2));
250                                         break;
251                                 case Code.Stloc_3 :
252                                         Simplify (i, OpCodes.Stloc,
253                                                 CodeReader.GetVariable (this, 3));
254                                         break;
255                                 case Code.Ldarg_S :
256                                         i.OpCode = OpCodes.Ldarg;
257                                         break;
258                                 case Code.Ldarga_S :
259                                         i.OpCode = OpCodes.Ldarga;
260                                         break;
261                                 case Code.Starg_S :
262                                         i.OpCode = OpCodes.Starg;
263                                         break;
264                                 case Code.Ldloc_S :
265                                         i.OpCode = OpCodes.Ldloc;
266                                         break;
267                                 case Code.Ldloca_S :
268                                         i.OpCode = OpCodes.Ldloca;
269                                         break;
270                                 case Code.Stloc_S :
271                                         i.OpCode = OpCodes.Stloc;
272                                         break;
273                                 case Code.Ldc_I4_M1 :
274                                         Simplify (i, OpCodes.Ldc_I4, -1);
275                                         break;
276                                 case Code.Ldc_I4_0 :
277                                         Simplify (i, OpCodes.Ldc_I4, 0);
278                                         break;
279                                 case Code.Ldc_I4_1 :
280                                         Simplify (i, OpCodes.Ldc_I4, 1);
281                                         break;
282                                 case Code.Ldc_I4_2 :
283                                         Simplify (i, OpCodes.Ldc_I4, 2);
284                                         break;
285                                 case Code.Ldc_I4_3 :
286                                         Simplify (i, OpCodes.Ldc_I4, 3);
287                                         break;
288                                 case Code.Ldc_I4_4 :
289                                         Simplify (i, OpCodes.Ldc_I4, 4);
290                                         break;
291                                 case Code.Ldc_I4_5 :
292                                         Simplify (i, OpCodes.Ldc_I4, 5);
293                                         break;
294                                 case Code.Ldc_I4_6 :
295                                         Simplify (i, OpCodes.Ldc_I4, 6);
296                                         break;
297                                 case Code.Ldc_I4_7 :
298                                         Simplify (i, OpCodes.Ldc_I4, 7);
299                                         break;
300                                 case Code.Ldc_I4_8 :
301                                         Simplify (i, OpCodes.Ldc_I4, 8);
302                                         break;
303                                 case Code.Ldc_I4_S :
304                                         i.OpCode = OpCodes.Ldc_I4;
305                                         i.Operand = (int) (sbyte) i.Operand;
306                                         break;
307                                 case Code.Br_S :
308                                         i.OpCode = OpCodes.Br;
309                                         break;
310                                 case Code.Brfalse_S :
311                                         i.OpCode = OpCodes.Brfalse;
312                                         break;
313                                 case Code.Brtrue_S :
314                                         i.OpCode = OpCodes.Brtrue;
315                                         break;
316                                 case Code.Beq_S :
317                                         i.OpCode = OpCodes.Beq;
318                                         break;
319                                 case Code.Bge_S :
320                                         i.OpCode = OpCodes.Bge;
321                                         break;
322                                 case Code.Bgt_S :
323                                         i.OpCode = OpCodes.Bgt;
324                                         break;
325                                 case Code.Ble_S :
326                                         i.OpCode = OpCodes.Ble;
327                                         break;
328                                 case Code.Blt_S :
329                                         i.OpCode = OpCodes.Blt;
330                                         break;
331                                 case Code.Bne_Un_S :
332                                         i.OpCode = OpCodes.Bne_Un;
333                                         break;
334                                 case Code.Bge_Un_S :
335                                         i.OpCode = OpCodes.Bge_Un;
336                                         break;
337                                 case Code.Bgt_Un_S :
338                                         i.OpCode = OpCodes.Bgt_Un;
339                                         break;
340                                 case Code.Ble_Un_S :
341                                         i.OpCode = OpCodes.Ble_Un;
342                                         break;
343                                 case Code.Blt_Un_S :
344                                         i.OpCode = OpCodes.Blt_Un;
345                                         break;
346                                 case Code.Leave_S :
347                                         i.OpCode = OpCodes.Leave;
348                                         break;
349                                 }
350                         }
351                 }
352
353                 static void Simplify (Instruction i, OpCode op, object operand)
354                 {
355                         i.OpCode = op;
356                         i.Operand = operand;
357                 }
358
359                 public void Accept (ICodeVisitor visitor)
360                 {
361                         visitor.VisitMethodBody (this);
362                         m_variables.Accept (visitor);
363                         m_instructions.Accept (visitor);
364                         m_exceptions.Accept (visitor);
365                         m_scopes.Accept (visitor);
366
367                         visitor.TerminateMethodBody (this);
368                 }
369         }
370 }