2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / PEAPI / Code.cs
blob60f09b4e92d2d185568506f47987d2632a797b1b
1 using System.IO;
2 using System.Collections;
4 namespace PEAPI {
6 /**************************************************************************/
7 /// <summary>
8 /// Descriptor for an IL instruction
9 /// </summary>
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;
17 public uint size = 0;
18 public uint offset;
20 internal virtual bool Check(MetaData md)
22 return false;
25 internal virtual void Write(FileImage output) { }
29 internal class CILByte : CILInstruction {
30 byte byteVal;
32 internal CILByte(byte bVal)
34 byteVal = bVal;
35 size = 1;
38 internal override void Write(FileImage output)
40 output.Write(byteVal);
45 internal class Instr : CILInstruction {
46 protected int instr;
48 internal Instr(int inst)
50 if (inst >= longInstrStart) {
51 instr = inst - longInstrStart;
52 twoByteInstr = true;
53 size = 2;
54 } else {
55 instr = inst;
56 size = 1;
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 {
70 int val;
71 bool byteNum;
73 internal IntInstr(int inst, int num, bool byteSize) : base(inst)
75 val = num;
76 byteNum = byteSize;
77 if (byteNum) size++;
78 else size += 4;
81 internal sealed override void Write(FileImage output)
83 base.Write(output);
84 if (byteNum)
85 output.Write((sbyte)val);
86 else
87 output.Write(val);
92 internal class UIntInstr : Instr {
93 int val;
94 bool byteNum;
96 internal UIntInstr(int inst, int num, bool byteSize) : base(inst)
98 val = num;
99 byteNum = byteSize;
100 if (byteNum) size++;
101 else size += 2;
104 internal sealed override void Write(FileImage output)
106 base.Write(output);
107 if (byteNum)
108 output.Write((byte)val);
109 else
110 output.Write((ushort)val);
115 internal class LongInstr : Instr {
116 long val;
118 internal LongInstr(int inst, long l) : base(inst)
120 val = l;
121 size += 8;
124 internal sealed override void Write(FileImage output)
126 base.Write(output);
127 output.Write(val);
132 internal class FloatInstr : Instr {
133 float fVal;
135 internal FloatInstr(int inst, float f) : base(inst)
137 fVal = f;
138 size += 4;
141 internal sealed override void Write(FileImage output)
143 base.Write(output);
144 output.Write(fVal);
149 internal class DoubleInstr : Instr {
150 double val;
152 internal DoubleInstr(int inst, double d) : base(inst)
154 val = d;
155 size += 8;
158 internal sealed override void Write(FileImage output)
160 base.Write(output);
161 output.Write(val);
166 internal class StringInstr : Instr {
167 string val;
168 byte[] bval;
169 uint strIndex;
171 internal StringInstr(int inst, string str) : base(inst)
173 val = str;
174 size += 4;
177 internal StringInstr (int inst, byte[] str) : base (inst)
179 bval = str;
180 size += 4;
183 internal sealed override bool Check(MetaData md)
185 if (val != null)
186 strIndex = md.AddToUSHeap(val);
187 else
188 strIndex = md.AddToUSHeap (bval);
189 return false;
192 internal sealed override void Write(FileImage output)
194 base.Write(output);
195 output.Write(USHeapIndex | strIndex);
200 internal class LabelInstr : CILInstruction {
201 CILLabel label;
203 internal LabelInstr(CILLabel lab)
205 label = lab;
206 label.AddLabelInstr(this);
210 internal class FieldInstr : Instr {
211 Field field;
213 internal FieldInstr(int inst, Field f) : base(inst)
215 field = f;
216 size += 4;
219 internal sealed override void Write(FileImage output)
221 base.Write(output);
222 output.Write(field.Token());
227 internal class MethInstr : Instr {
228 Method meth;
230 internal MethInstr(int inst, Method m) : base(inst)
232 meth = m;
233 size += 4;
236 internal sealed override void Write(FileImage output)
238 base.Write(output);
239 output.Write(meth.Token());
244 internal class SigInstr : Instr {
245 CalliSig signature;
247 internal SigInstr(int inst, CalliSig sig) : base(inst)
249 signature = sig;
250 size += 4;
253 internal sealed override bool Check(MetaData md)
255 md.AddToTable(MDTable.StandAloneSig,signature);
256 signature.BuildTables(md);
257 return false;
260 internal sealed override void Write(FileImage output)
262 base.Write(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);
273 size += 4;
276 internal sealed override void Write(FileImage output)
278 base.Write(output);
279 output.Write(theType.Token());
284 internal class BranchInstr : Instr {
285 CILLabel dest;
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)
292 dest = dst;
293 dest.AddBranch(this);
294 size++;
296 if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) {
297 shortVer = false;
298 size += 3;
302 internal sealed override bool Check(MetaData md)
304 target = (int)dest.GetLabelOffset() - (int)(offset + size);
305 return false;
308 internal sealed override void Write(FileImage output)
310 base.Write(output);
311 if (shortVer)
312 output.Write((sbyte)target);
313 else
314 output.Write(target);
319 internal class SwitchInstr : Instr {
320 CILLabel[] cases;
321 uint numCases = 0;
323 internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst)
325 cases = dsts;
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)
335 base.Write(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 /**************************************************************************/
346 /// <summary>
347 /// The IL instructions for a method
348 /// </summary>
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;
377 uint localSigIx = 0;
378 uint codeSize = 0, exceptSize = 0;
379 bool tinyFormat, fatExceptionFormat = false;
381 public uint Offset {
382 get { return offset; }
385 internal CILInstructions(MetaData md)
387 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++) {
396 buffer[i] = tmp[i];
399 //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
400 inst.offset = offset;
401 offset += inst.size;
402 buffer[tide++] = inst;
405 /// <summary>
406 /// Add a simple IL instruction
407 /// </summary>
408 /// <param name="inst">the IL instruction</param>
409 public void Inst(Op inst)
411 AddToBuffer(new Instr((int)inst));
414 /// <summary>
415 /// Add an IL instruction with an integer parameter
416 /// </summary>
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)));
424 else
425 AddToBuffer(new UIntInstr(instr,val,((inst < IntOp.ldc_i4_s) ||
426 (inst == IntOp.unaligned))));
429 /// <summary>
430 /// Add the load long instruction
431 /// </summary>
432 /// <param name="cVal">the long value</param>
433 public void ldc_i8(long cVal)
435 AddToBuffer(new LongInstr(0x21,cVal));
438 /// <summary>
439 /// Add the load float32 instruction
440 /// </summary>
441 /// <param name="cVal">the float value</param>
442 public void ldc_r4(float cVal)
444 AddToBuffer(new FloatInstr(0x22,cVal));
447 /// <summary>
448 /// Add the load float64 instruction
449 /// </summary>
450 /// <param name="cVal">the float value</param>
451 public void ldc_r8(double cVal)
453 AddToBuffer(new DoubleInstr(0x23,cVal));
456 /// <summary>
457 /// Add the load string instruction
458 /// </summary>
459 /// <param name="str">the string value</param>
460 public void ldstr(string str)
462 AddToBuffer(new StringInstr(0x72,str));
465 /// <summary>
466 /// Add the load string instruction
467 /// </summary>
468 public void ldstr (byte[] str)
470 AddToBuffer (new StringInstr (0x72, str));
473 /// <summary>
474 /// Add the calli instruction
475 /// </summary>
476 /// <param name="sig">the signature for the calli</param>
477 public void calli(CalliSig sig)
479 AddToBuffer(new SigInstr(0x29,sig));
482 /// <summary>
483 /// Add a label to the CIL instructions
484 /// </summary>
485 /// <param name="lab">the label to be added</param>
486 public void CodeLabel(CILLabel lab)
488 AddToBuffer(new LabelInstr(lab));
491 /// <summary>
492 /// Add an instruction with a field parameter
493 /// </summary>
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));
501 /// <summary>
502 /// Add an instruction with a method parameter
503 /// </summary>
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));
511 /// <summary>
512 /// Add an instruction with a type parameter
513 /// </summary>
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));
521 /// <summary>
522 /// Add a branch instruction
523 /// </summary>
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));
531 /// <summary>
532 /// Add a switch instruction
533 /// </summary>
534 /// <param name="labs">the target labels for the switch</param>
535 public void Switch(CILLabel[] labs)
537 AddToBuffer(new SwitchInstr(0x45,labs));
540 /// <summary>
541 /// Add a byte to the CIL instructions (.emitbyte)
542 /// </summary>
543 /// <param name="bVal"></param>
544 public void emitbyte(byte bVal)
546 AddToBuffer(new CILByte(bVal));
549 /// <summary>
550 /// Add an instruction which puts an integer on TOS. This method
551 /// selects the correct instruction based on the value of the integer.
552 /// </summary>
553 /// <param name="i">the integer value</param>
554 public void PushInt(int i)
556 if (i == -1) {
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));
563 } else {
564 AddToBuffer(new IntInstr((int)IntOp.ldc_i4,i,false));
568 /// <summary>
569 /// Add the instruction to load a long on TOS
570 /// </summary>
571 /// <param name="l">the long value</param>
572 public void PushLong(long l)
574 AddToBuffer(new LongInstr(0x21,l));
577 /// <summary>
578 /// Add an instruction to push the boolean value true on TOS
579 /// </summary>
580 public void PushTrue()
582 AddToBuffer(new Instr((int)Op.ldc_i4_1));
585 /// <summary>
586 /// Add an instruction to push the boolean value false on TOS
587 /// </summary>
588 public void PushFalse()
590 AddToBuffer(new Instr((int)Op.ldc_i4_0));
593 /// <summary>
594 /// Add the instruction to load an argument on TOS. This method
595 /// selects the correct instruction based on the value of argNo
596 /// </summary>
597 /// <param name="argNo">the number of the argument</param>
598 public void LoadArg(int argNo)
600 if (argNo < 4) {
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));
605 } else {
606 AddToBuffer(new UIntInstr(0x09,argNo,false));
610 /// <summary>
611 /// Add the instruction to load the address of an argument on TOS.
612 /// This method selects the correct instruction based on the value
613 /// of argNo.
614 /// </summary>
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));
620 } else {
621 AddToBuffer(new UIntInstr(0x0A,argNo,false));
625 /// <summary>
626 /// Add the instruction to load a local on TOS. This method selects
627 /// the correct instruction based on the value of locNo.
628 /// </summary>
629 /// <param name="locNo">the number of the local to load</param>
630 public void LoadLocal(int locNo)
632 if (locNo < 4) {
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));
637 } else {
638 AddToBuffer(new UIntInstr(0x0C,locNo,false));
642 /// <summary>
643 /// Add the instruction to load the address of a local on TOS.
644 /// This method selects the correct instruction based on the
645 /// value of locNo.
646 /// </summary>
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));
652 } else {
653 AddToBuffer(new UIntInstr(0x0D,locNo,false));
657 /// <summary>
658 /// Add the instruction to store to an argument. This method
659 /// selects the correct instruction based on the value of argNo.
660 /// </summary>
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));
666 } else {
667 AddToBuffer(new UIntInstr(0x0B,argNo,false));
671 /// <summary>
672 /// Add the instruction to store to a local. This method selects
673 /// the correct instruction based on the value of locNo.
674 /// </summary>
675 /// <param name="locNo">the local to be stored to</param>
676 public void StoreLocal(int locNo)
678 if (locNo < 4) {
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));
683 } else {
684 AddToBuffer(new UIntInstr(0x0E,locNo,false));
688 /// <summary>
689 /// Create a new CIL label. To place the label in the CIL instruction
690 /// stream use CodeLabel.
691 /// </summary>
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);
707 /// <summary>
708 /// Create a new label at this position in the code buffer
709 /// </summary>
710 /// <returns>the label at the current position</returns>
711 public CILLabel NewCodedLabel()
713 CILLabel lab = new CILLabel();
714 AddToBuffer(new LabelInstr(lab));
715 return lab;
718 /// <summary>
719 /// Mark this position as the start of a new block
720 /// (try, catch, filter, finally or fault)
721 /// </summary>
722 public void StartBlock()
724 if (blockStack == null) blockStack = new ArrayList();
725 blockStack.Insert(0,NewCodedLabel());
728 /// <summary>
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)
732 /// </summary>
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);
738 AddTryBlock(tBlock);
739 return tBlock;
742 /// <summary>
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.
746 /// </summary>
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],
752 NewCodedLabel());
753 tryBlock.AddHandler(catchBlock);
756 /// <summary>
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.
760 /// </summary>
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);
769 /// <summary>
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.
773 /// </summary>
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);
781 /// <summary>
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.
785 /// </summary>
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;
801 bool changed = true;
802 while (changed) {
803 changed = false;
804 for (int i=0; i < tide; i++) {
805 changed = buffer[i].Check(metaData) || changed;
807 if (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;
814 codeSize = offset;
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");
819 tinyFormat = true;
820 headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
821 codeSize++;
822 if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
823 } else {
824 //Console.WriteLine("Fat Header");
825 tinyFormat = false;
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];
835 tryBlock.SetSize();
836 numExceptClauses += (uint)tryBlock.NumHandlers();
837 if (tryBlock.isFat()) fatExceptionFormat = true;
840 uint data_size = ExHeaderSize + numExceptClauses *
841 (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
843 if (data_size > 255)
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;
851 } else {
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); }
860 codeSize += FatSize;
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));
869 if (tinyFormat) {
870 // Console.WriteLine("Writing tiny code");
871 output.Write((byte)headerFlags);
872 } else {
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)
909 this.start = start;
910 this.end = 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);
931 /// <summary>
932 /// The descriptor for a guarded block (.try)
933 /// </summary>
934 public class TryBlock : CodeBlock {
935 protected bool fatFormat = false;
936 protected int flags = 0;
937 ArrayList handlers = new ArrayList();
939 /// <summary>
940 /// Create a new try block
941 /// </summary>
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) { }
946 /// <summary>
947 /// Add a handler to this try block
948 /// </summary>
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()) {
963 fatFormat = true;
964 return;
969 internal int NumHandlers()
971 return handlers.Count;
974 internal override bool isFat()
976 return fatFormat;
979 //Hackish
980 internal void ResolveCatchBlocks (MetaData md)
982 for (int i=0; i < handlers.Count; i++) {
983 Catch c = handlers [i] as Catch;
984 if (c != null)
985 c.ResolveType (md);
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);
1022 /// <summary>
1023 /// The descriptor for a catch clause (.catch)
1024 /// </summary>
1025 public class Catch : HandlerBlock {
1027 MetaDataElement exceptType;
1029 /// <summary>
1030 /// Create a new catch clause
1031 /// </summary>
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());
1059 /// <summary>
1060 /// The descriptor for a filter clause (.filter)
1061 /// </summary>
1062 public class Filter : HandlerBlock {
1064 CILLabel filterLabel;
1066 /// <summary>
1067 /// Create a new filter clause
1068 /// </summary>
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()
1080 return FilterFlag;
1083 internal override void Write(FileImage output, bool fatFormat)
1085 base.Write(output,fatFormat);
1086 output.Write(filterLabel.GetLabelOffset());
1091 /// <summary>
1092 /// Descriptor for a finally block (.finally)
1093 /// </summary>
1094 public class Finally : HandlerBlock {
1096 /// <summary>
1097 /// Create a new finally clause
1098 /// </summary>
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()
1106 return FinallyFlag;
1109 internal override void Write(FileImage output, bool fatFormat)
1111 base.Write(output,fatFormat);
1112 output.Write((int)0);
1117 /// <summary>
1118 /// Descriptor for a fault block (.fault)
1119 /// </summary>
1120 public class Fault : HandlerBlock {
1122 /// <summary>
1123 /// Create a new fault clause
1124 /// </summary>
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()
1132 return FaultFlag;
1135 internal override void Write(FileImage output, bool fatFormat)
1137 base.Write(output,fatFormat);
1138 output.Write((int)0);
1143 /**************************************************************************/
1144 /// <summary>
1145 /// Descriptor for the locals for a method
1146 /// </summary>
1147 public class LocalSig : Signature {
1149 private static readonly byte LocalSigByte = 0x7;
1150 Local[] locals;
1152 public LocalSig(Local[] locals)
1154 this.locals = locals;
1155 tabIx = MDTable.StandAloneSig;
1158 internal sealed override void BuildTables(MetaData md)
1160 if (done) return;
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());
1168 done = true;
1173 /**************************************************************************/
1174 /// <summary>
1175 /// Signature for calli instruction
1176 /// </summary>
1177 public class CalliSig : Signature {
1179 private static readonly byte Sentinel = 0x41;
1180 CallConv callConv;
1181 Type returnType;
1182 Type[] parameters, optParams;
1183 uint numPars = 0, numOptPars = 0;
1185 /// <summary>
1186 /// Create a signature for a calli instruction
1187 /// </summary>
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;
1194 callConv = cconv;
1195 returnType = retType;
1196 parameters = pars;
1197 if (pars != null) numPars = (uint)pars.Length;
1200 /// <summary>
1201 /// Add the optional parameters to a vararg method
1202 /// This method sets the vararg calling convention
1203 /// </summary>
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;
1212 /// <summary>
1213 /// Add extra calling conventions to this callsite signature
1214 /// </summary>
1215 /// <param name="cconv"></param>
1216 public void AddCallingConv(CallConv cconv)
1218 callConv |= cconv;
1221 internal sealed override void BuildTables(MetaData md)
1223 if (done) return;
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);
1238 done = true;
1243 /**************************************************************************/
1244 /// <summary>
1245 /// Descriptor for a local of a method
1246 /// </summary>
1247 public class Local {
1249 private static readonly byte Pinned = 0x45;
1250 string name;
1251 Type type;
1252 bool pinned = false, byref = false;
1254 /// <summary>
1255 /// Create a new local variable
1256 /// </summary>
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)
1261 name = lName;
1262 type = lType;
1265 /// <summary>
1266 /// Create a new local variable that is byref and/or pinned
1267 /// </summary>
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)
1274 name = lName;
1275 type = lType;
1276 byref = byRef;
1277 pinned = isPinned;
1280 internal void TypeSig(MemoryStream str)
1282 if (pinned) str.WriteByte(Pinned);
1283 type.TypeSig(str);
1288 /**************************************************************************/
1289 /// <summary>
1290 /// A label in the IL
1291 /// </summary>
1292 public class CILLabel {
1294 CILInstruction branch;
1295 CILInstruction[] multipleBranches;
1296 int tide = 0;
1297 CILInstruction labInstr;
1298 uint offset = 0;
1299 bool absolute;
1302 public CILLabel (uint offset, bool absolute)
1304 this.offset = offset;
1305 this.absolute = absolute;
1308 public CILLabel (uint offset) : this (offset, false)
1313 internal CILLabel()
1317 internal void AddBranch(CILInstruction instr)
1319 if (branch == null) {
1320 branch = instr;
1321 return;
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)
1337 labInstr = lInstr;
1340 internal uint GetLabelOffset()
1342 if (absolute) return offset;
1343 if (labInstr == null) return 0;
1344 return labInstr.offset + offset;