Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

1351 lines
34 KiB
C#

using System.IO;
using System.Collections;
namespace PEAPI {
/**************************************************************************/
/// <summary>
/// Descriptor for an IL instruction
/// </summary>
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);
}
}
}
/**************************************************************************/
/// <summary>
/// The IL instructions for a method
/// </summary>
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;
}
/// <summary>
/// Add a simple IL instruction
/// </summary>
/// <param name="inst">the IL instruction</param>
public void Inst(Op inst)
{
AddToBuffer(new Instr((int)inst));
}
/// <summary>
/// Add an IL instruction with an integer parameter
/// </summary>
/// <param name="inst">the IL instruction</param>
/// <param name="val">the integer parameter value</param>
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))));
}
/// <summary>
/// Add the load long instruction
/// </summary>
/// <param name="cVal">the long value</param>
public void ldc_i8(long cVal)
{
AddToBuffer(new LongInstr(0x21,cVal));
}
/// <summary>
/// Add the load float32 instruction
/// </summary>
/// <param name="cVal">the float value</param>
public void ldc_r4(float cVal)
{
AddToBuffer(new FloatInstr(0x22,cVal));
}
/// <summary>
/// Add the load float64 instruction
/// </summary>
/// <param name="cVal">the float value</param>
public void ldc_r8(double cVal)
{
AddToBuffer(new DoubleInstr(0x23,cVal));
}
/// <summary>
/// Add the load string instruction
/// </summary>
/// <param name="str">the string value</param>
public void ldstr(string str)
{
AddToBuffer(new StringInstr(0x72,str));
}
/// <summary>
/// Add the load string instruction
/// </summary>
public void ldstr (byte[] str)
{
AddToBuffer (new StringInstr (0x72, str));
}
/// <summary>
/// Add the calli instruction
/// </summary>
/// <param name="sig">the signature for the calli</param>
public void calli(CalliSig sig)
{
AddToBuffer(new SigInstr(0x29,sig));
}
/// <summary>
/// Add a label to the CIL instructions
/// </summary>
/// <param name="lab">the label to be added</param>
public void CodeLabel(CILLabel lab)
{
AddToBuffer(new LabelInstr(lab));
}
/// <summary>
/// Add an instruction with a field parameter
/// </summary>
/// <param name="inst">the CIL instruction</param>
/// <param name="f">the field parameter</param>
public void FieldInst(FieldOp inst, Field f)
{
AddToBuffer(new FieldInstr((int)inst,f));
}
/// <summary>
/// Add an instruction with a method parameter
/// </summary>
/// <param name="inst">the CIL instruction</param>
/// <param name="m">the method parameter</param>
public void MethInst(MethodOp inst, Method m)
{
AddToBuffer(new MethInstr((int)inst,m));
}
/// <summary>
/// Add an instruction with a type parameter
/// </summary>
/// <param name="inst">the CIL instruction</param>
/// <param name="t">the type argument for the CIL instruction</param>
public void TypeInst(TypeOp inst, Type aType)
{
AddToBuffer(new TypeInstr((int)inst,aType,metaData));
}
/// <summary>
/// Add a branch instruction
/// </summary>
/// <param name="inst">the branch instruction</param>
/// <param name="lab">the label that is the target of the branch</param>
public void Branch(BranchOp inst, CILLabel lab)
{
AddToBuffer(new BranchInstr((int)inst,lab));
}
/// <summary>
/// Add a switch instruction
/// </summary>
/// <param name="labs">the target labels for the switch</param>
public void Switch(CILLabel[] labs)
{
AddToBuffer(new SwitchInstr(0x45,labs));
}
/// <summary>
/// Add a byte to the CIL instructions (.emitbyte)
/// </summary>
/// <param name="bVal"></param>
public void emitbyte(byte bVal)
{
AddToBuffer(new CILByte(bVal));
}
/// <summary>
/// Add an instruction which puts an integer on TOS. This method
/// selects the correct instruction based on the value of the integer.
/// </summary>
/// <param name="i">the integer value</param>
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));
}
}
/// <summary>
/// Add the instruction to load a long on TOS
/// </summary>
/// <param name="l">the long value</param>
public void PushLong(long l)
{
AddToBuffer(new LongInstr(0x21,l));
}
/// <summary>
/// Add an instruction to push the boolean value true on TOS
/// </summary>
public void PushTrue()
{
AddToBuffer(new Instr((int)Op.ldc_i4_1));
}
/// <summary>
/// Add an instruction to push the boolean value false on TOS
/// </summary>
public void PushFalse()
{
AddToBuffer(new Instr((int)Op.ldc_i4_0));
}
/// <summary>
/// Add the instruction to load an argument on TOS. This method
/// selects the correct instruction based on the value of argNo
/// </summary>
/// <param name="argNo">the number of the argument</param>
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));
}
}
/// <summary>
/// Add the instruction to load the address of an argument on TOS.
/// This method selects the correct instruction based on the value
/// of argNo.
/// </summary>
/// <param name="argNo">the number of the argument</param>
public void LoadArgAdr(int argNo)
{
if (argNo <= maxUByteVal) {
AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true));
} else {
AddToBuffer(new UIntInstr(0x0A,argNo,false));
}
}
/// <summary>
/// Add the instruction to load a local on TOS. This method selects
/// the correct instruction based on the value of locNo.
/// </summary>
/// <param name="locNo">the number of the local to load</param>
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));
}
}
/// <summary>
/// Add the instruction to load the address of a local on TOS.
/// This method selects the correct instruction based on the
/// value of locNo.
/// </summary>
/// <param name="locNo">the number of the local</param>
public void LoadLocalAdr(int locNo)
{
if (locNo <= maxUByteVal) {
AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true));
} else {
AddToBuffer(new UIntInstr(0x0D,locNo,false));
}
}
/// <summary>
/// Add the instruction to store to an argument. This method
/// selects the correct instruction based on the value of argNo.
/// </summary>
/// <param name="argNo">the argument to be stored to</param>
public void StoreArg(int argNo)
{
if (argNo <= maxUByteVal) {
AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true));
} else {
AddToBuffer(new UIntInstr(0x0B,argNo,false));
}
}
/// <summary>
/// Add the instruction to store to a local. This method selects
/// the correct instruction based on the value of locNo.
/// </summary>
/// <param name="locNo">the local to be stored to</param>
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));
}
}
/// <summary>
/// Create a new CIL label. To place the label in the CIL instruction
/// stream use CodeLabel.
/// </summary>
/// <returns>a new CIL label</returns>
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);
}
/// <summary>
/// Create a new label at this position in the code buffer
/// </summary>
/// <returns>the label at the current position</returns>
public CILLabel NewCodedLabel()
{
CILLabel lab = new CILLabel();
AddToBuffer(new LabelInstr(lab));
return lab;
}
/// <summary>
/// Mark this position as the start of a new block
/// (try, catch, filter, finally or fault)
/// </summary>
public void StartBlock()
{
if (blockStack == null) blockStack = new ArrayList();
blockStack.Insert(0,NewCodedLabel());
}
/// <summary>
/// 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)
/// </summary>
/// <returns>The try block just ended</returns>
public TryBlock EndTryBlock()
{
TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
blockStack.RemoveAt(0);
AddTryBlock(tBlock);
return tBlock;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="exceptType">the exception type to be caught</param>
/// <param name="tryBlock">the try block associated with this catch block</param>
public void EndCatchBlock(Class exceptType, TryBlock tryBlock)
{
Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
NewCodedLabel());
tryBlock.AddHandler(catchBlock);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="filterLab">the label where the filter code is</param>
/// <param name="tryBlock">the try block associated with this filter block</param>
public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock)
{
Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
tryBlock.AddHandler(filBlock);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="tryBlock">the try block associated with this finally block</param>
public void EndFinallyBlock(TryBlock tryBlock)
{
Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
tryBlock.AddHandler(finBlock);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="tryBlock">the try block associated with this fault block</param>
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);
}
}
/// <summary>
/// The descriptor for a guarded block (.try)
/// </summary>
public class TryBlock : CodeBlock {
protected bool fatFormat = false;
protected int flags = 0;
ArrayList handlers = new ArrayList();
/// <summary>
/// Create a new try block
/// </summary>
/// <param name="start">start label for the try block</param>
/// <param name="end">end label for the try block</param>
public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
/// <summary>
/// Add a handler to this try block
/// </summary>
/// <param name="handler">a handler to be added to the try block</param>
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);
}
}
/// <summary>
/// The descriptor for a catch clause (.catch)
/// </summary>
public class Catch : HandlerBlock {
MetaDataElement exceptType;
/// <summary>
/// Create a new catch clause
/// </summary>
/// <param name="except">the exception to be caught</param>
/// <param name="handlerStart">start of the handler code</param>
/// <param name="handlerEnd">end of the handler code</param>
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());
}
}
/// <summary>
/// The descriptor for a filter clause (.filter)
/// </summary>
public class Filter : HandlerBlock {
CILLabel filterLabel;
/// <summary>
/// Create a new filter clause
/// </summary>
/// <param name="filterLabel">the label where the filter code starts</param>
/// <param name="handlerStart">the start of the handler code</param>
/// <param name="handlerEnd">the end of the handler code</param>
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());
}
}
/// <summary>
/// Descriptor for a finally block (.finally)
/// </summary>
public class Finally : HandlerBlock {
/// <summary>
/// Create a new finally clause
/// </summary>
/// <param name="finallyStart">start of finally code</param>
/// <param name="finallyEnd">end of finally code</param>
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);
}
}
/// <summary>
/// Descriptor for a fault block (.fault)
/// </summary>
public class Fault : HandlerBlock {
/// <summary>
/// Create a new fault clause
/// </summary>
/// <param name="faultStart">start of the fault code</param>
/// <param name="faultEnd">end of the fault code</param>
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);
}
}
/**************************************************************************/
/// <summary>
/// Descriptor for the locals for a method
/// </summary>
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;
}
}
/**************************************************************************/
/// <summary>
/// Signature for calli instruction
/// </summary>
public class CalliSig : Signature {
private static readonly byte Sentinel = 0x41;
CallConv callConv;
Type returnType;
Type[] parameters, optParams;
uint numPars = 0, numOptPars = 0;
/// <summary>
/// Create a signature for a calli instruction
/// </summary>
/// <param name="cconv">calling conventions</param>
/// <param name="retType">return type</param>
/// <param name="pars">parameter types</param>
public CalliSig(CallConv cconv, Type retType, Type[] pars)
{
tabIx = MDTable.StandAloneSig;
callConv = cconv;
returnType = retType;
parameters = pars;
if (pars != null) numPars = (uint)pars.Length;
}
/// <summary>
/// Add the optional parameters to a vararg method
/// This method sets the vararg calling convention
/// </summary>
/// <param name="optPars">the optional pars for the vararg call</param>
public void AddVarArgs(Type[] optPars)
{
optParams = optPars;
if (optPars != null) numOptPars = (uint)optPars.Length;
callConv |= CallConv.Vararg;
}
/// <summary>
/// Add extra calling conventions to this callsite signature
/// </summary>
/// <param name="cconv"></param>
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;
}
}
/**************************************************************************/
/// <summary>
/// Descriptor for a local of a method
/// </summary>
public class Local {
private static readonly byte Pinned = 0x45;
string name;
Type type;
bool pinned = false, byref = false;
/// <summary>
/// Create a new local variable
/// </summary>
/// <param name="lName">name of the local variable</param>
/// <param name="lType">type of the local variable</param>
public Local(string lName, Type lType)
{
name = lName;
type = lType;
}
/// <summary>
/// Create a new local variable that is byref and/or pinned
/// </summary>
/// <param name="lName">local name</param>
/// <param name="lType">local type</param>
/// <param name="byRef">is byref</param>
/// <param name="isPinned">has pinned attribute</param>
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);
}
}
/**************************************************************************/
/// <summary>
/// A label in the IL
/// </summary>
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;
}
}
}