Merge branch 'cecil-light'
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Cil / Instruction.cs
1 //
2 // Instruction.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2010 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 using System;
30 using System.Text;
31
32 namespace Mono.Cecil.Cil {
33
34         public sealed class Instruction {
35
36                 internal int offset;
37                 internal OpCode opcode;
38                 internal object operand;
39
40                 internal Instruction previous;
41                 internal Instruction next;
42
43                 SequencePoint sequence_point;
44
45                 public int Offset {
46                         get { return offset; }
47                         set { offset = value; }
48                 }
49
50                 public OpCode OpCode {
51                         get { return opcode; }
52                         set { opcode = value; }
53                 }
54
55                 public object Operand {
56                         get { return operand; }
57                         set { operand = value; }
58                 }
59
60                 public Instruction Previous {
61                         get { return previous; }
62                         set { previous = value; }
63                 }
64
65                 public Instruction Next {
66                         get { return next; }
67                         set { next = value; }
68                 }
69
70                 public SequencePoint SequencePoint {
71                         get { return sequence_point; }
72                         set { sequence_point = value; }
73                 }
74
75                 internal Instruction (int offset, OpCode opCode)
76                 {
77                         this.offset = offset;
78                         this.opcode = opCode;
79                 }
80
81                 internal Instruction (OpCode opcode, object operand)
82                 {
83                         this.opcode = opcode;
84                         this.operand = operand;
85                 }
86
87                 public int GetSize ()
88                 {
89                         int size = opcode.Size;
90
91                         switch (opcode.OperandType) {
92                         case OperandType.InlineSwitch:
93                                 return size + (1 + ((Instruction []) operand).Length) * 4;
94                         case OperandType.InlineI8:
95                         case OperandType.InlineR:
96                                 return size + 8;
97                         case OperandType.InlineBrTarget:
98                         case OperandType.InlineField:
99                         case OperandType.InlineI:
100                         case OperandType.InlineMethod:
101                         case OperandType.InlineString:
102                         case OperandType.InlineTok:
103                         case OperandType.InlineType:
104                         case OperandType.ShortInlineR:
105                         case OperandType.InlineSig:
106                                 return size + 4;
107                         case OperandType.InlineArg:
108                         case OperandType.InlineVar:
109                                 return size + 2;
110                         case OperandType.ShortInlineBrTarget:
111                         case OperandType.ShortInlineI:
112                         case OperandType.ShortInlineArg:
113                         case OperandType.ShortInlineVar:
114                                 return size + 1;
115                         default:
116                                 return size;
117                         }
118                 }
119
120                 public override string ToString ()
121                 {
122                         var instruction = new StringBuilder ();
123
124                         AppendLabel (instruction, this);
125                         instruction.Append (':');
126                         instruction.Append (' ');
127                         instruction.Append (opcode.Name);
128
129                         if (operand == null)
130                                 return instruction.ToString ();
131
132                         instruction.Append (' ');
133
134                         switch (opcode.OperandType) {
135                         case OperandType.ShortInlineBrTarget:
136                         case OperandType.InlineBrTarget:
137                                 AppendLabel (instruction, (Instruction) operand);
138                                 break;
139                         case OperandType.InlineSwitch:
140                                 var labels = (Instruction []) operand;
141                                 for (int i = 0; i < labels.Length; i++) {
142                                         if (i > 0)
143                                                 instruction.Append (',');
144
145                                         AppendLabel (instruction, labels [i]);
146                                 }
147                                 break;
148                         case OperandType.InlineString:
149                                 instruction.Append ('\"');
150                                 instruction.Append (operand);
151                                 instruction.Append ('\"');
152                                 break;
153                         default:
154                                 instruction.Append (operand);
155                                 break;
156                         }
157
158                         return instruction.ToString ();
159                 }
160
161                 static void AppendLabel (StringBuilder builder, Instruction instruction)
162                 {
163                         builder.Append ("IL_");
164                         builder.Append (instruction.offset.ToString ("x4"));
165                 }
166
167                 public static Instruction Create (OpCode opcode)
168                 {
169                         if (opcode.OperandType != OperandType.InlineNone)
170                                 throw new ArgumentException ("opcode");
171
172                         return new Instruction (opcode, null);
173                 }
174
175                 public static Instruction Create (OpCode opcode, TypeReference type)
176                 {
177                         if (type == null)
178                                 throw new ArgumentNullException ("type");
179                         if (opcode.OperandType != OperandType.InlineType &&
180                                 opcode.OperandType != OperandType.InlineTok)
181                                 throw new ArgumentException ("opcode");
182
183                         return new Instruction (opcode, type);
184                 }
185
186                 public static Instruction Create (OpCode opcode, CallSite site)
187                 {
188                         if (site == null)
189                                 throw new ArgumentNullException ("site");
190                         if (opcode.Code != Code.Calli)
191                                 throw new ArgumentException ("code");
192
193                         return new Instruction (opcode, site);
194                 }
195
196                 public static Instruction Create (OpCode opcode, MethodReference method)
197                 {
198                         if (method == null)
199                                 throw new ArgumentNullException ("method");
200                         if (opcode.OperandType != OperandType.InlineMethod &&
201                                 opcode.OperandType != OperandType.InlineTok)
202                                 throw new ArgumentException ("opcode");
203
204                         return new Instruction (opcode, method);
205                 }
206
207                 public static Instruction Create (OpCode opcode, FieldReference field)
208                 {
209                         if (field == null)
210                                 throw new ArgumentNullException ("field");
211                         if (opcode.OperandType != OperandType.InlineField &&
212                                 opcode.OperandType != OperandType.InlineTok)
213                                 throw new ArgumentException ("opcode");
214
215                         return new Instruction (opcode, field);
216                 }
217
218                 public static Instruction Create (OpCode opcode, string value)
219                 {
220                         if (value == null)
221                                 throw new ArgumentNullException ("value");
222                         if (opcode.OperandType != OperandType.InlineString)
223                                 throw new ArgumentException ("opcode");
224
225                         return new Instruction (opcode, value);
226                 }
227
228                 public static Instruction Create (OpCode opcode, sbyte value)
229                 {
230                         if (opcode.OperandType != OperandType.ShortInlineI &&
231                                 opcode != OpCodes.Ldc_I4_S)
232                                 throw new ArgumentException ("opcode");
233
234                         return new Instruction (opcode, value);
235                 }
236
237                 public static Instruction Create (OpCode opcode, byte value)
238                 {
239                         if (opcode.OperandType != OperandType.ShortInlineI ||
240                                 opcode == OpCodes.Ldc_I4_S)
241                                 throw new ArgumentException ("opcode");
242
243                         return new Instruction (opcode, value);
244                 }
245
246                 public static Instruction Create (OpCode opcode, int value)
247                 {
248                         if (opcode.OperandType != OperandType.InlineI)
249                                 throw new ArgumentException ("opcode");
250
251                         return new Instruction (opcode, value);
252                 }
253
254                 public static Instruction Create (OpCode opcode, long value)
255                 {
256                         if (opcode.OperandType != OperandType.InlineI8)
257                                 throw new ArgumentException ("opcode");
258
259                         return new Instruction (opcode, value);
260                 }
261
262                 public static Instruction Create (OpCode opcode, float value)
263                 {
264                         if (opcode.OperandType != OperandType.ShortInlineR)
265                                 throw new ArgumentException ("opcode");
266
267                         return new Instruction (opcode, value);
268                 }
269
270                 public static Instruction Create (OpCode opcode, double value)
271                 {
272                         if (opcode.OperandType != OperandType.InlineR)
273                                 throw new ArgumentException ("opcode");
274
275                         return new Instruction (opcode, value);
276                 }
277
278                 public static Instruction Create (OpCode opcode, Instruction target)
279                 {
280                         if (target == null)
281                                 throw new ArgumentNullException ("target");
282                         if (opcode.OperandType != OperandType.InlineBrTarget &&
283                                 opcode.OperandType != OperandType.ShortInlineBrTarget)
284                                 throw new ArgumentException ("opcode");
285
286                         return new Instruction (opcode, target);
287                 }
288
289                 public static Instruction Create (OpCode opcode, Instruction [] targets)
290                 {
291                         if (targets == null)
292                                 throw new ArgumentNullException ("targets");
293                         if (opcode.OperandType != OperandType.InlineSwitch)
294                                 throw new ArgumentException ("opcode");
295
296                         return new Instruction (opcode, targets);
297                 }
298
299                 public static Instruction Create (OpCode opcode, VariableDefinition variable)
300                 {
301                         if (variable == null)
302                                 throw new ArgumentNullException ("variable");
303                         if (opcode.OperandType != OperandType.ShortInlineVar &&
304                                 opcode.OperandType != OperandType.InlineVar)
305                                 throw new ArgumentException ("opcode");
306
307                         return new Instruction (opcode, variable);
308                 }
309
310                 public static Instruction Create (OpCode opcode, ParameterDefinition parameter)
311                 {
312                         if (parameter == null)
313                                 throw new ArgumentNullException ("parameter");
314                         if (opcode.OperandType != OperandType.ShortInlineArg &&
315                                 opcode.OperandType != OperandType.InlineArg)
316                                 throw new ArgumentException ("opcode");
317
318                         return new Instruction (opcode, parameter);
319                 }
320         }
321 }