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 MethodBuilder mbuilder;
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;
32 internal ILGenerator (MethodBuilder mb, int size) {
36 code = new byte [size];
38 cur_stack = max_stack = 0;
39 num_fixups = num_labels = 0;
40 label_to_addr = new int [16];
41 fixups = new LabelFixup [16];
44 private void make_room (int nbytes) {
45 if (code_len + nbytes < code.Length)
47 byte[] new_code = new byte [code.Length + 128];
48 System.Array.Copy (code, new_code, code.Length);
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);
57 /* change to pass by ref to avoid copy */
58 private void ll_emit (OpCode opcode) {
60 * there is already enough room allocated in code.
62 if (opcode.Size == 1) {
63 code [code_len++] = (byte)opcode.Value;
65 code [code_len++] = (byte)(opcode.Value & 0xFF);
66 code [code_len++] = (byte)(opcode.Value >> 8);
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...).
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 */
83 case StackBehaviour.Push1_push1:
87 if (max_stack < cur_stack)
88 max_stack = cur_stack;
90 * Note that we adjust for the pop behaviour _after_ setting max_stack.
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:
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:
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:
121 private static int target_len (OpCode opcode) {
122 if (opcode.operandType == OperandType.InlineBrTarget)
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;
141 locals = new LocalBuilder [1];
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;
152 label_to_addr [num_labels] = -1;
153 return new Label (num_labels++);
155 public virtual void Emit (OpCode opcode) {
159 public virtual void Emit (OpCode opcode, Byte val) {
162 code [code_len++] = val;
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
172 public virtual void Emit (OpCode opcode, Int16 val) {}
173 public virtual void Emit (OpCode opcode, Int32 val) {
178 public virtual void Emit (OpCode opcode, Int64 val) {}
179 public virtual void Emit (OpCode opcode, Label label) {
180 int tlen = target_len (opcode);
183 if (num_fixups >= fixups.Length) {
184 LabelFixup[] newf = new LabelFixup [fixups.Length + 16];
185 System.Array.Copy (fixups, newf, fixups.Length);
188 fixups [num_fixups].size = tlen;
189 fixups [num_fixups].pos = code_len;
190 fixups [num_fixups].label_idx = label.label;
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
203 [CLSCompliant(false)]
204 public virtual void Emit (OpCode opcode, sbyte val) {
207 code [code_len++] = (byte)val;
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) {}
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) {}
217 public virtual void EmitWriteLine (FieldInfo field) {}
218 public virtual void EmitWriteLine (LocalBuilder lbuilder) {}
219 public virtual void EmitWriteLine (string val) {}
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;
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) {}
234 internal void label_fixup () {
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);
241 int old_cl = code_len;
242 code_len = fixups [i].pos;