merged Sys.Web.Services 2.0 support in my branch:
[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 static readonly byte longInstrOffset = 13;
288                 private int target = 0;
289
290                 internal BranchInstr(int inst, CILLabel dst) : base(inst) 
291                 {
292                         dest = dst;
293                         dest.AddBranch(this);
294                         size++;
295
296                         if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) {
297                                 shortVer = false;
298                                 size += 3;
299                         }
300                 }
301
302                 internal sealed override bool Check(MetaData md) 
303                 {
304                         target = (int)dest.GetLabelOffset() - (int)(offset + size);
305                         return false;
306                 }
307
308                 internal sealed override void Write(FileImage output) 
309                 {
310                         base.Write(output);
311                         if (shortVer)
312                                 output.Write((sbyte)target);
313                         else
314                                 output.Write(target);
315                 }
316
317         }
318
319         internal class SwitchInstr : Instr {
320                 CILLabel[] cases;
321                 uint numCases = 0;
322
323                 internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst) 
324                 {
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);
330                         }
331                 }
332
333                 internal sealed override void Write(FileImage output) 
334                 {
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);
340                         }
341                 }
342
343         }
344
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; 
365
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;
380
381                 public uint Offset {
382                         get { return offset; }
383                 }       
384
385                 internal CILInstructions(MetaData md) 
386                 {
387                         metaData = md;
388                 }
389
390                 private void AddToBuffer(CILInstruction inst) 
391                 {
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];
397                                 }
398                         }
399                         //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
400                         inst.offset = offset;
401                         offset += inst.size;
402                         buffer[tide++] = inst;
403                 }
404
405                 /// <summary>
406                 /// Add a simple IL instruction
407                 /// </summary>
408                 /// <param name="inst">the IL instruction</param>
409                 public void Inst(Op inst) 
410                 {
411                         AddToBuffer(new Instr((int)inst));
412                 }
413
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) 
420                 {
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))));
427                 }
428
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) 
434                 {
435                         AddToBuffer(new LongInstr(0x21,cVal));
436                 }
437
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) 
443                 {
444                         AddToBuffer(new FloatInstr(0x22,cVal));
445                 }
446
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) 
452                 {
453                         AddToBuffer(new DoubleInstr(0x23,cVal));
454                 }
455
456                 /// <summary>
457                 /// Add the load string instruction
458                 /// </summary>
459                 /// <param name="str">the string value</param>
460                 public void ldstr(string str) 
461                 {
462                         AddToBuffer(new StringInstr(0x72,str));
463                 }
464
465                 /// <summary>
466                 /// Add the load string instruction
467                 /// </summary>
468                 public void ldstr (byte[] str) 
469                 {
470                         AddToBuffer (new StringInstr (0x72, str));
471                 }
472
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) 
478                 {
479                         AddToBuffer(new SigInstr(0x29,sig));
480                 }
481
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) 
487                 {
488                         AddToBuffer(new LabelInstr(lab));
489                 }
490
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) 
497                 {
498                         AddToBuffer(new FieldInstr((int)inst,f));
499                 }
500
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) 
507                 {
508                         AddToBuffer(new MethInstr((int)inst,m));
509                 }
510
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) 
517                 {
518                         AddToBuffer(new TypeInstr((int)inst,aType,metaData));
519                 }
520
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) 
527                 {
528                         AddToBuffer(new BranchInstr((int)inst,lab));
529                 }
530
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) 
536                 {
537                         AddToBuffer(new SwitchInstr(0x45,labs));
538                 }
539
540                 /// <summary>
541                 /// Add a byte to the CIL instructions (.emitbyte)
542                 /// </summary>
543                 /// <param name="bVal"></param>
544                 public void emitbyte(byte bVal) 
545                 {
546                         AddToBuffer(new CILByte(bVal));
547                 }
548
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) 
555                 {
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)); 
565                         }
566                 }
567
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) 
573                 {
574                         AddToBuffer(new LongInstr(0x21,l));
575                 }
576
577                 /// <summary>
578                 /// Add an instruction to push the boolean value true on TOS
579                 /// </summary>
580                 public void PushTrue() 
581                 {
582                         AddToBuffer(new Instr((int)Op.ldc_i4_1));
583                 }
584
585                 /// <summary>
586                 ///  Add an instruction to push the boolean value false on TOS
587                 /// </summary>
588                 public void PushFalse() 
589                 {
590                         AddToBuffer(new Instr((int)Op.ldc_i4_0));
591                 }
592
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) 
599                 {
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)); 
607                         }
608                 }
609
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) 
617                 {
618                         if (argNo <= maxUByteVal) {
619                                 AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true));
620                         } else {
621                                 AddToBuffer(new UIntInstr(0x0A,argNo,false)); 
622                         }
623                 }
624
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) 
631                 {
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)); 
639                         }
640                 }
641
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) 
649                 {
650                         if (locNo <= maxUByteVal) {
651                                 AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true));
652                         } else {
653                                 AddToBuffer(new UIntInstr(0x0D,locNo,false)); 
654                         }
655                 }
656
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) 
663                 {
664                         if (argNo <= maxUByteVal) {
665                                 AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true));
666                         } else {
667                                 AddToBuffer(new UIntInstr(0x0B,argNo,false)); 
668                         }
669                 }
670
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) 
677                 {
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)); 
685                         }
686                 }
687
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() 
694                 {
695                         return new CILLabel();
696                 }
697
698                 public void AddTryBlock(TryBlock tryBlock) 
699                 {
700                         if (exceptions == null) 
701                                 exceptions = new ArrayList();
702                         else if (exceptions.Contains(tryBlock)) return;
703                         exceptions.Add(tryBlock);
704                 }
705
706                 /// <summary>
707                 /// Create a new label at this position in the code buffer
708                 /// </summary>
709                 /// <returns>the label at the current position</returns>
710                 public CILLabel NewCodedLabel() 
711                 {
712                         CILLabel lab = new CILLabel();
713                         AddToBuffer(new LabelInstr(lab));
714                         return lab;
715                 }
716
717                 /// <summary>
718                 /// Mark this position as the start of a new block
719                 /// (try, catch, filter, finally or fault)
720                 /// </summary>
721                 public void StartBlock() 
722                 {
723                         if (blockStack == null) blockStack = new ArrayList();
724                         blockStack.Insert(0,NewCodedLabel());
725                 }
726
727                 /// <summary>
728                 /// Mark this position as the end of the last started block and
729                 /// make it a try block.  This try block is added to the current 
730                 /// instructions (ie do not need to call AddTryBlock)
731                 /// </summary>
732                 /// <returns>The try block just ended</returns>
733                 public TryBlock EndTryBlock() 
734                 {
735                         TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
736                         blockStack.RemoveAt(0);
737                         AddTryBlock(tBlock);
738                         return tBlock;
739                 }
740
741                 /// <summary>
742                 /// Mark this position as the end of the last started block and
743                 /// make it a catch block.  This catch block is associated with the
744                 /// specified try block.
745                 /// </summary>
746                 /// <param name="exceptType">the exception type to be caught</param>
747                 /// <param name="tryBlock">the try block associated with this catch block</param>
748                 public void EndCatchBlock(Class exceptType, TryBlock tryBlock) 
749                 {
750                         Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
751                                         NewCodedLabel());
752                         tryBlock.AddHandler(catchBlock);
753                 }
754
755                 /// <summary>
756                 /// Mark this position as the end of the last started block and
757                 /// make it a filter block.  This filter block is associated with the
758                 /// specified try block.
759                 /// </summary>
760                 /// <param name="filterLab">the label where the filter code is</param>
761                 /// <param name="tryBlock">the try block associated with this filter block</param>
762                 public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) 
763                 {
764                         Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
765                         tryBlock.AddHandler(filBlock);
766                 }
767
768                 /// <summary>
769                 /// Mark this position as the end of the last started block and
770                 /// make it a finally block.  This finally block is associated with the
771                 /// specified try block.
772                 /// </summary>
773                 /// <param name="tryBlock">the try block associated with this finally block</param>
774                 public void EndFinallyBlock(TryBlock tryBlock) 
775                 {
776                         Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
777                         tryBlock.AddHandler(finBlock);
778                 }
779
780                 /// <summary>
781                 /// Mark this position as the end of the last started block and
782                 /// make it a fault block.  This fault block is associated with the
783                 /// specified try block.
784                 /// </summary>
785                 /// <param name="tryBlock">the try block associated with this fault block</param>
786                 public void EndFaultBlock(TryBlock tryBlock) 
787                 {
788                         Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel());
789                         tryBlock.AddHandler(fBlock);
790                 }
791
792                 internal uint GetCodeSize() 
793                 {
794                         return codeSize + paddingNeeded + exceptSize;
795                 }
796
797                 internal void CheckCode(uint locSigIx, bool initLocals, int maxStack) 
798                 {
799                         if (tide == 0) return;
800                         bool changed = true;
801                         while (changed) {
802                                 changed = false;
803                                 for (int i=0; i < tide; i++) {
804                                         changed = buffer[i].Check(metaData) || changed;
805                                 }
806                                 if (changed) {
807                                         for (int i=1; i < tide; i++) {
808                                                 buffer[i].offset = buffer[i-1].offset + buffer[i-1].size;
809                                         }
810                                         offset = buffer[tide-1].offset + buffer[tide-1].size;
811                                 }
812                         }
813                         codeSize = offset;
814                         // Console.WriteLine("codeSize before header added = " + codeSize);
815                         if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
816                                 // can use tiny header
817                                 //Console.WriteLine("Tiny Header");
818                                 tinyFormat = true;
819                                 headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
820                                 codeSize++;
821                                 if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
822                         } else {
823                                 //Console.WriteLine("Fat Header");
824                                 tinyFormat = false;
825                                 localSigIx = locSigIx;
826                                 this.maxStack = (short)maxStack;
827                                 headerFlags = FatFormat;
828                                 if (exceptions != null) {
829                                         // Console.WriteLine("Got exceptions");
830                                         headerFlags |= MoreSects;
831                                         uint numExceptClauses = 0;
832                                         for (int i=0; i < exceptions.Count; i++) {
833                                                 TryBlock tryBlock = (TryBlock)exceptions[i];
834                                                 tryBlock.SetSize();
835                                                 numExceptClauses += (uint)tryBlock.NumHandlers();
836                                                 if (tryBlock.isFat()) fatExceptionFormat = true;
837                                         }
838
839                                         uint data_size = ExHeaderSize + numExceptClauses *
840                                                 (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
841
842                                         if (data_size > 255)
843                                                 fatExceptionFormat = true;
844
845                                         // Console.WriteLine("numexceptclauses = " + numExceptClauses);
846                                         if (fatExceptionFormat) {
847                                                 // Console.WriteLine("Fat exception format");
848                                                 exceptHeader = FatExceptTable;
849                                                 exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
850                                         } else {
851                                                 // Console.WriteLine("Tiny exception format");
852                                                 exceptHeader = SmlExceptTable;
853                                                 exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
854                                         }
855                                         // Console.WriteLine("exceptSize = " + exceptSize);
856                                 }
857                                 if (initLocals) headerFlags |= InitLocals;
858                                 if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
859                                 codeSize += FatSize;
860                         }
861                         // Console.WriteLine("codeSize = " + codeSize + "  headerFlags = " + 
862                         //                   Hex.Short(headerFlags));
863                 }
864
865                 internal void Write(FileImage output) 
866                 {
867                         // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
868                         if (tinyFormat) {
869                                 // Console.WriteLine("Writing tiny code");
870                                 output.Write((byte)headerFlags);
871                         } else {
872                                 // Console.WriteLine("Writing fat code");
873                                 output.Write(headerFlags);
874                                 output.Write((ushort)maxStack);
875                                 output.Write(offset);
876                                 output.Write(localSigIx);
877                         }
878                         // Console.WriteLine(Hex.Int(tide) + " CIL instructions");
879                         // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
880                         for (int i=0; i < tide; i++) {
881                                 buffer[i].Write(output);
882                         }
883                         // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
884                         for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); }
885                         if (exceptions != null) {
886                                 // Console.WriteLine("Writing exceptions");
887                                 // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
888                                 output.Write(exceptHeader);
889                                 output.Write3Bytes((uint)exceptSize);
890                                 for (int i=0; i < exceptions.Count; i++) {
891                                         TryBlock tryBlock = (TryBlock)exceptions[i];
892                                         tryBlock.Write(output,fatExceptionFormat);
893                                 }
894                         }
895                 }
896
897         }
898
899         /**************************************************************************/  
900         public abstract class CodeBlock {
901
902                 private static readonly int maxCodeSize = 255;
903                 protected CILLabel start, end;
904                 protected bool small = true;
905
906                 public CodeBlock(CILLabel start, CILLabel end) 
907                 {
908                         this.start = start;
909                         this.end = end;
910                 }
911
912                 internal virtual bool isFat() 
913                 {
914                         // Console.WriteLine("block start = " + start.GetLabelOffset() +
915                         //                  "  block end = " + end.GetLabelOffset());
916                         return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
917                 }
918
919                 internal virtual void Write(FileImage output, bool fatFormat) 
920                 {
921                         if (fatFormat) output.Write(start.GetLabelOffset());
922                         else output.Write((short)start.GetLabelOffset());
923                         uint len = end.GetLabelOffset() - start.GetLabelOffset();
924                         if (fatFormat) output.Write(len);
925                         else output.Write((byte)len);
926                 }
927
928         }
929
930         /// <summary>
931         /// The descriptor for a guarded block (.try)
932         /// </summary>
933         public class TryBlock : CodeBlock {
934                 protected bool fatFormat = false;
935                 protected int flags = 0;
936                 ArrayList handlers = new ArrayList();
937
938                 /// <summary>
939                 /// Create a new try block
940                 /// </summary>
941                 /// <param name="start">start label for the try block</param>
942                 /// <param name="end">end label for the try block</param>
943                 public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
944
945                 /// <summary>
946                 /// Add a handler to this try block
947                 /// </summary>
948                 /// <param name="handler">a handler to be added to the try block</param>
949                 public void AddHandler(HandlerBlock handler) 
950                 {
951                         flags = handler.GetFlag();
952                         handlers.Add(handler);
953                 }
954
955                 internal void SetSize() 
956                 {
957                         fatFormat = base.isFat();
958                         if (fatFormat) return;
959                         for (int i=0; i < handlers.Count; i++) {
960                                 HandlerBlock handler = (HandlerBlock)handlers[i];
961                                 if (handler.isFat()) {
962                                         fatFormat = true;
963                                         return;
964                                 }
965                         }
966                 }
967
968                 internal int NumHandlers() 
969                 {
970                         return handlers.Count;
971                 }
972
973                 internal override bool isFat() 
974                 {
975                         return fatFormat;
976                 }
977
978                 internal override void Write(FileImage output, bool fatFormat) 
979                 {
980                         // Console.WriteLine("writing exception details");
981                         for (int i=0; i < handlers.Count; i++) {
982                                 // Console.WriteLine("Except block " + i);
983                                 HandlerBlock handler = (HandlerBlock)handlers[i];
984                                 if (fatFormat) output.Write(flags);
985                                 else output.Write((short)flags);
986                                 // Console.WriteLine("flags = " + Hex.Short(flags));
987                                 base.Write(output,fatFormat);
988                                 handler.Write(output,fatFormat);
989                         }
990                 }
991         }
992
993         public abstract class HandlerBlock : CodeBlock  {
994
995                 protected static readonly short ExceptionFlag = 0;
996                 protected static readonly short FilterFlag = 0x01;
997                 protected static readonly short FinallyFlag = 0x02;
998                 protected static readonly short FaultFlag = 0x04;
999
1000                 public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { }
1001
1002                 internal virtual short GetFlag() { return ExceptionFlag; }
1003
1004                 internal override void Write(FileImage output, bool fatFormat) 
1005                 {
1006                         base.Write(output,fatFormat);
1007                 }
1008
1009         }
1010
1011         /// <summary>
1012         /// The descriptor for a catch clause (.catch)
1013         /// </summary>
1014         public class Catch : HandlerBlock  {
1015
1016                 Class exceptType;
1017
1018                 /// <summary>
1019                 /// Create a new catch clause
1020                 /// </summary>
1021                 /// <param name="except">the exception to be caught</param>
1022                 /// <param name="handlerStart">start of the handler code</param>
1023                 /// <param name="handlerEnd">end of the handler code</param>
1024                 public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd) 
1025                         : base(handlerStart,handlerEnd) 
1026                 {
1027                         exceptType = except;
1028                 }
1029
1030                 internal override void Write(FileImage output, bool fatFormat) 
1031                 {
1032                         base.Write(output,fatFormat);
1033                         output.Write(exceptType.Token());
1034                 }
1035         }
1036
1037         /// <summary>
1038         /// The descriptor for a filter clause (.filter)
1039         /// </summary>
1040         public class Filter : HandlerBlock  {
1041
1042                 CILLabel filterLabel;
1043
1044                 /// <summary>
1045                 /// Create a new filter clause
1046                 /// </summary>
1047                 /// <param name="filterLabel">the label where the filter code starts</param>
1048                 /// <param name="handlerStart">the start of the handler code</param>
1049                 /// <param name="handlerEnd">the end of the handler code</param>
1050                 public Filter(CILLabel filterLabel, CILLabel handlerStart, 
1051                                 CILLabel handlerEnd) : base(handlerStart,handlerEnd) 
1052                                 {
1053                         this.filterLabel = filterLabel;
1054                 }
1055
1056                 internal override short GetFlag() 
1057                 {
1058                         return FilterFlag; 
1059                 }
1060
1061                 internal override void Write(FileImage output, bool fatFormat) 
1062                 {
1063                         base.Write(output,fatFormat);
1064                         output.Write(filterLabel.GetLabelOffset());
1065                 }
1066
1067         }
1068
1069         /// <summary>
1070         /// Descriptor for a finally block (.finally)
1071         /// </summary>
1072         public class Finally : HandlerBlock  {
1073
1074                 /// <summary>
1075                 /// Create a new finally clause
1076                 /// </summary>
1077                 /// <param name="finallyStart">start of finally code</param>
1078                 /// <param name="finallyEnd">end of finally code</param>
1079                 public Finally(CILLabel finallyStart, CILLabel finallyEnd)
1080                         : base(finallyStart,finallyEnd) { }
1081
1082                 internal override short GetFlag() 
1083                 {
1084                         return FinallyFlag; 
1085                 }
1086
1087                 internal override void Write(FileImage output, bool fatFormat) 
1088                 {
1089                         base.Write(output,fatFormat);
1090                         output.Write((int)0);
1091                 }
1092
1093         }
1094
1095         /// <summary>
1096         /// Descriptor for a fault block (.fault)
1097         /// </summary>
1098         public class Fault : HandlerBlock  {
1099
1100                 /// <summary>
1101                 /// Create a new fault clause
1102                 /// </summary>
1103                 /// <param name="faultStart">start of the fault code</param>
1104                 /// <param name="faultEnd">end of the fault code</param>
1105                 public Fault(CILLabel faultStart, CILLabel faultEnd)
1106                         : base(faultStart,faultEnd) { }
1107
1108                 internal override short GetFlag() 
1109                 {
1110                         return FaultFlag; 
1111                 }
1112
1113                 internal override void Write(FileImage output, bool fatFormat) 
1114                 {
1115                         base.Write(output,fatFormat);
1116                         output.Write((int)0);
1117
1118                 }
1119         }
1120
1121         /**************************************************************************/  
1122         /// <summary>
1123         /// Descriptor for the locals for a method
1124         /// </summary>
1125         public class LocalSig : Signature {
1126
1127                 private static readonly byte LocalSigByte = 0x7;
1128                 Local[] locals;
1129
1130                 public LocalSig(Local[] locals)         
1131                 {
1132                         this.locals = locals;
1133                         tabIx = MDTable.StandAloneSig;
1134                 }
1135
1136                 internal sealed override void BuildTables(MetaData md) 
1137                 {
1138                         if (done) return;
1139                         MemoryStream sig = new MemoryStream();
1140                         sig.WriteByte(LocalSigByte);
1141                         MetaData.CompressNum((uint)locals.Length,sig);
1142                         for (int i=0; i < locals.Length; i++) {
1143                                 ((Local)locals[i]).TypeSig(sig);
1144                         }
1145                         sigIx = md.AddToBlobHeap(sig.ToArray());
1146                         done = true;
1147                 }
1148
1149         }
1150
1151         /**************************************************************************/  
1152         /// <summary>
1153         /// Signature for calli instruction
1154         /// </summary>
1155         public class CalliSig : Signature {
1156
1157                 private static readonly byte Sentinel = 0x41;
1158                 CallConv callConv;
1159                 Type returnType;
1160                 Type[] parameters, optParams;
1161                 uint numPars = 0, numOptPars = 0;
1162
1163                 /// <summary>
1164                 /// Create a signature for a calli instruction
1165                 /// </summary>
1166                 /// <param name="cconv">calling conventions</param>
1167                 /// <param name="retType">return type</param>
1168                 /// <param name="pars">parameter types</param>
1169                 public CalliSig(CallConv cconv, Type retType, Type[] pars) 
1170                 {
1171                         tabIx = MDTable.StandAloneSig;
1172                         callConv = cconv;
1173                         returnType = retType;
1174                         parameters = pars;
1175                         if (pars != null) numPars = (uint)pars.Length;
1176                 }
1177
1178                 /// <summary>
1179                 /// Add the optional parameters to a vararg method
1180                 /// This method sets the vararg calling convention
1181                 /// </summary>
1182                 /// <param name="optPars">the optional pars for the vararg call</param>
1183                 public void AddVarArgs(Type[] optPars) 
1184                 {
1185                         optParams = optPars;
1186                         if (optPars != null) numOptPars = (uint)optPars.Length;
1187                         callConv |= CallConv.Vararg;
1188                 }
1189
1190                 /// <summary>
1191                 /// Add extra calling conventions to this callsite signature
1192                 /// </summary>
1193                 /// <param name="cconv"></param>
1194                 public void AddCallingConv(CallConv cconv) 
1195                 {
1196                         callConv |= cconv;
1197                 }
1198
1199                 internal sealed override void BuildTables(MetaData md) 
1200                 {
1201                         if (done) return;
1202                         MemoryStream sig = new MemoryStream();
1203                         sig.WriteByte((byte)callConv);
1204                         MetaData.CompressNum(numPars+numOptPars,sig);
1205                         returnType.TypeSig(sig);
1206                         for (int i=0; i < numPars; i++) {
1207                                 parameters[i].TypeSig(sig);
1208                         }
1209                         sigIx = md.AddToBlobHeap(sig.ToArray());
1210                         if (numOptPars > 0) {
1211                                 sig.WriteByte(Sentinel);
1212                                 for (int i=0; i < numOptPars; i++) {
1213                                         optParams[i].TypeSig(sig);
1214                                 }
1215                         }
1216                         done = true;
1217                 }
1218
1219         }
1220
1221         /**************************************************************************/  
1222         /// <summary>
1223         /// Descriptor for a local of a method
1224         /// </summary>
1225         public class Local {
1226
1227                 private static readonly byte Pinned = 0x45;
1228                 string name;
1229                 Type type;
1230                 bool pinned = false, byref = false;
1231
1232                 /// <summary>
1233                 /// Create a new local variable 
1234                 /// </summary>
1235                 /// <param name="lName">name of the local variable</param>
1236                 /// <param name="lType">type of the local variable</param>
1237                 public Local(string lName, Type lType) 
1238                 {
1239                         name = lName;
1240                         type = lType;
1241                 }
1242
1243                 /// <summary>
1244                 /// Create a new local variable that is byref and/or pinned
1245                 /// </summary>
1246                 /// <param name="lName">local name</param>
1247                 /// <param name="lType">local type</param>
1248                 /// <param name="byRef">is byref</param>
1249                 /// <param name="isPinned">has pinned attribute</param>
1250                 public Local(string lName, Type lType, bool byRef, bool isPinned)
1251                 {
1252                         name = lName;
1253                         type = lType;
1254                         byref = byRef;
1255                         pinned = isPinned;
1256                 }
1257
1258                 internal void TypeSig(MemoryStream str) 
1259                 {
1260                         if (pinned) str.WriteByte(Pinned);
1261                         type.TypeSig(str);
1262                 }
1263
1264         }
1265
1266         /**************************************************************************/  
1267         /// <summary>
1268         /// A label in the IL
1269         /// </summary>
1270         public class CILLabel {
1271
1272                 CILInstruction branch;
1273                 CILInstruction[] multipleBranches;
1274                 int tide = 0;
1275                 CILInstruction labInstr;
1276                 uint offset = 0;
1277
1278                 public CILLabel (uint offset) 
1279                 {
1280                         this.offset = offset;
1281                 }
1282
1283
1284                 internal CILLabel() 
1285                 {
1286                 }
1287
1288                 internal void AddBranch(CILInstruction instr) 
1289                 {
1290                         if (branch == null) {
1291                                 branch = instr;
1292                                 return;
1293                         }
1294                         if (multipleBranches == null) {
1295                                 multipleBranches = new CILInstruction[2];
1296                         } else if (tide >= multipleBranches.Length) {
1297                                 CILInstruction[] tmp = multipleBranches;
1298                                 multipleBranches = new CILInstruction[tmp.Length*2];
1299                                 for (int i=0; i < tide; i++) {
1300                                         multipleBranches[i] = tmp[i];
1301                                 }
1302                         }
1303                         multipleBranches[tide++] = instr;
1304                 }
1305
1306                 internal void AddLabelInstr(LabelInstr lInstr) 
1307                 {
1308                         labInstr = lInstr;
1309                 }
1310
1311                 internal uint GetLabelOffset() 
1312                 {
1313                         if (labInstr == null) return 0;
1314                         return labInstr.offset + offset;
1315                 }
1316
1317         }
1318
1319
1320 }
1321
1322