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
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;
54 internal int filter_offset
;
56 internal void Debug () {
58 System
.Console
.Write ("\ttype="+type
.ToString()+" start="+start
.ToString()+" len="+len
.ToString());
60 System
.Console
.WriteLine (" extype="+extype
.ToString());
62 System
.Console
.WriteLine (String
.Empty
);
66 internal struct ILExceptionInfo
{
67 #pragma warning disable 169
68 #pragma warning disable 414
69 internal ILExceptionBlock
[] handlers
;
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
)
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
)
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
)
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
)
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)
129 int i
= handlers
.Length
- 1;
131 handlers
[i
].len
= offset
- handlers
[i
].start
;
134 internal int LastClauseType ()
136 if (handlers
!= null)
137 return handlers
[handlers
.Length
-1].type
;
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
)
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 ();
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
);
166 handlers
[i
].len
= offset
- handlers
[i
].start
;
168 handlers
= new ILExceptionBlock
[1];
169 len
= offset
- start
;
174 internal struct ILTokenInfo
{
175 public MemberInfo member
;
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
199 public LabelData (int addr
, int maxStack
)
202 this.maxStack
= maxStack
;
209 #region Sync with reflection.h
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
;
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
)
240 code
= new byte [size
];
242 this.token_gen
= token_gen
;
245 private void make_room (int nbytes
)
247 if (code_len
+ nbytes
< code
.Length
)
249 byte[] new_code
= new byte [(code_len
+ nbytes
) * 2 + 128];
250 System
.Array
.Copy (code
, 0, new_code
, 0, code
.Length
);
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 */
286 case StackBehaviour
.Push1_push1
:
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
:
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
:
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
:
325 private static int target_len (OpCode opcode
)
327 if (opcode
.OperandType
== OperandType
.InlineBrTarget
)
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
);
341 case ILExceptionBlock
.FAULT
:
342 case ILExceptionBlock
.FINALLY
:
343 Emit (OpCodes
.Endfinally
);
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
);
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
;
398 ex_handlers
= new ILExceptionInfo
[1];
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
;
467 locals
= new LocalBuilder
[1];
470 res
.position
= (ushort)(locals
.Length
- 1);
474 public virtual Label
DefineLabel ()
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
);
484 labels
[num_labels
] = new LabelData (-1, 0);
486 return new Label (num_labels
++);
489 public virtual void Emit (OpCode opcode
)
495 public virtual void Emit (OpCode opcode
, Byte arg
)
499 code
[code_len
++] = arg
;
503 public virtual void Emit (OpCode opcode
, ConstructorInfo con
)
505 int token
= token_gen
.GetToken (con
, true);
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
);
519 if (BitConverter
.IsLittleEndian
){
520 System
.Array
.Copy (s
, 0, code
, code_len
, 8);
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);
542 public virtual void Emit (OpCode opcode
, Int16 arg
)
546 code
[code_len
++] = (byte) (arg
& 0xFF);
547 code
[code_len
++] = (byte) ((arg
>> 8) & 0xFF);
550 public virtual void Emit (OpCode opcode
, int arg
)
557 public virtual void Emit (OpCode opcode
, long arg
)
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
);
576 if (cur_stack
> labels
[label
.m_label
].maxStack
)
577 labels
[label
.m_label
].maxStack
= cur_stack
;
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
);
586 fixups
[num_fixups
].offset
= tlen
;
587 fixups
[num_fixups
].pos
= code_len
;
588 fixups
[num_fixups
].label_idx
= label
.m_label
;
594 public virtual void Emit (OpCode opcode
, Label
[] labels
)
597 throw new ArgumentNullException ("labels");
599 /* opcode needs to be switch. */
600 int count
= labels
.Length
;
601 make_room (6 + count
* 4);
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
;
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
);
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
;
640 public virtual void Emit (OpCode opcode
, LocalBuilder local
)
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;
653 /* inline the code from ll_emit () to optimize il code size */
654 if (opcode
.StackBehaviourPop
== StackBehaviour
.Pop1
) {
657 } else if (opcode
.StackBehaviourPush
== StackBehaviour
.Push1
|| opcode
.StackBehaviourPush
== StackBehaviour
.Pushi
) {
660 if (cur_stack
> max_stack
)
661 max_stack
= cur_stack
;
662 load_addr
= opcode
.StackBehaviourPush
== StackBehaviour
.Pushi
;
666 code
[code_len
++] = (byte)0x12;
667 code
[code_len
++] = (byte)pos
;
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);
677 code
[code_len
++] = (byte)(0x0a + pos
);
678 } else if (pos
< 256) {
679 code
[code_len
++] = (byte)0x13;
680 code
[code_len
++] = (byte)pos
;
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
) {
689 code
[code_len
++] = (byte)(0x06 + pos
);
690 } else if (pos
< 256) {
691 code
[code_len
++] = (byte)0x11;
692 code
[code_len
++] = (byte)pos
;
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);
705 public virtual void Emit (OpCode opcode
, MethodInfo meth
)
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);
717 Type declaringType
= meth
.DeclaringType
;
719 if (meth
.ReturnType
!= typeof (void))
722 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
723 cur_stack
-= meth
.GetParametersCount ();
726 private void Emit (OpCode opcode
, MethodInfo method
, int token
)
731 if (method
.ReturnType
!= typeof (void))
734 if (opcode
.StackBehaviourPop
== StackBehaviour
.Varpop
)
735 cur_stack
-= method
.GetParametersCount ();
738 [CLSCompliant(false)]
739 public void Emit (OpCode opcode
, sbyte arg
)
743 code
[code_len
++] = (byte)arg
;
746 public virtual void Emit (OpCode opcode
, SignatureHelper signature
)
748 int token
= token_gen
.GetToken (signature
);
754 public virtual void Emit (OpCode opcode
, float arg
)
756 byte[] s
= System
.BitConverter
.GetBytes (arg
);
759 if (BitConverter
.IsLittleEndian
){
760 System
.Array
.Copy (s
, 0, code
, code_len
, 4);
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
);
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.");
785 int token
= token_gen
.GetToken (cls
, opcode
!= OpCodes
.Ldtoken
);
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
);
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
)
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.
842 Emit (OpCodes
.Ldsfld
, fld
);
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
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 ());
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
)
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
);
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
);
979 int old_cl
= code_len
;
980 code_len
= fixups
[i
].pos
;
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
;
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
;
1006 internal TokenGenerator TokenGenerator
{
1012 public virtual int ILOffset
{
1013 get { return code_len; }
1017 internal class SequencePointList
1019 ISymbolDocumentWriter doc
;
1020 SequencePoint
[] points
;
1022 const int arrayGrow
= 10;
1024 public SequencePointList (ISymbolDocumentWriter doc
)
1029 public ISymbolDocumentWriter Document
{
1033 public int[] GetOffsets()
1035 int[] data
= new int [count
];
1036 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Offset
;
1039 public int[] GetLines()
1041 int[] data
= new int [count
];
1042 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Line
;
1045 public int[] GetColumns()
1047 int[] data
= new int [count
];
1048 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].Col
;
1051 public int[] GetEndLines()
1053 int[] data
= new int [count
];
1054 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndLine
;
1057 public int[] GetEndColumns()
1059 int[] data
= new int [count
];
1060 for (int n
=0; n
<count
; n
++) data
[n
] = points
[n
].EndCol
;
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 ();
1082 s
.EndLine
= endLine
;
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
);
1098 struct SequencePoint
{
1112 private const int _defaultCapacity
= 10;
1116 _array
= new Object
[_defaultCapacity
];
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
];
1133 public virtual int Count
1141 public virtual Object
Peek()
1144 throw new InvalidOperationException ();
1146 return _array
[_size
- 1];
1149 public virtual Object
Pop()
1152 throw new InvalidOperationException ();
1155 Object obj
= _array
[--_size
];
1156 _array
[_size
] = null;
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
);
1168 _array
[_size
++] = obj
;