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");
663 uint pos
= local
.position
;
664 bool load_addr
= false;
665 bool is_store
= false;
668 if (local
.ilgen
!= this)
669 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
671 /* inline the code from ll_emit () to optimize il code size */
672 if (opcode
.StackBehaviourPop
== StackBehaviour
.Pop1
) {
677 if (cur_stack
> max_stack
)
678 max_stack
= cur_stack
;
679 load_addr
= opcode
.StackBehaviourPush
== StackBehaviour
.Pushi
;
683 code
[code_len
++] = (byte)0x12;
684 code
[code_len
++] = (byte)pos
;
686 code
[code_len
++] = (byte)0xfe;
687 code
[code_len
++] = (byte)0x0d;
688 code
[code_len
++] = (byte)(pos
& 0xff);
689 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
694 code
[code_len
++] = (byte)(0x0a + pos
);
695 } else if (pos
< 256) {
696 code
[code_len
++] = (byte)0x13;
697 code
[code_len
++] = (byte)pos
;
699 code
[code_len
++] = (byte)0xfe;
700 code
[code_len
++] = (byte)0x0e;
701 code
[code_len
++] = (byte)(pos
& 0xff);
702 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
706 code
[code_len
++] = (byte)(0x06 + pos
);
707 } else if (pos
< 256) {
708 code
[code_len
++] = (byte)0x11;
709 code
[code_len
++] = (byte)pos
;
711 code
[code_len
++] = (byte)0xfe;
712 code
[code_len
++] = (byte)0x0c;
713 code
[code_len
++] = (byte)(pos
& 0xff);
714 code
[code_len
++] = (byte)((pos
>> 8) & 0xff);
720 public virtual void Emit (OpCode opcode
, MethodInfo meth
)
723 throw new ArgumentNullException ("meth");
725 // For compatibility with MS
726 if ((meth
is DynamicMethod
) && ((opcode
== OpCodes
.Ldftn
) || (opcode
== OpCodes
.Ldvirtftn
) || (opcode
== OpCodes
.Ldtoken
)))
727 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
729 int token
= token_gen
.GetToken (meth
);
732 Type declaringType
= meth
.DeclaringType
;
733 // Might be a DynamicMethod with no declaring type
734 if (declaringType
!= null) {
735 if (declaringType
.Module
== module
)
736 add_token_fixup (meth
);
739 if (meth
.ReturnType
!= void_type
)
742 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
743 cur_stack
-= meth
.GetParameterCount ();
746 private void Emit (OpCode opcode
, MethodInfo method
, int token
)
750 // Might be a DynamicMethod with no declaring type
751 Type declaringType
= method
.DeclaringType
;
752 if (declaringType
!= null) {
753 if (declaringType
.Module
== module
)
754 add_token_fixup (method
);
757 if (method
.ReturnType
!= void_type
)
760 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
761 cur_stack
-= method
.GetParameterCount ();
764 [CLSCompliant(false)]
765 public void Emit (OpCode opcode
, sbyte arg
)
769 code
[code_len
++] = (byte)arg
;
772 public virtual void Emit (OpCode opcode
, SignatureHelper signature
)
774 int token
= token_gen
.GetToken (signature
);
780 public virtual void Emit (OpCode opcode
, float arg
)
782 byte[] s
= System
.BitConverter
.GetBytes (arg
);
785 if (BitConverter
.IsLittleEndian
){
786 System
.Array
.Copy (s
, 0, code
, code_len
, 4);
789 code
[code_len
++] = s
[3];
790 code
[code_len
++] = s
[2];
791 code
[code_len
++] = s
[1];
792 code
[code_len
++] = s
[0];
796 public virtual void Emit (OpCode opcode
, string str
)
798 int token
= token_gen
.GetToken (str
);
804 public virtual void Emit (OpCode opcode
, Type cls
)
808 emit_int (token_gen
.GetToken (cls
));
811 [MonoLimitation ("vararg methods are not supported")]
812 public virtual void EmitCall (OpCode opcode
, MethodInfo methodInfo
, Type
[] optionalParameterTypes
)
814 if (methodInfo
== null)
815 throw new ArgumentNullException ("methodInfo");
816 short value = opcode
.Value
;
817 if (!(value == OpCodes
.Call
.Value
|| value == OpCodes
.Callvirt
.Value
))
818 throw new NotSupportedException ("Only Call and CallVirt are allowed");
819 if ((methodInfo
.CallingConvention
& CallingConventions
.VarArgs
) == 0)
820 optionalParameterTypes
= null;
821 if (optionalParameterTypes
!= null){
822 if ((methodInfo
.CallingConvention
& CallingConventions
.VarArgs
) == 0){
823 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
826 int token
= token_gen
.GetToken (methodInfo
, optionalParameterTypes
);
827 Emit (opcode
, methodInfo
, token
);
830 Emit (opcode
, methodInfo
);
833 public virtual void EmitCalli (OpCode opcode
, CallingConvention unmanagedCallConv
, Type returnType
, Type
[] parameterTypes
)
835 SignatureHelper helper
= SignatureHelper
.GetMethodSigHelper (module
, 0, unmanagedCallConv
, returnType
, parameterTypes
);
836 Emit (opcode
, helper
);
839 public virtual void EmitCalli (OpCode opcode
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
, Type
[] optionalParameterTypes
)
841 if (optionalParameterTypes
!= null)
842 throw new NotImplementedException ();
844 SignatureHelper helper
= SignatureHelper
.GetMethodSigHelper (module
, callingConvention
, 0, returnType
, parameterTypes
);
845 Emit (opcode
, helper
);
848 public virtual void EmitWriteLine (FieldInfo fld
)
851 throw new ArgumentNullException ("fld");
853 // The MS implementation does not check for valuetypes here but it
854 // should. Also, it should check that if the field is not static,
855 // then it is a member of this type.
857 Emit (OpCodes
.Ldsfld
, fld
);
859 Emit (OpCodes
.Ldarg_0
);
860 Emit (OpCodes
.Ldfld
, fld
);
862 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { fld.FieldType }
));
865 public virtual void EmitWriteLine (LocalBuilder localBuilder
)
867 if (localBuilder
== null)
868 throw new ArgumentNullException ("localBuilder");
869 if (localBuilder
.LocalType
is TypeBuilder
)
870 throw new ArgumentException ("Output streams do not support TypeBuilders.");
871 // The MS implementation does not check for valuetypes here but it
873 Emit (OpCodes
.Ldloc
, localBuilder
);
874 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { localBuilder.LocalType }
));
877 public virtual void EmitWriteLine (string value)
879 Emit (OpCodes
.Ldstr
, value);
880 Emit (OpCodes
.Call
, typeof (Console
).GetMethod ("WriteLine", new Type
[1] { typeof(string)}
));
883 public virtual void EndExceptionBlock ()
885 if (open_blocks
== null)
886 open_blocks
= new Stack (defaultExceptionStackSize
);
888 if (open_blocks
.Count
<= 0)
889 throw new NotSupportedException ("Not in an exception block");
891 if (ex_handlers
[cur_block
].LastClauseType () == ILExceptionBlock
.FILTER_START
)
892 throw new InvalidOperationException ("Incorrect code generation for exception block.");
894 InternalEndClause ();
895 MarkLabel (ex_handlers
[cur_block
].end
);
896 ex_handlers
[cur_block
].End (code_len
);
897 ex_handlers
[cur_block
].Debug (cur_block
);
898 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
900 if (open_blocks
.Count
> 0)
901 cur_block
= (int)open_blocks
.Peek ();
902 //Console.WriteLine ("curblock restored to {0}", cur_block);
903 //throw new NotImplementedException ();
906 public virtual void EndScope ()
909 public virtual void MarkLabel (Label loc
)
911 if (loc
.label
< 0 || loc
.label
>= num_labels
)
912 throw new System
.ArgumentException ("The label is not valid");
913 if (labels
[loc
.label
].addr
>= 0)
914 throw new System
.ArgumentException ("The label was already defined");
915 labels
[loc
.label
].addr
= code_len
;
916 if (labels
[loc
.label
].maxStack
> cur_stack
)
917 cur_stack
= labels
[loc
.label
].maxStack
;
920 public virtual void MarkSequencePoint (ISymbolDocumentWriter document
, int startLine
,
921 int startColumn
, int endLine
, int endColumn
)
923 if (currentSequence
== null || currentSequence
.Document
!= document
) {
924 if (sequencePointLists
== null)
925 sequencePointLists
= new ArrayList ();
926 currentSequence
= new SequencePointList (document
);
927 sequencePointLists
.Add (currentSequence
);
930 currentSequence
.AddSequencePoint (code_len
, startLine
, startColumn
, endLine
, endColumn
);
933 internal void GenerateDebugInfo (ISymbolWriter symbolWriter
)
935 if (sequencePointLists
!= null) {
936 SequencePointList first
= (SequencePointList
) sequencePointLists
[0];
937 SequencePointList last
= (SequencePointList
) sequencePointLists
[sequencePointLists
.Count
- 1];
938 symbolWriter
.SetMethodSourceRange (first
.Document
, first
.StartLine
, first
.StartColumn
, last
.Document
, last
.EndLine
, last
.EndColumn
);
940 foreach (SequencePointList list
in sequencePointLists
)
941 symbolWriter
.DefineSequencePoints (list
.Document
, list
.GetOffsets(), list
.GetLines(), list
.GetColumns(), list
.GetEndLines(), list
.GetEndColumns());
943 if (locals
!= null) {
944 foreach (LocalBuilder local
in locals
) {
945 if (local
.Name
!= null && local
.Name
.Length
> 0) {
946 SignatureHelper sighelper
= SignatureHelper
.GetLocalVarSigHelper (module
);
947 sighelper
.AddArgument (local
.LocalType
);
948 byte[] signature
= sighelper
.GetSignature ();
949 symbolWriter
.DefineLocalVariable (local
.Name
, FieldAttributes
.Public
, signature
, SymAddressKind
.ILOffset
, local
.position
, 0, 0, local
.StartOffset
, local
.EndOffset
);
953 sequencePointLists
= null;
957 internal bool HasDebugInfo
959 get { return sequencePointLists != null; }
962 public virtual void ThrowException (Type excType
)
965 throw new ArgumentNullException ("excType");
966 if (! ((excType
== typeof (Exception
)) ||
967 excType
.IsSubclassOf (typeof (Exception
))))
968 throw new ArgumentException ("Type should be an exception type", "excType");
969 ConstructorInfo ctor
= excType
.GetConstructor (Type
.EmptyTypes
);
971 throw new ArgumentException ("Type should have a default constructor", "excType");
972 Emit (OpCodes
.Newobj
, ctor
);
973 Emit (OpCodes
.Throw
);
976 [MonoTODO("Not implemented")]
977 public virtual void UsingNamespace (String usingNamespace
)
979 throw new NotImplementedException ();
982 internal void label_fixup ()
984 for (int i
= 0; i
< num_fixups
; ++i
) {
985 if (labels
[fixups
[i
].label_idx
].addr
< 0)
986 throw new ArgumentException ("Label not marked");
987 // Diff is the offset from the end of the jump instruction to the address of the label
988 int diff
= labels
[fixups
[i
].label_idx
].addr
- (fixups
[i
].pos
+ fixups
[i
].offset
);
989 if (fixups
[i
].offset
== 1) {
990 code
[fixups
[i
].pos
] = (byte)((sbyte) diff
);
992 int old_cl
= code_len
;
993 code_len
= fixups
[i
].pos
;
1000 // Still used by symbolwriter
1001 [Obsolete ("Use ILOffset", true)]
1002 internal static int Mono_GetCurrentOffset (ILGenerator ig
)
1007 #if NET_4_0 || BOOTSTRAP_NET_4_0
1012 virtual int ILOffset
{
1013 get { return code_len; }
1016 void _ILGenerator
.GetIDsOfNames ([In
] ref Guid riid
, IntPtr rgszNames
, uint cNames
, uint lcid
, IntPtr rgDispId
)
1018 throw new NotImplementedException ();
1021 void _ILGenerator
.GetTypeInfo (uint iTInfo
, uint lcid
, IntPtr ppTInfo
)
1023 throw new NotImplementedException ();
1026 void _ILGenerator
.GetTypeInfoCount (out uint pcTInfo
)
1028 throw new NotImplementedException ();
1031 void _ILGenerator
.Invoke (uint dispIdMember
, [In
] ref Guid riid
, uint lcid
, short wFlags
, IntPtr pDispParams
, IntPtr pVarResult
, IntPtr pExcepInfo
, IntPtr puArgErr
)
1033 throw new NotImplementedException ();
1037 internal class SequencePointList
1039 ISymbolDocumentWriter doc
;
1040 SequencePoint
[] points
;
1042 const int arrayGrow
= 10;
1044 public SequencePointList (ISymbolDocumentWriter doc
)
1049 public ISymbolDocumentWriter Document
{
1053 public int[] GetOffsets()
1055 int[] data
= new int [count
];
1056 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Offset
;
1059 public int[] GetLines()
1061 int[] data
= new int [count
];
1062 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Line
;
1065 public int[] GetColumns()
1067 int[] data
= new int [count
];
1068 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Col
;
1071 public int[] GetEndLines()
1073 int[] data
= new int [count
];
1074 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndLine
;
1077 public int[] GetEndColumns()
1079 int[] data
= new int [count
];
1080 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndCol
;
1083 public int StartLine
{
1084 get { return points[0].Line; }
1086 public int EndLine
{
1087 get { return points[count - 1].Line; }
1089 public int StartColumn
{
1090 get { return points[0].Col; }
1092 public int EndColumn
{
1093 get { return points[count - 1].Col; }
1096 public void AddSequencePoint (int offset
, int line
, int col
, int endLine
, int endCol
)
1098 SequencePoint s
= new SequencePoint ();
1102 s
.EndLine
= endLine
;
1105 if (points
== null) {
1106 points
= new SequencePoint
[arrayGrow
];
1107 } else if (count
>= points
.Length
) {
1108 SequencePoint
[] temp
= new SequencePoint
[count
+ arrayGrow
];
1109 Array
.Copy (points
, temp
, points
.Length
);
1118 struct SequencePoint
{