[System.Private.CoreLib] Fix the type conflicts with corefx types
[mono-project.git] / mcs / class / System.Private.CoreLib / System.Reflection.Emit / ILGenerator.cs
blob5f7e1cfab7fdb014ae0abe780e0b1979f764225b
2 //
3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // System.Reflection.Emit/ILGenerator.cs
28 // Author:
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
34 #if MONO_FEATURE_SRE
35 using System;
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Diagnostics.SymbolStore;
39 using System.Runtime.InteropServices;
41 namespace System.Reflection.Emit {
43 internal struct ILExceptionBlock {
44 public const int CATCH = 0;
45 public const int FILTER = 1;
46 public const int FINALLY = 2;
47 public const int FAULT = 4;
48 public const int FILTER_START = -1;
50 internal Type extype;
51 internal int type;
52 internal int start;
53 internal int len;
54 internal int filter_offset;
56 internal void Debug () {
57 #if FALSE
58 System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
59 if (extype != null)
60 System.Console.WriteLine (" extype="+extype.ToString());
61 else
62 System.Console.WriteLine (String.Empty);
63 #endif
66 internal struct ILExceptionInfo {
67 #pragma warning disable 169
68 #pragma warning disable 414
69 internal ILExceptionBlock[] handlers;
70 internal int start;
71 internal int len;
72 internal Label end;
73 #pragma warning restore 169
74 #pragma warning restore 414
76 internal int NumHandlers ()
78 return handlers.Length;
81 internal void AddCatch (Type extype, int offset)
83 int i;
84 End (offset);
85 add_block (offset);
86 i = handlers.Length - 1;
87 handlers [i].type = ILExceptionBlock.CATCH;
88 handlers [i].start = offset;
89 handlers [i].extype = extype;
92 internal void AddFinally (int offset)
94 int i;
95 End (offset);
96 add_block (offset);
97 i = handlers.Length - 1;
98 handlers [i].type = ILExceptionBlock.FINALLY;
99 handlers [i].start = offset;
100 handlers [i].extype = null;
103 internal void AddFault (int offset)
105 int i;
106 End (offset);
107 add_block (offset);
108 i = handlers.Length - 1;
109 handlers [i].type = ILExceptionBlock.FAULT;
110 handlers [i].start = offset;
111 handlers [i].extype = null;
114 internal void AddFilter (int offset)
116 int i;
117 End (offset);
118 add_block (offset);
119 i = handlers.Length - 1;
120 handlers [i].type = ILExceptionBlock.FILTER_START;
121 handlers [i].extype = null;
122 handlers [i].filter_offset = offset;
125 internal void End (int offset)
127 if (handlers == null)
128 return;
129 int i = handlers.Length - 1;
130 if (i >= 0)
131 handlers [i].len = offset - handlers [i].start;
134 internal int LastClauseType ()
136 if (handlers != null)
137 return handlers [handlers.Length-1].type;
138 else
139 return ILExceptionBlock.CATCH;
142 internal void PatchFilterClause (int start)
144 if (handlers != null && handlers.Length > 0) {
145 handlers [handlers.Length - 1].start = start;
146 handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
150 internal void Debug (int b)
152 #if FALSE
153 System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
154 for (int i = 0; i < handlers.Length; ++i)
155 handlers [i].Debug ();
156 #endif
159 void add_block (int offset)
161 if (handlers != null) {
162 int i = handlers.Length;
163 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
164 System.Array.Copy (handlers, new_b, i);
165 handlers = new_b;
166 handlers [i].len = offset - handlers [i].start;
167 } else {
168 handlers = new ILExceptionBlock [1];
169 len = offset - start;
174 internal struct ILTokenInfo {
175 public MemberInfo member;
176 public int code_pos;
179 internal interface TokenGenerator {
180 int GetToken (string str);
182 int GetToken (MemberInfo member, bool create_open_instance);
184 int GetToken (MethodBase method, Type[] opt_param_types);
186 int GetToken (SignatureHelper helper);
189 [StructLayout (LayoutKind.Sequential)]
190 public partial class ILGenerator {
191 private struct LabelFixup {
192 public int offset; // The number of bytes between pos and the
193 // offset of the jump
194 public int pos; // Where offset of the label is placed
195 public int label_idx; // The label to jump to
198 struct LabelData {
199 public LabelData (int addr, int maxStack)
201 this.addr = addr;
202 this.maxStack = maxStack;
205 public int addr;
206 public int maxStack;
209 #region Sync with reflection.h
210 private byte[] code;
211 private int code_len;
212 private int max_stack;
213 private int cur_stack;
214 private LocalBuilder[] locals;
215 private ILExceptionInfo[] ex_handlers;
216 private int num_token_fixups;
217 private object token_fixups;
218 #endregion
220 private LabelData [] labels;
221 private int num_labels;
222 private LabelFixup[] fixups;
223 private int num_fixups;
224 internal Module module;
225 private int cur_block;
226 private Stack open_blocks;
227 private TokenGenerator token_gen;
229 const int defaultFixupSize = 4;
230 const int defaultLabelsSize = 4;
231 const int defaultExceptionStackSize = 2;
233 ArrayList sequencePointLists;
234 SequencePointList currentSequence;
236 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
238 if (size < 0)
239 size = 128;
240 code = new byte [size];
241 module = m;
242 this.token_gen = token_gen;
245 private void make_room (int nbytes)
247 if (code_len + nbytes < code.Length)
248 return;
249 byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
250 System.Array.Copy (code, 0, new_code, 0, code.Length);
251 code = new_code;
254 private void emit_int (int val)
256 code [code_len++] = (byte) (val & 0xFF);
257 code [code_len++] = (byte) ((val >> 8) & 0xFF);
258 code [code_len++] = (byte) ((val >> 16) & 0xFF);
259 code [code_len++] = (byte) ((val >> 24) & 0xFF);
262 /* change to pass by ref to avoid copy */
263 private void ll_emit (OpCode opcode)
266 * there is already enough room allocated in code.
268 if (opcode.Size == 2)
269 code [code_len++] = (byte)(opcode.Value >> 8);
270 code [code_len++] = (byte)(opcode.Value & 0xff);
272 * We should probably keep track of stack needs here.
273 * Or we may want to run the verifier on the code before saving it
274 * (this may be needed anyway when the ILGenerator is not used...).
276 switch (opcode.StackBehaviourPush) {
277 case StackBehaviour.Push1:
278 case StackBehaviour.Pushi:
279 case StackBehaviour.Pushi8:
280 case StackBehaviour.Pushr4:
281 case StackBehaviour.Pushr8:
282 case StackBehaviour.Pushref:
283 case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
284 cur_stack ++;
285 break;
286 case StackBehaviour.Push1_push1:
287 cur_stack += 2;
288 break;
290 if (max_stack < cur_stack)
291 max_stack = cur_stack;
294 * Note that we adjust for the pop behaviour _after_ setting max_stack.
296 switch (opcode.StackBehaviourPop) {
297 case StackBehaviour.Varpop:
298 break; /* we are conservative and assume it doesn't decrease the stack needs */
299 case StackBehaviour.Pop1:
300 case StackBehaviour.Popi:
301 case StackBehaviour.Popref:
302 cur_stack --;
303 break;
304 case StackBehaviour.Pop1_pop1:
305 case StackBehaviour.Popi_pop1:
306 case StackBehaviour.Popi_popi:
307 case StackBehaviour.Popi_popi8:
308 case StackBehaviour.Popi_popr4:
309 case StackBehaviour.Popi_popr8:
310 case StackBehaviour.Popref_pop1:
311 case StackBehaviour.Popref_popi:
312 cur_stack -= 2;
313 break;
314 case StackBehaviour.Popi_popi_popi:
315 case StackBehaviour.Popref_popi_popi:
316 case StackBehaviour.Popref_popi_popi8:
317 case StackBehaviour.Popref_popi_popr4:
318 case StackBehaviour.Popref_popi_popr8:
319 case StackBehaviour.Popref_popi_popref:
320 cur_stack -= 3;
321 break;
325 private static int target_len (OpCode opcode)
327 if (opcode.OperandType == OperandType.InlineBrTarget)
328 return 4;
329 return 1;
332 private void InternalEndClause ()
334 switch (ex_handlers [cur_block].LastClauseType ()) {
335 case ILExceptionBlock.CATCH:
336 case ILExceptionBlock.FILTER:
337 case ILExceptionBlock.FILTER_START:
338 // how could we optimize code size here?
339 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
340 break;
341 case ILExceptionBlock.FAULT:
342 case ILExceptionBlock.FINALLY:
343 Emit (OpCodes.Endfinally);
344 break;
348 public virtual void BeginCatchBlock (Type exceptionType)
350 if (open_blocks == null)
351 open_blocks = new Stack (defaultExceptionStackSize);
353 if (open_blocks.Count <= 0)
354 throw new NotSupportedException ("Not in an exception block");
355 if (exceptionType != null && exceptionType.IsUserType)
356 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
357 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
358 if (exceptionType != null)
359 throw new ArgumentException ("Do not supply an exception type for filter clause");
360 Emit (OpCodes.Endfilter);
361 ex_handlers [cur_block].PatchFilterClause (code_len);
362 } else {
363 InternalEndClause ();
364 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
367 cur_stack = 1; // the exception object is on the stack by default
368 if (max_stack < cur_stack)
369 max_stack = cur_stack;
371 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
374 public virtual void BeginExceptFilterBlock ()
376 if (open_blocks == null)
377 open_blocks = new Stack (defaultExceptionStackSize);
379 if (open_blocks.Count <= 0)
380 throw new NotSupportedException ("Not in an exception block");
381 InternalEndClause ();
383 ex_handlers [cur_block].AddFilter (code_len);
386 public virtual Label BeginExceptionBlock ()
388 //System.Console.WriteLine ("Begin Block");
389 if (open_blocks == null)
390 open_blocks = new Stack (defaultExceptionStackSize);
392 if (ex_handlers != null) {
393 cur_block = ex_handlers.Length;
394 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
395 System.Array.Copy (ex_handlers, new_ex, cur_block);
396 ex_handlers = new_ex;
397 } else {
398 ex_handlers = new ILExceptionInfo [1];
399 cur_block = 0;
401 open_blocks.Push (cur_block);
402 ex_handlers [cur_block].start = code_len;
403 return ex_handlers [cur_block].end = DefineLabel ();
406 public virtual void BeginFaultBlock()
408 if (open_blocks == null)
409 open_blocks = new Stack (defaultExceptionStackSize);
411 if (open_blocks.Count <= 0)
412 throw new NotSupportedException ("Not in an exception block");
414 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
415 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
416 ex_handlers [cur_block].PatchFilterClause (code_len);
419 InternalEndClause ();
420 //System.Console.WriteLine ("Begin fault Block");
421 ex_handlers [cur_block].AddFault (code_len);
424 public virtual void BeginFinallyBlock()
426 if (open_blocks == null)
427 open_blocks = new Stack (defaultExceptionStackSize);
429 if (open_blocks.Count <= 0)
430 throw new NotSupportedException ("Not in an exception block");
432 InternalEndClause ();
434 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
435 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
436 ex_handlers [cur_block].PatchFilterClause (code_len);
439 //System.Console.WriteLine ("Begin finally Block");
440 ex_handlers [cur_block].AddFinally (code_len);
443 public virtual void BeginScope ()
446 public virtual LocalBuilder DeclareLocal (Type localType)
448 return DeclareLocal (localType, false);
452 public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
454 if (localType == null)
455 throw new ArgumentNullException ("localType");
456 if (localType.IsUserType)
457 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
458 LocalBuilder res = new LocalBuilder (localType, this);
459 res.is_pinned = pinned;
461 if (locals != null) {
462 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
463 System.Array.Copy (locals, new_l, locals.Length);
464 new_l [locals.Length] = res;
465 locals = new_l;
466 } else {
467 locals = new LocalBuilder [1];
468 locals [0] = res;
470 res.position = (ushort)(locals.Length - 1);
471 return res;
474 public virtual Label DefineLabel ()
476 if (labels == null)
477 labels = new LabelData [defaultLabelsSize];
478 else if (num_labels >= labels.Length) {
479 LabelData [] t = new LabelData [labels.Length * 2];
480 Array.Copy (labels, t, labels.Length);
481 labels = t;
484 labels [num_labels] = new LabelData (-1, 0);
486 return new Label (num_labels++);
489 public virtual void Emit (OpCode opcode)
491 make_room (2);
492 ll_emit (opcode);
495 public virtual void Emit (OpCode opcode, Byte arg)
497 make_room (3);
498 ll_emit (opcode);
499 code [code_len++] = arg;
502 [ComVisible (true)]
503 public virtual void Emit (OpCode opcode, ConstructorInfo con)
505 int token = token_gen.GetToken (con, true);
506 make_room (6);
507 ll_emit (opcode);
508 emit_int (token);
510 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
511 cur_stack -= con.GetParametersCount ();
514 public virtual void Emit (OpCode opcode, double arg)
516 byte[] s = System.BitConverter.GetBytes (arg);
517 make_room (10);
518 ll_emit (opcode);
519 if (BitConverter.IsLittleEndian){
520 System.Array.Copy (s, 0, code, code_len, 8);
521 code_len += 8;
522 } else {
523 code [code_len++] = s [7];
524 code [code_len++] = s [6];
525 code [code_len++] = s [5];
526 code [code_len++] = s [4];
527 code [code_len++] = s [3];
528 code [code_len++] = s [2];
529 code [code_len++] = s [1];
530 code [code_len++] = s [0];
534 public virtual void Emit (OpCode opcode, FieldInfo field)
536 int token = token_gen.GetToken (field, true);
537 make_room (6);
538 ll_emit (opcode);
539 emit_int (token);
542 public virtual void Emit (OpCode opcode, Int16 arg)
544 make_room (4);
545 ll_emit (opcode);
546 code [code_len++] = (byte) (arg & 0xFF);
547 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
550 public virtual void Emit (OpCode opcode, int arg)
552 make_room (6);
553 ll_emit (opcode);
554 emit_int (arg);
557 public virtual void Emit (OpCode opcode, long arg)
559 make_room (10);
560 ll_emit (opcode);
561 code [code_len++] = (byte) (arg & 0xFF);
562 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
563 code [code_len++] = (byte) ((arg >> 16) & 0xFF);
564 code [code_len++] = (byte) ((arg >> 24) & 0xFF);
565 code [code_len++] = (byte) ((arg >> 32) & 0xFF);
566 code [code_len++] = (byte) ((arg >> 40) & 0xFF);
567 code [code_len++] = (byte) ((arg >> 48) & 0xFF);
568 code [code_len++] = (byte) ((arg >> 56) & 0xFF);
571 public virtual void Emit (OpCode opcode, Label label)
573 int tlen = target_len (opcode);
574 make_room (6);
575 ll_emit (opcode);
576 if (cur_stack > labels [label.m_label].maxStack)
577 labels [label.m_label].maxStack = cur_stack;
579 if (fixups == null)
580 fixups = new LabelFixup [defaultFixupSize];
581 else if (num_fixups >= fixups.Length) {
582 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
583 System.Array.Copy (fixups, newf, fixups.Length);
584 fixups = newf;
586 fixups [num_fixups].offset = tlen;
587 fixups [num_fixups].pos = code_len;
588 fixups [num_fixups].label_idx = label.m_label;
589 num_fixups++;
590 code_len += tlen;
594 public virtual void Emit (OpCode opcode, Label[] labels)
596 if (labels == null)
597 throw new ArgumentNullException ("labels");
599 /* opcode needs to be switch. */
600 int count = labels.Length;
601 make_room (6 + count * 4);
602 ll_emit (opcode);
604 for (int i = 0; i < count; ++i)
605 if (cur_stack > this.labels [labels [i].m_label].maxStack)
606 this.labels [labels [i].m_label].maxStack = cur_stack;
608 emit_int (count);
609 if (fixups == null)
610 fixups = new LabelFixup [defaultFixupSize + count];
611 else if (num_fixups + count >= fixups.Length) {
612 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
613 System.Array.Copy (fixups, newf, fixups.Length);
614 fixups = newf;
617 // ECMA 335, Partition III, p94 (7-10)
619 // The switch instruction implements a jump table. The format of
620 // the instruction is an unsigned int32 representing the number of targets N,
621 // followed by N int32 values specifying jump targets: these targets are
622 // represented as offsets (positive or negative) from the beginning of the
623 // instruction following this switch instruction.
625 // We must make sure it gets an offset from the *end* of the last label
626 // (eg, the beginning of the instruction following this).
628 // remaining is the number of bytes from the current instruction to the
629 // instruction that will be emitted.
631 for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
632 fixups [num_fixups].offset = remaining;
633 fixups [num_fixups].pos = code_len;
634 fixups [num_fixups].label_idx = labels [i].m_label;
635 num_fixups++;
636 code_len += 4;
640 public virtual void Emit (OpCode opcode, LocalBuilder local)
642 if (local == null)
643 throw new ArgumentNullException ("local");
644 if (local.ilgen != this)
645 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
647 uint pos = local.position;
648 bool load_addr = false;
649 bool is_store = false;
650 bool is_load = false;
651 make_room (6);
653 /* inline the code from ll_emit () to optimize il code size */
654 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
655 cur_stack --;
656 is_store = true;
657 } else if (opcode.StackBehaviourPush == StackBehaviour.Push1 || opcode.StackBehaviourPush == StackBehaviour.Pushi) {
658 cur_stack++;
659 is_load = true;
660 if (cur_stack > max_stack)
661 max_stack = cur_stack;
662 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
664 if (load_addr) {
665 if (pos < 256) {
666 code [code_len++] = (byte)0x12;
667 code [code_len++] = (byte)pos;
668 } else {
669 code [code_len++] = (byte)0xfe;
670 code [code_len++] = (byte)0x0d;
671 code [code_len++] = (byte)(pos & 0xff);
672 code [code_len++] = (byte)((pos >> 8) & 0xff);
674 } else {
675 if (is_store) {
676 if (pos < 4) {
677 code [code_len++] = (byte)(0x0a + pos);
678 } else if (pos < 256) {
679 code [code_len++] = (byte)0x13;
680 code [code_len++] = (byte)pos;
681 } else {
682 code [code_len++] = (byte)0xfe;
683 code [code_len++] = (byte)0x0e;
684 code [code_len++] = (byte)(pos & 0xff);
685 code [code_len++] = (byte)((pos >> 8) & 0xff);
687 } else if (is_load) {
688 if (pos < 4) {
689 code [code_len++] = (byte)(0x06 + pos);
690 } else if (pos < 256) {
691 code [code_len++] = (byte)0x11;
692 code [code_len++] = (byte)pos;
693 } else {
694 code [code_len++] = (byte)0xfe;
695 code [code_len++] = (byte)0x0c;
696 code [code_len++] = (byte)(pos & 0xff);
697 code [code_len++] = (byte)((pos >> 8) & 0xff);
699 } else {
700 ll_emit (opcode);
705 public virtual void Emit (OpCode opcode, MethodInfo meth)
707 if (meth == null)
708 throw new ArgumentNullException ("meth");
710 // For compatibility with MS
711 if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
712 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
714 int token = token_gen.GetToken (meth, true);
715 make_room (6);
716 ll_emit (opcode);
717 Type declaringType = meth.DeclaringType;
718 emit_int (token);
719 if (meth.ReturnType != typeof (void))
720 cur_stack ++;
722 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
723 cur_stack -= meth.GetParametersCount ();
726 private void Emit (OpCode opcode, MethodInfo method, int token)
728 make_room (6);
729 ll_emit (opcode);
730 emit_int (token);
731 if (method.ReturnType != typeof (void))
732 cur_stack ++;
734 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
735 cur_stack -= method.GetParametersCount ();
738 [CLSCompliant(false)]
739 public void Emit (OpCode opcode, sbyte arg)
741 make_room (3);
742 ll_emit (opcode);
743 code [code_len++] = (byte)arg;
746 public virtual void Emit (OpCode opcode, SignatureHelper signature)
748 int token = token_gen.GetToken (signature);
749 make_room (6);
750 ll_emit (opcode);
751 emit_int (token);
754 public virtual void Emit (OpCode opcode, float arg)
756 byte[] s = System.BitConverter.GetBytes (arg);
757 make_room (6);
758 ll_emit (opcode);
759 if (BitConverter.IsLittleEndian){
760 System.Array.Copy (s, 0, code, code_len, 4);
761 code_len += 4;
762 } else {
763 code [code_len++] = s [3];
764 code [code_len++] = s [2];
765 code [code_len++] = s [1];
766 code [code_len++] = s [0];
770 public virtual void Emit (OpCode opcode, string str)
772 int token = token_gen.GetToken (str);
773 make_room (6);
774 ll_emit (opcode);
775 emit_int (token);
778 public virtual void Emit (OpCode opcode, Type cls)
780 if (cls != null && cls.IsByRef)
781 throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
783 make_room (6);
784 ll_emit (opcode);
785 int token = token_gen.GetToken (cls, opcode != OpCodes.Ldtoken);
786 emit_int (token);
789 // FIXME: vararg methods are not supported
790 public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
792 if (methodInfo == null)
793 throw new ArgumentNullException ("methodInfo");
794 short value = opcode.Value;
795 if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
796 throw new NotSupportedException ("Only Call and CallVirt are allowed");
797 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
798 optionalParameterTypes = null;
799 if (optionalParameterTypes != null){
800 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
801 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
804 int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
805 Emit (opcode, methodInfo, token);
806 return;
808 Emit (opcode, methodInfo);
811 public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
813 // GetMethodSigHelper expects a ModuleBuilder or null, and module might be
814 // a normal module when using dynamic methods.
815 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, 0, unmanagedCallConv, returnType, parameterTypes);
816 Emit (opcode, helper);
819 public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
821 if (optionalParameterTypes != null)
822 throw new NotImplementedException ();
824 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, callingConvention, 0, returnType, parameterTypes);
825 Emit (opcode, helper);
828 static Type GetConsoleType ()
830 return Type.GetType ("System.Console, System.Console", throwOnError: true);
833 public virtual void EmitWriteLine (FieldInfo fld)
835 if (fld == null)
836 throw new ArgumentNullException ("fld");
838 // The MS implementation does not check for valuetypes here but it
839 // should. Also, it should check that if the field is not static,
840 // then it is a member of this type.
841 if (fld.IsStatic)
842 Emit (OpCodes.Ldsfld, fld);
843 else {
844 Emit (OpCodes.Ldarg_0);
845 Emit (OpCodes.Ldfld, fld);
847 Emit (OpCodes.Call, GetConsoleType ().GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
850 public virtual void EmitWriteLine (LocalBuilder localBuilder)
852 if (localBuilder == null)
853 throw new ArgumentNullException ("localBuilder");
854 if (localBuilder.LocalType is TypeBuilder)
855 throw new ArgumentException ("Output streams do not support TypeBuilders.");
856 // The MS implementation does not check for valuetypes here but it
857 // should.
858 Emit (OpCodes.Ldloc, localBuilder);
859 Emit (OpCodes.Call, GetConsoleType ().GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
862 public virtual void EmitWriteLine (string value)
864 Emit (OpCodes.Ldstr, value);
865 Emit (OpCodes.Call, GetConsoleType ().GetMethod ("WriteLine", new Type[1] { typeof(string)}));
868 public virtual void EndExceptionBlock ()
870 if (open_blocks == null)
871 open_blocks = new Stack (defaultExceptionStackSize);
873 if (open_blocks.Count <= 0)
874 throw new NotSupportedException ("Not in an exception block");
876 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
877 throw new InvalidOperationException ("Incorrect code generation for exception block.");
879 InternalEndClause ();
880 MarkLabel (ex_handlers [cur_block].end);
881 ex_handlers [cur_block].End (code_len);
882 ex_handlers [cur_block].Debug (cur_block);
883 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
884 open_blocks.Pop ();
885 if (open_blocks.Count > 0)
886 cur_block = (int)open_blocks.Peek ();
887 //Console.WriteLine ("curblock restored to {0}", cur_block);
888 //throw new NotImplementedException ();
891 public virtual void EndScope ()
894 public virtual void MarkLabel (Label loc)
896 if (loc.m_label < 0 || loc.m_label >= num_labels)
897 throw new System.ArgumentException ("The label is not valid");
898 if (labels [loc.m_label].addr >= 0)
899 throw new System.ArgumentException ("The label was already defined");
900 labels [loc.m_label].addr = code_len;
901 if (labels [loc.m_label].maxStack > cur_stack)
902 cur_stack = labels [loc.m_label].maxStack;
905 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
906 int startColumn, int endLine, int endColumn)
908 if (currentSequence == null || currentSequence.Document != document) {
909 if (sequencePointLists == null)
910 sequencePointLists = new ArrayList ();
911 currentSequence = new SequencePointList (document);
912 sequencePointLists.Add (currentSequence);
915 currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
919 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
921 if (sequencePointLists != null) {
922 SequencePointList first = (SequencePointList) sequencePointLists [0];
923 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
924 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
926 foreach (SequencePointList list in sequencePointLists)
927 symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
929 if (locals != null) {
930 foreach (LocalBuilder local in locals) {
931 if (local.Name != null && local.Name.Length > 0) {
932 SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module as ModuleBuilder);
933 sighelper.AddArgument (local.LocalType);
934 byte[] signature = sighelper.GetSignature ();
935 symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
939 sequencePointLists = null;
944 internal bool HasDebugInfo
946 get { return sequencePointLists != null; }
949 public virtual void ThrowException (Type excType)
951 if (excType == null)
952 throw new ArgumentNullException ("excType");
953 if (! ((excType == typeof (Exception)) ||
954 excType.IsSubclassOf (typeof (Exception))))
955 throw new ArgumentException ("Type should be an exception type", "excType");
956 ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
957 if (ctor == null)
958 throw new ArgumentException ("Type should have a default constructor", "excType");
959 Emit (OpCodes.Newobj, ctor);
960 Emit (OpCodes.Throw);
963 // FIXME: "Not implemented"
964 public virtual void UsingNamespace (String usingNamespace)
966 throw new NotImplementedException ();
969 internal void label_fixup (MethodBase mb)
971 for (int i = 0; i < num_fixups; ++i) {
972 if (labels [fixups [i].label_idx].addr < 0)
973 throw new ArgumentException (string.Format ("Label #{0} is not marked in method `{1}'", fixups [i].label_idx + 1, mb.Name));
974 // Diff is the offset from the end of the jump instruction to the address of the label
975 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
976 if (fixups [i].offset == 1) {
977 code [fixups [i].pos] = (byte)((sbyte) diff);
978 } else {
979 int old_cl = code_len;
980 code_len = fixups [i].pos;
981 emit_int (diff);
982 code_len = old_cl;
987 // Used by DynamicILGenerator and MethodBuilder.SetMethodBody
988 internal void SetCode (byte[] code, int max_stack) {
989 // Make a copy to avoid possible security problems
990 this.code = (byte[])code.Clone ();
991 this.code_len = code.Length;
992 this.max_stack = max_stack;
993 this.cur_stack = 0;
996 internal unsafe void SetCode (byte *code, int code_size, int max_stack) {
997 // Make a copy to avoid possible security problems
998 this.code = new byte [code_size];
999 for (int i = 0; i < code_size; ++i)
1000 this.code [i] = code [i];
1001 this.code_len = code_size;
1002 this.max_stack = max_stack;
1003 this.cur_stack = 0;
1006 internal TokenGenerator TokenGenerator {
1007 get {
1008 return token_gen;
1012 public virtual int ILOffset {
1013 get { return code_len; }
1017 internal class SequencePointList
1019 ISymbolDocumentWriter doc;
1020 SequencePoint[] points;
1021 int count;
1022 const int arrayGrow = 10;
1024 public SequencePointList (ISymbolDocumentWriter doc)
1026 this.doc = doc;
1029 public ISymbolDocumentWriter Document {
1030 get { return doc; }
1033 public int[] GetOffsets()
1035 int[] data = new int [count];
1036 for (int n=0; n<count; n++) data [n] = points[n].Offset;
1037 return data;
1039 public int[] GetLines()
1041 int[] data = new int [count];
1042 for (int n=0; n<count; n++) data [n] = points[n].Line;
1043 return data;
1045 public int[] GetColumns()
1047 int[] data = new int [count];
1048 for (int n=0; n<count; n++) data [n] = points[n].Col;
1049 return data;
1051 public int[] GetEndLines()
1053 int[] data = new int [count];
1054 for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1055 return data;
1057 public int[] GetEndColumns()
1059 int[] data = new int [count];
1060 for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1061 return data;
1063 public int StartLine {
1064 get { return points[0].Line; }
1066 public int EndLine {
1067 get { return points[count - 1].Line; }
1069 public int StartColumn {
1070 get { return points[0].Col; }
1072 public int EndColumn {
1073 get { return points[count - 1].Col; }
1076 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1078 SequencePoint s = new SequencePoint ();
1079 s.Offset = offset;
1080 s.Line = line;
1081 s.Col = col;
1082 s.EndLine = endLine;
1083 s.EndCol = endCol;
1085 if (points == null) {
1086 points = new SequencePoint [arrayGrow];
1087 } else if (count >= points.Length) {
1088 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1089 Array.Copy (points, temp, points.Length);
1090 points = temp;
1093 points [count] = s;
1094 count++;
1098 struct SequencePoint {
1099 public int Offset;
1100 public int Line;
1101 public int Col;
1102 public int EndLine;
1103 public int EndCol;
1106 class Stack
1108 Object[] _array;
1109 int _size;
1110 int _version;
1112 private const int _defaultCapacity = 10;
1114 public Stack()
1116 _array = new Object[_defaultCapacity];
1117 _size = 0;
1118 _version = 0;
1121 public Stack(int initialCapacity)
1123 if (initialCapacity < 0)
1124 throw new ArgumentOutOfRangeException(nameof(initialCapacity), SR.ArgumentOutOfRange_NeedNonNegNum);
1126 if (initialCapacity < _defaultCapacity)
1127 initialCapacity = _defaultCapacity;
1128 _array = new Object[initialCapacity];
1129 _size = 0;
1130 _version = 0;
1133 public virtual int Count
1137 return _size;
1141 public virtual Object Peek()
1143 if (_size == 0)
1144 throw new InvalidOperationException ();
1146 return _array[_size - 1];
1149 public virtual Object Pop()
1151 if (_size == 0)
1152 throw new InvalidOperationException ();
1154 _version++;
1155 Object obj = _array[--_size];
1156 _array[_size] = null;
1157 return obj;
1160 public virtual void Push(Object obj)
1162 if (_size == _array.Length)
1164 Object[] newArray = new Object[2 * _array.Length];
1165 Array.Copy(_array, 0, newArray, 0, _size);
1166 _array = newArray;
1168 _array[_size++] = obj;
1169 _version++;
1173 #endif