Thu Dec 13 20:10:57 CET 2001 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ILGenerator.cs
1
2 //
3 // System.Reflection.Emit/ILGenerator.cs
4 //
5 // Author:
6 //   Paolo Molaro (lupus@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc.  http://www.ximian.com
9 //
10
11 using System;
12 using System.Diagnostics.SymbolStore;
13
14 namespace System.Reflection.Emit {
15         public class ILGenerator: Object {
16                 private struct LabelFixup {
17                         public int size;
18                         public int pos;
19                         public int label_idx;
20                 };
21                 private byte[] code;
22                 private MethodBase mbuilder; /* a MethodBuilder or ConstructorBuilder */
23                 private int code_len;
24                 private int max_stack;
25                 private int cur_stack;
26                 private LocalBuilder[] locals;
27                 private int[] label_to_addr;
28                 private int num_labels;
29                 private LabelFixup[] fixups;
30                 private int num_fixups;
31                 private AssemblyBuilder abuilder;
32
33                 internal ILGenerator (MethodBase mb, int size) {
34                         if (size < 0)
35                                 size = 256;
36                         code_len = 0;
37                         code = new byte [size];
38                         mbuilder = mb;
39                         cur_stack = max_stack = 0;
40                         num_fixups = num_labels = 0;
41                         label_to_addr = new int [16];
42                         fixups = new LabelFixup [16];
43                         if (mb is MethodBuilder) {
44                                 abuilder = (AssemblyBuilder)((MethodBuilder)mb).TypeBuilder.Module.Assembly;
45                         } else if (mb is ConstructorBuilder) {
46                                 abuilder = (AssemblyBuilder)((ConstructorBuilder)mb).TypeBuilder.Module.Assembly;
47                         }
48                 }
49
50                 private void make_room (int nbytes) {
51                         if (code_len + nbytes < code.Length)
52                                 return;
53                         byte[] new_code = new byte [code.Length + 128];
54                         System.Array.Copy (code, new_code, code.Length);
55                         code = new_code;
56                 }
57                 private void emit_int (int val) {
58                         code [code_len++] = (byte) (val & 0xFF);
59                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
60                         code [code_len++] = (byte) ((val >> 16) & 0xFF);
61                         code [code_len++] = (byte) ((val << 24) & 0xFF);
62                 }
63                 /* change to pass by ref to avoid copy */
64                 private void ll_emit (OpCode opcode) {
65                         /* 
66                          * there is already enough room allocated in code.
67                          */
68                         if (opcode.Size == 1) {
69                                 code [code_len++] = (byte)opcode.Value;
70                         } else {
71                                 code [code_len++] = (byte)(opcode.Value & 0xFF);
72                                 code [code_len++] = (byte)(opcode.Value >> 8);
73                         }
74                         /*
75                          * We should probably keep track of stack needs here.
76                          * Or we may want to run the verifier on the code before saving it
77                          * (this may be needed anyway when the ILGenerator is not used...).
78                          */
79                         switch (opcode.StackBehaviourPush) {
80                         case StackBehaviour.Push1:
81                         case StackBehaviour.Pushi:
82                         case StackBehaviour.Pushi8:
83                         case StackBehaviour.Pushr4:
84                         case StackBehaviour.Pushr8:
85                         case StackBehaviour.Pushref:
86                         case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
87                                 cur_stack ++;
88                                 break;
89                         case StackBehaviour.Push1_push1:
90                                 cur_stack += 2;
91                                 break;
92                         }
93                         if (max_stack < cur_stack)
94                                 max_stack = cur_stack;
95                         /* 
96                          * Note that we adjust for the pop behaviour _after_ setting max_stack.
97                          */
98                         switch (opcode.StackBehaviourPop) {
99                         case StackBehaviour.Varpop:
100                                 break; /* we are conservative and assume it doesn't decrease the stack needs */
101                         case StackBehaviour.Pop1:
102                         case StackBehaviour.Popi:
103                         case StackBehaviour.Popref:
104                                 cur_stack --;
105                                 break;
106                         case StackBehaviour.Pop1_pop1:
107                         case StackBehaviour.Popi_pop1:
108                         case StackBehaviour.Popi_popi:
109                         case StackBehaviour.Popi_popi8:
110                         case StackBehaviour.Popi_popr4:
111                         case StackBehaviour.Popi_popr8:
112                         case StackBehaviour.Popref_pop1:
113                         case StackBehaviour.Popref_popi:
114                                 cur_stack -= 2;
115                                 break;
116                         case StackBehaviour.Popi_popi_popi:
117                         case StackBehaviour.Popref_popi_popi:
118                         case StackBehaviour.Popref_popi_popi8:
119                         case StackBehaviour.Popref_popi_popr4:
120                         case StackBehaviour.Popref_popi_popr8:
121                         case StackBehaviour.Popref_popi_popref:
122                                 cur_stack -= 3;
123                                 break;
124                         }
125                 }
126
127                 private static int target_len (OpCode opcode) {
128                         if (opcode.operandType == OperandType.InlineBrTarget)
129                                 return 4;
130                         return 1;
131                 }
132
133                 public virtual void BeginCatchBlock (Type exceptionType) {}
134                 public virtual void BeginExceptFilterBlock () {}
135                 public virtual void BeginExceptionBlock () {}
136                 public virtual void BeginFaultBlock() {}
137                 public virtual void BeginFinallyBlock() {}
138                 public virtual void BeginScope () {}
139                 public virtual LocalBuilder DeclareLocal (Type localType) {
140                         LocalBuilder res = new LocalBuilder (localType);
141                         if (locals != null) {
142                                 LocalBuilder[] new_l = new LocalBuilder [locals.Length];
143                                 System.Array.Copy (locals, new_l, locals.Length);
144                                 new_l [locals.Length] = res;
145                                 locals = new_l;
146                         } else {
147                                 locals = new LocalBuilder [1];
148                                 locals [0] = res;
149                         }
150                         res.position = locals.Length - 1;
151                         return res;
152                 }
153                 public virtual Label DefineLabel () {
154                         if (num_labels >= label_to_addr.Length) {
155                                 int[] new_l = new int [label_to_addr.Length + 16];
156                                 System.Array.Copy (label_to_addr, new_l, label_to_addr.Length);
157                                 label_to_addr = new_l;
158                         }
159                         label_to_addr [num_labels] = -1;
160                         return new Label (num_labels++);
161                 }
162                 public virtual void Emit (OpCode opcode) {
163                         make_room (2);
164                         ll_emit (opcode);
165                 }
166                 public virtual void Emit (OpCode opcode, Byte val) {
167                         make_room (3);
168                         ll_emit (opcode);
169                         code [code_len++] = val;
170                 }
171                 public virtual void Emit (OpCode opcode, ConstructorInfo constructor) {
172                         int token = abuilder.GetToken (constructor);
173                         make_room (6);
174                         ll_emit (opcode);
175                         emit_int (token);
176                 }
177                 public virtual void Emit (OpCode opcode, Double val) {}
178                 public virtual void Emit (OpCode opcode, FieldInfo field) {
179                         int token = abuilder.GetToken (field);
180                         make_room (6);
181                         ll_emit (opcode);
182                         emit_int (token);
183                 }
184                 public virtual void Emit (OpCode opcode, Int16 val) {
185                         make_room (4);
186                         ll_emit (opcode);
187                         code [code_len++] = (byte) (val & 0xFF);
188                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
189                 }
190                 public virtual void Emit (OpCode opcode, Int32 val) {
191                         make_room (6);
192                         ll_emit (opcode);
193                         emit_int (val);
194                 }
195                 public virtual void Emit (OpCode opcode, Int64 val) {}
196                 public virtual void Emit (OpCode opcode, Label label) {
197                         int tlen = target_len (opcode);
198                         make_room (6);
199                         ll_emit (opcode);
200                         if (num_fixups >= fixups.Length) {
201                                 LabelFixup[] newf = new LabelFixup [fixups.Length + 16];
202                                 System.Array.Copy (fixups, newf, fixups.Length);
203                                 fixups = newf;
204                         }
205                         fixups [num_fixups].size = tlen;
206                         fixups [num_fixups].pos = code_len;
207                         fixups [num_fixups].label_idx = label.label;
208                         num_fixups++;
209                         code_len += tlen;
210
211                 }
212                 public virtual void Emit (OpCode opcode, Label[] labels) {
213                         /* opcode needs to be switch. */
214                         int count = labels.Length;
215                         make_room (6 + count * 4);
216                         ll_emit (opcode);
217                         emit_int (count);
218                         if (num_fixups + count >= fixups.Length) {
219                                 LabelFixup[] newf = new LabelFixup [fixups.Length + count + 16];
220                                 System.Array.Copy (fixups, newf, fixups.Length);
221                                 fixups = newf;
222                         }
223                         for (int i = 0; i < count; ++i) {
224                                 fixups [num_fixups].size = 4;
225                                 fixups [num_fixups].pos = code_len;
226                                 fixups [num_fixups].label_idx = labels [i].label;
227                                 num_fixups++;
228                                 code_len += 4;
229                         }
230                 }
231                 public virtual void Emit (OpCode opcode, LocalBuilder lbuilder) {
232                         make_room (6);
233                         ll_emit (opcode);
234                         code [code_len++] = (byte) (lbuilder.position & 0xFF);
235                         if (opcode.operandType == OperandType.InlineVar) {
236                                 code [code_len++] = (byte) ((lbuilder.position >> 8) & 0xFF);
237                         }
238                 }
239                 public virtual void Emit (OpCode opcode, MethodInfo method) {
240                         int token = abuilder.GetToken (method);
241                         make_room (6);
242                         ll_emit (opcode);
243                         emit_int (token);
244                 }
245                 [CLSCompliant(false)]
246                 public virtual void Emit (OpCode opcode, sbyte val) {
247                         make_room (3);
248                         ll_emit (opcode);
249                         code [code_len++] = (byte)val;
250                 }
251                 public virtual void Emit (OpCode opcode, SignatureHelper shelper) {
252                         int token = 0; // FIXME: request a token from the modulebuilder
253                         make_room (6);
254                         ll_emit (opcode);
255                         emit_int (token);
256                 }
257                 public virtual void Emit (OpCode opcode, float val) {}
258                 public virtual void Emit (OpCode opcode, string val) {
259                         int token = abuilder.GetToken (val);
260                         make_room (3);
261                         ll_emit (opcode);
262                         emit_int (token);
263                 }
264                 public virtual void Emit (OpCode opcode, Type type) {}
265
266                 public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes) {}
267                 public void EmitCalli (OpCode opcode, CallingConventions call_conv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes) {}
268
269                 public virtual void EmitWriteLine (FieldInfo field) {}
270                 public virtual void EmitWriteLine (LocalBuilder lbuilder) {}
271                 public virtual void EmitWriteLine (string val) {}
272
273                 public virtual void EndExceptionBlock () {}
274                 public virtual void EndScope () {}
275                 public virtual void MarkLabel (Label loc) {
276                         if (loc.label < 0 || loc.label >= num_labels)
277                                 throw new System.ArgumentException ("The label is not valid");
278                         if (label_to_addr [loc.label] >= 0)
279                                 throw new System.ArgumentException ("The label was already defined");
280                         label_to_addr [loc.label] = code_len;
281                 }
282                 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int EndColumn) {}
283                 public virtual void ThrowException (Type exceptionType) {}
284                 public virtual void UsingNamespace (String usingNamespace) {}
285
286                 internal void label_fixup () {
287                         int i;
288                         for (i = 0; i < num_fixups; ++i) {
289                                 int diff = label_to_addr [fixups [i].label_idx] - fixups [i].pos;
290                                 if (fixups [i].size == 1) {
291                                         code [fixups [i].pos] = (byte)((sbyte) diff - 1);
292                                 } else {
293                                         int old_cl = code_len;
294                                         code_len = fixups [i].pos;
295                                         emit_int (diff - 4);
296                                         code_len = old_cl;
297                                 }
298                         }
299                 }
300         }
301 }