2 using System
.Collections
;
6 /**************************************************************************/
8 /// Descriptor for an IL instruction
10 internal abstract class CILInstruction
{
11 protected static readonly sbyte maxByteVal
= 127;
12 protected static readonly sbyte minByteVal
= -128;
13 protected static readonly byte leadByte
= 0xFE;
14 protected static readonly uint USHeapIndex
= 0x70000000;
15 protected static readonly int longInstrStart
= (int)Op
.arglist
;
16 public bool twoByteInstr
= false;
20 internal virtual bool Check(MetaData md
)
25 internal virtual void Write(FileImage output
) { }
29 internal class CILByte
: CILInstruction
{
32 internal CILByte(byte bVal
)
38 internal override void Write(FileImage output
)
40 output
.Write(byteVal
);
45 internal class Instr
: CILInstruction
{
48 internal Instr(int inst
)
50 if (inst
>= longInstrStart
) {
51 instr
= inst
- longInstrStart
;
60 internal override void Write(FileImage output
)
62 //Console.WriteLine("Writing instruction " + instr + " with size " + size);
63 if (twoByteInstr
) output
.Write(leadByte
);
64 output
.Write((byte)instr
);
69 internal class IntInstr
: Instr
{
73 internal IntInstr(int inst
, int num
, bool byteSize
) : base(inst
)
81 internal sealed override void Write(FileImage output
)
85 output
.Write((sbyte)val
);
92 internal class UIntInstr
: Instr
{
96 internal UIntInstr(int inst
, int num
, bool byteSize
) : base(inst
)
104 internal sealed override void Write(FileImage output
)
108 output
.Write((byte)val
);
110 output
.Write((ushort)val
);
115 internal class LongInstr
: Instr
{
118 internal LongInstr(int inst
, long l
) : base(inst
)
124 internal sealed override void Write(FileImage output
)
132 internal class FloatInstr
: Instr
{
135 internal FloatInstr(int inst
, float f
) : base(inst
)
141 internal sealed override void Write(FileImage output
)
149 internal class DoubleInstr
: Instr
{
152 internal DoubleInstr(int inst
, double d
) : base(inst
)
158 internal sealed override void Write(FileImage output
)
166 internal class StringInstr
: Instr
{
171 internal StringInstr(int inst
, string str
) : base(inst
)
177 internal StringInstr (int inst
, byte[] str
) : base (inst
)
183 internal sealed override bool Check(MetaData md
)
186 strIndex
= md
.AddToUSHeap(val
);
188 strIndex
= md
.AddToUSHeap (bval
);
192 internal sealed override void Write(FileImage output
)
195 output
.Write(USHeapIndex
| strIndex
);
200 internal class LabelInstr
: CILInstruction
{
203 internal LabelInstr(CILLabel lab
)
206 label
.AddLabelInstr(this);
210 internal class FieldInstr
: Instr
{
213 internal FieldInstr(int inst
, Field f
) : base(inst
)
219 internal sealed override void Write(FileImage output
)
222 output
.Write(field
.Token());
227 internal class MethInstr
: Instr
{
230 internal MethInstr(int inst
, Method m
) : base(inst
)
236 internal sealed override void Write(FileImage output
)
239 output
.Write(meth
.Token());
244 internal class SigInstr
: Instr
{
247 internal SigInstr(int inst
, CalliSig sig
) : base(inst
)
253 internal sealed override bool Check(MetaData md
)
255 md
.AddToTable(MDTable
.StandAloneSig
,signature
);
256 signature
.BuildTables(md
);
260 internal sealed override void Write(FileImage output
)
263 output
.Write(signature
.Token());
267 internal class TypeInstr
: Instr
{
268 MetaDataElement theType
;
270 internal TypeInstr(int inst
, Type aType
, MetaData md
) : base(inst
)
272 theType
= aType
.GetTypeSpec(md
);
276 internal sealed override void Write(FileImage output
)
279 output
.Write(theType
.Token());
284 internal class BranchInstr
: Instr
{
286 private bool shortVer
= true;
287 private static readonly byte longInstrOffset
= 13;
288 private int target
= 0;
290 internal BranchInstr(int inst
, CILLabel dst
) : base(inst
)
293 dest
.AddBranch(this);
296 if (inst
>= (int) BranchOp
.br
&& inst
!= (int) BranchOp
.leave_s
) {
302 internal sealed override bool Check(MetaData md
)
304 target
= (int)dest
.GetLabelOffset() - (int)(offset
+ size
);
308 internal sealed override void Write(FileImage output
)
312 output
.Write((sbyte)target
);
314 output
.Write(target
);
319 internal class SwitchInstr
: Instr
{
323 internal SwitchInstr(int inst
, CILLabel
[] dsts
) : base(inst
)
326 if (cases
!= null) numCases
= (uint)cases
.Length
;
327 size
+= 4 + (numCases
* 4);
328 for (int i
=0; i
< numCases
; i
++) {
329 cases
[i
].AddBranch(this);
333 internal sealed override void Write(FileImage output
)
336 output
.Write(numCases
);
337 for (int i
=0; i
< numCases
; i
++) {
338 int target
= (int)cases
[i
].GetLabelOffset() - (int)(offset
+ size
);
339 output
.Write(target
);
345 /**************************************************************************/
347 /// The IL instructions for a method
349 public class CILInstructions
{
350 private static readonly uint ExHeaderSize
= 4;
351 private static readonly uint FatExClauseSize
= 24;
352 private static readonly uint SmlExClauseSize
= 12;
353 private static readonly sbyte maxByteVal
= 127;
354 private static readonly sbyte minByteVal
= -128;
355 private static readonly byte maxUByteVal
= 255;
356 private static readonly int smallSize
= 64;
357 private static readonly ushort TinyFormat
= 0x2;
358 private static readonly ushort FatFormat
= 0x3003;
359 private static readonly ushort MoreSects
= 0x8;
360 private static readonly ushort InitLocals
= 0x10;
361 private static readonly uint FatSize
= 12;
362 private static readonly uint FatWords
= FatSize
/4;
363 private static readonly byte FatExceptTable
= 0x41;
364 private static readonly byte SmlExceptTable
= 0x01;
366 private MetaData metaData
;
367 private ArrayList exceptions
, blockStack
;
368 //private bool codeChecked = false;
369 private static readonly int INITSIZE
= 5;
370 private CILInstruction
[] buffer
= new CILInstruction
[INITSIZE
];
371 private int tide
= 0;
372 private uint offset
= 0;
373 private ushort headerFlags
= 0;
374 private short maxStack
;
375 private uint paddingNeeded
= 0;
376 private byte exceptHeader
= 0;
378 uint codeSize
= 0, exceptSize
= 0;
379 bool tinyFormat
, fatExceptionFormat
= false;
382 get { return offset; }
385 internal CILInstructions(MetaData md
)
390 private void AddToBuffer(CILInstruction inst
)
392 if (tide
>= buffer
.Length
) {
393 CILInstruction
[] tmp
= buffer
;
394 buffer
= new CILInstruction
[tmp
.Length
* 2];
395 for (int i
=0; i
< tide
; i
++) {
399 //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
400 inst
.offset
= offset
;
402 buffer
[tide
++] = inst
;
406 /// Add a simple IL instruction
408 /// <param name="inst">the IL instruction</param>
409 public void Inst(Op inst
)
411 AddToBuffer(new Instr((int)inst
));
415 /// Add an IL instruction with an integer parameter
417 /// <param name="inst">the IL instruction</param>
418 /// <param name="val">the integer parameter value</param>
419 public void IntInst(IntOp inst
, int val
)
421 int instr
= (int)inst
;
422 if ((inst
== IntOp
.ldc_i4_s
) || (inst
== IntOp
.ldc_i4
))
423 AddToBuffer(new IntInstr(instr
,val
,(inst
== IntOp
.ldc_i4_s
)));
425 AddToBuffer(new UIntInstr(instr
,val
,((inst
< IntOp
.ldc_i4_s
) ||
426 (inst
== IntOp
.unaligned
))));
430 /// Add the load long instruction
432 /// <param name="cVal">the long value</param>
433 public void ldc_i8(long cVal
)
435 AddToBuffer(new LongInstr(0x21,cVal
));
439 /// Add the load float32 instruction
441 /// <param name="cVal">the float value</param>
442 public void ldc_r4(float cVal
)
444 AddToBuffer(new FloatInstr(0x22,cVal
));
448 /// Add the load float64 instruction
450 /// <param name="cVal">the float value</param>
451 public void ldc_r8(double cVal
)
453 AddToBuffer(new DoubleInstr(0x23,cVal
));
457 /// Add the load string instruction
459 /// <param name="str">the string value</param>
460 public void ldstr(string str
)
462 AddToBuffer(new StringInstr(0x72,str
));
466 /// Add the load string instruction
468 public void ldstr (byte[] str
)
470 AddToBuffer (new StringInstr (0x72, str
));
474 /// Add the calli instruction
476 /// <param name="sig">the signature for the calli</param>
477 public void calli(CalliSig sig
)
479 AddToBuffer(new SigInstr(0x29,sig
));
483 /// Add a label to the CIL instructions
485 /// <param name="lab">the label to be added</param>
486 public void CodeLabel(CILLabel lab
)
488 AddToBuffer(new LabelInstr(lab
));
492 /// Add an instruction with a field parameter
494 /// <param name="inst">the CIL instruction</param>
495 /// <param name="f">the field parameter</param>
496 public void FieldInst(FieldOp inst
, Field f
)
498 AddToBuffer(new FieldInstr((int)inst
,f
));
502 /// Add an instruction with a method parameter
504 /// <param name="inst">the CIL instruction</param>
505 /// <param name="m">the method parameter</param>
506 public void MethInst(MethodOp inst
, Method m
)
508 AddToBuffer(new MethInstr((int)inst
,m
));
512 /// Add an instruction with a type parameter
514 /// <param name="inst">the CIL instruction</param>
515 /// <param name="t">the type argument for the CIL instruction</param>
516 public void TypeInst(TypeOp inst
, Type aType
)
518 AddToBuffer(new TypeInstr((int)inst
,aType
,metaData
));
522 /// Add a branch instruction
524 /// <param name="inst">the branch instruction</param>
525 /// <param name="lab">the label that is the target of the branch</param>
526 public void Branch(BranchOp inst
, CILLabel lab
)
528 AddToBuffer(new BranchInstr((int)inst
,lab
));
532 /// Add a switch instruction
534 /// <param name="labs">the target labels for the switch</param>
535 public void Switch(CILLabel
[] labs
)
537 AddToBuffer(new SwitchInstr(0x45,labs
));
541 /// Add a byte to the CIL instructions (.emitbyte)
543 /// <param name="bVal"></param>
544 public void emitbyte(byte bVal
)
546 AddToBuffer(new CILByte(bVal
));
550 /// Add an instruction which puts an integer on TOS. This method
551 /// selects the correct instruction based on the value of the integer.
553 /// <param name="i">the integer value</param>
554 public void PushInt(int i
)
557 AddToBuffer(new Instr((int)Op
.ldc_i4_m1
));
558 } else if ((i
>= 0) && (i
<= 8)) {
559 Op op
= (Op
)(Op
.ldc_i4_0
+ i
);
560 AddToBuffer(new Instr((int)op
));
561 } else if ((i
>= minByteVal
) && (i
<= maxByteVal
)) {
562 AddToBuffer(new IntInstr((int)IntOp
.ldc_i4_s
,i
,true));
564 AddToBuffer(new IntInstr((int)IntOp
.ldc_i4
,i
,false));
569 /// Add the instruction to load a long on TOS
571 /// <param name="l">the long value</param>
572 public void PushLong(long l
)
574 AddToBuffer(new LongInstr(0x21,l
));
578 /// Add an instruction to push the boolean value true on TOS
580 public void PushTrue()
582 AddToBuffer(new Instr((int)Op
.ldc_i4_1
));
586 /// Add an instruction to push the boolean value false on TOS
588 public void PushFalse()
590 AddToBuffer(new Instr((int)Op
.ldc_i4_0
));
594 /// Add the instruction to load an argument on TOS. This method
595 /// selects the correct instruction based on the value of argNo
597 /// <param name="argNo">the number of the argument</param>
598 public void LoadArg(int argNo
)
601 int op
= (int)Op
.ldarg_0
+ argNo
;
602 AddToBuffer(new Instr(op
));
603 } else if (argNo
<= maxUByteVal
) {
604 AddToBuffer(new UIntInstr((int)IntOp
.ldarg
,argNo
,true));
606 AddToBuffer(new UIntInstr(0x09,argNo
,false));
611 /// Add the instruction to load the address of an argument on TOS.
612 /// This method selects the correct instruction based on the value
615 /// <param name="argNo">the number of the argument</param>
616 public void LoadArgAdr(int argNo
)
618 if (argNo
<= maxUByteVal
) {
619 AddToBuffer(new UIntInstr((int)IntOp
.ldarga
,argNo
,true));
621 AddToBuffer(new UIntInstr(0x0A,argNo
,false));
626 /// Add the instruction to load a local on TOS. This method selects
627 /// the correct instruction based on the value of locNo.
629 /// <param name="locNo">the number of the local to load</param>
630 public void LoadLocal(int locNo
)
633 int op
= (int)Op
.ldloc_0
+ locNo
;
634 AddToBuffer(new Instr(op
));
635 } else if (locNo
<= maxUByteVal
) {
636 AddToBuffer(new UIntInstr((int)IntOp
.ldloc
,locNo
,true));
638 AddToBuffer(new UIntInstr(0x0C,locNo
,false));
643 /// Add the instruction to load the address of a local on TOS.
644 /// This method selects the correct instruction based on the
647 /// <param name="locNo">the number of the local</param>
648 public void LoadLocalAdr(int locNo
)
650 if (locNo
<= maxUByteVal
) {
651 AddToBuffer(new UIntInstr((int)IntOp
.ldloca
,locNo
,true));
653 AddToBuffer(new UIntInstr(0x0D,locNo
,false));
658 /// Add the instruction to store to an argument. This method
659 /// selects the correct instruction based on the value of argNo.
661 /// <param name="argNo">the argument to be stored to</param>
662 public void StoreArg(int argNo
)
664 if (argNo
<= maxUByteVal
) {
665 AddToBuffer(new UIntInstr((int)IntOp
.starg
,argNo
,true));
667 AddToBuffer(new UIntInstr(0x0B,argNo
,false));
672 /// Add the instruction to store to a local. This method selects
673 /// the correct instruction based on the value of locNo.
675 /// <param name="locNo">the local to be stored to</param>
676 public void StoreLocal(int locNo
)
679 int op
= (int)Op
.stloc_0
+ locNo
;
680 AddToBuffer(new Instr(op
));
681 } else if (locNo
<= maxUByteVal
) {
682 AddToBuffer(new UIntInstr((int)IntOp
.stloc
,locNo
,true));
684 AddToBuffer(new UIntInstr(0x0E,locNo
,false));
689 /// Create a new CIL label. To place the label in the CIL instruction
690 /// stream use CodeLabel.
692 /// <returns>a new CIL label</returns>
693 public CILLabel
NewLabel()
695 return new CILLabel();
698 public void AddTryBlock(TryBlock tryBlock
)
700 if (exceptions
== null)
701 exceptions
= new ArrayList();
702 else if (exceptions
.Contains(tryBlock
)) return;
703 exceptions
.Add(tryBlock
);
704 tryBlock
.ResolveCatchBlocks (metaData
);
708 /// Create a new label at this position in the code buffer
710 /// <returns>the label at the current position</returns>
711 public CILLabel
NewCodedLabel()
713 CILLabel lab
= new CILLabel();
714 AddToBuffer(new LabelInstr(lab
));
719 /// Mark this position as the start of a new block
720 /// (try, catch, filter, finally or fault)
722 public void StartBlock()
724 if (blockStack
== null) blockStack
= new ArrayList();
725 blockStack
.Insert(0,NewCodedLabel());
729 /// Mark this position as the end of the last started block and
730 /// make it a try block. This try block is added to the current
731 /// instructions (ie do not need to call AddTryBlock)
733 /// <returns>The try block just ended</returns>
734 public TryBlock
EndTryBlock()
736 TryBlock tBlock
= new TryBlock((CILLabel
)blockStack
[0],NewCodedLabel());
737 blockStack
.RemoveAt(0);
743 /// Mark this position as the end of the last started block and
744 /// make it a catch block. This catch block is associated with the
745 /// specified try block.
747 /// <param name="exceptType">the exception type to be caught</param>
748 /// <param name="tryBlock">the try block associated with this catch block</param>
749 public void EndCatchBlock(Class exceptType
, TryBlock tryBlock
)
751 Catch catchBlock
= new Catch(exceptType
,(CILLabel
)blockStack
[0],
753 tryBlock
.AddHandler(catchBlock
);
757 /// Mark this position as the end of the last started block and
758 /// make it a filter block. This filter block is associated with the
759 /// specified try block.
761 /// <param name="filterLab">the label where the filter code is</param>
762 /// <param name="tryBlock">the try block associated with this filter block</param>
763 public void EndFilterBlock(CILLabel filterLab
, TryBlock tryBlock
)
765 Filter filBlock
= new Filter(filterLab
,(CILLabel
)blockStack
[0],NewCodedLabel());
766 tryBlock
.AddHandler(filBlock
);
770 /// Mark this position as the end of the last started block and
771 /// make it a finally block. This finally block is associated with the
772 /// specified try block.
774 /// <param name="tryBlock">the try block associated with this finally block</param>
775 public void EndFinallyBlock(TryBlock tryBlock
)
777 Finally finBlock
= new Finally((CILLabel
)blockStack
[0],NewCodedLabel());
778 tryBlock
.AddHandler(finBlock
);
782 /// Mark this position as the end of the last started block and
783 /// make it a fault block. This fault block is associated with the
784 /// specified try block.
786 /// <param name="tryBlock">the try block associated with this fault block</param>
787 public void EndFaultBlock(TryBlock tryBlock
)
789 Fault fBlock
= new Fault((CILLabel
)blockStack
[0],NewCodedLabel());
790 tryBlock
.AddHandler(fBlock
);
793 internal uint GetCodeSize()
795 return codeSize
+ paddingNeeded
+ exceptSize
;
798 internal void CheckCode(uint locSigIx
, bool initLocals
, int maxStack
)
800 if (tide
== 0) return;
804 for (int i
=0; i
< tide
; i
++) {
805 changed
= buffer
[i
].Check(metaData
) || changed
;
808 for (int i
=1; i
< tide
; i
++) {
809 buffer
[i
].offset
= buffer
[i
-1].offset
+ buffer
[i
-1].size
;
811 offset
= buffer
[tide
-1].offset
+ buffer
[tide
-1].size
;
815 // Console.WriteLine("codeSize before header added = " + codeSize);
816 if ((offset
< smallSize
) && (maxStack
<= 8) && (locSigIx
== 0) && (exceptions
== null)) {
817 // can use tiny header
818 //Console.WriteLine("Tiny Header");
820 headerFlags
= (ushort)(TinyFormat
| ((ushort)codeSize
<< 2));
822 if ((codeSize
% 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
824 //Console.WriteLine("Fat Header");
826 localSigIx
= locSigIx
;
827 this.maxStack
= (short)maxStack
;
828 headerFlags
= FatFormat
;
829 if (exceptions
!= null) {
830 // Console.WriteLine("Got exceptions");
831 headerFlags
|= MoreSects
;
832 uint numExceptClauses
= 0;
833 for (int i
=0; i
< exceptions
.Count
; i
++) {
834 TryBlock tryBlock
= (TryBlock
)exceptions
[i
];
836 numExceptClauses
+= (uint)tryBlock
.NumHandlers();
837 if (tryBlock
.isFat()) fatExceptionFormat
= true;
840 uint data_size
= ExHeaderSize
+ numExceptClauses
*
841 (fatExceptionFormat
? FatExClauseSize
: SmlExClauseSize
);
844 fatExceptionFormat
= true;
846 // Console.WriteLine("numexceptclauses = " + numExceptClauses);
847 if (fatExceptionFormat
) {
848 // Console.WriteLine("Fat exception format");
849 exceptHeader
= FatExceptTable
;
850 exceptSize
= ExHeaderSize
+ numExceptClauses
* FatExClauseSize
;
852 // Console.WriteLine("Tiny exception format");
853 exceptHeader
= SmlExceptTable
;
854 exceptSize
= ExHeaderSize
+ numExceptClauses
* SmlExClauseSize
;
856 // Console.WriteLine("exceptSize = " + exceptSize);
858 if (initLocals
) headerFlags
|= InitLocals
;
859 if ((offset
% 4) != 0) { paddingNeeded = 4 - (offset % 4); }
862 // Console.WriteLine("codeSize = " + codeSize + " headerFlags = " +
863 // Hex.Short(headerFlags));
866 internal void Write(FileImage output
)
868 // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
870 // Console.WriteLine("Writing tiny code");
871 output
.Write((byte)headerFlags
);
873 // Console.WriteLine("Writing fat code");
874 output
.Write(headerFlags
);
875 output
.Write((ushort)maxStack
);
876 output
.Write(offset
);
877 output
.Write(localSigIx
);
879 // Console.WriteLine(Hex.Int(tide) + " CIL instructions");
880 // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
881 for (int i
=0; i
< tide
; i
++) {
882 buffer
[i
].Write(output
);
884 // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
885 for (int i
=0; i
< paddingNeeded
; i
++) { output.Write((byte)0); }
886 if (exceptions
!= null) {
887 // Console.WriteLine("Writing exceptions");
888 // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
889 output
.Write(exceptHeader
);
890 output
.Write3Bytes((uint)exceptSize
);
891 for (int i
=0; i
< exceptions
.Count
; i
++) {
892 TryBlock tryBlock
= (TryBlock
)exceptions
[i
];
893 tryBlock
.Write(output
,fatExceptionFormat
);
900 /**************************************************************************/
901 public abstract class CodeBlock
{
903 private static readonly int maxCodeSize
= 255;
904 protected CILLabel start
, end
;
905 protected bool small
= true;
907 public CodeBlock(CILLabel start
, CILLabel end
)
913 internal virtual bool isFat()
915 // Console.WriteLine("block start = " + start.GetLabelOffset() +
916 // " block end = " + end.GetLabelOffset());
917 return (end
.GetLabelOffset() - start
.GetLabelOffset()) > maxCodeSize
;
920 internal virtual void Write(FileImage output
, bool fatFormat
)
922 if (fatFormat
) output
.Write(start
.GetLabelOffset());
923 else output
.Write((short)start
.GetLabelOffset());
924 uint len
= end
.GetLabelOffset() - start
.GetLabelOffset();
925 if (fatFormat
) output
.Write(len
);
926 else output
.Write((byte)len
);
932 /// The descriptor for a guarded block (.try)
934 public class TryBlock
: CodeBlock
{
935 protected bool fatFormat
= false;
936 protected int flags
= 0;
937 ArrayList handlers
= new ArrayList();
940 /// Create a new try block
942 /// <param name="start">start label for the try block</param>
943 /// <param name="end">end label for the try block</param>
944 public TryBlock(CILLabel start
, CILLabel end
) : base(start
,end
) { }
947 /// Add a handler to this try block
949 /// <param name="handler">a handler to be added to the try block</param>
950 public void AddHandler(HandlerBlock handler
)
952 flags
= handler
.GetFlag();
953 handlers
.Add(handler
);
956 internal void SetSize()
958 fatFormat
= base.isFat();
959 if (fatFormat
) return;
960 for (int i
=0; i
< handlers
.Count
; i
++) {
961 HandlerBlock handler
= (HandlerBlock
)handlers
[i
];
962 if (handler
.isFat()) {
969 internal int NumHandlers()
971 return handlers
.Count
;
974 internal override bool isFat()
980 internal void ResolveCatchBlocks (MetaData md
)
982 for (int i
=0; i
< handlers
.Count
; i
++) {
983 Catch c
= handlers
[i
] as Catch
;
989 internal override void Write(FileImage output
, bool fatFormat
)
991 // Console.WriteLine("writing exception details");
992 for (int i
=0; i
< handlers
.Count
; i
++) {
993 // Console.WriteLine("Except block " + i);
994 HandlerBlock handler
= (HandlerBlock
)handlers
[i
];
995 if (fatFormat
) output
.Write(flags
);
996 else output
.Write((short)flags
);
997 // Console.WriteLine("flags = " + Hex.Short(flags));
998 base.Write(output
,fatFormat
);
999 handler
.Write(output
,fatFormat
);
1004 public abstract class HandlerBlock
: CodeBlock
{
1006 protected static readonly short ExceptionFlag
= 0;
1007 protected static readonly short FilterFlag
= 0x01;
1008 protected static readonly short FinallyFlag
= 0x02;
1009 protected static readonly short FaultFlag
= 0x04;
1011 public HandlerBlock(CILLabel start
, CILLabel end
) : base(start
,end
) { }
1013 internal virtual short GetFlag() { return ExceptionFlag; }
1015 internal override void Write(FileImage output
, bool fatFormat
)
1017 base.Write(output
,fatFormat
);
1023 /// The descriptor for a catch clause (.catch)
1025 public class Catch
: HandlerBlock
{
1027 MetaDataElement exceptType
;
1030 /// Create a new catch clause
1032 /// <param name="except">the exception to be caught</param>
1033 /// <param name="handlerStart">start of the handler code</param>
1034 /// <param name="handlerEnd">end of the handler code</param>
1035 public Catch(Class except
, CILLabel handlerStart
, CILLabel handlerEnd
)
1036 : base(handlerStart
, handlerEnd
)
1038 exceptType
= except
;
1041 public Catch(Type except
, CILLabel handlerStart
, CILLabel handlerEnd
)
1042 : base(handlerStart
,handlerEnd
)
1044 exceptType
= except
;
1047 internal void ResolveType (MetaData md
)
1049 exceptType
= ((Type
) exceptType
).GetTypeSpec (md
);
1052 internal override void Write(FileImage output
, bool fatFormat
)
1054 base.Write(output
,fatFormat
);
1055 output
.Write(exceptType
.Token());
1060 /// The descriptor for a filter clause (.filter)
1062 public class Filter
: HandlerBlock
{
1064 CILLabel filterLabel
;
1067 /// Create a new filter clause
1069 /// <param name="filterLabel">the label where the filter code starts</param>
1070 /// <param name="handlerStart">the start of the handler code</param>
1071 /// <param name="handlerEnd">the end of the handler code</param>
1072 public Filter(CILLabel filterLabel
, CILLabel handlerStart
,
1073 CILLabel handlerEnd
) : base(handlerStart
,handlerEnd
)
1075 this.filterLabel
= filterLabel
;
1078 internal override short GetFlag()
1083 internal override void Write(FileImage output
, bool fatFormat
)
1085 base.Write(output
,fatFormat
);
1086 output
.Write(filterLabel
.GetLabelOffset());
1092 /// Descriptor for a finally block (.finally)
1094 public class Finally
: HandlerBlock
{
1097 /// Create a new finally clause
1099 /// <param name="finallyStart">start of finally code</param>
1100 /// <param name="finallyEnd">end of finally code</param>
1101 public Finally(CILLabel finallyStart
, CILLabel finallyEnd
)
1102 : base(finallyStart
,finallyEnd
) { }
1104 internal override short GetFlag()
1109 internal override void Write(FileImage output
, bool fatFormat
)
1111 base.Write(output
,fatFormat
);
1112 output
.Write((int)0);
1118 /// Descriptor for a fault block (.fault)
1120 public class Fault
: HandlerBlock
{
1123 /// Create a new fault clause
1125 /// <param name="faultStart">start of the fault code</param>
1126 /// <param name="faultEnd">end of the fault code</param>
1127 public Fault(CILLabel faultStart
, CILLabel faultEnd
)
1128 : base(faultStart
,faultEnd
) { }
1130 internal override short GetFlag()
1135 internal override void Write(FileImage output
, bool fatFormat
)
1137 base.Write(output
,fatFormat
);
1138 output
.Write((int)0);
1143 /**************************************************************************/
1145 /// Descriptor for the locals for a method
1147 public class LocalSig
: Signature
{
1149 private static readonly byte LocalSigByte
= 0x7;
1152 public LocalSig(Local
[] locals
)
1154 this.locals
= locals
;
1155 tabIx
= MDTable
.StandAloneSig
;
1158 internal sealed override void BuildTables(MetaData md
)
1161 MemoryStream sig
= new MemoryStream();
1162 sig
.WriteByte(LocalSigByte
);
1163 MetaData
.CompressNum((uint)locals
.Length
,sig
);
1164 for (int i
=0; i
< locals
.Length
; i
++) {
1165 ((Local
)locals
[i
]).TypeSig(sig
);
1167 sigIx
= md
.AddToBlobHeap(sig
.ToArray());
1173 /**************************************************************************/
1175 /// Signature for calli instruction
1177 public class CalliSig
: Signature
{
1179 private static readonly byte Sentinel
= 0x41;
1182 Type
[] parameters
, optParams
;
1183 uint numPars
= 0, numOptPars
= 0;
1186 /// Create a signature for a calli instruction
1188 /// <param name="cconv">calling conventions</param>
1189 /// <param name="retType">return type</param>
1190 /// <param name="pars">parameter types</param>
1191 public CalliSig(CallConv cconv
, Type retType
, Type
[] pars
)
1193 tabIx
= MDTable
.StandAloneSig
;
1195 returnType
= retType
;
1197 if (pars
!= null) numPars
= (uint)pars
.Length
;
1201 /// Add the optional parameters to a vararg method
1202 /// This method sets the vararg calling convention
1204 /// <param name="optPars">the optional pars for the vararg call</param>
1205 public void AddVarArgs(Type
[] optPars
)
1207 optParams
= optPars
;
1208 if (optPars
!= null) numOptPars
= (uint)optPars
.Length
;
1209 callConv
|= CallConv
.Vararg
;
1213 /// Add extra calling conventions to this callsite signature
1215 /// <param name="cconv"></param>
1216 public void AddCallingConv(CallConv cconv
)
1221 internal sealed override void BuildTables(MetaData md
)
1224 MemoryStream sig
= new MemoryStream();
1225 sig
.WriteByte((byte)callConv
);
1226 MetaData
.CompressNum(numPars
+numOptPars
,sig
);
1227 returnType
.TypeSig(sig
);
1228 for (int i
=0; i
< numPars
; i
++) {
1229 parameters
[i
].TypeSig(sig
);
1231 sigIx
= md
.AddToBlobHeap(sig
.ToArray());
1232 if (numOptPars
> 0) {
1233 sig
.WriteByte(Sentinel
);
1234 for (int i
=0; i
< numOptPars
; i
++) {
1235 optParams
[i
].TypeSig(sig
);
1243 /**************************************************************************/
1245 /// Descriptor for a local of a method
1247 public class Local
{
1249 private static readonly byte Pinned
= 0x45;
1252 bool pinned
= false, byref
= false;
1255 /// Create a new local variable
1257 /// <param name="lName">name of the local variable</param>
1258 /// <param name="lType">type of the local variable</param>
1259 public Local(string lName
, Type lType
)
1266 /// Create a new local variable that is byref and/or pinned
1268 /// <param name="lName">local name</param>
1269 /// <param name="lType">local type</param>
1270 /// <param name="byRef">is byref</param>
1271 /// <param name="isPinned">has pinned attribute</param>
1272 public Local(string lName
, Type lType
, bool byRef
, bool isPinned
)
1280 internal void TypeSig(MemoryStream str
)
1282 if (pinned
) str
.WriteByte(Pinned
);
1288 /**************************************************************************/
1290 /// A label in the IL
1292 public class CILLabel
{
1294 CILInstruction branch
;
1295 CILInstruction
[] multipleBranches
;
1297 CILInstruction labInstr
;
1302 public CILLabel (uint offset
, bool absolute
)
1304 this.offset
= offset
;
1305 this.absolute
= absolute
;
1308 public CILLabel (uint offset
) : this (offset
, false)
1317 internal void AddBranch(CILInstruction instr
)
1319 if (branch
== null) {
1323 if (multipleBranches
== null) {
1324 multipleBranches
= new CILInstruction
[2];
1325 } else if (tide
>= multipleBranches
.Length
) {
1326 CILInstruction
[] tmp
= multipleBranches
;
1327 multipleBranches
= new CILInstruction
[tmp
.Length
*2];
1328 for (int i
=0; i
< tide
; i
++) {
1329 multipleBranches
[i
] = tmp
[i
];
1332 multipleBranches
[tide
++] = instr
;
1335 internal void AddLabelInstr(LabelInstr lInstr
)
1340 internal uint GetLabelOffset()
1342 if (absolute
) return offset
;
1343 if (labInstr
== null) return 0;
1344 return labInstr
.offset
+ offset
;