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