Remove wrong using
[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                         tryBlock.ResolveCatchBlocks (metaData);
705                 }
706
707                 /// <summary>
708                 /// Create a new label at this position in the code buffer
709                 /// </summary>
710                 /// <returns>the label at the current position</returns>
711                 public CILLabel NewCodedLabel() 
712                 {
713                         CILLabel lab = new CILLabel();
714                         AddToBuffer(new LabelInstr(lab));
715                         return lab;
716                 }
717
718                 /// <summary>
719                 /// Mark this position as the start of a new block
720                 /// (try, catch, filter, finally or fault)
721                 /// </summary>
722                 public void StartBlock() 
723                 {
724                         if (blockStack == null) blockStack = new ArrayList();
725                         blockStack.Insert(0,NewCodedLabel());
726                 }
727
728                 /// <summary>
729                 /// Mark this position as the end of the last started block and
730                 /// make it a try block.  This try block is added to the current 
731                 /// instructions (ie do not need to call AddTryBlock)
732                 /// </summary>
733                 /// <returns>The try block just ended</returns>
734                 public TryBlock EndTryBlock() 
735                 {
736                         TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
737                         blockStack.RemoveAt(0);
738                         AddTryBlock(tBlock);
739                         return tBlock;
740                 }
741
742                 /// <summary>
743                 /// Mark this position as the end of the last started block and
744                 /// make it a catch block.  This catch block is associated with the
745                 /// specified try block.
746                 /// </summary>
747                 /// <param name="exceptType">the exception type to be caught</param>
748                 /// <param name="tryBlock">the try block associated with this catch block</param>
749                 public void EndCatchBlock(Class exceptType, TryBlock tryBlock) 
750                 {
751                         Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
752                                         NewCodedLabel());
753                         tryBlock.AddHandler(catchBlock);
754                 }
755
756                 /// <summary>
757                 /// Mark this position as the end of the last started block and
758                 /// make it a filter block.  This filter block is associated with the
759                 /// specified try block.
760                 /// </summary>
761                 /// <param name="filterLab">the label where the filter code is</param>
762                 /// <param name="tryBlock">the try block associated with this filter block</param>
763                 public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) 
764                 {
765                         Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
766                         tryBlock.AddHandler(filBlock);
767                 }
768
769                 /// <summary>
770                 /// Mark this position as the end of the last started block and
771                 /// make it a finally block.  This finally block is associated with the
772                 /// specified try block.
773                 /// </summary>
774                 /// <param name="tryBlock">the try block associated with this finally block</param>
775                 public void EndFinallyBlock(TryBlock tryBlock) 
776                 {
777                         Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
778                         tryBlock.AddHandler(finBlock);
779                 }
780
781                 /// <summary>
782                 /// Mark this position as the end of the last started block and
783                 /// make it a fault block.  This fault block is associated with the
784                 /// specified try block.
785                 /// </summary>
786                 /// <param name="tryBlock">the try block associated with this fault block</param>
787                 public void EndFaultBlock(TryBlock tryBlock) 
788                 {
789                         Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel());
790                         tryBlock.AddHandler(fBlock);
791                 }
792
793                 internal uint GetCodeSize() 
794                 {
795                         return codeSize + paddingNeeded + exceptSize;
796                 }
797
798                 internal void CheckCode(uint locSigIx, bool initLocals, int maxStack) 
799                 {
800                         if (tide == 0) return;
801                         bool changed = true;
802                         while (changed) {
803                                 changed = false;
804                                 for (int i=0; i < tide; i++) {
805                                         changed = buffer[i].Check(metaData) || changed;
806                                 }
807                                 if (changed) {
808                                         for (int i=1; i < tide; i++) {
809                                                 buffer[i].offset = buffer[i-1].offset + buffer[i-1].size;
810                                         }
811                                         offset = buffer[tide-1].offset + buffer[tide-1].size;
812                                 }
813                         }
814                         codeSize = offset;
815                         // Console.WriteLine("codeSize before header added = " + codeSize);
816                         if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
817                                 // can use tiny header
818                                 //Console.WriteLine("Tiny Header");
819                                 tinyFormat = true;
820                                 headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
821                                 codeSize++;
822                                 if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
823                         } else {
824                                 //Console.WriteLine("Fat Header");
825                                 tinyFormat = false;
826                                 localSigIx = locSigIx;
827                                 this.maxStack = (short)maxStack;
828                                 headerFlags = FatFormat;
829                                 if (exceptions != null) {
830                                         // Console.WriteLine("Got exceptions");
831                                         headerFlags |= MoreSects;
832                                         uint numExceptClauses = 0;
833                                         for (int i=0; i < exceptions.Count; i++) {
834                                                 TryBlock tryBlock = (TryBlock)exceptions[i];
835                                                 tryBlock.SetSize();
836                                                 numExceptClauses += (uint)tryBlock.NumHandlers();
837                                                 if (tryBlock.isFat()) fatExceptionFormat = true;
838                                         }
839
840                                         uint data_size = ExHeaderSize + numExceptClauses *
841                                                 (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
842
843                                         if (data_size > 255)
844                                                 fatExceptionFormat = true;
845
846                                         // Console.WriteLine("numexceptclauses = " + numExceptClauses);
847                                         if (fatExceptionFormat) {
848                                                 // Console.WriteLine("Fat exception format");
849                                                 exceptHeader = FatExceptTable;
850                                                 exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
851                                         } else {
852                                                 // Console.WriteLine("Tiny exception format");
853                                                 exceptHeader = SmlExceptTable;
854                                                 exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
855                                         }
856                                         // Console.WriteLine("exceptSize = " + exceptSize);
857                                 }
858                                 if (initLocals) headerFlags |= InitLocals;
859                                 if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
860                                 codeSize += FatSize;
861                         }
862                         // Console.WriteLine("codeSize = " + codeSize + "  headerFlags = " + 
863                         //                   Hex.Short(headerFlags));
864                 }
865
866                 internal void Write(FileImage output) 
867                 {
868                         // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
869                         if (tinyFormat) {
870                                 // Console.WriteLine("Writing tiny code");
871                                 output.Write((byte)headerFlags);
872                         } else {
873                                 // Console.WriteLine("Writing fat code");
874                                 output.Write(headerFlags);
875                                 output.Write((ushort)maxStack);
876                                 output.Write(offset);
877                                 output.Write(localSigIx);
878                         }
879                         // Console.WriteLine(Hex.Int(tide) + " CIL instructions");
880                         // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
881                         for (int i=0; i < tide; i++) {
882                                 buffer[i].Write(output);
883                         }
884                         // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
885                         for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); }
886                         if (exceptions != null) {
887                                 // Console.WriteLine("Writing exceptions");
888                                 // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
889                                 output.Write(exceptHeader);
890                                 output.Write3Bytes((uint)exceptSize);
891                                 for (int i=0; i < exceptions.Count; i++) {
892                                         TryBlock tryBlock = (TryBlock)exceptions[i];
893                                         tryBlock.Write(output,fatExceptionFormat);
894                                 }
895                         }
896                 }
897
898         }
899
900         /**************************************************************************/  
901         public abstract class CodeBlock {
902
903                 private static readonly int maxCodeSize = 255;
904                 protected CILLabel start, end;
905                 protected bool small = true;
906
907                 public CodeBlock(CILLabel start, CILLabel end) 
908                 {
909                         this.start = start;
910                         this.end = end;
911                 }
912
913                 internal virtual bool isFat() 
914                 {
915                         // Console.WriteLine("block start = " + start.GetLabelOffset() +
916                         //                  "  block end = " + end.GetLabelOffset());
917                         return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
918                 }
919
920                 internal virtual void Write(FileImage output, bool fatFormat) 
921                 {
922                         if (fatFormat) output.Write(start.GetLabelOffset());
923                         else output.Write((short)start.GetLabelOffset());
924                         uint len = end.GetLabelOffset() - start.GetLabelOffset();
925                         if (fatFormat) output.Write(len);
926                         else output.Write((byte)len);
927                 }
928
929         }
930
931         /// <summary>
932         /// The descriptor for a guarded block (.try)
933         /// </summary>
934         public class TryBlock : CodeBlock {
935                 protected bool fatFormat = false;
936                 protected int flags = 0;
937                 ArrayList handlers = new ArrayList();
938
939                 /// <summary>
940                 /// Create a new try block
941                 /// </summary>
942                 /// <param name="start">start label for the try block</param>
943                 /// <param name="end">end label for the try block</param>
944                 public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
945
946                 /// <summary>
947                 /// Add a handler to this try block
948                 /// </summary>
949                 /// <param name="handler">a handler to be added to the try block</param>
950                 public void AddHandler(HandlerBlock handler) 
951                 {
952                         flags = handler.GetFlag();
953                         handlers.Add(handler);
954                 }
955
956                 internal void SetSize() 
957                 {
958                         fatFormat = base.isFat();
959                         if (fatFormat) return;
960                         for (int i=0; i < handlers.Count; i++) {
961                                 HandlerBlock handler = (HandlerBlock)handlers[i];
962                                 if (handler.isFat()) {
963                                         fatFormat = true;
964                                         return;
965                                 }
966                         }
967                 }
968
969                 internal int NumHandlers() 
970                 {
971                         return handlers.Count;
972                 }
973
974                 internal override bool isFat() 
975                 {
976                         return fatFormat;
977                 }
978
979                 //Hackish
980                 internal void ResolveCatchBlocks (MetaData md)
981                 {
982                         for (int i=0; i < handlers.Count; i++) {
983                                 Catch c = handlers [i] as Catch;
984                                 if (c != null)
985                                         c.ResolveType (md);
986                         }
987                 }
988
989                 internal override void Write(FileImage output, bool fatFormat) 
990                 {
991                         // Console.WriteLine("writing exception details");
992                         for (int i=0; i < handlers.Count; i++) {
993                                 // Console.WriteLine("Except block " + i);
994                                 HandlerBlock handler = (HandlerBlock)handlers[i];
995                                 if (fatFormat) output.Write(flags);
996                                 else output.Write((short)flags);
997                                 // Console.WriteLine("flags = " + Hex.Short(flags));
998                                 base.Write(output,fatFormat);
999                                 handler.Write(output,fatFormat);
1000                         }
1001                 }
1002         }
1003
1004         public abstract class HandlerBlock : CodeBlock  {
1005
1006                 protected static readonly short ExceptionFlag = 0;
1007                 protected static readonly short FilterFlag = 0x01;
1008                 protected static readonly short FinallyFlag = 0x02;
1009                 protected static readonly short FaultFlag = 0x04;
1010
1011                 public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { }
1012
1013                 internal virtual short GetFlag() { return ExceptionFlag; }
1014
1015                 internal override void Write(FileImage output, bool fatFormat) 
1016                 {
1017                         base.Write(output,fatFormat);
1018                 }
1019
1020         }
1021
1022         /// <summary>
1023         /// The descriptor for a catch clause (.catch)
1024         /// </summary>
1025         public class Catch : HandlerBlock  {
1026
1027                 MetaDataElement exceptType;
1028
1029                 /// <summary>
1030                 /// Create a new catch clause
1031                 /// </summary>
1032                 /// <param name="except">the exception to be caught</param>
1033                 /// <param name="handlerStart">start of the handler code</param>
1034                 /// <param name="handlerEnd">end of the handler code</param>
1035                 public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)
1036                         : base(handlerStart, handlerEnd)
1037                 {
1038                         exceptType = except;
1039                 }
1040
1041                 public Catch(Type except, CILLabel handlerStart, CILLabel handlerEnd)
1042                         : base(handlerStart,handlerEnd) 
1043                 {
1044                         exceptType = except;
1045                 }
1046
1047                 internal void ResolveType (MetaData md)
1048                 {
1049                        exceptType = ((Type) exceptType).GetTypeSpec (md);
1050                 }
1051
1052                 internal override void Write(FileImage output, bool fatFormat) 
1053                 {
1054                         base.Write(output,fatFormat);
1055                         output.Write(exceptType.Token());
1056                 }
1057         }
1058
1059         /// <summary>
1060         /// The descriptor for a filter clause (.filter)
1061         /// </summary>
1062         public class Filter : HandlerBlock  {
1063
1064                 CILLabel filterLabel;
1065
1066                 /// <summary>
1067                 /// Create a new filter clause
1068                 /// </summary>
1069                 /// <param name="filterLabel">the label where the filter code starts</param>
1070                 /// <param name="handlerStart">the start of the handler code</param>
1071                 /// <param name="handlerEnd">the end of the handler code</param>
1072                 public Filter(CILLabel filterLabel, CILLabel handlerStart, 
1073                                 CILLabel handlerEnd) : base(handlerStart,handlerEnd) 
1074                                 {
1075                         this.filterLabel = filterLabel;
1076                 }
1077
1078                 internal override short GetFlag() 
1079                 {
1080                         return FilterFlag; 
1081                 }
1082
1083                 internal override void Write(FileImage output, bool fatFormat) 
1084                 {
1085                         base.Write(output,fatFormat);
1086                         output.Write(filterLabel.GetLabelOffset());
1087                 }
1088
1089         }
1090
1091         /// <summary>
1092         /// Descriptor for a finally block (.finally)
1093         /// </summary>
1094         public class Finally : HandlerBlock  {
1095
1096                 /// <summary>
1097                 /// Create a new finally clause
1098                 /// </summary>
1099                 /// <param name="finallyStart">start of finally code</param>
1100                 /// <param name="finallyEnd">end of finally code</param>
1101                 public Finally(CILLabel finallyStart, CILLabel finallyEnd)
1102                         : base(finallyStart,finallyEnd) { }
1103
1104                 internal override short GetFlag() 
1105                 {
1106                         return FinallyFlag; 
1107                 }
1108
1109                 internal override void Write(FileImage output, bool fatFormat) 
1110                 {
1111                         base.Write(output,fatFormat);
1112                         output.Write((int)0);
1113                 }
1114
1115         }
1116
1117         /// <summary>
1118         /// Descriptor for a fault block (.fault)
1119         /// </summary>
1120         public class Fault : HandlerBlock  {
1121
1122                 /// <summary>
1123                 /// Create a new fault clause
1124                 /// </summary>
1125                 /// <param name="faultStart">start of the fault code</param>
1126                 /// <param name="faultEnd">end of the fault code</param>
1127                 public Fault(CILLabel faultStart, CILLabel faultEnd)
1128                         : base(faultStart,faultEnd) { }
1129
1130                 internal override short GetFlag() 
1131                 {
1132                         return FaultFlag; 
1133                 }
1134
1135                 internal override void Write(FileImage output, bool fatFormat) 
1136                 {
1137                         base.Write(output,fatFormat);
1138                         output.Write((int)0);
1139
1140                 }
1141         }
1142
1143         /**************************************************************************/  
1144         /// <summary>
1145         /// Descriptor for the locals for a method
1146         /// </summary>
1147         public class LocalSig : Signature {
1148
1149                 private static readonly byte LocalSigByte = 0x7;
1150                 Local[] locals;
1151
1152                 public LocalSig(Local[] locals)         
1153                 {
1154                         this.locals = locals;
1155                         tabIx = MDTable.StandAloneSig;
1156                 }
1157
1158                 internal sealed override void BuildTables(MetaData md) 
1159                 {
1160                         if (done) return;
1161                         MemoryStream sig = new MemoryStream();
1162                         sig.WriteByte(LocalSigByte);
1163                         MetaData.CompressNum((uint)locals.Length,sig);
1164                         for (int i=0; i < locals.Length; i++) {
1165                                 ((Local)locals[i]).TypeSig(sig);
1166                         }
1167                         sigIx = md.AddToBlobHeap(sig.ToArray());
1168                         done = true;
1169                 }
1170
1171         }
1172
1173         /**************************************************************************/  
1174         /// <summary>
1175         /// Signature for calli instruction
1176         /// </summary>
1177         public class CalliSig : Signature {
1178
1179                 private static readonly byte Sentinel = 0x41;
1180                 CallConv callConv;
1181                 Type returnType;
1182                 Type[] parameters, optParams;
1183                 uint numPars = 0, numOptPars = 0;
1184
1185                 /// <summary>
1186                 /// Create a signature for a calli instruction
1187                 /// </summary>
1188                 /// <param name="cconv">calling conventions</param>
1189                 /// <param name="retType">return type</param>
1190                 /// <param name="pars">parameter types</param>
1191                 public CalliSig(CallConv cconv, Type retType, Type[] pars) 
1192                 {
1193                         tabIx = MDTable.StandAloneSig;
1194                         callConv = cconv;
1195                         returnType = retType;
1196                         parameters = pars;
1197                         if (pars != null) numPars = (uint)pars.Length;
1198                 }
1199
1200                 /// <summary>
1201                 /// Add the optional parameters to a vararg method
1202                 /// This method sets the vararg calling convention
1203                 /// </summary>
1204                 /// <param name="optPars">the optional pars for the vararg call</param>
1205                 public void AddVarArgs(Type[] optPars) 
1206                 {
1207                         optParams = optPars;
1208                         if (optPars != null) numOptPars = (uint)optPars.Length;
1209                         callConv |= CallConv.Vararg;
1210                 }
1211
1212                 /// <summary>
1213                 /// Add extra calling conventions to this callsite signature
1214                 /// </summary>
1215                 /// <param name="cconv"></param>
1216                 public void AddCallingConv(CallConv cconv) 
1217                 {
1218                         callConv |= cconv;
1219                 }
1220
1221                 internal sealed override void BuildTables(MetaData md) 
1222                 {
1223                         if (done) return;
1224                         MemoryStream sig = new MemoryStream();
1225                         sig.WriteByte((byte)callConv);
1226                         MetaData.CompressNum(numPars+numOptPars,sig);
1227                         returnType.TypeSig(sig);
1228                         for (int i=0; i < numPars; i++) {
1229                                 parameters[i].TypeSig(sig);
1230                         }
1231                         sigIx = md.AddToBlobHeap(sig.ToArray());
1232                         if (numOptPars > 0) {
1233                                 sig.WriteByte(Sentinel);
1234                                 for (int i=0; i < numOptPars; i++) {
1235                                         optParams[i].TypeSig(sig);
1236                                 }
1237                         }
1238                         done = true;
1239                 }
1240
1241         }
1242
1243         /**************************************************************************/  
1244         /// <summary>
1245         /// Descriptor for a local of a method
1246         /// </summary>
1247         public class Local {
1248
1249                 private static readonly byte Pinned = 0x45;
1250                 string name;
1251                 Type type;
1252                 bool pinned = false, byref = false;
1253
1254                 /// <summary>
1255                 /// Create a new local variable 
1256                 /// </summary>
1257                 /// <param name="lName">name of the local variable</param>
1258                 /// <param name="lType">type of the local variable</param>
1259                 public Local(string lName, Type lType) 
1260                 {
1261                         name = lName;
1262                         type = lType;
1263                 }
1264
1265                 /// <summary>
1266                 /// Create a new local variable that is byref and/or pinned
1267                 /// </summary>
1268                 /// <param name="lName">local name</param>
1269                 /// <param name="lType">local type</param>
1270                 /// <param name="byRef">is byref</param>
1271                 /// <param name="isPinned">has pinned attribute</param>
1272                 public Local(string lName, Type lType, bool byRef, bool isPinned)
1273                 {
1274                         name = lName;
1275                         type = lType;
1276                         byref = byRef;
1277                         pinned = isPinned;
1278                 }
1279
1280                 internal void TypeSig(MemoryStream str) 
1281                 {
1282                         if (pinned) str.WriteByte(Pinned);
1283                         type.TypeSig(str);
1284                 }
1285
1286         }
1287
1288         /**************************************************************************/  
1289         /// <summary>
1290         /// A label in the IL
1291         /// </summary>
1292         public class CILLabel {
1293
1294                 CILInstruction branch;
1295                 CILInstruction[] multipleBranches;
1296                 int tide = 0;
1297                 CILInstruction labInstr;
1298                 uint offset = 0;
1299                 bool absolute;
1300
1301
1302                 public CILLabel (uint offset, bool absolute) 
1303                 {
1304                         this.offset = offset;
1305                         this.absolute = absolute;
1306                 }
1307
1308                 public CILLabel (uint offset) : this (offset, false)
1309                 {
1310                 }
1311
1312
1313                 internal CILLabel() 
1314                 {
1315                 }
1316
1317                 internal void AddBranch(CILInstruction instr) 
1318                 {
1319                         if (branch == null) {
1320                                 branch = instr;
1321                                 return;
1322                         }
1323                         if (multipleBranches == null) {
1324                                 multipleBranches = new CILInstruction[2];
1325                         } else if (tide >= multipleBranches.Length) {
1326                                 CILInstruction[] tmp = multipleBranches;
1327                                 multipleBranches = new CILInstruction[tmp.Length*2];
1328                                 for (int i=0; i < tide; i++) {
1329                                         multipleBranches[i] = tmp[i];
1330                                 }
1331                         }
1332                         multipleBranches[tide++] = instr;
1333                 }
1334
1335                 internal void AddLabelInstr(LabelInstr lInstr) 
1336                 {
1337                         labInstr = lInstr;
1338                 }
1339
1340                 internal uint GetLabelOffset() 
1341                 {
1342                         if (absolute) return offset;
1343                         if (labInstr == null) return 0;
1344                         return labInstr.offset + offset;
1345                 }
1346
1347         }
1348
1349
1350 }
1351
1352