/*
* PERWAPI - An API for Reading and Writing PE Files
*
* Copyright (c) Diane Corney, Queensland University of Technology, 2004.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the PERWAPI Copyright as included with this
* distribution in the file PERWAPIcopyright.rtf.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY as is explained in the copyright notice.
*
* The author may be contacted at d.corney@qut.edu.au
*
* Version Date: 26/01/07
*/
using System;
using System.IO;
using System.Collections;
using System.Security.Cryptography;
namespace QUT.PERWAPI
{
/**************************************************************************/
///
/// Base class for Method Descriptors
///
public abstract class Method : Member
{
protected MethSig sig;
protected ArrayList genericParams;
/*-------------------- Constructors ---------------------------------*/
internal Method(string methName, Type rType, Class paren)
: base(methName, paren)
{
sig = new MethSig(methName);
sig.retType = rType;
}
internal Method(string name) : base(name) { }
///
/// Add calling conventions to this method descriptor
///
///
public void AddCallConv(CallConv cconv)
{
sig.callConv |= cconv;
}
///
/// Get the calling conventions for this method
///
///
public CallConv GetCallConv()
{
return sig.callConv;
}
///
/// Set the return type
///
/// type returned
internal void AddRetType(Type retT)
{
System.Diagnostics.Debug.Assert(retT != null);
sig.retType = retT;
}
///
/// Get the method return type
///
/// method return type
public Type GetRetType()
{
return sig.retType;
}
///
/// Get the types of the method parameters
///
/// list of parameter types
public Type[] GetParTypes()
{
return sig.parTypes;
}
///
/// Get the optional parameter types (for varargs)
///
/// list of vararg types
public Type[] GetOptParTypes()
{
return sig.optParTypes;
}
public int GetGenericParamCount()
{
return genericParams == null ? 0 : genericParams.Count;
}
///
/// Add a generic type to this method
///
/// the name of the generic type
/// the descriptor for the generic type
public GenericParam AddGenericParam(string name)
{
if (genericParams == null) genericParams = new ArrayList();
GenericParam gp = new GenericParam(name, this, genericParams.Count);
sig.callConv |= CallConv.Generic;
genericParams.Add(gp);
sig.numGenPars = (uint)genericParams.Count;
return gp;
}
///
/// Get the descriptor for a generic type
///
/// the name of the generic type
/// descriptor for generic type "name"
public GenericParam GetGenericParam(string name)
{
int pos = FindGenericParam(name);
if (pos == -1) return null;
return (GenericParam)genericParams[pos];
}
public GenericParam GetGenericParam(int ix)
{
if ((genericParams == null) || (ix >= genericParams.Count)) return null;
return (GenericParam)genericParams[ix];
}
public void RemoveGenericParam(string name)
{
int pos = FindGenericParam(name);
if (pos == -1) return;
DeleteGenericParam(pos);
}
public void RemoveGenericParam(int ix)
{
if (genericParams == null) return;
if (ix >= genericParams.Count) return;
DeleteGenericParam(ix);
}
public MethodSpec Instantiate(Type[] genTypes)
{
if (genTypes == null) return null;
if ((genericParams == null) || (genericParams.Count == 0))
throw new Exception("Cannot instantiate non-generic method");
if (genTypes.Length != genericParams.Count)
throw new Exception("Wrong number of type parameters for instantiation\nNeeded "
+ genericParams.Count + " but got " + genTypes.Length);
return new MethodSpec(this, genTypes);
}
public GenericParam[] GetGenericParams()
{ // KJG June 2005
if (genericParams == null) return null;
return (GenericParam[])genericParams.ToArray(typeof(GenericParam));
}
/*------------------------- internal functions --------------------------*/
internal abstract void TypeSig(MemoryStream sig);
internal bool HasNameAndSig(string name, Type[] sigTypes)
{
if (this.name != name) return false;
return sig.HasSig(sigTypes);
}
internal bool HasNameAndSig(string name, Type[] sigTypes, Type[] optPars)
{
if (this.name != name) return false;
return sig.HasSig(sigTypes, optPars);
}
internal MethSig GetSig() { return sig; }
internal MethSig GetSig(PEReader buff) {
if (sig == null)
sig = buff.ReadMethSig(this, this.sigIx);
return sig;
}
internal void SetSig(MethSig sig)
{
this.sig = sig;
this.sig.name = name;
}
internal override string NameString()
{
return parent.NameString() + sig.NameString();
}
private int FindGenericParam(string name)
{
if (genericParams == null) return -1;
for (int i = 0; i < genericParams.Count; i++)
{
GenericParam gp = (GenericParam)genericParams[i];
if (gp.GetName() == name) return i;
}
return -1;
}
private void DeleteGenericParam(int pos)
{
genericParams.RemoveAt(pos);
for (int i = pos; i < genericParams.Count; i++)
{
GenericParam gp = (GenericParam)genericParams[i];
gp.Index = (uint)i;
}
}
internal void AddGenericParam(GenericParam par)
{
if (genericParams == null) genericParams = new ArrayList();
genericParams.Add(par);
//sig.callConv |= CallConv.Generic;
//sig.numGenPars = (uint)genericParams.Count;
}
internal ArrayList GenericParams
{
get { return genericParams; }
set { genericParams = value; }
}
internal void SetGenericParams(GenericParam[] pars)
{
genericParams = new ArrayList(pars);
sig.callConv |= CallConv.Generic;
sig.numGenPars = (uint)genericParams.Count;
}
internal override void WriteType(CILWriter output)
{
sig.WriteCallConv(output);
sig.retType.WriteType(output);
output.Write(" ");
parent.WriteName(output);
output.Write("::" + name);
sig.WriteParTypes(output);
}
}
/**************************************************************************/
///
/// Descriptor for an Instantiation of a generic method
///
public class MethodSpec : Method
{
Method methParent;
uint instIx;
Type[] instTypes;
internal static byte GENERICINST = 0x0A;
/*-------------------- Constructors ---------------------------------*/
public MethodSpec(Method mParent, Type[] instTypes)
: base(null)
{
this.methParent = mParent;
this.instTypes = instTypes;
tabIx = MDTable.MethodSpec;
}
internal MethodSpec(PEReader buff)
: base(null)
{
parentIx = buff.GetCodedIndex(CIx.MethodDefOrRef);
instIx = buff.GetBlobIx();
tabIx = MDTable.MethodSpec;
this.unresolved = true;
}
internal static void Read(PEReader buff, TableRow[] specs)
{
for (int i = 0; i < specs.Length; i++)
specs[i] = new MethodSpec(buff);
}
internal override void Resolve(PEReader buff) {
methParent = (Method)buff.GetCodedElement(CIx.MethodDefOrRef, parentIx);
buff.currentMethodScope = methParent; // set scopes - Fix by CK
buff.currentClassScope = (Class)methParent.GetParent();
//
// EXPERIMENTAL: The signature of the methParent must be
// visible as the signature of this MethodSpec. The type-actuals
// are held in the instTypes array.
this.sig = this.methParent.GetSig(buff);
instTypes = buff.ReadMethSpecSig(instIx);
this.unresolved = false;
//
buff.currentMethodScope = null;
buff.currentClassScope = null;
}
internal override void TypeSig(MemoryStream str)
{
str.WriteByte(GENERICINST);
MetaDataOut.CompressNum(BlobUtil.CompressUInt((uint)instTypes.Length), str);
for (int i = 0; i < instTypes.Length; i++)
{
instTypes[i].TypeSig(str);
}
}
internal static uint Size(MetaData md)
{
return md.CodedIndexSize(CIx.MethodDefOrRef) + md.BlobIndexSize();
}
internal override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.MethodSpec, this);
if (!(methParent is MethodDef)) // Never build a method def
methParent.BuildMDTables(md);
for (int i = 0; i < instTypes.Length; i++)
{
instTypes[i].BuildMDTables(md);
}
}
internal override void BuildSignatures(MetaDataOut md)
{
MemoryStream outSig = new MemoryStream();
TypeSig(outSig);
instIx = md.AddToBlobHeap(outSig.ToArray());
}
internal override void Write(PEWriter output)
{
output.WriteCodedIndex(CIx.MethodDefOrRef, methParent);
output.BlobIndex(instIx);
}
/*-------------------- Public Methods ------------------------------*/
public Type[] GetGenericParamTypes()
{ // KJG 15 July 2005
return instTypes;
}
public Method GetMethParent()
{ // KJG 15 July 2005
return methParent;
}
}
/**************************************************************************/
///
/// Descriptor for a method defined in another assembly/module
///
public class MethodRef : Method
{
internal MethodDef defOf;
MethodDef varArgParent = null;
/*-------------------- Constructors ---------------------------------*/
internal MethodRef(Class paren, string name, Type retType, Type[] pars)
: base(name, retType, paren)
{
sig.parTypes = pars;
if (pars != null) sig.numPars = (uint)pars.Length;
}
internal MethodRef(uint parIx, string name, uint sigIx)
: base(name)
{
this.parentIx = parIx;
this.sigIx = sigIx;
}
internal MethodRef(MethSig sig)
: base(sig.name)
{
this.sig = sig;
}
internal override void Resolve(PEReader buff)
{
if (sig == null)
{
buff.currentMethodScope = this;
buff.currentClassScope = parent;
sig = buff.ReadMethSig(this, name, sigIx);
buff.currentMethodScope = null;
buff.currentClassScope = null;
}
}
internal override Member ResolveParent(PEReader buff)
{
if (parent != null) return this;
buff.currentMethodScope = this;
MetaDataElement paren = buff.GetCodedElement(CIx.MemberRefParent, parentIx);
buff.currentMethodScope = null;
if (paren is MethodDef)
{
parent = null;
varArgParent = (MethodDef)paren;
//this.sig = buff.ReadMethSig(this,name,sigIx);
((MethodDef)paren).AddVarArgSig(this);
return this;
}
else if (paren is ClassSpec)
{
((ClassSpec)paren).AddMethod(this);
return this;
}
else if (paren is PrimitiveType)
{
paren = MSCorLib.mscorlib.GetDefaultClass();
}
else if (paren is ClassDef)
{
this.sig = buff.ReadMethSig(this, name, sigIx);
return ((ClassDef)paren).GetMethod(this.sig);
}
else if (paren is TypeSpec)
{
paren = new ConstructedTypeSpec((TypeSpec)paren);
//Console.WriteLine("Got TypeSpec as parent of Member");
//return this;
//throw new Exception("Got TypeSpec as parent of Member");
//((TypeSpec)paren).AddMethod(buff,this);
}
if (paren is ReferenceScope)
parent = ((ReferenceScope)paren).GetDefaultClass();
parent = (Class)paren;
//if ((MethodRef)parent.GetMethodDesc(name) != null) throw new PEFileException("Existing method!!");
//sig = buff.ReadMethSig(this,name,sigIx);
//MethodRef existing = (MethodRef)parent.GetMethod(sig);
//if (existing != null)
// return existing;
parent.AddToMethodList(this);
return this;
}
public void MakeVarArgMethod(MethodDef paren, Type[] optPars)
{
if (paren != null)
{
parent = null;
varArgParent = paren;
}
sig.optParTypes = optPars;
if (sig.optParTypes != null) sig.numOptPars = (uint)sig.optParTypes.Length;
sig.callConv = CallConv.Vararg;
}
internal void MakeGenericPars(uint num)
{
// Experimental (kjg) 2007-09-03
// It appears that for some system dll the MethodRef may not
// have any generic params defined, but the methodSig does.
if (genericParams == null)
if (genericParams == null) genericParams = new ArrayList();
for (int i = genericParams.Count; i < num; i++)
{
genericParams.Add(new GenericParam("GPar" + i, this, i));
}
// Previous code ...
//if (genericParams != null) {
// for (int i=genericParams.Count; i < num; i++) {
// genericParams.Add(new GenericParam("GPar"+i,this,i));
// }
//}
//sig.numGenPars = (uint)genericParams.Count;
}
/*------------------------- public set and get methods --------------------------*/
///
/// Set the parameter types for this method
///
/// List of types of method parameters
public void SetParTypes(Type[] pars)
{
if (pars == null)
{
sig.numPars = 0;
return;
}
sig.parTypes = pars;
sig.numPars = (uint)pars.Length;
}
///
/// Set the list of optional parameter types for this method
///
/// list of optional parameter types
public void SetOptParTypes(Type[] pars)
{
if (pars == null)
{
sig.numOptPars = 0;
return;
}
sig.optParTypes = pars;
sig.numOptPars = (uint)sig.optParTypes.Length;
}
/*------------------------- internal functions --------------------------*/
internal sealed override void TypeSig(MemoryStream sigStream)
{
sig.TypeSig(sigStream);
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.MemberRef, this);
nameIx = md.AddToStringsHeap(name);
if (parent != null)
{
if (parent is ClassSpec) md.ConditionalAddTypeSpec(parent);
if (parent is ConstructedTypeSpec)
md.ConditionalAddTypeSpec(((ConstructedTypeSpec)parent).Spec);
parent.BuildMDTables(md);
}
sig.BuildTables(md);
}
internal sealed override void BuildSignatures(MetaDataOut md)
{
sig.BuildSignatures(md);
MemoryStream sigStream = new MemoryStream();
TypeSig(sigStream);
sigIx = md.AddToBlobHeap(sigStream.ToArray());
done = false;
}
internal override void BuildCILInfo(CILWriter output)
{
parent.BuildCILInfo(output);
}
internal static uint Size(MetaData md)
{
return md.CodedIndexSize(CIx.MemberRefParent) + md.StringsIndexSize() + md.BlobIndexSize();
}
internal sealed override void Write(PEWriter output)
{
if (varArgParent != null)
output.WriteCodedIndex(CIx.MemberRefParent, varArgParent);
else if (parent is ConstructedTypeSpec)
output.WriteCodedIndex(CIx.MemberRefParent, ((ConstructedTypeSpec)parent).Spec);
else
output.WriteCodedIndex(CIx.MemberRefParent, parent);
output.StringsIndex(nameIx);
output.BlobIndex(sigIx);
}
internal sealed override uint GetCodedIx(CIx code)
{
switch (code)
{
case (CIx.HasCustomAttr): return 6;
case (CIx.MethodDefOrRef): return 1;
case (CIx.CustomAttributeType): return 3;
}
return 0;
}
}
/**************************************************************************/
///
/// Descriptor for a method defined in THIS assembly/module
/// IL .method
///
public class MethodDef : Method
{
private static readonly ushort PInvokeImpl = 0x2000;
private static readonly ushort NotPInvoke = 0xDFFF;
private static readonly ushort HasSecurity = 0x4000;
private static readonly ushort NoSecurity = 0xBFFF;
//private static readonly uint UnmanagedExport = 0x0008;
uint parIx = 0, textOffset = 0;
internal MethodRef refOf;
// The default max stack depth to be assigned when the depth can not be calculated.
private static readonly int DefaultMaxStackDepth = 8;
CILInstructions code;
uint rva;
Param[] parList;
Local[] locals;
bool initLocals;
ushort methFlags = 0, implFlags = 0;
int maxStack = 0, numLocals = 0;
uint numPars = 0;
bool entryPoint = false;
internal LocalSig localSig;
MethodRef varArgSig;
ImplMap pinvokeImpl;
ArrayList security = null;
internal uint locToken = 0;
/*-------------------- Constructors ---------------------------------*/
internal MethodDef(string name, Type retType, Param[] pars, ClassDef paren)
: base(name, retType, paren)
{
sig.SetParTypes(pars);
parList = pars;
parent = paren;
tabIx = MDTable.Method;
}
internal MethodDef(ClassDef paren, MethSig mSig, Param[] pars)
: base(mSig.name)
{
sig = mSig;
parList = pars;
parent = paren;
tabIx = MDTable.Method;
}
internal MethodDef(ClassSpec paren, MethSig mSig, Param[] pars)
: base(mSig.name)
{
parent = paren;
parList = pars;
sig = mSig;
tabIx = MDTable.Method;
}
internal MethodDef(PEReader buff)
: base(null)
{
rva = buff.ReadUInt32();
implFlags = buff.ReadUInt16();
methFlags = buff.ReadUInt16();
name = buff.GetString();
sigIx = buff.GetBlobIx();
parIx = buff.GetIndex(MDTable.Param);
tabIx = MDTable.Method;
}
internal static void Read(PEReader buff, TableRow[] methDefs)
{
MethodDef prevDef = null;
prevDef = new MethodDef(buff);
methDefs[0] = prevDef;
for (int i = 1; i < methDefs.Length; i++)
{
prevDef.Row = (uint)i;
MethodDef methDef = new MethodDef(buff);
prevDef.numPars = methDef.parIx - prevDef.parIx;
prevDef = methDef;
methDefs[i] = methDef;
}
prevDef.Row = (uint)methDefs.Length;
prevDef.numPars = (buff.GetTableSize(MDTable.Param) + 1) - prevDef.parIx;
}
internal static void GetMethodRefs(PEReader buff, uint num, ClassRef parent)
{
for (int i = 0; i < num; i++)
{
uint rva = buff.ReadUInt32();
ushort implFlags = buff.ReadUInt16();
ushort methFlags = buff.ReadUInt16();
string name = buff.GetString();
uint sigIx = buff.GetBlobIx();
uint parIx = buff.GetIndex(MDTable.Param);
if (IsPublicOrProtected(methFlags))
{
MethodRef mRef = new MethodRef(parIx, name, sigIx); // changed
mRef.SetParent(parent);
//Console.WriteLine(parent.NameString());
MethSig mSig = buff.ReadMethSig(mRef, name, sigIx);
//mSig.name = name;
mRef.SetSig(mSig); // changed
parent.AddToMethodList(mRef);
}
}
}
private void DoPars(PEReader buff, bool resolvePars)
{
if (sig == null) sig = buff.ReadMethSig(this, sigIx);
sig.name = name;
parList = new Param[sig.numPars];
if (parIx > buff.GetTableSize(MDTable.Param))
{
// EXPERIMENTAL kjg 19 November 2007
// It is actually allowed that a method def does not
// have corresponding Param metadata, provided the
// parameter types may be constructed from the sig.
for (uint i = 0; i < sig.numPars; i++)
{
parList[i] = Param.DefaultParam();
parList[i].SetParType(sig.parTypes[i]);
}
}
else
{
for (uint i = 0; i < sig.numPars; i++)
{
parList[i] = (Param)buff.GetElement(MDTable.Param, i + parIx);
if (resolvePars) parList[i].Resolve(buff, i + parIx, sig.parTypes[i]);
else parList[i].SetParType(sig.parTypes[i]);
}
}
}
private void DoCode(PEReader buff)
{
if (rva != 0)
{
if (Diag.DiagOn) Console.WriteLine("Reading byte codes for method " + name);
buff.ReadByteCodes(this, rva);
}
}
internal sealed override void Resolve(PEReader buff)
{
buff.currentMethodScope = this;
buff.currentClassScope = parent;
DoPars(buff, true);
if (!buff.skipBody)
{
DoCode(buff);
}
buff.currentMethodScope = null;
buff.currentClassScope = null;
}
/*------------------------- public set and get methods --------------------------*/
///
/// Get the parameters of this method
///
/// Array of params of this method
public Param[] GetParams()
{
return parList;
}
///
/// Set the parameters for this method
///
/// Descriptors of the parameters for this method
public void SetParams(Param[] pars)
{
parList = pars;
sig.SetParTypes(pars);
}
///
/// Add some attributes to this method descriptor
///
/// the attributes to be added
public void AddMethAttribute(MethAttr ma) { methFlags |= (ushort)ma; }
///
/// Property to get and set the attributes for this method
///
public MethAttr GetMethAttributes() { return (MethAttr)methFlags; }
public void SetMethAttributes(MethAttr ma) { methFlags = (ushort)ma; }
///
/// Add some implementation attributes to this method descriptor
///
/// the attributes to be added
public void AddImplAttribute(ImplAttr ia)
{
implFlags |= (ushort)ia;
}
///
/// Property to get and set the implementation attributes for this method
///
public ImplAttr GetImplAttributes() { return (ImplAttr)implFlags; }
public void SetImplAttributes(ImplAttr ia) { implFlags = (ushort)ia; }
public void AddPInvokeInfo(ModuleRef scope, string methName,
PInvokeAttr callAttr)
{
pinvokeImpl = new ImplMap((ushort)callAttr, this, methName, scope);
methFlags |= PInvokeImpl;
}
public void RemovePInvokeInfo()
{
pinvokeImpl = null;
methFlags &= NotPInvoke;
}
public void AddSecurity(SecurityAction act, byte[] permissionSet)
{
methFlags |= HasSecurity;
if (security == null) security = new ArrayList();
security.Add(new DeclSecurity(this, act, permissionSet));
}
public void AddSecurity(DeclSecurity sec)
{
methFlags |= HasSecurity;
if (security == null) security = new ArrayList();
security.Add(sec);
}
public DeclSecurity[] GetSecurity()
{
if (security == null) return null;
return (DeclSecurity[])security.ToArray(typeof(DeclSecurity));
}
public void RemoveSecurity()
{
security = null;
methFlags &= NoSecurity;
}
///
/// Set the maximum stack height for this method
///
/// the maximum height of the stack
public void SetMaxStack(int maxStack)
{
this.maxStack = maxStack;
}
///
/// Retrieve the maximum size of the stack for the code
/// of this method
///
/// max stack height for CIL codes
public int GetMaxStack()
{
return maxStack;
}
///
/// Add local variables to this method
///
/// the locals to be added
/// are locals initialised to default values
public void AddLocals(Local[] locals, bool initLocals)
{
if (locals == null) return;
this.locals = locals;
this.initLocals = initLocals;
numLocals = locals.Length;
for (int i = 0; i < numLocals; i++)
{
this.locals[i].SetIndex(i);
}
}
///
/// Retrieve the locals for this method
///
/// list of locals declared in this method
public Local[] GetLocals() { return locals; }
///
/// Remove all the locals from this method
///
public void RemoveLocals()
{
locals = null;
numLocals = 0;
initLocals = false;
}
///
/// Mark this method as having an entry point
///
public void DeclareEntryPoint() { entryPoint = true; }
///
/// Does this method have an entrypoint?
///
public bool HasEntryPoint() { return entryPoint; }
///
/// Remove the entry point from this method
///
public void RemoveEntryPoint() { entryPoint = false; }
///
/// Create a code buffer for this method to add the IL instructions to
///
/// a buffer for this method's IL instructions
public CILInstructions CreateCodeBuffer()
{
code = new CILInstructions(this);
return code;
}
///
/// Get the CIL code buffer for this method
///
/// Code buffer for this method
public CILInstructions GetCodeBuffer() { return code; }
///
/// Make a method reference descriptor for this method to be used
/// as a callsite signature for this vararg method
///
/// the optional pars for the vararg method call
///
public MethodRef MakeVarArgSignature(Type[] optPars)
{
MethSig mSig = new MethSig(name);
mSig.parTypes = sig.parTypes;
mSig.retType = sig.retType;
varArgSig = new MethodRef(sig);
varArgSig.MakeVarArgMethod(this, optPars);
return varArgSig;
}
public MethodRef GetVarArgSignature()
{
return varArgSig;
}
///
/// Get the MethodRef equivalent to this MethodDef. Assumes
/// that one has been created.
///
/// MethodRef for this MethodDef
public MethodRef RefOf() { return refOf; }
///
/// Get the MethodRef equivalent to this MethodDef. If one
/// does not exist, then create it.
///
/// MethodRef for this MethodDef
public MethodRef MakeRefOf()
{
if (refOf != null) return refOf;
ClassRef parRef = ((ClassDef)parent).MakeRefOf();
refOf = parRef.GetMethod(name, sig.parTypes);
if (refOf == null)
{
Type rType = sig.MakeRefRetType();
Type[] pTypes = sig.MakeRefParTypes();
refOf = new MethodRef(parRef, name, rType, pTypes);
refOf.defOf = this;
refOf.AddCallConv(this.GetCallConv());
}
return refOf;
}
/*------------------------- internal functions --------------------------*/
private static bool IsPublicOrProtected(ushort methFlags)
{
return (methFlags & (ushort)MethAttr.Public) == (ushort)MethAttr.Public ||
(methFlags & (ushort)MethAttr.Family) == (ushort)MethAttr.Family;
}
internal void InsertGenericParam(GenericParam genPar)
{
if (genericParams == null) genericParams = new ArrayList();
for (int i = 0; i < genericParams.Count - genPar.Index; i++)
{
genericParams.Add(null);
}
genericParams.Insert((int)genPar.Index, genPar);
}
internal override bool isDef() { return true; }
internal PEFile GetScope()
{
return ((ClassDef)parent).GetScope();
}
internal void ChangeRefsToDefs(ClassDef newPar, ClassDef[] oldTypes)
{
parent = newPar;
sig.ChangeParTypes(newPar, oldTypes);
if (code != null)
code.ChangeRefsToDefs(newPar, oldTypes);
}
internal void AddPInvokeInfo(ImplMap impl)
{
pinvokeImpl = impl;
methFlags |= PInvokeImpl;
}
internal void AddVarArgSig(MethodRef meth)
{
varArgSig = meth;
//meth.MakeVarArgMethod(this,null);
}
internal sealed override void TypeSig(MemoryStream sigStream)
{
sig.TypeSig(sigStream);
}
// fix for Whidbey bug
internal void AddGenericsToTable(MetaDataOut md)
{
if (genericParams != null)
{
for (int i = 0; i < genericParams.Count; i++)
{
md.AddToTable(MDTable.GenericParam, (GenericParam)genericParams[i]);
}
}
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.Method, this);
nameIx = md.AddToStringsHeap(name);
if (genericParams != null)
{
for (int i = 0; i < genericParams.Count; i++)
{
((GenericParam)genericParams[i]).BuildMDTables(md);
}
}
if (security != null)
{
for (int i = 0; i < security.Count; i++)
{
((DeclSecurity)security[i]).BuildMDTables(md);
}
}
if (pinvokeImpl != null) pinvokeImpl.BuildMDTables(md);
if (entryPoint) md.SetEntryPoint(this);
if (locals != null)
{
localSig = new LocalSig(locals);
localSig.BuildMDTables(md);
}
// The following code is done out of line in method
// TraverseCode *after* all the method indices have
// been allocated in the metadata.
// (kjg, March 2010)
//try {
// if (code != null) {
// if (code.IsEmpty()) {
// code = null;
// }
// else {
// code.BuildTables(md);
// }
// }
//}
//catch (InstructionException ex) {
// throw new Exception(ex.AddMethodName(name));
//}
parIx = md.TableIndex(MDTable.Param);
for (int i = 0; i < sig.numPars; i++)
{
parList[i].seqNo = (ushort)(i + 1);
parList[i].BuildMDTables(md);
}
sig.BuildTables(md);
}
internal void TraverseCode(MetaDataOut md) {
try {
if (code != null) {
if (code.IsEmpty()) {
code = null;
}
else {
code.BuildTables(md);
}
}
}
catch (InstructionException ex) {
throw new Exception(ex.AddMethodName(name));
}
}
internal sealed override void BuildCILInfo(CILWriter output)
{
if (genericParams != null)
{
for (int i = 0; i < genericParams.Count; i++)
{
((GenericParam)genericParams[i]).BuildCILInfo(output);
}
}
if (security != null)
{
for (int i = 0; i < security.Count; i++)
{
((DeclSecurity)security[i]).BuildCILInfo(output);
}
}
if (pinvokeImpl != null) pinvokeImpl.BuildCILInfo(output);
if (locals != null)
{
for (int i = 0; i < locals.Length; i++)
{
locals[i].BuildCILInfo(output);
}
}
try
{
if (code != null) code.BuildCILInfo(output);
}
catch (InstructionException ex)
{
throw new Exception(ex.AddMethodName(name));
}
sig.BuildCILInfo(output);
}
internal sealed override void BuildSignatures(MetaDataOut md)
{
if (locals != null)
{
localSig.BuildSignatures(md);
locToken = localSig.Token();
}
if (code != null)
{
// If the stack depth has not been explicity set, try to work out what is needed.
if (maxStack == 0)
{
try
{
// Set the flag to show if the return type is void or other.
code.ReturnsVoid = GetRetType().SameType(PrimitiveType.Void);
// Calculate the max stack depth
maxStack = code.GetMaxStackDepthRequired();
}
catch (CouldNotFindMaxStackDepth)
{
// Could not find the depth, assign the default
maxStack = DefaultMaxStackDepth;
}
}
code.CheckCode(locToken, initLocals, maxStack, md);
textOffset = md.AddCode(code);
if (Diag.DiagOn) Console.WriteLine("code offset = " + textOffset);
}
sig.BuildSignatures(md);
MemoryStream outSig = new MemoryStream();
TypeSig(outSig);
sigIx = md.AddToBlobHeap(outSig.ToArray());
done = false;
}
internal static uint Size(MetaData md)
{
return 8 + md.StringsIndexSize() + md.BlobIndexSize() + md.TableIndexSize(MDTable.Param);
}
internal sealed override void Write(PEWriter output)
{
if (code == null) output.Write(0);
else output.WriteCodeRVA(textOffset);
output.Write(implFlags);
output.Write(methFlags);
output.StringsIndex(nameIx);
output.BlobIndex(sigIx);
output.WriteIndex(MDTable.Param, parIx);
}
internal override void Write(CILWriter output)
{
output.Write(" .method ");
WriteFlags(output, methFlags);
sig.Write(output);
output.Write(" " + name + "(");
if (parList != null)
{
for (int i = 0; i < parList.Length; i++)
{
parList[i].Write(output);
if (i < parList.Length - 1)
{
output.Write(", ");
}
}
}
output.Write(") ");
uint codeType = implFlags & (uint)0x11;
if (codeType == 0)
{
output.Write("cil ");
}
else if (codeType == 1)
{
output.Write("native ");
}
else if (codeType == 3)
{
output.Write("runtime ");
}
if ((implFlags & (uint)ImplAttr.Unmanaged) == 0)
{
output.Write("managed ");
}
else
{
output.Write("unmanaged ");
}
if ((implFlags & (uint)ImplAttr.ForwardRef) != 0)
{
output.Write("forwardref ");
}
if ((implFlags & (uint)ImplAttr.InternalCall) != 0)
{
output.Write("internalcall ");
}
if ((implFlags & (uint)ImplAttr.Synchronized) != 0)
{
output.Write("synchronized ");
}
if ((implFlags & (uint)ImplAttr.NoInLining) != 0)
{
output.Write("noinlining ");
}
output.WriteLine(" {");
if ((locals != null) && (locals.Length > 0))
{
output.Write(" .locals (");
for (int i = 0; i < locals.Length; i++)
{
if (i > 0)
{
output.Write(" ");
}
locals[i].Write(output);
if (i < locals.Length - 1)
{
output.WriteLine(",");
}
}
output.WriteLine(" )");
}
if (entryPoint)
{
output.WriteLine(" .entrypoint");
}
if (code != null) code.Write(output);
output.WriteLine(" }");
}
internal sealed override uint GetCodedIx(CIx code)
{
switch (code)
{
case (CIx.HasCustomAttr): return 0;
case (CIx.HasDeclSecurity): return 1;
case (CIx.MemberRefParent): return 3;
case (CIx.MethodDefOrRef): return 0;
case (CIx.MemberForwarded): return 1;
case (CIx.CustomAttributeType): return 2;
case (CIx.TypeOrMethodDef): return 1;
}
return 0;
}
}
}