Merge pull request #2996 from UCIS/patch-7
[mono.git] / mcs / class / PEAPI / Code.cs
1 using System.IO;
2 using System.Collections;
3
4 namespace PEAPI {
5
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;
19
20                 internal virtual bool Check(MetaData md) 
21                 {
22                         return false;
23                 }
24
25                 internal virtual void Write(FileImage output) { }
26
27         }
28
29         internal class CILByte : CILInstruction {
30                 byte byteVal;
31
32                 internal CILByte(byte bVal) 
33                 {
34                         byteVal = bVal;
35                         size = 1;
36                 }
37
38                 internal override void Write(FileImage output) 
39                 {
40                         output.Write(byteVal);
41                 }
42
43         }
44
45         internal class Instr : CILInstruction {
46                 protected int instr;
47
48                 internal Instr(int inst) 
49                 {
50                         if (inst >= longInstrStart) {
51                                 instr = inst - longInstrStart;
52                                 twoByteInstr = true;
53                                 size = 2;
54                         } else {
55                                 instr = inst;
56                                 size = 1;
57                         }
58                 }
59
60                 internal override void Write(FileImage output) 
61                 {
62                         //Console.WriteLine("Writing instruction " + instr + " with size " + size);
63                         if (twoByteInstr) output.Write(leadByte);
64                         output.Write((byte)instr);
65                 }
66
67         }
68
69         internal class IntInstr : Instr {
70                 int val;
71                 bool byteNum;
72
73                 internal IntInstr(int inst, int num, bool byteSize) : base(inst) 
74                 {
75                         val = num;
76                         byteNum = byteSize;
77                         if (byteNum) size++;
78                         else size += 4;
79                 }
80
81                 internal sealed override void Write(FileImage output) 
82                 {
83                         base.Write(output);
84                         if (byteNum) 
85                                 output.Write((sbyte)val);
86                         else 
87                                 output.Write(val); 
88                 }
89
90         }
91
92         internal class UIntInstr : Instr {
93                 int val;
94                 bool byteNum;
95
96                 internal UIntInstr(int inst, int num, bool byteSize) : base(inst) 
97                 {
98                         val = num;
99                         byteNum = byteSize;
100                         if (byteNum) size++;
101                         else size += 2;
102                 }
103
104                 internal sealed override void Write(FileImage output) 
105                 {
106                         base.Write(output);
107                         if (byteNum)
108                                 output.Write((byte)val);
109                         else
110                                 output.Write((ushort)val); 
111                 }
112
113         }
114
115         internal class LongInstr : Instr {
116                 long val;
117
118                 internal LongInstr(int inst, long l) : base(inst) 
119                 {
120                         val = l;
121                         size += 8;
122                 }
123
124                 internal sealed override void Write(FileImage output) 
125                 {
126                         base.Write(output);
127                         output.Write(val);
128                 }
129
130         }
131
132         internal class FloatInstr : Instr {
133                 float fVal;
134
135                 internal FloatInstr(int inst, float f) : base(inst) 
136                 {
137                         fVal = f;
138                         size += 4;
139                 }
140
141                 internal sealed override void Write(FileImage output) 
142                 {
143                         base.Write(output);
144                         output.Write(fVal);
145                 }
146
147         }
148
149         internal class DoubleInstr : Instr {
150                 double val;
151
152                 internal DoubleInstr(int inst, double d) : base(inst) 
153                 {
154                         val = d;
155                         size += 8;
156                 }
157
158                 internal sealed override void Write(FileImage output) 
159                 {
160                         base.Write(output);
161                         output.Write(val);
162                 }
163
164         }
165
166         internal class StringInstr : Instr {
167                 string val;
168                 byte[] bval;                                                  
169                 uint strIndex;
170
171                 internal StringInstr(int inst, string str) : base(inst) 
172                 {
173                         val = str;  
174                         size += 4;
175                 }
176
177                 internal StringInstr (int inst, byte[] str) : base (inst) 
178                 {
179                         bval = str;
180                         size += 4;
181                 }
182
183                 internal sealed override bool Check(MetaData md) 
184                 {
185                         if (val != null)
186                                 strIndex = md.AddToUSHeap(val);
187                         else
188                                 strIndex = md.AddToUSHeap (bval);
189                         return false;
190                 }
191
192                 internal sealed override void Write(FileImage output) 
193                 {
194                         base.Write(output);
195                         output.Write(USHeapIndex  | strIndex);
196                 }
197
198         }
199
200         internal class LabelInstr : CILInstruction {
201                 CILLabel label;
202
203                 internal LabelInstr(CILLabel lab) 
204                 {
205                         label = lab;
206                         label.AddLabelInstr(this);
207                 }
208         }
209
210         internal class FieldInstr : Instr {
211                 Field field;
212
213                 internal FieldInstr(int inst, Field f) : base(inst) 
214                 {
215                         field = f;
216                         size += 4;
217                 }
218
219                 internal sealed override void Write(FileImage output) 
220                 {
221                         base.Write(output);
222                         output.Write(field.Token());
223                 }
224
225         }
226
227         internal class MethInstr : Instr {
228                 Method meth;
229
230                 internal MethInstr(int inst, Method m) : base(inst) 
231                 {
232                         meth = m;
233                         size += 4;
234                 }
235
236                 internal sealed override void Write(FileImage output) 
237                 {
238                         base.Write(output);
239                         output.Write(meth.Token());
240                 }
241
242         }
243
244         internal class SigInstr : Instr {
245                 CalliSig signature;
246
247                 internal SigInstr(int inst, CalliSig sig) : base(inst) 
248                 {
249                         signature = sig;
250                         size += 4;
251                 }
252
253                 internal sealed override bool Check(MetaData md) 
254                 {
255                         md.AddToTable(MDTable.StandAloneSig,signature);
256                         signature.BuildTables(md);
257                         return false;
258                 }
259
260                 internal sealed override void Write(FileImage output) 
261                 {
262                         base.Write(output);
263                         output.Write(signature.Token());
264                 }
265         }
266
267         internal class TypeInstr : Instr {
268                 MetaDataElement theType;
269
270                 internal TypeInstr(int inst, Type aType, MetaData md) : base(inst) 
271                 {
272                         theType = aType.GetTypeSpec(md);
273                         size += 4;
274                 }
275
276                 internal sealed override void Write(FileImage output) 
277                 {
278                         base.Write(output);
279                         output.Write(theType.Token());
280                 }
281
282         }
283
284         internal class BranchInstr : Instr {
285                 CILLabel dest;
286                 private bool shortVer = true;
287                 private int target = 0;
288
289                 internal BranchInstr(int inst, CILLabel dst) : base(inst) 
290                 {
291                         dest = dst;
292                         dest.AddBranch(this);
293                         size++;
294
295                         if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) {
296                                 shortVer = false;
297                                 size += 3;
298                         }
299                 }
300
301                 internal sealed override bool Check(MetaData md) 
302                 {
303                         target = (int)dest.GetLabelOffset() - (int)(offset + size);
304                         return false;
305                 }
306
307                 internal sealed override void Write(FileImage output) 
308                 {
309                         base.Write(output);
310                         if (shortVer)
311                                 output.Write((sbyte)target);
312                         else
313                                 output.Write(target);
314                 }
315
316         }
317
318         internal class SwitchInstr : Instr {
319                 CILLabel[] cases;
320                 uint numCases = 0;
321
322                 internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst) 
323                 {
324                         cases = dsts;
325                         if (cases != null) numCases = (uint)cases.Length;
326                         size += 4 + (numCases * 4);
327                         for (int i=0; i < numCases; i++) {
328                                 cases[i].AddBranch(this);
329                         }
330                 }
331
332                 internal sealed override void Write(FileImage output) 
333                 {
334                         base.Write(output);
335                         output.Write(numCases);
336                         for (int i=0; i < numCases; i++) {
337                                 int target = (int)cases[i].GetLabelOffset() - (int)(offset + size);
338                                 output.Write(target);
339                         }
340                 }
341
342         }
343
344         /**************************************************************************/  
345         /// <summary>
346         /// The IL instructions for a method
347         /// </summary>
348         public class CILInstructions  {
349                 private static readonly uint ExHeaderSize = 4;
350                 private static readonly uint FatExClauseSize = 24;
351                 private static readonly uint SmlExClauseSize = 12;
352                 private static readonly sbyte maxByteVal = 127;
353                 private static readonly sbyte minByteVal = -128;
354                 private static readonly byte maxUByteVal = 255;
355                 private static readonly int smallSize = 64;
356                 private static readonly ushort TinyFormat = 0x2;
357                 private static readonly ushort FatFormat = 0x3003;
358                 private static readonly ushort MoreSects = 0x8;
359                 private static readonly ushort InitLocals = 0x10;
360                 private static readonly uint FatSize = 12;
361                 private static readonly byte FatExceptTable = 0x41;
362                 private static readonly byte SmlExceptTable = 0x01; 
363
364                 private MetaData metaData;
365                 private ArrayList exceptions, blockStack;
366                 //private bool codeChecked = false;
367                 private static readonly int INITSIZE = 5;
368                 private CILInstruction[] buffer = new CILInstruction[INITSIZE];
369                 private int tide = 0;
370                 private uint offset = 0;
371                 private ushort headerFlags = 0;
372                 private short maxStack;
373                 private uint paddingNeeded = 0;
374                 private byte exceptHeader = 0;
375                 uint localSigIx = 0;
376                 uint codeSize = 0, exceptSize = 0;
377                 bool tinyFormat, fatExceptionFormat = false;
378
379                 public uint Offset {
380                         get { return offset; }
381                 }       
382
383                 internal CILInstructions(MetaData md) 
384                 {
385                         metaData = md;
386                 }
387
388                 private void AddToBuffer(CILInstruction inst) 
389                 {
390                         if (tide >= buffer.Length) {
391                                 CILInstruction[] tmp = buffer;
392                                 buffer = new CILInstruction[tmp.Length * 2];
393                                 for (int i=0; i < tide; i++) {
394                                         buffer[i] = tmp[i];
395                                 }
396                         }
397                         //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
398                         inst.offset = offset;
399                         offset += inst.size;
400                         buffer[tide++] = inst;
401                 }
402
403                 /// <summary>
404                 /// Add a simple IL instruction
405                 /// </summary>
406                 /// <param name="inst">the IL instruction</param>
407                 public void Inst(Op inst) 
408                 {
409                         AddToBuffer(new Instr((int)inst));
410                 }
411
412                 /// <summary>
413                 /// Add an IL instruction with an integer parameter
414                 /// </summary>
415                 /// <param name="inst">the IL instruction</param>
416                 /// <param name="val">the integer parameter value</param>
417                 public void IntInst(IntOp inst, int val) 
418                 {
419                         int instr = (int)inst;
420                         if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4)) 
421                                 AddToBuffer(new IntInstr(instr,val,(inst == IntOp.ldc_i4_s)));
422                         else
423                                 AddToBuffer(new UIntInstr(instr,val,((inst < IntOp.ldc_i4_s) ||
424                                                                 (inst == IntOp.unaligned))));
425                 }
426
427                 /// <summary>
428                 /// Add the load long instruction
429                 /// </summary>
430                 /// <param name="cVal">the long value</param>
431                 public void ldc_i8(long cVal) 
432                 {
433                         AddToBuffer(new LongInstr(0x21,cVal));
434                 }
435
436                 /// <summary>
437                 /// Add the load float32 instruction
438                 /// </summary>
439                 /// <param name="cVal">the float value</param>
440                 public void ldc_r4(float cVal) 
441                 {
442                         AddToBuffer(new FloatInstr(0x22,cVal));
443                 }
444
445                 /// <summary>
446                 /// Add the load float64 instruction
447                 /// </summary>
448                 /// <param name="cVal">the float value</param>
449                 public void ldc_r8(double cVal) 
450                 {
451                         AddToBuffer(new DoubleInstr(0x23,cVal));
452                 }
453
454                 /// <summary>
455                 /// Add the load string instruction
456                 /// </summary>
457                 /// <param name="str">the string value</param>
458                 public void ldstr(string str) 
459                 {
460                         AddToBuffer(new StringInstr(0x72,str));
461                 }
462
463                 /// <summary>
464                 /// Add the load string instruction
465                 /// </summary>
466                 public void ldstr (byte[] str) 
467                 {
468                         AddToBuffer (new StringInstr (0x72, str));
469                 }
470
471                 /// <summary>
472                 /// Add the calli instruction
473                 /// </summary>
474                 /// <param name="sig">the signature for the calli</param>
475                 public void calli(CalliSig sig) 
476                 {
477                         AddToBuffer(new SigInstr(0x29,sig));
478                 }
479
480                 /// <summary>
481                 /// Add a label to the CIL instructions
482                 /// </summary>
483                 /// <param name="lab">the label to be added</param>
484                 public void CodeLabel(CILLabel lab) 
485                 {
486                         AddToBuffer(new LabelInstr(lab));
487                 }
488
489                 /// <summary>
490                 /// Add an instruction with a field parameter
491                 /// </summary>
492                 /// <param name="inst">the CIL instruction</param>
493                 /// <param name="f">the field parameter</param>
494                 public void FieldInst(FieldOp inst, Field f) 
495                 {
496                         AddToBuffer(new FieldInstr((int)inst,f));
497                 }
498
499                 /// <summary>
500                 /// Add an instruction with a method parameter
501                 /// </summary>
502                 /// <param name="inst">the CIL instruction</param>
503                 /// <param name="m">the method parameter</param>
504                 public void MethInst(MethodOp inst, Method m) 
505                 {
506                         AddToBuffer(new MethInstr((int)inst,m));
507                 }
508
509                 /// <summary>
510                 /// Add an instruction with a type parameter
511                 /// </summary>
512                 /// <param name="inst">the CIL instruction</param>
513                 /// <param name="t">the type argument for the CIL instruction</param>
514                 public void TypeInst(TypeOp inst, Type aType) 
515                 {
516                         AddToBuffer(new TypeInstr((int)inst,aType,metaData));
517                 }
518
519                 /// <summary>
520                 /// Add a branch instruction
521                 /// </summary>
522                 /// <param name="inst">the branch instruction</param>
523                 /// <param name="lab">the label that is the target of the branch</param>
524                 public void Branch(BranchOp inst,  CILLabel lab) 
525                 {
526                         AddToBuffer(new BranchInstr((int)inst,lab));
527                 }
528
529                 /// <summary>
530                 /// Add a switch instruction
531                 /// </summary>
532                 /// <param name="labs">the target labels for the switch</param>
533                 public void Switch(CILLabel[] labs) 
534                 {
535                         AddToBuffer(new SwitchInstr(0x45,labs));
536                 }
537
538                 /// <summary>
539                 /// Add a byte to the CIL instructions (.emitbyte)
540                 /// </summary>
541                 /// <param name="bVal"></param>
542                 public void emitbyte(byte bVal) 
543                 {
544                         AddToBuffer(new CILByte(bVal));
545                 }
546
547                 /// <summary>
548                 /// Add an instruction which puts an integer on TOS.  This method
549                 /// selects the correct instruction based on the value of the integer.
550                 /// </summary>
551                 /// <param name="i">the integer value</param>
552                 public void PushInt(int i) 
553                 {
554                         if (i == -1) {
555                                 AddToBuffer(new Instr((int)Op.ldc_i4_m1));
556                         } else if ((i >= 0) && (i <= 8)) {
557                                 Op op = (Op)(Op.ldc_i4_0 + i);
558                                 AddToBuffer(new Instr((int)op));
559                         } else if ((i >= minByteVal) && (i <= maxByteVal)) {
560                                 AddToBuffer(new IntInstr((int)IntOp.ldc_i4_s,i,true));
561                         } else {
562                                 AddToBuffer(new IntInstr((int)IntOp.ldc_i4,i,false)); 
563                         }
564                 }
565
566                 /// <summary>
567                 /// Add the instruction to load a long on TOS
568                 /// </summary>
569                 /// <param name="l">the long value</param>
570                 public void PushLong(long l) 
571                 {
572                         AddToBuffer(new LongInstr(0x21,l));
573                 }
574
575                 /// <summary>
576                 /// Add an instruction to push the boolean value true on TOS
577                 /// </summary>
578                 public void PushTrue() 
579                 {
580                         AddToBuffer(new Instr((int)Op.ldc_i4_1));
581                 }
582
583                 /// <summary>
584                 ///  Add an instruction to push the boolean value false on TOS
585                 /// </summary>
586                 public void PushFalse() 
587                 {
588                         AddToBuffer(new Instr((int)Op.ldc_i4_0));
589                 }
590
591                 /// <summary>
592                 /// Add the instruction to load an argument on TOS.  This method
593                 /// selects the correct instruction based on the value of argNo
594                 /// </summary>
595                 /// <param name="argNo">the number of the argument</param>
596                 public void LoadArg(int argNo) 
597                 {
598                         if (argNo < 4) {
599                                 int op = (int)Op.ldarg_0 + argNo;
600                                 AddToBuffer(new Instr(op));
601                         } else if (argNo <= maxUByteVal) {
602                                 AddToBuffer(new UIntInstr((int)IntOp.ldarg,argNo,true));
603                         } else {
604                                 AddToBuffer(new UIntInstr(0x09,argNo,false)); 
605                         }
606                 }
607
608                 /// <summary>
609                 /// Add the instruction to load the address of an argument on TOS.
610                 /// This method selects the correct instruction based on the value
611                 /// of argNo.
612                 /// </summary>
613                 /// <param name="argNo">the number of the argument</param>
614                 public void LoadArgAdr(int argNo) 
615                 {
616                         if (argNo <= maxUByteVal) {
617                                 AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true));
618                         } else {
619                                 AddToBuffer(new UIntInstr(0x0A,argNo,false)); 
620                         }
621                 }
622
623                 /// <summary>
624                 /// Add the instruction to load a local on TOS.  This method selects
625                 /// the correct instruction based on the value of locNo.
626                 /// </summary>
627                 /// <param name="locNo">the number of the local to load</param>
628                 public void LoadLocal(int locNo) 
629                 {
630                         if (locNo < 4) {
631                                 int op = (int)Op.ldloc_0 + locNo;
632                                 AddToBuffer(new Instr(op));
633                         } else if (locNo <= maxUByteVal) {
634                                 AddToBuffer(new UIntInstr((int)IntOp.ldloc,locNo,true));
635                         } else {
636                                 AddToBuffer(new UIntInstr(0x0C,locNo,false)); 
637                         }
638                 }
639
640                 /// <summary>
641                 /// Add the instruction to load the address of a local on TOS.
642                 /// This method selects the correct instruction based on the 
643                 /// value of locNo.
644                 /// </summary>
645                 /// <param name="locNo">the number of the local</param>
646                 public void LoadLocalAdr(int locNo) 
647                 {
648                         if (locNo <= maxUByteVal) {
649                                 AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true));
650                         } else {
651                                 AddToBuffer(new UIntInstr(0x0D,locNo,false)); 
652                         }
653                 }
654
655                 /// <summary>
656                 /// Add the instruction to store to an argument.  This method
657                 /// selects the correct instruction based on the value of argNo.
658                 /// </summary>
659                 /// <param name="argNo">the argument to be stored to</param>
660                 public void StoreArg(int argNo) 
661                 {
662                         if (argNo <= maxUByteVal) {
663                                 AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true));
664                         } else {
665                                 AddToBuffer(new UIntInstr(0x0B,argNo,false)); 
666                         }
667                 }
668
669                 /// <summary>
670                 /// Add the instruction to store to a local.  This method selects
671                 /// the correct instruction based on the value of locNo.
672                 /// </summary>
673                 /// <param name="locNo">the local to be stored to</param>
674                 public void StoreLocal(int locNo) 
675                 {
676                         if (locNo < 4) {
677                                 int op = (int)Op.stloc_0 + locNo;
678                                 AddToBuffer(new Instr(op));
679                         } else if (locNo <= maxUByteVal) {
680                                 AddToBuffer(new UIntInstr((int)IntOp.stloc,locNo,true));
681                         } else {
682                                 AddToBuffer(new UIntInstr(0x0E,locNo,false)); 
683                         }
684                 }
685
686                 /// <summary>
687                 /// Create a new CIL label.  To place the label in the CIL instruction
688                 /// stream use CodeLabel.
689                 /// </summary>
690                 /// <returns>a new CIL label</returns>
691                 public CILLabel NewLabel() 
692                 {
693                         return new CILLabel();
694                 }
695
696                 public void AddTryBlock(TryBlock tryBlock) 
697                 {
698                         if (exceptions == null) 
699                                 exceptions = new ArrayList();
700                         else if (exceptions.Contains(tryBlock)) return;
701                         exceptions.Add(tryBlock);
702                         tryBlock.ResolveCatchBlocks (metaData);
703                 }
704
705                 /// <summary>
706                 /// Create a new label at this position in the code buffer
707                 /// </summary>
708                 /// <returns>the label at the current position</returns>
709                 public CILLabel NewCodedLabel() 
710                 {
711                         CILLabel lab = new CILLabel();
712                         AddToBuffer(new LabelInstr(lab));
713                         return lab;
714                 }
715
716                 /// <summary>
717                 /// Mark this position as the start of a new block
718                 /// (try, catch, filter, finally or fault)
719                 /// </summary>
720                 public void StartBlock() 
721                 {
722                         if (blockStack == null) blockStack = new ArrayList();
723                         blockStack.Insert(0,NewCodedLabel());
724                 }
725
726                 /// <summary>
727                 /// Mark this position as the end of the last started block and
728                 /// make it a try block.  This try block is added to the current 
729                 /// instructions (ie do not need to call AddTryBlock)
730                 /// </summary>
731                 /// <returns>The try block just ended</returns>
732                 public TryBlock EndTryBlock() 
733                 {
734                         TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
735                         blockStack.RemoveAt(0);
736                         AddTryBlock(tBlock);
737                         return tBlock;
738                 }
739
740                 /// <summary>
741                 /// Mark this position as the end of the last started block and
742                 /// make it a catch block.  This catch block is associated with the
743                 /// specified try block.
744                 /// </summary>
745                 /// <param name="exceptType">the exception type to be caught</param>
746                 /// <param name="tryBlock">the try block associated with this catch block</param>
747                 public void EndCatchBlock(Class exceptType, TryBlock tryBlock) 
748                 {
749                         Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
750                                         NewCodedLabel());
751                         tryBlock.AddHandler(catchBlock);
752                 }
753
754                 /// <summary>
755                 /// Mark this position as the end of the last started block and
756                 /// make it a filter block.  This filter block is associated with the
757                 /// specified try block.
758                 /// </summary>
759                 /// <param name="filterLab">the label where the filter code is</param>
760                 /// <param name="tryBlock">the try block associated with this filter block</param>
761                 public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) 
762                 {
763                         Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
764                         tryBlock.AddHandler(filBlock);
765                 }
766
767                 /// <summary>
768                 /// Mark this position as the end of the last started block and
769                 /// make it a finally block.  This finally block is associated with the
770                 /// specified try block.
771                 /// </summary>
772                 /// <param name="tryBlock">the try block associated with this finally block</param>
773                 public void EndFinallyBlock(TryBlock tryBlock) 
774                 {
775                         Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
776                         tryBlock.AddHandler(finBlock);
777                 }
778
779                 /// <summary>
780                 /// Mark this position as the end of the last started block and
781                 /// make it a fault block.  This fault block is associated with the
782                 /// specified try block.
783                 /// </summary>
784                 /// <param name="tryBlock">the try block associated with this fault block</param>
785                 public void EndFaultBlock(TryBlock tryBlock) 
786                 {
787                         Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel());
788                         tryBlock.AddHandler(fBlock);
789                 }
790
791                 internal uint GetCodeSize() 
792                 {
793                         return codeSize + paddingNeeded + exceptSize;
794                 }
795
796                 internal void CheckCode(uint locSigIx, bool initLocals, int maxStack) 
797                 {
798                         if (tide == 0) return;
799                         bool changed = true;
800                         while (changed) {
801                                 changed = false;
802                                 for (int i=0; i < tide; i++) {
803                                         changed = buffer[i].Check(metaData) || changed;
804                                 }
805                                 if (changed) {
806                                         for (int i=1; i < tide; i++) {
807                                                 buffer[i].offset = buffer[i-1].offset + buffer[i-1].size;
808                                         }
809                                         offset = buffer[tide-1].offset + buffer[tide-1].size;
810                                 }
811                         }
812                         codeSize = offset;
813                         // Console.WriteLine("codeSize before header added = " + codeSize);
814                         if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
815                                 // can use tiny header
816                                 //Console.WriteLine("Tiny Header");
817                                 tinyFormat = true;
818                                 headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
819                                 codeSize++;
820                                 if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
821                         } else {
822                                 //Console.WriteLine("Fat Header");
823                                 tinyFormat = false;
824                                 localSigIx = locSigIx;
825                                 this.maxStack = (short)maxStack;
826                                 headerFlags = FatFormat;
827                                 if (exceptions != null) {
828                                         // Console.WriteLine("Got exceptions");
829                                         headerFlags |= MoreSects;
830                                         uint numExceptClauses = 0;
831                                         for (int i=0; i < exceptions.Count; i++) {
832                                                 TryBlock tryBlock = (TryBlock)exceptions[i];
833                                                 tryBlock.SetSize();
834                                                 numExceptClauses += (uint)tryBlock.NumHandlers();
835                                                 if (tryBlock.isFat()) fatExceptionFormat = true;
836                                         }
837
838                                         uint data_size = ExHeaderSize + numExceptClauses *
839                                                 (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
840
841                                         if (data_size > 255)
842                                                 fatExceptionFormat = true;
843
844                                         // Console.WriteLine("numexceptclauses = " + numExceptClauses);
845                                         if (fatExceptionFormat) {
846                                                 // Console.WriteLine("Fat exception format");
847                                                 exceptHeader = FatExceptTable;
848                                                 exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
849                                         } else {
850                                                 // Console.WriteLine("Tiny exception format");
851                                                 exceptHeader = SmlExceptTable;
852                                                 exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
853                                         }
854                                         // Console.WriteLine("exceptSize = " + exceptSize);
855                                 }
856                                 if (initLocals) headerFlags |= InitLocals;
857                                 if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
858                                 codeSize += FatSize;
859                         }
860                         // Console.WriteLine("codeSize = " + codeSize + "  headerFlags = " + 
861                         //                   Hex.Short(headerFlags));
862                 }
863
864                 internal void Write(FileImage output) 
865                 {
866                         // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
867                         if (tinyFormat) {
868                                 // Console.WriteLine("Writing tiny code");
869                                 output.Write((byte)headerFlags);
870                         } else {
871                                 // Console.WriteLine("Writing fat code");
872                                 output.Write(headerFlags);
873                                 output.Write((ushort)maxStack);
874                                 output.Write(offset);
875                                 output.Write(localSigIx);
876                         }
877                         // Console.WriteLine(Hex.Int(tide) + " CIL instructions");
878                         // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
879                         for (int i=0; i < tide; i++) {
880                                 buffer[i].Write(output);
881                         }
882                         // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
883                         for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); }
884                         if (exceptions != null) {
885                                 // Console.WriteLine("Writing exceptions");
886                                 // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
887                                 output.Write(exceptHeader);
888                                 output.Write3Bytes((uint)exceptSize);
889                                 for (int i=0; i < exceptions.Count; i++) {
890                                         TryBlock tryBlock = (TryBlock)exceptions[i];
891                                         tryBlock.Write(output,fatExceptionFormat);
892                                 }
893                         }
894                 }
895
896         }
897
898         /**************************************************************************/  
899         public abstract class CodeBlock {
900
901                 private static readonly int maxCodeSize = 255;
902                 protected CILLabel start, end;
903                 protected bool small = true;
904
905                 public CodeBlock(CILLabel start, CILLabel end) 
906                 {
907                         this.start = start;
908                         this.end = end;
909                 }
910
911                 internal virtual bool isFat() 
912                 {
913                         // Console.WriteLine("block start = " + start.GetLabelOffset() +
914                         //                  "  block end = " + end.GetLabelOffset());
915                         return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
916                 }
917
918                 internal virtual void Write(FileImage output, bool fatFormat) 
919                 {
920                         if (fatFormat) output.Write(start.GetLabelOffset());
921                         else output.Write((short)start.GetLabelOffset());
922                         uint len = end.GetLabelOffset() - start.GetLabelOffset();
923                         if (fatFormat) output.Write(len);
924                         else output.Write((byte)len);
925                 }
926
927         }
928
929         /// <summary>
930         /// The descriptor for a guarded block (.try)
931         /// </summary>
932         public class TryBlock : CodeBlock {
933                 protected bool fatFormat = false;
934                 protected int flags = 0;
935                 ArrayList handlers = new ArrayList();
936
937                 /// <summary>
938                 /// Create a new try block
939                 /// </summary>
940                 /// <param name="start">start label for the try block</param>
941                 /// <param name="end">end label for the try block</param>
942                 public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
943
944                 /// <summary>
945                 /// Add a handler to this try block
946                 /// </summary>
947                 /// <param name="handler">a handler to be added to the try block</param>
948                 public void AddHandler(HandlerBlock handler) 
949                 {
950                         flags = handler.GetFlag();
951                         handlers.Add(handler);
952                 }
953
954                 internal void SetSize() 
955                 {
956                         fatFormat = base.isFat();
957                         if (fatFormat) return;
958                         for (int i=0; i < handlers.Count; i++) {
959                                 HandlerBlock handler = (HandlerBlock)handlers[i];
960                                 if (handler.isFat()) {
961                                         fatFormat = true;
962                                         return;
963                                 }
964                         }
965                 }
966
967                 internal int NumHandlers() 
968                 {
969                         return handlers.Count;
970                 }
971
972                 internal override bool isFat() 
973                 {
974                         return fatFormat;
975                 }
976
977                 //Hackish
978                 internal void ResolveCatchBlocks (MetaData md)
979                 {
980                         for (int i=0; i < handlers.Count; i++) {
981                                 Catch c = handlers [i] as Catch;
982                                 if (c != null)
983                                         c.ResolveType (md);
984                         }
985                 }
986
987                 internal override void Write(FileImage output, bool fatFormat) 
988                 {
989                         // Console.WriteLine("writing exception details");
990                         for (int i=0; i < handlers.Count; i++) {
991                                 // Console.WriteLine("Except block " + i);
992                                 HandlerBlock handler = (HandlerBlock)handlers[i];
993                                 if (fatFormat) output.Write(flags);
994                                 else output.Write((short)flags);
995                                 // Console.WriteLine("flags = " + Hex.Short(flags));
996                                 base.Write(output,fatFormat);
997                                 handler.Write(output,fatFormat);
998                         }
999                 }
1000         }
1001
1002         public abstract class HandlerBlock : CodeBlock  {
1003
1004                 protected static readonly short ExceptionFlag = 0;
1005                 protected static readonly short FilterFlag = 0x01;
1006                 protected static readonly short FinallyFlag = 0x02;
1007                 protected static readonly short FaultFlag = 0x04;
1008
1009                 public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { }
1010
1011                 internal virtual short GetFlag() { return ExceptionFlag; }
1012
1013                 internal override void Write(FileImage output, bool fatFormat) 
1014                 {
1015                         base.Write(output,fatFormat);
1016                 }
1017
1018         }
1019
1020         /// <summary>
1021         /// The descriptor for a catch clause (.catch)
1022         /// </summary>
1023         public class Catch : HandlerBlock  {
1024
1025                 MetaDataElement exceptType;
1026
1027                 /// <summary>
1028                 /// Create a new catch clause
1029                 /// </summary>
1030                 /// <param name="except">the exception to be caught</param>
1031                 /// <param name="handlerStart">start of the handler code</param>
1032                 /// <param name="handlerEnd">end of the handler code</param>
1033                 public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)
1034                         : base(handlerStart, handlerEnd)
1035                 {
1036                         exceptType = except;
1037                 }
1038
1039                 public Catch(Type except, CILLabel handlerStart, CILLabel handlerEnd)
1040                         : base(handlerStart,handlerEnd) 
1041                 {
1042                         exceptType = except;
1043                 }
1044
1045                 internal void ResolveType (MetaData md)
1046                 {
1047                        exceptType = ((Type) exceptType).GetTypeSpec (md);
1048                 }
1049
1050                 internal override void Write(FileImage output, bool fatFormat) 
1051                 {
1052                         base.Write(output,fatFormat);
1053                         output.Write(exceptType.Token());
1054                 }
1055         }
1056
1057         /// <summary>
1058         /// The descriptor for a filter clause (.filter)
1059         /// </summary>
1060         public class Filter : HandlerBlock  {
1061
1062                 CILLabel filterLabel;
1063
1064                 /// <summary>
1065                 /// Create a new filter clause
1066                 /// </summary>
1067                 /// <param name="filterLabel">the label where the filter code starts</param>
1068                 /// <param name="handlerStart">the start of the handler code</param>
1069                 /// <param name="handlerEnd">the end of the handler code</param>
1070                 public Filter(CILLabel filterLabel, CILLabel handlerStart, 
1071                                 CILLabel handlerEnd) : base(handlerStart,handlerEnd) 
1072                                 {
1073                         this.filterLabel = filterLabel;
1074                 }
1075
1076                 internal override short GetFlag() 
1077                 {
1078                         return FilterFlag; 
1079                 }
1080
1081                 internal override void Write(FileImage output, bool fatFormat) 
1082                 {
1083                         base.Write(output,fatFormat);
1084                         output.Write(filterLabel.GetLabelOffset());
1085                 }
1086
1087         }
1088
1089         /// <summary>
1090         /// Descriptor for a finally block (.finally)
1091         /// </summary>
1092         public class Finally : HandlerBlock  {
1093
1094                 /// <summary>
1095                 /// Create a new finally clause
1096                 /// </summary>
1097                 /// <param name="finallyStart">start of finally code</param>
1098                 /// <param name="finallyEnd">end of finally code</param>
1099                 public Finally(CILLabel finallyStart, CILLabel finallyEnd)
1100                         : base(finallyStart,finallyEnd) { }
1101
1102                 internal override short GetFlag() 
1103                 {
1104                         return FinallyFlag; 
1105                 }
1106
1107                 internal override void Write(FileImage output, bool fatFormat) 
1108                 {
1109                         base.Write(output,fatFormat);
1110                         output.Write((int)0);
1111                 }
1112
1113         }
1114
1115         /// <summary>
1116         /// Descriptor for a fault block (.fault)
1117         /// </summary>
1118         public class Fault : HandlerBlock  {
1119
1120                 /// <summary>
1121                 /// Create a new fault clause
1122                 /// </summary>
1123                 /// <param name="faultStart">start of the fault code</param>
1124                 /// <param name="faultEnd">end of the fault code</param>
1125                 public Fault(CILLabel faultStart, CILLabel faultEnd)
1126                         : base(faultStart,faultEnd) { }
1127
1128                 internal override short GetFlag() 
1129                 {
1130                         return FaultFlag; 
1131                 }
1132
1133                 internal override void Write(FileImage output, bool fatFormat) 
1134                 {
1135                         base.Write(output,fatFormat);
1136                         output.Write((int)0);
1137
1138                 }
1139         }
1140
1141         /**************************************************************************/  
1142         /// <summary>
1143         /// Descriptor for the locals for a method
1144         /// </summary>
1145         public class LocalSig : Signature {
1146
1147                 private static readonly byte LocalSigByte = 0x7;
1148                 Local[] locals;
1149
1150                 public LocalSig(Local[] locals)         
1151                 {
1152                         this.locals = locals;
1153                         tabIx = MDTable.StandAloneSig;
1154                 }
1155
1156                 internal sealed override void BuildTables(MetaData md) 
1157                 {
1158                         if (done) return;
1159                         MemoryStream sig = new MemoryStream();
1160                         sig.WriteByte(LocalSigByte);
1161                         MetaData.CompressNum((uint)locals.Length,sig);
1162                         for (int i=0; i < locals.Length; i++) {
1163                                 ((Local)locals[i]).TypeSig(sig);
1164                         }
1165                         sigIx = md.AddToBlobHeap(sig.ToArray());
1166                         done = true;
1167                 }
1168
1169         }
1170
1171         /**************************************************************************/  
1172         /// <summary>
1173         /// Signature for calli instruction
1174         /// </summary>
1175         public class CalliSig : Signature {
1176
1177                 private static readonly byte Sentinel = 0x41;
1178                 CallConv callConv;
1179                 Type returnType;
1180                 Type[] parameters, optParams;
1181                 uint numPars = 0, numOptPars = 0;
1182
1183                 /// <summary>
1184                 /// Create a signature for a calli instruction
1185                 /// </summary>
1186                 /// <param name="cconv">calling conventions</param>
1187                 /// <param name="retType">return type</param>
1188                 /// <param name="pars">parameter types</param>
1189                 public CalliSig(CallConv cconv, Type retType, Type[] pars) 
1190                 {
1191                         tabIx = MDTable.StandAloneSig;
1192                         callConv = cconv;
1193                         returnType = retType;
1194                         parameters = pars;
1195                         if (pars != null) numPars = (uint)pars.Length;
1196                 }
1197
1198                 /// <summary>
1199                 /// Add the optional parameters to a vararg method
1200                 /// This method sets the vararg calling convention
1201                 /// </summary>
1202                 /// <param name="optPars">the optional pars for the vararg call</param>
1203                 public void AddVarArgs(Type[] optPars) 
1204                 {
1205                         optParams = optPars;
1206                         if (optPars != null) numOptPars = (uint)optPars.Length;
1207                         callConv |= CallConv.Vararg;
1208                 }
1209
1210                 /// <summary>
1211                 /// Add extra calling conventions to this callsite signature
1212                 /// </summary>
1213                 /// <param name="cconv"></param>
1214                 public void AddCallingConv(CallConv cconv) 
1215                 {
1216                         callConv |= cconv;
1217                 }
1218
1219                 internal sealed override void BuildTables(MetaData md) 
1220                 {
1221                         if (done) return;
1222                         MemoryStream sig = new MemoryStream();
1223                         sig.WriteByte((byte)callConv);
1224                         MetaData.CompressNum(numPars+numOptPars,sig);
1225                         returnType.TypeSig(sig);
1226                         for (int i=0; i < numPars; i++) {
1227                                 parameters[i].TypeSig(sig);
1228                         }
1229                         sigIx = md.AddToBlobHeap(sig.ToArray());
1230                         if (numOptPars > 0) {
1231                                 sig.WriteByte(Sentinel);
1232                                 for (int i=0; i < numOptPars; i++) {
1233                                         optParams[i].TypeSig(sig);
1234                                 }
1235                         }
1236                         done = true;
1237                 }
1238
1239         }
1240
1241         /**************************************************************************/  
1242         /// <summary>
1243         /// Descriptor for a local of a method
1244         /// </summary>
1245         public class Local {
1246
1247                 private static readonly byte Pinned = 0x45;
1248                 string name;
1249                 Type type;
1250                 bool pinned = false, byref = false;
1251
1252                 /// <summary>
1253                 /// Create a new local variable 
1254                 /// </summary>
1255                 /// <param name="lName">name of the local variable</param>
1256                 /// <param name="lType">type of the local variable</param>
1257                 public Local(string lName, Type lType) 
1258                 {
1259                         name = lName;
1260                         type = lType;
1261                 }
1262
1263                 /// <summary>
1264                 /// Create a new local variable that is byref and/or pinned
1265                 /// </summary>
1266                 /// <param name="lName">local name</param>
1267                 /// <param name="lType">local type</param>
1268                 /// <param name="byRef">is byref</param>
1269                 /// <param name="isPinned">has pinned attribute</param>
1270                 public Local(string lName, Type lType, bool byRef, bool isPinned)
1271                 {
1272                         name = lName;
1273                         type = lType;
1274                         byref = byRef;
1275                         pinned = isPinned;
1276                 }
1277
1278                 internal void TypeSig(MemoryStream str) 
1279                 {
1280                         if (pinned) str.WriteByte(Pinned);
1281                         type.TypeSig(str);
1282                 }
1283
1284         }
1285
1286         /**************************************************************************/  
1287         /// <summary>
1288         /// A label in the IL
1289         /// </summary>
1290         public class CILLabel {
1291
1292                 CILInstruction branch;
1293                 CILInstruction[] multipleBranches;
1294                 int tide = 0;
1295                 CILInstruction labInstr;
1296                 uint offset = 0;
1297                 bool absolute;
1298
1299
1300                 public CILLabel (uint offset, bool absolute) 
1301                 {
1302                         this.offset = offset;
1303                         this.absolute = absolute;
1304                 }
1305
1306                 public CILLabel (uint offset) : this (offset, false)
1307                 {
1308                 }
1309
1310
1311                 internal CILLabel() 
1312                 {
1313                 }
1314
1315                 internal void AddBranch(CILInstruction instr) 
1316                 {
1317                         if (branch == null) {
1318                                 branch = instr;
1319                                 return;
1320                         }
1321                         if (multipleBranches == null) {
1322                                 multipleBranches = new CILInstruction[2];
1323                         } else if (tide >= multipleBranches.Length) {
1324                                 CILInstruction[] tmp = multipleBranches;
1325                                 multipleBranches = new CILInstruction[tmp.Length*2];
1326                                 for (int i=0; i < tide; i++) {
1327                                         multipleBranches[i] = tmp[i];
1328                                 }
1329                         }
1330                         multipleBranches[tide++] = instr;
1331                 }
1332
1333                 internal void AddLabelInstr(LabelInstr lInstr) 
1334                 {
1335                         labInstr = lInstr;
1336                 }
1337
1338                 internal uint GetLabelOffset() 
1339                 {
1340                         if (absolute) return offset;
1341                         if (labInstr == null) return 0;
1342                         return labInstr.offset + offset;
1343                 }
1344
1345         }
1346
1347
1348 }
1349
1350