using System.IO; using System.Collections; namespace PEAPI { /**************************************************************************/ /// /// Descriptor for an IL instruction /// internal abstract class CILInstruction { protected static readonly sbyte maxByteVal = 127; protected static readonly sbyte minByteVal = -128; protected static readonly byte leadByte = 0xFE; protected static readonly uint USHeapIndex = 0x70000000; protected static readonly int longInstrStart = (int)Op.arglist; public bool twoByteInstr = false; public uint size = 0; public uint offset; internal virtual bool Check(MetaData md) { return false; } internal virtual void Write(FileImage output) { } } internal class CILByte : CILInstruction { byte byteVal; internal CILByte(byte bVal) { byteVal = bVal; size = 1; } internal override void Write(FileImage output) { output.Write(byteVal); } } internal class Instr : CILInstruction { protected int instr; internal Instr(int inst) { if (inst >= longInstrStart) { instr = inst - longInstrStart; twoByteInstr = true; size = 2; } else { instr = inst; size = 1; } } internal override void Write(FileImage output) { //Console.WriteLine("Writing instruction " + instr + " with size " + size); if (twoByteInstr) output.Write(leadByte); output.Write((byte)instr); } } internal class IntInstr : Instr { int val; bool byteNum; internal IntInstr(int inst, int num, bool byteSize) : base(inst) { val = num; byteNum = byteSize; if (byteNum) size++; else size += 4; } internal sealed override void Write(FileImage output) { base.Write(output); if (byteNum) output.Write((sbyte)val); else output.Write(val); } } internal class UIntInstr : Instr { int val; bool byteNum; internal UIntInstr(int inst, int num, bool byteSize) : base(inst) { val = num; byteNum = byteSize; if (byteNum) size++; else size += 2; } internal sealed override void Write(FileImage output) { base.Write(output); if (byteNum) output.Write((byte)val); else output.Write((ushort)val); } } internal class LongInstr : Instr { long val; internal LongInstr(int inst, long l) : base(inst) { val = l; size += 8; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(val); } } internal class FloatInstr : Instr { float fVal; internal FloatInstr(int inst, float f) : base(inst) { fVal = f; size += 4; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(fVal); } } internal class DoubleInstr : Instr { double val; internal DoubleInstr(int inst, double d) : base(inst) { val = d; size += 8; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(val); } } internal class StringInstr : Instr { string val; byte[] bval; uint strIndex; internal StringInstr(int inst, string str) : base(inst) { val = str; size += 4; } internal StringInstr (int inst, byte[] str) : base (inst) { bval = str; size += 4; } internal sealed override bool Check(MetaData md) { if (val != null) strIndex = md.AddToUSHeap(val); else strIndex = md.AddToUSHeap (bval); return false; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(USHeapIndex | strIndex); } } internal class LabelInstr : CILInstruction { CILLabel label; internal LabelInstr(CILLabel lab) { label = lab; label.AddLabelInstr(this); } } internal class FieldInstr : Instr { Field field; internal FieldInstr(int inst, Field f) : base(inst) { field = f; size += 4; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(field.Token()); } } internal class MethInstr : Instr { Method meth; internal MethInstr(int inst, Method m) : base(inst) { meth = m; size += 4; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(meth.Token()); } } internal class SigInstr : Instr { CalliSig signature; internal SigInstr(int inst, CalliSig sig) : base(inst) { signature = sig; size += 4; } internal sealed override bool Check(MetaData md) { md.AddToTable(MDTable.StandAloneSig,signature); signature.BuildTables(md); return false; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(signature.Token()); } } internal class TypeInstr : Instr { MetaDataElement theType; internal TypeInstr(int inst, Type aType, MetaData md) : base(inst) { theType = aType.GetTypeSpec(md); size += 4; } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(theType.Token()); } } internal class BranchInstr : Instr { CILLabel dest; private bool shortVer = true; private int target = 0; internal BranchInstr(int inst, CILLabel dst) : base(inst) { dest = dst; dest.AddBranch(this); size++; if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) { shortVer = false; size += 3; } } internal sealed override bool Check(MetaData md) { target = (int)dest.GetLabelOffset() - (int)(offset + size); return false; } internal sealed override void Write(FileImage output) { base.Write(output); if (shortVer) output.Write((sbyte)target); else output.Write(target); } } internal class SwitchInstr : Instr { CILLabel[] cases; uint numCases = 0; internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst) { cases = dsts; if (cases != null) numCases = (uint)cases.Length; size += 4 + (numCases * 4); for (int i=0; i < numCases; i++) { cases[i].AddBranch(this); } } internal sealed override void Write(FileImage output) { base.Write(output); output.Write(numCases); for (int i=0; i < numCases; i++) { int target = (int)cases[i].GetLabelOffset() - (int)(offset + size); output.Write(target); } } } /**************************************************************************/ /// /// The IL instructions for a method /// public class CILInstructions { private static readonly uint ExHeaderSize = 4; private static readonly uint FatExClauseSize = 24; private static readonly uint SmlExClauseSize = 12; private static readonly sbyte maxByteVal = 127; private static readonly sbyte minByteVal = -128; private static readonly byte maxUByteVal = 255; private static readonly int smallSize = 64; private static readonly ushort TinyFormat = 0x2; private static readonly ushort FatFormat = 0x3003; private static readonly ushort MoreSects = 0x8; private static readonly ushort InitLocals = 0x10; private static readonly uint FatSize = 12; private static readonly byte FatExceptTable = 0x41; private static readonly byte SmlExceptTable = 0x01; private MetaData metaData; private ArrayList exceptions, blockStack; //private bool codeChecked = false; private static readonly int INITSIZE = 5; private CILInstruction[] buffer = new CILInstruction[INITSIZE]; private int tide = 0; private uint offset = 0; private ushort headerFlags = 0; private short maxStack; private uint paddingNeeded = 0; private byte exceptHeader = 0; uint localSigIx = 0; uint codeSize = 0, exceptSize = 0; bool tinyFormat, fatExceptionFormat = false; public uint Offset { get { return offset; } } internal CILInstructions(MetaData md) { metaData = md; } private void AddToBuffer(CILInstruction inst) { if (tide >= buffer.Length) { CILInstruction[] tmp = buffer; buffer = new CILInstruction[tmp.Length * 2]; for (int i=0; i < tide; i++) { buffer[i] = tmp[i]; } } //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size); inst.offset = offset; offset += inst.size; buffer[tide++] = inst; } /// /// Add a simple IL instruction /// /// the IL instruction public void Inst(Op inst) { AddToBuffer(new Instr((int)inst)); } /// /// Add an IL instruction with an integer parameter /// /// the IL instruction /// the integer parameter value public void IntInst(IntOp inst, int val) { int instr = (int)inst; if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4)) AddToBuffer(new IntInstr(instr,val,(inst == IntOp.ldc_i4_s))); else AddToBuffer(new UIntInstr(instr,val,((inst < IntOp.ldc_i4_s) || (inst == IntOp.unaligned)))); } /// /// Add the load long instruction /// /// the long value public void ldc_i8(long cVal) { AddToBuffer(new LongInstr(0x21,cVal)); } /// /// Add the load float32 instruction /// /// the float value public void ldc_r4(float cVal) { AddToBuffer(new FloatInstr(0x22,cVal)); } /// /// Add the load float64 instruction /// /// the float value public void ldc_r8(double cVal) { AddToBuffer(new DoubleInstr(0x23,cVal)); } /// /// Add the load string instruction /// /// the string value public void ldstr(string str) { AddToBuffer(new StringInstr(0x72,str)); } /// /// Add the load string instruction /// public void ldstr (byte[] str) { AddToBuffer (new StringInstr (0x72, str)); } /// /// Add the calli instruction /// /// the signature for the calli public void calli(CalliSig sig) { AddToBuffer(new SigInstr(0x29,sig)); } /// /// Add a label to the CIL instructions /// /// the label to be added public void CodeLabel(CILLabel lab) { AddToBuffer(new LabelInstr(lab)); } /// /// Add an instruction with a field parameter /// /// the CIL instruction /// the field parameter public void FieldInst(FieldOp inst, Field f) { AddToBuffer(new FieldInstr((int)inst,f)); } /// /// Add an instruction with a method parameter /// /// the CIL instruction /// the method parameter public void MethInst(MethodOp inst, Method m) { AddToBuffer(new MethInstr((int)inst,m)); } /// /// Add an instruction with a type parameter /// /// the CIL instruction /// the type argument for the CIL instruction public void TypeInst(TypeOp inst, Type aType) { AddToBuffer(new TypeInstr((int)inst,aType,metaData)); } /// /// Add a branch instruction /// /// the branch instruction /// the label that is the target of the branch public void Branch(BranchOp inst, CILLabel lab) { AddToBuffer(new BranchInstr((int)inst,lab)); } /// /// Add a switch instruction /// /// the target labels for the switch public void Switch(CILLabel[] labs) { AddToBuffer(new SwitchInstr(0x45,labs)); } /// /// Add a byte to the CIL instructions (.emitbyte) /// /// public void emitbyte(byte bVal) { AddToBuffer(new CILByte(bVal)); } /// /// Add an instruction which puts an integer on TOS. This method /// selects the correct instruction based on the value of the integer. /// /// the integer value public void PushInt(int i) { if (i == -1) { AddToBuffer(new Instr((int)Op.ldc_i4_m1)); } else if ((i >= 0) && (i <= 8)) { Op op = (Op)(Op.ldc_i4_0 + i); AddToBuffer(new Instr((int)op)); } else if ((i >= minByteVal) && (i <= maxByteVal)) { AddToBuffer(new IntInstr((int)IntOp.ldc_i4_s,i,true)); } else { AddToBuffer(new IntInstr((int)IntOp.ldc_i4,i,false)); } } /// /// Add the instruction to load a long on TOS /// /// the long value public void PushLong(long l) { AddToBuffer(new LongInstr(0x21,l)); } /// /// Add an instruction to push the boolean value true on TOS /// public void PushTrue() { AddToBuffer(new Instr((int)Op.ldc_i4_1)); } /// /// Add an instruction to push the boolean value false on TOS /// public void PushFalse() { AddToBuffer(new Instr((int)Op.ldc_i4_0)); } /// /// Add the instruction to load an argument on TOS. This method /// selects the correct instruction based on the value of argNo /// /// the number of the argument public void LoadArg(int argNo) { if (argNo < 4) { int op = (int)Op.ldarg_0 + argNo; AddToBuffer(new Instr(op)); } else if (argNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.ldarg,argNo,true)); } else { AddToBuffer(new UIntInstr(0x09,argNo,false)); } } /// /// Add the instruction to load the address of an argument on TOS. /// This method selects the correct instruction based on the value /// of argNo. /// /// the number of the argument public void LoadArgAdr(int argNo) { if (argNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true)); } else { AddToBuffer(new UIntInstr(0x0A,argNo,false)); } } /// /// Add the instruction to load a local on TOS. This method selects /// the correct instruction based on the value of locNo. /// /// the number of the local to load public void LoadLocal(int locNo) { if (locNo < 4) { int op = (int)Op.ldloc_0 + locNo; AddToBuffer(new Instr(op)); } else if (locNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.ldloc,locNo,true)); } else { AddToBuffer(new UIntInstr(0x0C,locNo,false)); } } /// /// Add the instruction to load the address of a local on TOS. /// This method selects the correct instruction based on the /// value of locNo. /// /// the number of the local public void LoadLocalAdr(int locNo) { if (locNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true)); } else { AddToBuffer(new UIntInstr(0x0D,locNo,false)); } } /// /// Add the instruction to store to an argument. This method /// selects the correct instruction based on the value of argNo. /// /// the argument to be stored to public void StoreArg(int argNo) { if (argNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true)); } else { AddToBuffer(new UIntInstr(0x0B,argNo,false)); } } /// /// Add the instruction to store to a local. This method selects /// the correct instruction based on the value of locNo. /// /// the local to be stored to public void StoreLocal(int locNo) { if (locNo < 4) { int op = (int)Op.stloc_0 + locNo; AddToBuffer(new Instr(op)); } else if (locNo <= maxUByteVal) { AddToBuffer(new UIntInstr((int)IntOp.stloc,locNo,true)); } else { AddToBuffer(new UIntInstr(0x0E,locNo,false)); } } /// /// Create a new CIL label. To place the label in the CIL instruction /// stream use CodeLabel. /// /// a new CIL label public CILLabel NewLabel() { return new CILLabel(); } public void AddTryBlock(TryBlock tryBlock) { if (exceptions == null) exceptions = new ArrayList(); else if (exceptions.Contains(tryBlock)) return; exceptions.Add(tryBlock); tryBlock.ResolveCatchBlocks (metaData); } /// /// Create a new label at this position in the code buffer /// /// the label at the current position public CILLabel NewCodedLabel() { CILLabel lab = new CILLabel(); AddToBuffer(new LabelInstr(lab)); return lab; } /// /// Mark this position as the start of a new block /// (try, catch, filter, finally or fault) /// public void StartBlock() { if (blockStack == null) blockStack = new ArrayList(); blockStack.Insert(0,NewCodedLabel()); } /// /// Mark this position as the end of the last started block and /// make it a try block. This try block is added to the current /// instructions (ie do not need to call AddTryBlock) /// /// The try block just ended public TryBlock EndTryBlock() { TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel()); blockStack.RemoveAt(0); AddTryBlock(tBlock); return tBlock; } /// /// Mark this position as the end of the last started block and /// make it a catch block. This catch block is associated with the /// specified try block. /// /// the exception type to be caught /// the try block associated with this catch block public void EndCatchBlock(Class exceptType, TryBlock tryBlock) { Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0], NewCodedLabel()); tryBlock.AddHandler(catchBlock); } /// /// Mark this position as the end of the last started block and /// make it a filter block. This filter block is associated with the /// specified try block. /// /// the label where the filter code is /// the try block associated with this filter block public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) { Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel()); tryBlock.AddHandler(filBlock); } /// /// Mark this position as the end of the last started block and /// make it a finally block. This finally block is associated with the /// specified try block. /// /// the try block associated with this finally block public void EndFinallyBlock(TryBlock tryBlock) { Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel()); tryBlock.AddHandler(finBlock); } /// /// Mark this position as the end of the last started block and /// make it a fault block. This fault block is associated with the /// specified try block. /// /// the try block associated with this fault block public void EndFaultBlock(TryBlock tryBlock) { Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel()); tryBlock.AddHandler(fBlock); } internal uint GetCodeSize() { return codeSize + paddingNeeded + exceptSize; } internal void CheckCode(uint locSigIx, bool initLocals, int maxStack) { if (tide == 0) return; bool changed = true; while (changed) { changed = false; for (int i=0; i < tide; i++) { changed = buffer[i].Check(metaData) || changed; } if (changed) { for (int i=1; i < tide; i++) { buffer[i].offset = buffer[i-1].offset + buffer[i-1].size; } offset = buffer[tide-1].offset + buffer[tide-1].size; } } codeSize = offset; // Console.WriteLine("codeSize before header added = " + codeSize); if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) { // can use tiny header //Console.WriteLine("Tiny Header"); tinyFormat = true; headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2)); codeSize++; if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); } } else { //Console.WriteLine("Fat Header"); tinyFormat = false; localSigIx = locSigIx; this.maxStack = (short)maxStack; headerFlags = FatFormat; if (exceptions != null) { // Console.WriteLine("Got exceptions"); headerFlags |= MoreSects; uint numExceptClauses = 0; for (int i=0; i < exceptions.Count; i++) { TryBlock tryBlock = (TryBlock)exceptions[i]; tryBlock.SetSize(); numExceptClauses += (uint)tryBlock.NumHandlers(); if (tryBlock.isFat()) fatExceptionFormat = true; } uint data_size = ExHeaderSize + numExceptClauses * (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize); if (data_size > 255) fatExceptionFormat = true; // Console.WriteLine("numexceptclauses = " + numExceptClauses); if (fatExceptionFormat) { // Console.WriteLine("Fat exception format"); exceptHeader = FatExceptTable; exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize; } else { // Console.WriteLine("Tiny exception format"); exceptHeader = SmlExceptTable; exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize; } // Console.WriteLine("exceptSize = " + exceptSize); } if (initLocals) headerFlags |= InitLocals; if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); } codeSize += FatSize; } // Console.WriteLine("codeSize = " + codeSize + " headerFlags = " + // Hex.Short(headerFlags)); } internal void Write(FileImage output) { // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags)); if (tinyFormat) { // Console.WriteLine("Writing tiny code"); output.Write((byte)headerFlags); } else { // Console.WriteLine("Writing fat code"); output.Write(headerFlags); output.Write((ushort)maxStack); output.Write(offset); output.Write(localSigIx); } // Console.WriteLine(Hex.Int(tide) + " CIL instructions"); // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current)); for (int i=0; i < tide; i++) { buffer[i].Write(output); } // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current)); for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); } if (exceptions != null) { // Console.WriteLine("Writing exceptions"); // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize)); output.Write(exceptHeader); output.Write3Bytes((uint)exceptSize); for (int i=0; i < exceptions.Count; i++) { TryBlock tryBlock = (TryBlock)exceptions[i]; tryBlock.Write(output,fatExceptionFormat); } } } } /**************************************************************************/ public abstract class CodeBlock { private static readonly int maxCodeSize = 255; protected CILLabel start, end; protected bool small = true; public CodeBlock(CILLabel start, CILLabel end) { this.start = start; this.end = end; } internal virtual bool isFat() { // Console.WriteLine("block start = " + start.GetLabelOffset() + // " block end = " + end.GetLabelOffset()); return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize; } internal virtual void Write(FileImage output, bool fatFormat) { if (fatFormat) output.Write(start.GetLabelOffset()); else output.Write((short)start.GetLabelOffset()); uint len = end.GetLabelOffset() - start.GetLabelOffset(); if (fatFormat) output.Write(len); else output.Write((byte)len); } } /// /// The descriptor for a guarded block (.try) /// public class TryBlock : CodeBlock { protected bool fatFormat = false; protected int flags = 0; ArrayList handlers = new ArrayList(); /// /// Create a new try block /// /// start label for the try block /// end label for the try block public TryBlock(CILLabel start, CILLabel end) : base(start,end) { } /// /// Add a handler to this try block /// /// a handler to be added to the try block public void AddHandler(HandlerBlock handler) { flags = handler.GetFlag(); handlers.Add(handler); } internal void SetSize() { fatFormat = base.isFat(); if (fatFormat) return; for (int i=0; i < handlers.Count; i++) { HandlerBlock handler = (HandlerBlock)handlers[i]; if (handler.isFat()) { fatFormat = true; return; } } } internal int NumHandlers() { return handlers.Count; } internal override bool isFat() { return fatFormat; } //Hackish internal void ResolveCatchBlocks (MetaData md) { for (int i=0; i < handlers.Count; i++) { Catch c = handlers [i] as Catch; if (c != null) c.ResolveType (md); } } internal override void Write(FileImage output, bool fatFormat) { // Console.WriteLine("writing exception details"); for (int i=0; i < handlers.Count; i++) { // Console.WriteLine("Except block " + i); HandlerBlock handler = (HandlerBlock)handlers[i]; if (fatFormat) output.Write(flags); else output.Write((short)flags); // Console.WriteLine("flags = " + Hex.Short(flags)); base.Write(output,fatFormat); handler.Write(output,fatFormat); } } } public abstract class HandlerBlock : CodeBlock { protected static readonly short ExceptionFlag = 0; protected static readonly short FilterFlag = 0x01; protected static readonly short FinallyFlag = 0x02; protected static readonly short FaultFlag = 0x04; public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { } internal virtual short GetFlag() { return ExceptionFlag; } internal override void Write(FileImage output, bool fatFormat) { base.Write(output,fatFormat); } } /// /// The descriptor for a catch clause (.catch) /// public class Catch : HandlerBlock { MetaDataElement exceptType; /// /// Create a new catch clause /// /// the exception to be caught /// start of the handler code /// end of the handler code public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd) : base(handlerStart, handlerEnd) { exceptType = except; } public Catch(Type except, CILLabel handlerStart, CILLabel handlerEnd) : base(handlerStart,handlerEnd) { exceptType = except; } internal void ResolveType (MetaData md) { exceptType = ((Type) exceptType).GetTypeSpec (md); } internal override void Write(FileImage output, bool fatFormat) { base.Write(output,fatFormat); output.Write(exceptType.Token()); } } /// /// The descriptor for a filter clause (.filter) /// public class Filter : HandlerBlock { CILLabel filterLabel; /// /// Create a new filter clause /// /// the label where the filter code starts /// the start of the handler code /// the end of the handler code public Filter(CILLabel filterLabel, CILLabel handlerStart, CILLabel handlerEnd) : base(handlerStart,handlerEnd) { this.filterLabel = filterLabel; } internal override short GetFlag() { return FilterFlag; } internal override void Write(FileImage output, bool fatFormat) { base.Write(output,fatFormat); output.Write(filterLabel.GetLabelOffset()); } } /// /// Descriptor for a finally block (.finally) /// public class Finally : HandlerBlock { /// /// Create a new finally clause /// /// start of finally code /// end of finally code public Finally(CILLabel finallyStart, CILLabel finallyEnd) : base(finallyStart,finallyEnd) { } internal override short GetFlag() { return FinallyFlag; } internal override void Write(FileImage output, bool fatFormat) { base.Write(output,fatFormat); output.Write((int)0); } } /// /// Descriptor for a fault block (.fault) /// public class Fault : HandlerBlock { /// /// Create a new fault clause /// /// start of the fault code /// end of the fault code public Fault(CILLabel faultStart, CILLabel faultEnd) : base(faultStart,faultEnd) { } internal override short GetFlag() { return FaultFlag; } internal override void Write(FileImage output, bool fatFormat) { base.Write(output,fatFormat); output.Write((int)0); } } /**************************************************************************/ /// /// Descriptor for the locals for a method /// public class LocalSig : Signature { private static readonly byte LocalSigByte = 0x7; Local[] locals; public LocalSig(Local[] locals) { this.locals = locals; tabIx = MDTable.StandAloneSig; } internal sealed override void BuildTables(MetaData md) { if (done) return; MemoryStream sig = new MemoryStream(); sig.WriteByte(LocalSigByte); MetaData.CompressNum((uint)locals.Length,sig); for (int i=0; i < locals.Length; i++) { ((Local)locals[i]).TypeSig(sig); } sigIx = md.AddToBlobHeap(sig.ToArray()); done = true; } } /**************************************************************************/ /// /// Signature for calli instruction /// public class CalliSig : Signature { private static readonly byte Sentinel = 0x41; CallConv callConv; Type returnType; Type[] parameters, optParams; uint numPars = 0, numOptPars = 0; /// /// Create a signature for a calli instruction /// /// calling conventions /// return type /// parameter types public CalliSig(CallConv cconv, Type retType, Type[] pars) { tabIx = MDTable.StandAloneSig; callConv = cconv; returnType = retType; parameters = pars; if (pars != null) numPars = (uint)pars.Length; } /// /// Add the optional parameters to a vararg method /// This method sets the vararg calling convention /// /// the optional pars for the vararg call public void AddVarArgs(Type[] optPars) { optParams = optPars; if (optPars != null) numOptPars = (uint)optPars.Length; callConv |= CallConv.Vararg; } /// /// Add extra calling conventions to this callsite signature /// /// public void AddCallingConv(CallConv cconv) { callConv |= cconv; } internal sealed override void BuildTables(MetaData md) { if (done) return; MemoryStream sig = new MemoryStream(); sig.WriteByte((byte)callConv); MetaData.CompressNum(numPars+numOptPars,sig); returnType.TypeSig(sig); for (int i=0; i < numPars; i++) { parameters[i].TypeSig(sig); } sigIx = md.AddToBlobHeap(sig.ToArray()); if (numOptPars > 0) { sig.WriteByte(Sentinel); for (int i=0; i < numOptPars; i++) { optParams[i].TypeSig(sig); } } done = true; } } /**************************************************************************/ /// /// Descriptor for a local of a method /// public class Local { private static readonly byte Pinned = 0x45; string name; Type type; bool pinned = false, byref = false; /// /// Create a new local variable /// /// name of the local variable /// type of the local variable public Local(string lName, Type lType) { name = lName; type = lType; } /// /// Create a new local variable that is byref and/or pinned /// /// local name /// local type /// is byref /// has pinned attribute public Local(string lName, Type lType, bool byRef, bool isPinned) { name = lName; type = lType; byref = byRef; pinned = isPinned; } internal void TypeSig(MemoryStream str) { if (pinned) str.WriteByte(Pinned); type.TypeSig(str); } } /**************************************************************************/ /// /// A label in the IL /// public class CILLabel { CILInstruction branch; CILInstruction[] multipleBranches; int tide = 0; CILInstruction labInstr; uint offset = 0; bool absolute; public CILLabel (uint offset, bool absolute) { this.offset = offset; this.absolute = absolute; } public CILLabel (uint offset) : this (offset, false) { } internal CILLabel() { } internal void AddBranch(CILInstruction instr) { if (branch == null) { branch = instr; return; } if (multipleBranches == null) { multipleBranches = new CILInstruction[2]; } else if (tide >= multipleBranches.Length) { CILInstruction[] tmp = multipleBranches; multipleBranches = new CILInstruction[tmp.Length*2]; for (int i=0; i < tide; i++) { multipleBranches[i] = tmp[i]; } } multipleBranches[tide++] = instr; } internal void AddLabelInstr(LabelInstr lInstr) { labInstr = lInstr; } internal uint GetLabelOffset() { if (absolute) return offset; if (labInstr == null) return 0; return labInstr.offset + offset; } } }