3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
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
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
35 using System
.Collections
;
36 using System
.Diagnostics
.SymbolStore
;
37 using System
.Runtime
.InteropServices
;
39 namespace System
.Reflection
.Emit
{
41 internal struct ILExceptionBlock
{
42 public const int CATCH
= 0;
43 public const int FILTER
= 1;
44 public const int FINALLY
= 2;
45 public const int FAULT
= 4;
46 public const int FILTER_START
= -1;
52 internal int filter_offset
;
54 internal void Debug () {
56 System
.Console
.Write ("\ttype="+type
.ToString()+" start="+start
.ToString()+" len="+len
.ToString());
58 System
.Console
.WriteLine (" extype="+extype
.ToString());
60 System
.Console
.WriteLine (String
.Empty
);
64 internal struct ILExceptionInfo
{
65 #pragma warning disable 169
66 #pragma warning disable 414
67 ILExceptionBlock
[] handlers
;
71 #pragma warning restore 169
72 #pragma warning restore 414
74 internal int NumHandlers ()
76 return handlers
.Length
;
79 internal void AddCatch (Type extype
, int offset
)
84 i
= handlers
.Length
- 1;
85 handlers
[i
].type
= ILExceptionBlock
.CATCH
;
86 handlers
[i
].start
= offset
;
87 handlers
[i
].extype
= extype
;
90 internal void AddFinally (int offset
)
95 i
= handlers
.Length
- 1;
96 handlers
[i
].type
= ILExceptionBlock
.FINALLY
;
97 handlers
[i
].start
= offset
;
98 handlers
[i
].extype
= null;
101 internal void AddFault (int offset
)
106 i
= handlers
.Length
- 1;
107 handlers
[i
].type
= ILExceptionBlock
.FAULT
;
108 handlers
[i
].start
= offset
;
109 handlers
[i
].extype
= null;
112 internal void AddFilter (int offset
)
117 i
= handlers
.Length
- 1;
118 handlers
[i
].type
= ILExceptionBlock
.FILTER_START
;
119 handlers
[i
].extype
= null;
120 handlers
[i
].filter_offset
= offset
;
123 internal void End (int offset
)
125 if (handlers
== null)
127 int i
= handlers
.Length
- 1;
129 handlers
[i
].len
= offset
- handlers
[i
].start
;
132 internal int LastClauseType ()
134 if (handlers
!= null)
135 return handlers
[handlers
.Length
-1].type
;
137 return ILExceptionBlock
.CATCH
;
140 internal void PatchFilterClause (int start
)
142 if (handlers
!= null && handlers
.Length
> 0) {
143 handlers
[handlers
.Length
- 1].start
= start
;
144 handlers
[handlers
.Length
- 1].type
= ILExceptionBlock
.FILTER
;
148 internal void Debug (int b
)
151 System
.Console
.WriteLine ("Handler {0} at {1}, len: {2}", b
, start
, len
);
152 for (int i
= 0; i
< handlers
.Length
; ++i
)
153 handlers
[i
].Debug ();
157 void add_block (int offset
)
159 if (handlers
!= null) {
160 int i
= handlers
.Length
;
161 ILExceptionBlock
[] new_b
= new ILExceptionBlock
[i
+ 1];
162 System
.Array
.Copy (handlers
, new_b
, i
);
164 handlers
[i
].len
= offset
- handlers
[i
].start
;
166 handlers
= new ILExceptionBlock
[1];
167 len
= offset
- start
;
172 internal struct ILTokenInfo
{
173 public MemberInfo member
;
177 internal interface TokenGenerator
{
178 int GetToken (string str
);
180 int GetToken (MemberInfo member
);
182 int GetToken (MethodInfo method
, Type
[] opt_param_types
);
184 int GetToken (SignatureHelper helper
);
188 [ComDefaultInterface (typeof (_ILGenerator
))]
189 [ClassInterface (ClassInterfaceType
.None
)]
190 public class ILGenerator
: _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
199 public LabelData (int addr
, int maxStack
)
202 this.maxStack
= maxStack
;
209 static readonly Type void_type
= typeof (void);
210 #region Sync with reflection.h
212 private int code_len
;
213 private int max_stack
;
214 private int cur_stack
;
215 private LocalBuilder
[] locals
;
216 private ILExceptionInfo
[] ex_handlers
;
217 private int num_token_fixups
;
218 private ILTokenInfo
[] token_fixups
;
221 private LabelData
[] labels
;
222 private int num_labels
;
223 private LabelFixup
[] fixups
;
224 private int num_fixups
;
225 internal Module module
;
226 private int cur_block
;
227 private Stack open_blocks
;
228 private TokenGenerator token_gen
;
230 const int defaultFixupSize
= 4;
231 const int defaultLabelsSize
= 4;
232 const int defaultExceptionStackSize
= 2;
234 ArrayList sequencePointLists
;
235 SequencePointList currentSequence
;
237 internal ILGenerator (Module m
, TokenGenerator token_gen
, int size
)
241 code
= new byte [size
];
242 token_fixups
= new ILTokenInfo
[8];
244 this.token_gen
= token_gen
;
247 private void add_token_fixup (MemberInfo mi
)
249 if (num_token_fixups
== token_fixups
.Length
) {
250 ILTokenInfo
[] ntf
= new ILTokenInfo
[num_token_fixups
* 2];
251 token_fixups
.CopyTo (ntf
, 0);
254 token_fixups
[num_token_fixups
].member
= mi
;
255 token_fixups
[num_token_fixups
++].code_pos
= code_len
;
258 private void make_room (int nbytes
)
260 if (code_len
+ nbytes
< code
.Length
)
262 byte[] new_code
= new byte [(code_len
+ nbytes
) * 2 + 128];
263 System
.Array
.Copy (code
, 0, new_code
, 0, code
.Length
);
267 private void emit_int (int val
)
269 code
[code_len
++] = (byte) (val
& 0xFF);
270 code
[code_len
++] = (byte) ((val
>> 8) & 0xFF);
271 code
[code_len
++] = (byte) ((val
>> 16) & 0xFF);
272 code
[code_len
++] = (byte) ((val
>> 24) & 0xFF);
275 /* change to pass by ref to avoid copy */
276 private void ll_emit (OpCode opcode
)
279 * there is already enough room allocated in code.
281 // access op1 and op2 directly since the Value property is useless
282 if (opcode
.Size
== 2)
283 code
[code_len
++] = opcode
.op1
;
284 code
[code_len
++] = opcode
.op2
;
286 * We should probably keep track of stack needs here.
287 * Or we may want to run the verifier on the code before saving it
288 * (this may be needed anyway when the ILGenerator is not used...).
290 switch (opcode
.StackBehaviourPush
) {
291 case StackBehaviour
.Push1
:
292 case StackBehaviour
.Pushi
:
293 case StackBehaviour
.Pushi8
:
294 case StackBehaviour
.Pushr4
:
295 case StackBehaviour
.Pushr8
:
296 case StackBehaviour
.Pushref
:
297 case StackBehaviour
.Varpush
: /* again we are conservative and assume it pushes 1 */
300 case StackBehaviour
.Push1_push1
:
304 if (max_stack
< cur_stack
)
305 max_stack
= cur_stack
;
308 * Note that we adjust for the pop behaviour _after_ setting max_stack.
310 switch (opcode
.StackBehaviourPop
) {
311 case StackBehaviour
.Varpop
:
312 break; /* we are conservative and assume it doesn't decrease the stack needs */
313 case StackBehaviour
.Pop1
:
314 case StackBehaviour
.Popi
:
315 case StackBehaviour
.Popref
:
318 case StackBehaviour
.Pop1_pop1
:
319 case StackBehaviour
.Popi_pop1
:
320 case StackBehaviour
.Popi_popi
:
321 case StackBehaviour
.Popi_popi8
:
322 case StackBehaviour
.Popi_popr4
:
323 case StackBehaviour
.Popi_popr8
:
324 case StackBehaviour
.Popref_pop1
:
325 case StackBehaviour
.Popref_popi
:
328 case StackBehaviour
.Popi_popi_popi
:
329 case StackBehaviour
.Popref_popi_popi
:
330 case StackBehaviour
.Popref_popi_popi8
:
331 case StackBehaviour
.Popref_popi_popr4
:
332 case StackBehaviour
.Popref_popi_popr8
:
333 case StackBehaviour
.Popref_popi_popref
:
339 private static int target_len (OpCode opcode
)
341 if (opcode
.OperandType
== OperandType
.InlineBrTarget
)
346 private void InternalEndClause ()
348 switch (ex_handlers
[cur_block
].LastClauseType ()) {
349 case ILExceptionBlock
.CATCH
:
350 case ILExceptionBlock
.FILTER
:
351 case ILExceptionBlock
.FILTER_START
:
352 // how could we optimize code size here?
353 Emit (OpCodes
.Leave
, ex_handlers
[cur_block
].end
);
355 case ILExceptionBlock
.FAULT
:
356 case ILExceptionBlock
.FINALLY
:
357 Emit (OpCodes
.Endfinally
);
362 public virtual void BeginCatchBlock (Type exceptionType
)
364 if (open_blocks
== null)
365 open_blocks
= new Stack (defaultExceptionStackSize
);
367 if (open_blocks
.Count
<= 0)
368 throw new NotSupportedException ("Not in an exception block");
369 if (exceptionType
!= null && exceptionType
.IsUserType
)
370 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
371 if (ex_handlers
[cur_block
].LastClauseType () == ILExceptionBlock
.FILTER_START
) {
372 if (exceptionType
!= null)
373 throw new ArgumentException ("Do not supply an exception type for filter clause");
374 Emit (OpCodes
.Endfilter
);
375 ex_handlers
[cur_block
].PatchFilterClause (code_len
);
377 InternalEndClause ();
378 ex_handlers
[cur_block
].AddCatch (exceptionType
, code_len
);
381 cur_stack
= 1; // the exception object is on the stack by default
382 if (max_stack
< cur_stack
)
383 max_stack
= cur_stack
;
385 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
388 public virtual void BeginExceptFilterBlock ()
390 if (open_blocks
== null)
391 open_blocks
= new Stack (defaultExceptionStackSize
);
393 if (open_blocks
.Count
<= 0)
394 throw new NotSupportedException ("Not in an exception block");
395 InternalEndClause ();
397 ex_handlers
[cur_block
].AddFilter (code_len
);
400 public virtual Label
BeginExceptionBlock ()
402 //System.Console.WriteLine ("Begin Block");
403 if (open_blocks
== null)
404 open_blocks
= new Stack (defaultExceptionStackSize
);
406 if (ex_handlers
!= null) {
407 cur_block
= ex_handlers
.Length
;
408 ILExceptionInfo
[] new_ex
= new ILExceptionInfo
[cur_block
+ 1];
409 System
.Array
.Copy (ex_handlers
, new_ex
, cur_block
);
410 ex_handlers
= new_ex
;
412 ex_handlers
= new ILExceptionInfo
[1];
415 open_blocks
.Push (cur_block
);
416 ex_handlers
[cur_block
].start
= code_len
;
417 return ex_handlers
[cur_block
].end
= DefineLabel ();
420 public virtual void BeginFaultBlock()
422 if (open_blocks
== null)
423 open_blocks
= new Stack (defaultExceptionStackSize
);
425 if (open_blocks
.Count
<= 0)
426 throw new NotSupportedException ("Not in an exception block");
428 if (ex_handlers
[cur_block
].LastClauseType () == ILExceptionBlock
.FILTER_START
) {
429 Emit (OpCodes
.Leave
, ex_handlers
[cur_block
].end
);
430 ex_handlers
[cur_block
].PatchFilterClause (code_len
);
433 InternalEndClause ();
434 //System.Console.WriteLine ("Begin fault Block");
435 ex_handlers
[cur_block
].AddFault (code_len
);
438 public virtual void BeginFinallyBlock()
440 if (open_blocks
== null)
441 open_blocks
= new Stack (defaultExceptionStackSize
);
443 if (open_blocks
.Count
<= 0)
444 throw new NotSupportedException ("Not in an exception block");
446 InternalEndClause ();
448 if (ex_handlers
[cur_block
].LastClauseType () == ILExceptionBlock
.FILTER_START
) {
449 Emit (OpCodes
.Leave
, ex_handlers
[cur_block
].end
);
450 ex_handlers
[cur_block
].PatchFilterClause (code_len
);
453 //System.Console.WriteLine ("Begin finally Block");
454 ex_handlers
[cur_block
].AddFinally (code_len
);
457 public virtual void BeginScope ()
460 public virtual LocalBuilder
DeclareLocal (Type localType
)
462 return DeclareLocal (localType
, false);
466 public virtual LocalBuilder
DeclareLocal (Type localType
, bool pinned
)
468 if (localType
== null)
469 throw new ArgumentNullException ("localType");
470 if (localType
.IsUserType
)
471 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
472 LocalBuilder res
= new LocalBuilder (localType
, this);
473 res
.is_pinned
= pinned
;
475 if (locals
!= null) {
476 LocalBuilder
[] new_l
= new LocalBuilder
[locals
.Length
+ 1];
477 System
.Array
.Copy (locals
, new_l
, locals
.Length
);
478 new_l
[locals
.Length
] = res
;
481 locals
= new LocalBuilder
[1];
484 res
.position
= (ushort)(locals
.Length
- 1);
488 public virtual Label
DefineLabel ()
491 labels
= new LabelData
[defaultLabelsSize
];
492 else if (num_labels
>= labels
.Length
) {
493 LabelData
[] t
= new LabelData
[labels
.Length
* 2];
494 Array
.Copy (labels
, t
, labels
.Length
);
498 labels
[num_labels
] = new LabelData (-1, 0);
500 return new Label (num_labels
++);
503 public virtual void Emit (OpCode opcode
)
509 public virtual void Emit (OpCode opcode
, Byte arg
)
513 code
[code_len
++] = arg
;
517 public virtual void Emit (OpCode opcode
, ConstructorInfo con
)
519 int token
= token_gen
.GetToken (con
);
522 if (con
.DeclaringType
.Module
== module
)
523 add_token_fixup (con
);
526 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
527 cur_stack
-= con
.GetParameterCount ();
530 public virtual void Emit (OpCode opcode
, double arg
)
532 byte[] s
= System
.BitConverter
.GetBytes (arg
);
535 if (BitConverter
.IsLittleEndian
){
536 System
.Array
.Copy (s
, 0, code
, code_len
, 8);
539 code
[code_len
++] = s
[7];
540 code
[code_len
++] = s
[6];
541 code
[code_len
++] = s
[5];
542 code
[code_len
++] = s
[4];
543 code
[code_len
++] = s
[3];
544 code
[code_len
++] = s
[2];
545 code
[code_len
++] = s
[1];
546 code
[code_len
++] = s
[0];
550 public virtual void Emit (OpCode opcode
, FieldInfo field
)
552 int token
= token_gen
.GetToken (field
);
555 if (field
.DeclaringType
.Module
== module
)
556 add_token_fixup (field
);
560 public virtual void Emit (OpCode opcode
, Int16 arg
)
564 code
[code_len
++] = (byte) (arg
& 0xFF);
565 code
[code_len
++] = (byte) ((arg
>> 8) & 0xFF);
568 public virtual void Emit (OpCode opcode
, int arg
)
575 public virtual void Emit (OpCode opcode
, long arg
)
579 code
[code_len
++] = (byte) (arg
& 0xFF);
580 code
[code_len
++] = (byte) ((arg
>> 8) & 0xFF);
581 code
[code_len
++] = (byte) ((arg
>> 16) & 0xFF);
582 code
[code_len
++] = (byte) ((arg
>> 24) & 0xFF);
583 code
[code_len
++] = (byte) ((arg
>> 32) & 0xFF);
584 code
[code_len
++] = (byte) ((arg
>> 40) & 0xFF);
585 code
[code_len
++] = (byte) ((arg
>> 48) & 0xFF);
586 code
[code_len
++] = (byte) ((arg
>> 56) & 0xFF);
589 public virtual void Emit (OpCode opcode
, Label label
)
591 int tlen
= target_len (opcode
);
594 if (cur_stack
> labels
[label
.label
].maxStack
)
595 labels
[label
.label
].maxStack
= cur_stack
;
598 fixups
= new LabelFixup
[defaultFixupSize
];
599 else if (num_fixups
>= fixups
.Length
) {
600 LabelFixup
[] newf
= new LabelFixup
[fixups
.Length
* 2];
601 System
.Array
.Copy (fixups
, newf
, fixups
.Length
);
604 fixups
[num_fixups
].offset
= tlen
;
605 fixups
[num_fixups
].pos
= code_len
;
606 fixups
[num_fixups
].label_idx
= label
.label
;
612 public virtual void Emit (OpCode opcode
, Label
[] labels
)
615 throw new ArgumentNullException ("labels");
617 /* opcode needs to be switch. */
618 int count
= labels
.Length
;
619 make_room (6 + count
* 4);
622 for (int i
= 0; i
< count
; ++i
)
623 if (cur_stack
> this.labels
[labels
[i
].label
].maxStack
)
624 this.labels
[labels
[i
].label
].maxStack
= cur_stack
;
628 fixups
= new LabelFixup
[defaultFixupSize
+ count
];
629 else if (num_fixups
+ count
>= fixups
.Length
) {
630 LabelFixup
[] newf
= new LabelFixup
[count
+ fixups
.Length
* 2];
631 System
.Array
.Copy (fixups
, newf
, fixups
.Length
);
635 // ECMA 335, Partition III, p94 (7-10)
637 // The switch instruction implements a jump table. The format of
638 // the instruction is an unsigned int32 representing the number of targets N,
639 // followed by N int32 values specifying jump targets: these targets are
640 // represented as offsets (positive or negative) from the beginning of the
641 // instruction following this switch instruction.
643 // We must make sure it gets an offset from the *end* of the last label
644 // (eg, the beginning of the instruction following this).
646 // remaining is the number of bytes from the current instruction to the
647 // instruction that will be emitted.
649 for (int i
= 0, remaining
= count
* 4; i
< count
; ++i
, remaining
-= 4) {
650 fixups
[num_fixups
].offset
= remaining
;
651 fixups
[num_fixups
].pos
= code_len
;
652 fixups
[num_fixups
].label_idx
= labels
[i
].label
;
658 public virtual void Emit (OpCode opcode
, LocalBuilder local
)
661 throw new ArgumentNullException ("local");
662 if (local
.ilgen
!= this)
663 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
665 uint pos
= local
.position
;
666 bool load_addr
= false;
667 bool is_store
= false;
668 bool is_load
= false;
671 /* inline the code from ll_emit () to optimize il code size */
672 if (opcode
.StackBehaviourPop
== StackBehaviour
.Pop1
) {
675 } else if (opcode
.StackBehaviourPush
== StackBehaviour
.Push1
|| opcode
.StackBehaviourPush
== StackBehaviour
.Pushi
) {
678 if (cur_stack
> max_stack
)
679 max_stack
= cur_stack
;
680 load_addr
= opcode
.StackBehaviourPush
== StackBehaviour
.Pushi
;
684 code
[code_len
++] = (byte)0x12;
685 code
[code_len
++] = (byte)pos
;
687 code
[code_len
++] = (byte)0xfe;
688 code
[code_len
++] = (byte)0x0d;
689 code
[code_len
++] = (byte)(pos
& 0xff);
690 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
695 code
[code_len
++] = (byte)(0x0a + pos
);
696 } else if (pos
< 256) {
697 code
[code_len
++] = (byte)0x13;
698 code
[code_len
++] = (byte)pos
;
700 code
[code_len
++] = (byte)0xfe;
701 code
[code_len
++] = (byte)0x0e;
702 code
[code_len
++] = (byte)(pos
& 0xff);
703 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
705 } else if (is_load
) {
707 code
[code_len
++] = (byte)(0x06 + pos
);
708 } else if (pos
< 256) {
709 code
[code_len
++] = (byte)0x11;
710 code
[code_len
++] = (byte)pos
;
712 code
[code_len
++] = (byte)0xfe;
713 code
[code_len
++] = (byte)0x0c;
714 code
[code_len
++] = (byte)(pos
& 0xff);
715 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
723 public virtual void Emit (OpCode opcode
, MethodInfo meth
)
726 throw new ArgumentNullException ("meth");
728 // For compatibility with MS
729 if ((meth
is DynamicMethod
) && ((opcode
== OpCodes
.Ldftn
) || (opcode
== OpCodes
.Ldvirtftn
) || (opcode
== OpCodes
.Ldtoken
)))
730 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
732 int token
= token_gen
.GetToken (meth
);
735 Type declaringType
= meth
.DeclaringType
;
736 // Might be a DynamicMethod with no declaring type
737 if (declaringType
!= null) {
738 if (declaringType
.Module
== module
)
739 add_token_fixup (meth
);
742 if (meth
.ReturnType
!= void_type
)
745 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
746 cur_stack
-= meth
.GetParameterCount ();
749 private void Emit (OpCode opcode
, MethodInfo method
, int token
)
753 // Might be a DynamicMethod with no declaring type
754 Type declaringType
= method
.DeclaringType
;
755 if (declaringType
!= null) {
756 if (declaringType
.Module
== module
)
757 add_token_fixup (method
);
760 if (method
.ReturnType
!= void_type
)
763 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
764 cur_stack
-= method
.GetParameterCount ();
767 [CLSCompliant(false)]
768 public void Emit (OpCode opcode
, sbyte arg
)
772 code
[code_len
++] = (byte)arg
;
775 public virtual void Emit (OpCode opcode
, SignatureHelper signature
)
777 int token
= token_gen
.GetToken (signature
);
783 public virtual void Emit (OpCode opcode
, float arg
)
785 byte[] s
= System
.BitConverter
.GetBytes (arg
);
788 if (BitConverter
.IsLittleEndian
){
789 System
.Array
.Copy (s
, 0, code
, code_len
, 4);
792 code
[code_len
++] = s
[3];
793 code
[code_len
++] = s
[2];
794 code
[code_len
++] = s
[1];
795 code
[code_len
++] = s
[0];
799 public virtual void Emit (OpCode opcode
, string str
)
801 int token
= token_gen
.GetToken (str
);
807 public virtual void Emit (OpCode opcode
, Type cls
)
809 if (cls
!= null && cls
.IsByRef
)
810 throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
814 emit_int (token_gen
.GetToken (cls
));
817 [MonoLimitation ("vararg methods are not supported")]
818 public virtual void EmitCall (OpCode opcode
, MethodInfo methodInfo
, Type
[] optionalParameterTypes
)
820 if (methodInfo
== null)
821 throw new ArgumentNullException ("methodInfo");
822 short value = opcode
.Value
;
823 if (!(value == OpCodes
.Call
.Value
|| value == OpCodes
.Callvirt
.Value
))
824 throw new NotSupportedException ("Only Call and CallVirt are allowed");
825 if ((methodInfo
.CallingConvention
& CallingConventions
.VarArgs
) == 0)
826 optionalParameterTypes
= null;
827 if (optionalParameterTypes
!= null){
828 if ((methodInfo
.CallingConvention
& CallingConventions
.VarArgs
) == 0){
829 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
832 int token
= token_gen
.GetToken (methodInfo
, optionalParameterTypes
);
833 Emit (opcode
, methodInfo
, token
);
836 Emit (opcode
, methodInfo
);
839 public virtual void EmitCalli (OpCode opcode
, CallingConvention unmanagedCallConv
, Type returnType
, Type
[] parameterTypes
)
841 SignatureHelper helper
= SignatureHelper
.GetMethodSigHelper (module
, 0, unmanagedCallConv
, returnType
, parameterTypes
);
842 Emit (opcode
, helper
);
845 public virtual void EmitCalli (OpCode opcode
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
, Type
[] optionalParameterTypes
)
847 if (optionalParameterTypes
!= null)
848 throw new NotImplementedException ();
850 SignatureHelper helper
= SignatureHelper
.GetMethodSigHelper (module
, callingConvention
, 0, returnType
, parameterTypes
);
851 Emit (opcode
, helper
);
854 public virtual void EmitWriteLine (FieldInfo fld
)
857 throw new ArgumentNullException ("fld");
859 // The MS implementation does not check for valuetypes here but it
860 // should. Also, it should check that if the field is not static,
861 // then it is a member of this type.
863 Emit (OpCodes
.Ldsfld
, fld
);
865 Emit (OpCodes
.Ldarg_0
);
866 Emit (OpCodes
.Ldfld
, fld
);
868 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { fld.FieldType }
));
871 public virtual void EmitWriteLine (LocalBuilder localBuilder
)
873 if (localBuilder
== null)
874 throw new ArgumentNullException ("localBuilder");
875 if (localBuilder
.LocalType
is TypeBuilder
)
876 throw new ArgumentException ("Output streams do not support TypeBuilders.");
877 // The MS implementation does not check for valuetypes here but it
879 Emit (OpCodes
.Ldloc
, localBuilder
);
880 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { localBuilder.LocalType }
));
883 public virtual void EmitWriteLine (string value)
885 Emit (OpCodes
.Ldstr
, value);
886 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { typeof(string)}
));
889 public virtual void EndExceptionBlock ()
891 if (open_blocks
== null)
892 open_blocks
= new Stack (defaultExceptionStackSize
);
894 if (open_blocks
.Count
<= 0)
895 throw new NotSupportedException ("Not in an exception block");
897 if (ex_handlers
[cur_block
].LastClauseType () == ILExceptionBlock
.FILTER_START
)
898 throw new InvalidOperationException ("Incorrect code generation for exception block.");
900 InternalEndClause ();
901 MarkLabel (ex_handlers
[cur_block
].end
);
902 ex_handlers
[cur_block
].End (code_len
);
903 ex_handlers
[cur_block
].Debug (cur_block
);
904 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
906 if (open_blocks
.Count
> 0)
907 cur_block
= (int)open_blocks
.Peek ();
908 //Console.WriteLine ("curblock restored to {0}", cur_block);
909 //throw new NotImplementedException ();
912 public virtual void EndScope ()
915 public virtual void MarkLabel (Label loc
)
917 if (loc
.label
< 0 || loc
.label
>= num_labels
)
918 throw new System
.ArgumentException ("The label is not valid");
919 if (labels
[loc
.label
].addr
>= 0)
920 throw new System
.ArgumentException ("The label was already defined");
921 labels
[loc
.label
].addr
= code_len
;
922 if (labels
[loc
.label
].maxStack
> cur_stack
)
923 cur_stack
= labels
[loc
.label
].maxStack
;
926 public virtual void MarkSequencePoint (ISymbolDocumentWriter document
, int startLine
,
927 int startColumn
, int endLine
, int endColumn
)
929 if (currentSequence
== null || currentSequence
.Document
!= document
) {
930 if (sequencePointLists
== null)
931 sequencePointLists
= new ArrayList ();
932 currentSequence
= new SequencePointList (document
);
933 sequencePointLists
.Add (currentSequence
);
936 currentSequence
.AddSequencePoint (code_len
, startLine
, startColumn
, endLine
, endColumn
);
939 internal void GenerateDebugInfo (ISymbolWriter symbolWriter
)
941 if (sequencePointLists
!= null) {
942 SequencePointList first
= (SequencePointList
) sequencePointLists
[0];
943 SequencePointList last
= (SequencePointList
) sequencePointLists
[sequencePointLists
.Count
- 1];
944 symbolWriter
.SetMethodSourceRange (first
.Document
, first
.StartLine
, first
.StartColumn
, last
.Document
, last
.EndLine
, last
.EndColumn
);
946 foreach (SequencePointList list
in sequencePointLists
)
947 symbolWriter
.DefineSequencePoints (list
.Document
, list
.GetOffsets(), list
.GetLines(), list
.GetColumns(), list
.GetEndLines(), list
.GetEndColumns());
949 if (locals
!= null) {
950 foreach (LocalBuilder local
in locals
) {
951 if (local
.Name
!= null && local
.Name
.Length
> 0) {
952 SignatureHelper sighelper
= SignatureHelper
.GetLocalVarSigHelper (module
);
953 sighelper
.AddArgument (local
.LocalType
);
954 byte[] signature
= sighelper
.GetSignature ();
955 symbolWriter
.DefineLocalVariable (local
.Name
, FieldAttributes
.Public
, signature
, SymAddressKind
.ILOffset
, local
.position
, 0, 0, local
.StartOffset
, local
.EndOffset
);
959 sequencePointLists
= null;
963 internal bool HasDebugInfo
965 get { return sequencePointLists != null; }
968 public virtual void ThrowException (Type excType
)
971 throw new ArgumentNullException ("excType");
972 if (! ((excType
== typeof (Exception
)) ||
973 excType
.IsSubclassOf (typeof (Exception
))))
974 throw new ArgumentException ("Type should be an exception type", "excType");
975 ConstructorInfo ctor
= excType
.GetConstructor (Type
.EmptyTypes
);
977 throw new ArgumentException ("Type should have a default constructor", "excType");
978 Emit (OpCodes
.Newobj
, ctor
);
979 Emit (OpCodes
.Throw
);
982 [MonoTODO("Not implemented")]
983 public virtual void UsingNamespace (String usingNamespace
)
985 throw new NotImplementedException ();
988 internal void label_fixup ()
990 for (int i
= 0; i
< num_fixups
; ++i
) {
991 if (labels
[fixups
[i
].label_idx
].addr
< 0)
992 throw new ArgumentException ("Label not marked");
993 // Diff is the offset from the end of the jump instruction to the address of the label
994 int diff
= labels
[fixups
[i
].label_idx
].addr
- (fixups
[i
].pos
+ fixups
[i
].offset
);
995 if (fixups
[i
].offset
== 1) {
996 code
[fixups
[i
].pos
] = (byte)((sbyte) diff
);
998 int old_cl
= code_len
;
999 code_len
= fixups
[i
].pos
;
1006 // Still used by symbolwriter
1007 [Obsolete ("Use ILOffset", true)]
1008 internal static int Mono_GetCurrentOffset (ILGenerator ig
)
1013 #if NET_4_0 || BOOTSTRAP_NET_4_0
1018 virtual int ILOffset
{
1019 get { return code_len; }
1022 void _ILGenerator
.GetIDsOfNames ([In
] ref Guid riid
, IntPtr rgszNames
, uint cNames
, uint lcid
, IntPtr rgDispId
)
1024 throw new NotImplementedException ();
1027 void _ILGenerator
.GetTypeInfo (uint iTInfo
, uint lcid
, IntPtr ppTInfo
)
1029 throw new NotImplementedException ();
1032 void _ILGenerator
.GetTypeInfoCount (out uint pcTInfo
)
1034 throw new NotImplementedException ();
1037 void _ILGenerator
.Invoke (uint dispIdMember
, [In
] ref Guid riid
, uint lcid
, short wFlags
, IntPtr pDispParams
, IntPtr pVarResult
, IntPtr pExcepInfo
, IntPtr puArgErr
)
1039 throw new NotImplementedException ();
1043 internal class SequencePointList
1045 ISymbolDocumentWriter doc
;
1046 SequencePoint
[] points
;
1048 const int arrayGrow
= 10;
1050 public SequencePointList (ISymbolDocumentWriter doc
)
1055 public ISymbolDocumentWriter Document
{
1059 public int[] GetOffsets()
1061 int[] data
= new int [count
];
1062 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Offset
;
1065 public int[] GetLines()
1067 int[] data
= new int [count
];
1068 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Line
;
1071 public int[] GetColumns()
1073 int[] data
= new int [count
];
1074 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Col
;
1077 public int[] GetEndLines()
1079 int[] data
= new int [count
];
1080 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndLine
;
1083 public int[] GetEndColumns()
1085 int[] data
= new int [count
];
1086 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndCol
;
1089 public int StartLine
{
1090 get { return points[0].Line; }
1092 public int EndLine
{
1093 get { return points[count - 1].Line; }
1095 public int StartColumn
{
1096 get { return points[0].Col; }
1098 public int EndColumn
{
1099 get { return points[count - 1].Col; }
1102 public void AddSequencePoint (int offset
, int line
, int col
, int endLine
, int endCol
)
1104 SequencePoint s
= new SequencePoint ();
1108 s
.EndLine
= endLine
;
1111 if (points
== null) {
1112 points
= new SequencePoint
[arrayGrow
];
1113 } else if (count
>= points
.Length
) {
1114 SequencePoint
[] temp
= new SequencePoint
[count
+ arrayGrow
];
1115 Array
.Copy (points
, temp
, points
.Length
);
1124 struct SequencePoint
{