3 // System.Reflection.Emit/ILGenerator.cs
6 // Paolo Molaro (lupus@ximian.com)
8 // (C) 2001 Ximian, Inc. http://www.ximian.com
12 using System.Diagnostics.SymbolStore;
14 namespace System.Reflection.Emit {
15 public class ILGenerator: Object {
16 private struct LabelFixup {
22 private MethodBase mbuilder; /* a MethodBuilder or ConstructorBuilder */
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;
33 internal ILGenerator (MethodBase mb, int size) {
37 code = new byte [size];
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;
50 private void make_room (int nbytes) {
51 if (code_len + nbytes < code.Length)
53 byte[] new_code = new byte [code.Length + 128];
54 System.Array.Copy (code, new_code, code.Length);
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);
63 /* change to pass by ref to avoid copy */
64 private void ll_emit (OpCode opcode) {
66 * there is already enough room allocated in code.
68 if (opcode.Size == 1) {
69 code [code_len++] = (byte)opcode.Value;
71 code [code_len++] = (byte)(opcode.Value & 0xFF);
72 code [code_len++] = (byte)(opcode.Value >> 8);
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...).
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 */
89 case StackBehaviour.Push1_push1:
93 if (max_stack < cur_stack)
94 max_stack = cur_stack;
96 * Note that we adjust for the pop behaviour _after_ setting max_stack.
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:
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:
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:
127 private static int target_len (OpCode opcode) {
128 if (opcode.operandType == OperandType.InlineBrTarget)
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;
147 locals = new LocalBuilder [1];
150 res.position = locals.Length - 1;
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;
159 label_to_addr [num_labels] = -1;
160 return new Label (num_labels++);
162 public virtual void Emit (OpCode opcode) {
166 public virtual void Emit (OpCode opcode, Byte val) {
169 code [code_len++] = val;
171 public virtual void Emit (OpCode opcode, ConstructorInfo constructor) {
172 int token = abuilder.GetToken (constructor);
177 public virtual void Emit (OpCode opcode, Double val) {}
178 public virtual void Emit (OpCode opcode, FieldInfo field) {
179 int token = abuilder.GetToken (field);
184 public virtual void Emit (OpCode opcode, Int16 val) {
187 code [code_len++] = (byte) (val & 0xFF);
188 code [code_len++] = (byte) ((val >> 8) & 0xFF);
190 public virtual void Emit (OpCode opcode, Int32 val) {
195 public virtual void Emit (OpCode opcode, Int64 val) {}
196 public virtual void Emit (OpCode opcode, Label label) {
197 int tlen = target_len (opcode);
200 if (num_fixups >= fixups.Length) {
201 LabelFixup[] newf = new LabelFixup [fixups.Length + 16];
202 System.Array.Copy (fixups, newf, fixups.Length);
205 fixups [num_fixups].size = tlen;
206 fixups [num_fixups].pos = code_len;
207 fixups [num_fixups].label_idx = label.label;
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);
218 if (num_fixups + count >= fixups.Length) {
219 LabelFixup[] newf = new LabelFixup [fixups.Length + count + 16];
220 System.Array.Copy (fixups, newf, fixups.Length);
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;
231 public virtual void Emit (OpCode opcode, LocalBuilder lbuilder) {
234 code [code_len++] = (byte) (lbuilder.position & 0xFF);
235 if (opcode.operandType == OperandType.InlineVar) {
236 code [code_len++] = (byte) ((lbuilder.position >> 8) & 0xFF);
239 public virtual void Emit (OpCode opcode, MethodInfo method) {
240 int token = abuilder.GetToken (method);
245 [CLSCompliant(false)]
246 public virtual void Emit (OpCode opcode, sbyte val) {
249 code [code_len++] = (byte)val;
251 public virtual void Emit (OpCode opcode, SignatureHelper shelper) {
252 int token = 0; // FIXME: request a token from the modulebuilder
257 public virtual void Emit (OpCode opcode, float val) {}
258 public virtual void Emit (OpCode opcode, string val) {
259 int token = abuilder.GetToken (val);
264 public virtual void Emit (OpCode opcode, Type type) {}
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) {}
269 public virtual void EmitWriteLine (FieldInfo field) {}
270 public virtual void EmitWriteLine (LocalBuilder lbuilder) {}
271 public virtual void EmitWriteLine (string val) {}
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;
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) {}
286 internal void label_fixup () {
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);
293 int old_cl = code_len;
294 code_len = fixups [i].pos;