New tests.
[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                                         if (instr.Operand == body.Method.This)
133                                                 ni.Operand = nb.Method.This;
134                                         else {
135                                                 int param = body.Method.Parameters.IndexOf ((ParameterDefinition) instr.Operand);
136                                                 ni.Operand = parent.Parameters [param];
137                                         }
138                                         break;
139                                 case OperandType.InlineVar :
140                                 case OperandType.ShortInlineVar :
141                                         int var = body.Variables.IndexOf ((VariableDefinition) instr.Operand);
142                                         ni.Operand = nb.Variables [var];
143                                         break;
144                                 case OperandType.InlineField :
145                                         ni.Operand = context.Import ((FieldReference) instr.Operand);
146                                         break;
147                                 case OperandType.InlineMethod :
148                                         ni.Operand = context.Import ((MethodReference) instr.Operand);
149                                         break;
150                                 case OperandType.InlineType :
151                                         ni.Operand = context.Import ((TypeReference) instr.Operand);
152                                         break;
153                                 case OperandType.InlineTok :
154                                         if (instr.Operand is TypeReference)
155                                                 ni.Operand = context.Import ((TypeReference) instr.Operand);
156                                         else if (instr.Operand is FieldReference)
157                                                 ni.Operand = context.Import ((FieldReference) instr.Operand);
158                                         else if (instr.Operand is MethodReference)
159                                                 ni.Operand = context.Import ((MethodReference) instr.Operand);
160                                         break;
161                                 case OperandType.ShortInlineBrTarget :
162                                 case OperandType.InlineBrTarget :
163                                         break;
164                                 default :
165                                         ni.Operand = instr.Operand;
166                                         break;
167                                 }
168
169                                 nb.Instructions.Add (ni);
170                         }
171
172                         for (int i = 0; i < body.Instructions.Count; i++) {
173                                 Instruction instr = nb.Instructions [i];
174                                 if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget &&
175                                         instr.OpCode.OperandType != OperandType.InlineBrTarget)
176                                         continue;
177
178                                 instr.Operand = GetInstruction (body, nb, (Instruction) body.Instructions [i].Operand);
179                         }
180
181                         foreach (ExceptionHandler eh in body.ExceptionHandlers) {
182                                 ExceptionHandler neh = new ExceptionHandler (eh.Type);
183                                 neh.TryStart = GetInstruction (body, nb, eh.TryStart);
184                                 neh.TryEnd = GetInstruction (body, nb, eh.TryEnd);
185                                 neh.HandlerStart = GetInstruction (body, nb, eh.HandlerStart);
186                                 neh.HandlerEnd = GetInstruction (body, nb, eh.HandlerEnd);
187
188                                 switch (eh.Type) {
189                                 case ExceptionHandlerType.Catch :
190                                         neh.CatchType = context.Import (eh.CatchType);
191                                         break;
192                                 case ExceptionHandlerType.Filter :
193                                         neh.FilterStart = GetInstruction (body, nb, eh.FilterStart);
194                                         neh.FilterEnd = GetInstruction (body, nb, eh.FilterEnd);
195                                         break;
196                                 }
197
198                                 nb.ExceptionHandlers.Add (neh);
199                         }
200
201                         return nb;
202                 }
203
204                 public void Simplify ()
205                 {
206                         foreach (Instruction i in this.Instructions) {
207                                 if (i.OpCode.OpCodeType != OpCodeType.Macro)
208                                         continue;
209
210                                 switch (i.OpCode.Code) {
211                                 case Code.Ldarg_0 :
212                                         Simplify (i, OpCodes.Ldarg,
213                                                 CodeReader.GetParameter (this, 0));
214                                         break;
215                                 case Code.Ldarg_1 :
216                                         Simplify (i, OpCodes.Ldarg,
217                                                 CodeReader.GetParameter (this, 1));
218                                         break;
219                                 case Code.Ldarg_2 :
220                                         Simplify (i, OpCodes.Ldarg,
221                                                 CodeReader.GetParameter (this, 2));
222                                         break;
223                                 case Code.Ldarg_3 :
224                                         Simplify (i, OpCodes.Ldarg,
225                                                 CodeReader.GetParameter (this, 3));
226                                         break;
227                                 case Code.Ldloc_0 :
228                                         Simplify (i, OpCodes.Ldloc,
229                                                 CodeReader.GetVariable (this, 0));
230                                         break;
231                                 case Code.Ldloc_1 :
232                                         Simplify (i, OpCodes.Ldloc,
233                                                 CodeReader.GetVariable (this, 1));
234                                         break;
235                                 case Code.Ldloc_2 :
236                                         Simplify (i, OpCodes.Ldloc,
237                                                 CodeReader.GetVariable (this, 2));
238                                         break;
239                                 case Code.Ldloc_3 :
240                                         Simplify (i, OpCodes.Ldloc,
241                                                 CodeReader.GetVariable (this, 3));
242                                         break;
243                                 case Code.Stloc_0 :
244                                         Simplify (i, OpCodes.Stloc,
245                                                 CodeReader.GetVariable (this, 0));
246                                         break;
247                                 case Code.Stloc_1 :
248                                         Simplify (i, OpCodes.Stloc,
249                                                 CodeReader.GetVariable (this, 1));
250                                         break;
251                                 case Code.Stloc_2 :
252                                         Simplify (i, OpCodes.Stloc,
253                                                 CodeReader.GetVariable (this, 2));
254                                         break;
255                                 case Code.Stloc_3 :
256                                         Simplify (i, OpCodes.Stloc,
257                                                 CodeReader.GetVariable (this, 3));
258                                         break;
259                                 case Code.Ldarg_S :
260                                         i.OpCode = OpCodes.Ldarg;
261                                         break;
262                                 case Code.Ldarga_S :
263                                         i.OpCode = OpCodes.Ldarga;
264                                         break;
265                                 case Code.Starg_S :
266                                         i.OpCode = OpCodes.Starg;
267                                         break;
268                                 case Code.Ldloc_S :
269                                         i.OpCode = OpCodes.Ldloc;
270                                         break;
271                                 case Code.Ldloca_S :
272                                         i.OpCode = OpCodes.Ldloca;
273                                         break;
274                                 case Code.Stloc_S :
275                                         i.OpCode = OpCodes.Stloc;
276                                         break;
277                                 case Code.Ldc_I4_M1 :
278                                         Simplify (i, OpCodes.Ldc_I4, -1);
279                                         break;
280                                 case Code.Ldc_I4_0 :
281                                         Simplify (i, OpCodes.Ldc_I4, 0);
282                                         break;
283                                 case Code.Ldc_I4_1 :
284                                         Simplify (i, OpCodes.Ldc_I4, 1);
285                                         break;
286                                 case Code.Ldc_I4_2 :
287                                         Simplify (i, OpCodes.Ldc_I4, 2);
288                                         break;
289                                 case Code.Ldc_I4_3 :
290                                         Simplify (i, OpCodes.Ldc_I4, 3);
291                                         break;
292                                 case Code.Ldc_I4_4 :
293                                         Simplify (i, OpCodes.Ldc_I4, 4);
294                                         break;
295                                 case Code.Ldc_I4_5 :
296                                         Simplify (i, OpCodes.Ldc_I4, 5);
297                                         break;
298                                 case Code.Ldc_I4_6 :
299                                         Simplify (i, OpCodes.Ldc_I4, 6);
300                                         break;
301                                 case Code.Ldc_I4_7 :
302                                         Simplify (i, OpCodes.Ldc_I4, 7);
303                                         break;
304                                 case Code.Ldc_I4_8 :
305                                         Simplify (i, OpCodes.Ldc_I4, 8);
306                                         break;
307                                 case Code.Ldc_I4_S :
308                                         i.OpCode = OpCodes.Ldc_I4;
309                                         i.Operand = (int) (sbyte) i.Operand;
310                                         break;
311                                 case Code.Br_S :
312                                         i.OpCode = OpCodes.Br;
313                                         break;
314                                 case Code.Brfalse_S :
315                                         i.OpCode = OpCodes.Brfalse;
316                                         break;
317                                 case Code.Brtrue_S :
318                                         i.OpCode = OpCodes.Brtrue;
319                                         break;
320                                 case Code.Beq_S :
321                                         i.OpCode = OpCodes.Beq;
322                                         break;
323                                 case Code.Bge_S :
324                                         i.OpCode = OpCodes.Bge;
325                                         break;
326                                 case Code.Bgt_S :
327                                         i.OpCode = OpCodes.Bgt;
328                                         break;
329                                 case Code.Ble_S :
330                                         i.OpCode = OpCodes.Ble;
331                                         break;
332                                 case Code.Blt_S :
333                                         i.OpCode = OpCodes.Blt;
334                                         break;
335                                 case Code.Bne_Un_S :
336                                         i.OpCode = OpCodes.Bne_Un;
337                                         break;
338                                 case Code.Bge_Un_S :
339                                         i.OpCode = OpCodes.Bge_Un;
340                                         break;
341                                 case Code.Bgt_Un_S :
342                                         i.OpCode = OpCodes.Bgt_Un;
343                                         break;
344                                 case Code.Ble_Un_S :
345                                         i.OpCode = OpCodes.Ble_Un;
346                                         break;
347                                 case Code.Blt_Un_S :
348                                         i.OpCode = OpCodes.Blt_Un;
349                                         break;
350                                 case Code.Leave_S :
351                                         i.OpCode = OpCodes.Leave;
352                                         break;
353                                 }
354                         }
355                 }
356
357                 static void Simplify (Instruction i, OpCode op, object operand)
358                 {
359                         i.OpCode = op;
360                         i.Operand = operand;
361                 }
362
363                 public void Accept (ICodeVisitor visitor)
364                 {
365                         visitor.VisitMethodBody (this);
366                         m_variables.Accept (visitor);
367                         m_instructions.Accept (visitor);
368                         m_exceptions.Accept (visitor);
369                         m_scopes.Accept (visitor);
370
371                         visitor.TerminateMethodBody (this);
372                 }
373         }
374 }