Fixed Optimize for ldc_i4
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Cil / CilWorker.cs
1 //
2 // CilWorker.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 System;
32         using SR = System.Reflection;
33
34         public sealed class CilWorker {
35
36                 MethodBody m_mbody;
37                 InstructionCollection m_instrs;
38
39                 internal CilWorker (MethodBody body)
40                 {
41                         m_mbody = body;
42                         m_instrs = m_mbody.Instructions;
43                 }
44
45                 public MethodBody GetBody ()
46                 {
47                         return m_mbody;
48                 }
49
50                 public Instruction Create (OpCode opcode)
51                 {
52                         if (opcode.OperandType != OperandType.InlineNone)
53                                 throw new ArgumentException ("opcode");
54
55                         return FinalCreate (opcode);
56                 }
57
58                 public Instruction Create (OpCode opcode, TypeReference type)
59                 {
60                         if (opcode.OperandType != OperandType.InlineType &&
61                                 opcode.OperandType != OperandType.InlineTok)
62                                 throw new ArgumentException ("opcode");
63
64                         return FinalCreate (opcode, type);
65                 }
66
67                 public Instruction Create (OpCode opcode, MethodReference meth)
68                 {
69                         if (opcode.OperandType != OperandType.InlineMethod &&
70                                 opcode.OperandType != OperandType.InlineTok)
71                                 throw new ArgumentException ("opcode");
72
73                         return FinalCreate (opcode, meth);
74                 }
75
76                 public Instruction Create (OpCode opcode, FieldReference field)
77                 {
78                         if (opcode.OperandType != OperandType.InlineField &&
79                                 opcode.OperandType != OperandType.InlineTok)
80                                 throw new ArgumentException ("opcode");
81
82                         return FinalCreate (opcode, field);
83                 }
84
85                 public Instruction Create (OpCode opcode, string str)
86                 {
87                         if (opcode.OperandType != OperandType.InlineString)
88                                 throw new ArgumentException ("opcode");
89
90                         return FinalCreate (opcode, str);
91                 }
92
93                 public Instruction Create (OpCode opcode, sbyte b)
94                 {
95                         if (opcode.OperandType != OperandType.ShortInlineI &&
96                                 opcode != OpCodes.Ldc_I4_S)
97                                 throw new ArgumentException ("opcode");
98
99                         return FinalCreate (opcode, b);
100                 }
101
102                 public Instruction Create (OpCode opcode, byte b)
103                 {
104                         if (opcode.OperandType != OperandType.ShortInlineI ||
105                                 opcode == OpCodes.Ldc_I4_S)
106                                 throw new ArgumentException ("opcode");
107
108                         return FinalCreate (opcode, b);
109                 }
110
111                 public Instruction Create (OpCode opcode, int i)
112                 {
113                         if (opcode.OperandType != OperandType.InlineI)
114                                 throw new ArgumentException ("opcode");
115
116                         return FinalCreate (opcode, i);
117                 }
118
119                 public Instruction Create (OpCode opcode, long l)
120                 {
121                         if (opcode.OperandType != OperandType.InlineI8)
122                                 throw new ArgumentException ("opcode");
123
124                         return FinalCreate (opcode, l);
125                 }
126
127                 public Instruction Create (OpCode opcode, float f)
128                 {
129                         if (opcode.OperandType != OperandType.ShortInlineR)
130                                 throw new ArgumentException ("opcode");
131
132                         return FinalCreate (opcode, f);
133                 }
134
135                 public Instruction Create (OpCode opcode, double d)
136                 {
137                         if (opcode.OperandType != OperandType.InlineR)
138                                 throw new ArgumentException ("opcode");
139
140                         return FinalCreate (opcode, d);
141                 }
142
143                 public Instruction Create (OpCode opcode, Instruction label)
144                 {
145                         if (opcode.OperandType != OperandType.InlineBrTarget &&
146                                 opcode.OperandType != OperandType.ShortInlineBrTarget)
147                                 throw new ArgumentException ("opcode");
148
149                         return FinalCreate (opcode, label);
150                 }
151
152                 public Instruction Create (OpCode opcode, Instruction [] labels)
153                 {
154                         if (opcode.OperandType != OperandType.InlineSwitch)
155                                 throw new ArgumentException ("opcode");
156
157                         return FinalCreate (opcode, labels);
158                 }
159
160                 public Instruction Create (OpCode opcode, VariableDefinition var)
161                 {
162                         if (opcode.OperandType != OperandType.ShortInlineVar &&
163                                 opcode.OperandType != OperandType.InlineVar)
164                                 throw new ArgumentException ("opcode");
165
166                         return FinalCreate (opcode, var);
167                 }
168
169                 public Instruction Create (OpCode opcode, ParameterDefinition param)
170                 {
171                         if (opcode.OperandType != OperandType.ShortInlineParam &&
172                                 opcode.OperandType != OperandType.InlineParam)
173                                 throw new ArgumentException ("opcode");
174
175                         return FinalCreate (opcode, param);
176                 }
177
178                 Instruction FinalCreate (OpCode opcode)
179                 {
180                         return FinalCreate (opcode, null);
181                 }
182
183                 Instruction FinalCreate (OpCode opcode, object operand)
184                 {
185                         return new Instruction (opcode, operand);
186                 }
187
188                 public Instruction Emit (OpCode opcode)
189                 {
190                         Instruction instr = Create (opcode);
191                         Append (instr);
192                         return instr;
193                 }
194
195                 public Instruction Emit (OpCode opcode, TypeReference type)
196                 {
197                         Instruction instr = Create (opcode, type);
198                         Append (instr);
199                         return instr;
200                 }
201
202                 public Instruction Emit (OpCode opcode, MethodReference meth)
203                 {
204                         Instruction instr = Create (opcode, meth);
205                         Append (instr);
206                         return instr;
207                 }
208
209                 public Instruction Emit (OpCode opcode, FieldReference field)
210                 {
211                         Instruction instr = Create (opcode, field);
212                         Append (instr);
213                         return instr;
214                 }
215
216                 public Instruction Emit (OpCode opcode, string str)
217                 {
218                         Instruction instr = Create (opcode, str);
219                         Append (instr);
220                         return instr;
221                 }
222
223                 public Instruction Emit (OpCode opcode, byte b)
224                 {
225                         Instruction instr = Create (opcode, b);
226                         Append (instr);
227                         return instr;
228                 }
229
230                 public Instruction Emit (OpCode opcode, sbyte b)
231                 {
232                         Instruction instr = Create (opcode, b);
233                         Append (instr);
234                         return instr;
235                 }
236
237                 public Instruction Emit (OpCode opcode, int i)
238                 {
239                         Instruction instr = Create (opcode, i);
240                         Append (instr);
241                         return instr;
242                 }
243
244                 public Instruction Emit (OpCode opcode, long l)
245                 {
246                         Instruction instr = Create (opcode, l);
247                         Append (instr);
248                         return instr;
249                 }
250
251                 public Instruction Emit (OpCode opcode, float f)
252                 {
253                         Instruction instr = Create (opcode, f);
254                         Append (instr);
255                         return instr;
256                 }
257
258                 public Instruction Emit (OpCode opcode, double d)
259                 {
260                         Instruction instr = Create (opcode, d);
261                         Append (instr);
262                         return instr;
263                 }
264
265                 public Instruction Emit (OpCode opcode, Instruction target)
266                 {
267                         Instruction instr = Create (opcode, target);
268                         Append (instr);
269                         return instr;
270                 }
271
272                 public Instruction Emit (OpCode opcode, Instruction [] targets)
273                 {
274                         Instruction instr = Create (opcode, targets);
275                         Append (instr);
276                         return instr;
277                 }
278
279                 public Instruction Emit (OpCode opcode, VariableDefinition var)
280                 {
281                         Instruction instr = Create (opcode, var);
282                         Append (instr);
283                         return instr;
284                 }
285
286                 public Instruction Emit (OpCode opcode, ParameterDefinition param)
287                 {
288                         Instruction instr = Create (opcode, param);
289                         Append (instr);
290                         return instr;
291                 }
292
293                 public void InsertBefore (Instruction target, Instruction instr)
294                 {
295                         int index = m_instrs.IndexOf (target);
296                         if (index == -1)
297                                 throw new ArgumentOutOfRangeException ("Target instruction not in method body");
298
299                         m_instrs.Insert (index, instr);
300                         instr.Previous = target.Previous;
301                         if (target.Previous != null)
302                                 target.Previous.Next = instr;
303                         target.Previous = instr;
304                         instr.Next = target;
305                 }
306
307                 public void InsertAfter (Instruction target, Instruction instr)
308                 {
309                         int index = m_instrs.IndexOf (target);
310                         if (index == -1)
311                                 throw new ArgumentOutOfRangeException ("Target instruction not in method body");
312
313                         m_instrs.Insert (index + 1, instr);
314                         instr.Next = target.Next;
315                         if (target.Next != null)
316                                 target.Next.Previous = instr;
317                         target.Next = instr;
318                         instr.Previous = target;
319                 }
320
321                 public void Append (Instruction instr)
322                 {
323                         Instruction last = null, current = instr;
324                         if (m_instrs.Count > 0)
325                                 last = m_instrs [m_instrs.Count - 1];
326
327                         if (last != null) {
328                                 last.Next = instr;
329                                 current.Previous = last;
330                         }
331
332                         m_instrs.Add (current);
333                 }
334
335                 public void Replace (Instruction old, Instruction instr)
336                 {
337                         int index = m_instrs.IndexOf (old);
338                         if (index == -1)
339                                 throw new ArgumentOutOfRangeException ("Target instruction not in method body");
340
341                         InsertAfter (old, instr);
342                         Remove (old);
343                 }
344
345                 public void Remove (Instruction instr)
346                 {
347                         if (!m_instrs.Contains (instr))
348                                 throw new ArgumentException ("Instruction not in method body");
349
350                         if (instr.Previous != null)
351                                 instr.Previous.Next = instr.Next;
352                         if (instr.Next != null)
353                                 instr.Next.Previous = instr.Previous;
354                         m_instrs.Remove (instr);
355                 }
356         }
357 }