a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
1565 lines
46 KiB
C#
1565 lines
46 KiB
C#
//
|
|
// ReflectionWriter.cs
|
|
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// (C) 2005 - 2007 Jb Evain
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
namespace Mono.Cecil {
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
using Mono.Cecil.Binary;
|
|
using Mono.Cecil.Cil;
|
|
using Mono.Cecil.Metadata;
|
|
using Mono.Cecil.Signatures;
|
|
|
|
internal sealed class ReflectionWriter : BaseReflectionVisitor {
|
|
|
|
StructureWriter m_structureWriter;
|
|
ModuleDefinition m_mod;
|
|
SignatureWriter m_sigWriter;
|
|
CodeWriter m_codeWriter;
|
|
MetadataWriter m_mdWriter;
|
|
MetadataTableWriter m_tableWriter;
|
|
MetadataRowWriter m_rowWriter;
|
|
|
|
bool m_saveSymbols;
|
|
string m_asmOutput;
|
|
ISymbolWriter m_symbolWriter;
|
|
|
|
ArrayList m_typeDefStack;
|
|
ArrayList m_methodStack;
|
|
ArrayList m_fieldStack;
|
|
ArrayList m_genericParamStack;
|
|
IDictionary m_typeSpecTokenCache;
|
|
IDictionary m_memberRefTokenCache;
|
|
|
|
uint m_methodIndex;
|
|
uint m_fieldIndex;
|
|
uint m_paramIndex;
|
|
uint m_eventIndex;
|
|
uint m_propertyIndex;
|
|
|
|
MemoryBinaryWriter m_constWriter;
|
|
|
|
public StructureWriter StructureWriter {
|
|
get { return m_structureWriter; }
|
|
set {
|
|
m_structureWriter = value;
|
|
|
|
Initialize ();
|
|
}
|
|
}
|
|
|
|
public CodeWriter CodeWriter {
|
|
get { return m_codeWriter; }
|
|
}
|
|
|
|
public bool SaveSymbols {
|
|
get { return m_saveSymbols; }
|
|
set { m_saveSymbols = value; }
|
|
}
|
|
|
|
public string OutputFile
|
|
{
|
|
get { return m_asmOutput; }
|
|
set { m_asmOutput = value; }
|
|
}
|
|
|
|
public ISymbolWriter SymbolWriter {
|
|
get { return m_symbolWriter; }
|
|
set { m_symbolWriter = value; }
|
|
}
|
|
|
|
public SignatureWriter SignatureWriter {
|
|
get { return m_sigWriter; }
|
|
}
|
|
|
|
public MetadataWriter MetadataWriter {
|
|
get { return m_mdWriter; }
|
|
}
|
|
|
|
public MetadataTableWriter MetadataTableWriter {
|
|
get { return m_tableWriter; }
|
|
}
|
|
|
|
public MetadataRowWriter MetadataRowWriter {
|
|
get { return m_rowWriter; }
|
|
}
|
|
|
|
public ReflectionWriter (ModuleDefinition mod)
|
|
{
|
|
m_mod = mod;
|
|
}
|
|
|
|
void Initialize ()
|
|
{
|
|
m_mdWriter = new MetadataWriter (
|
|
m_mod.Assembly,
|
|
m_mod.Image.MetadataRoot,
|
|
m_structureWriter.Assembly.Kind,
|
|
m_mod.Assembly.Runtime,
|
|
m_structureWriter.GetWriter ());
|
|
m_tableWriter = m_mdWriter.GetTableVisitor ();
|
|
m_rowWriter = m_tableWriter.GetRowVisitor () as MetadataRowWriter;
|
|
m_sigWriter = new SignatureWriter (m_mdWriter);
|
|
m_codeWriter = new CodeWriter (this, m_mdWriter.CilWriter);
|
|
|
|
m_typeDefStack = new ArrayList ();
|
|
m_methodStack = new ArrayList ();
|
|
m_fieldStack = new ArrayList ();
|
|
m_genericParamStack = new ArrayList ();
|
|
m_typeSpecTokenCache = new Hashtable ();
|
|
m_memberRefTokenCache = new Hashtable ();
|
|
|
|
m_methodIndex = 1;
|
|
m_fieldIndex = 1;
|
|
m_paramIndex = 1;
|
|
m_eventIndex = 1;
|
|
m_propertyIndex = 1;
|
|
|
|
m_constWriter = new MemoryBinaryWriter ();
|
|
}
|
|
|
|
public TypeReference GetCoreType (string name)
|
|
{
|
|
return m_mod.Controller.Reader.SearchCoreType (name);
|
|
}
|
|
|
|
public static uint GetRidFor (IMetadataTokenProvider tp)
|
|
{
|
|
return tp.MetadataToken.RID;
|
|
}
|
|
|
|
public uint GetRidFor (AssemblyNameReference asmName)
|
|
{
|
|
return (uint) m_mod.AssemblyReferences.IndexOf (asmName) + 1;
|
|
}
|
|
|
|
public uint GetRidFor (ModuleDefinition mod)
|
|
{
|
|
return (uint) m_mod.Assembly.Modules.IndexOf (mod) + 1;
|
|
}
|
|
|
|
public uint GetRidFor (ModuleReference modRef)
|
|
{
|
|
return (uint) m_mod.ModuleReferences.IndexOf (modRef) + 1;
|
|
}
|
|
|
|
static bool IsTypeSpec (TypeReference type)
|
|
{
|
|
return type is TypeSpecification || type is GenericParameter;
|
|
}
|
|
|
|
public MetadataToken GetTypeDefOrRefToken (TypeReference type)
|
|
{
|
|
if (IsTypeSpec (type)) {
|
|
uint sig = m_sigWriter.AddTypeSpec (GetTypeSpecSig (type));
|
|
if (m_typeSpecTokenCache.Contains (sig))
|
|
return (MetadataToken) m_typeSpecTokenCache [sig];
|
|
|
|
TypeSpecTable tsTable = m_tableWriter.GetTypeSpecTable ();
|
|
TypeSpecRow tsRow = m_rowWriter.CreateTypeSpecRow (sig);
|
|
tsTable.Rows.Add (tsRow);
|
|
|
|
MetadataToken token = new MetadataToken (TokenType.TypeSpec, (uint) tsTable.Rows.Count);
|
|
if (! (type is GenericParameter))
|
|
type.MetadataToken = token;
|
|
|
|
m_typeSpecTokenCache [sig] = token;
|
|
return token;
|
|
} else if (type != null)
|
|
return type.MetadataToken;
|
|
else // <Module> and interfaces
|
|
return new MetadataToken (TokenType.TypeRef, 0);
|
|
}
|
|
|
|
public MetadataToken GetMemberRefToken (MemberReference member)
|
|
{
|
|
if (member is MethodSpecification)
|
|
return GetMemberRefToken (((MethodSpecification) member).ElementMethod);
|
|
if (member is IMemberDefinition)
|
|
return member.MetadataToken;
|
|
if (m_memberRefTokenCache.Contains (member))
|
|
return (MetadataToken) m_memberRefTokenCache [member];
|
|
|
|
MemberRefTable mrTable = m_tableWriter.GetMemberRefTable ();
|
|
|
|
uint sig = 0;
|
|
if (member is FieldReference)
|
|
sig = m_sigWriter.AddFieldSig (GetFieldSig ((FieldReference) member));
|
|
else if (member is MethodReference)
|
|
sig = m_sigWriter.AddMethodRefSig (GetMethodRefSig ((MethodReference) member));
|
|
|
|
MetadataToken declaringType = GetTypeDefOrRefToken (member.DeclaringType);
|
|
uint name = m_mdWriter.AddString (member.Name);
|
|
|
|
for (int i = 0; i < mrTable.Rows.Count; i++) {
|
|
MemberRefRow row = mrTable [i];
|
|
if (row.Class == declaringType && row.Name == name && row.Signature == sig)
|
|
return MetadataToken.FromMetadataRow (TokenType.MemberRef, i);
|
|
}
|
|
|
|
MemberRefRow mrRow = m_rowWriter.CreateMemberRefRow (
|
|
declaringType,
|
|
name,
|
|
sig);
|
|
|
|
mrTable.Rows.Add (mrRow);
|
|
member.MetadataToken = new MetadataToken (
|
|
TokenType.MemberRef, (uint) mrTable.Rows.Count);
|
|
m_memberRefTokenCache [member] = member.MetadataToken;
|
|
return member.MetadataToken;
|
|
}
|
|
|
|
public MetadataToken GetMethodSpecToken (GenericInstanceMethod gim)
|
|
{
|
|
uint sig = m_sigWriter.AddMethodSpec (GetMethodSpecSig (gim));
|
|
MethodSpecTable msTable = m_tableWriter.GetMethodSpecTable ();
|
|
|
|
MetadataToken meth = GetMemberRefToken (gim.ElementMethod);
|
|
|
|
for (int i = 0; i < msTable.Rows.Count; i++) {
|
|
MethodSpecRow row = msTable [i];
|
|
if (row.Method == meth && row.Instantiation == sig)
|
|
return MetadataToken.FromMetadataRow (TokenType.MethodSpec, i);
|
|
}
|
|
|
|
MethodSpecRow msRow = m_rowWriter.CreateMethodSpecRow (
|
|
meth,
|
|
sig);
|
|
msTable.Rows.Add (msRow);
|
|
gim.MetadataToken = new MetadataToken (TokenType.MethodSpec, (uint) msTable.Rows.Count);
|
|
return gim.MetadataToken;
|
|
}
|
|
|
|
public override void VisitModuleDefinition (ModuleDefinition mod)
|
|
{
|
|
mod.FullLoad ();
|
|
}
|
|
|
|
public override void VisitTypeDefinitionCollection (TypeDefinitionCollection types)
|
|
{
|
|
TypeDefTable tdTable = m_tableWriter.GetTypeDefTable ();
|
|
|
|
if (types [Constants.ModuleType] == null)
|
|
types.Add (new TypeDefinition (
|
|
Constants.ModuleType, string.Empty, TypeAttributes.NotPublic));
|
|
|
|
foreach (TypeDefinition t in types)
|
|
m_typeDefStack.Add (t);
|
|
|
|
m_typeDefStack.Sort (TableComparers.TypeDef.Instance);
|
|
|
|
for (int i = 0; i < m_typeDefStack.Count; i++) {
|
|
TypeDefinition t = (TypeDefinition) m_typeDefStack [i];
|
|
if (t.Module.Assembly != m_mod.Assembly)
|
|
throw new ReflectionException ("A type as not been correctly imported");
|
|
|
|
t.MetadataToken = new MetadataToken (TokenType.TypeDef, (uint) (i + 1));
|
|
}
|
|
|
|
foreach (TypeDefinition t in m_typeDefStack) {
|
|
TypeDefRow tdRow = m_rowWriter.CreateTypeDefRow (
|
|
t.Attributes,
|
|
m_mdWriter.AddString (t.Name),
|
|
m_mdWriter.AddString (t.Namespace),
|
|
GetTypeDefOrRefToken (t.BaseType),
|
|
0,
|
|
0);
|
|
|
|
tdTable.Rows.Add (tdRow);
|
|
}
|
|
}
|
|
|
|
public void CompleteTypeDefinitions ()
|
|
{
|
|
TypeDefTable tdTable = m_tableWriter.GetTypeDefTable ();
|
|
|
|
for (int i = 0; i < m_typeDefStack.Count; i++) {
|
|
TypeDefRow tdRow = tdTable [i];
|
|
TypeDefinition t = (TypeDefinition) m_typeDefStack [i];
|
|
tdRow.FieldList = m_fieldIndex;
|
|
tdRow.MethodList = m_methodIndex;
|
|
if (t.HasFields) {
|
|
foreach (FieldDefinition field in t.Fields)
|
|
VisitFieldDefinition (field);
|
|
}
|
|
if (t.HasConstructors) {
|
|
foreach (MethodDefinition ctor in t.Constructors)
|
|
VisitMethodDefinition (ctor);
|
|
}
|
|
if (t.HasMethods) {
|
|
foreach (MethodDefinition meth in t.Methods)
|
|
VisitMethodDefinition (meth);
|
|
}
|
|
|
|
if (t.HasLayoutInfo)
|
|
WriteLayout (t);
|
|
}
|
|
|
|
foreach (FieldDefinition field in m_fieldStack) {
|
|
if (field.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (field.CustomAttributes);
|
|
if (field.MarshalSpec != null)
|
|
VisitMarshalSpec (field.MarshalSpec);
|
|
}
|
|
|
|
foreach (MethodDefinition meth in m_methodStack) {
|
|
if (meth.ReturnType.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (meth.ReturnType.CustomAttributes);
|
|
if (meth.HasParameters) {
|
|
foreach (ParameterDefinition param in meth.Parameters) {
|
|
if (param.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (param.CustomAttributes);
|
|
}
|
|
}
|
|
if (meth.HasGenericParameters)
|
|
VisitGenericParameterCollection (meth.GenericParameters);
|
|
if (meth.HasOverrides)
|
|
VisitOverrideCollection (meth.Overrides);
|
|
if (meth.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (meth.CustomAttributes);
|
|
if (meth.HasSecurityDeclarations)
|
|
VisitSecurityDeclarationCollection (meth.SecurityDeclarations);
|
|
if (meth.PInvokeInfo != null) {
|
|
meth.Attributes |= MethodAttributes.PInvokeImpl;
|
|
VisitPInvokeInfo (meth.PInvokeInfo);
|
|
}
|
|
}
|
|
|
|
foreach (TypeDefinition t in m_typeDefStack)
|
|
t.Accept (this);
|
|
}
|
|
|
|
public override void VisitTypeReferenceCollection (TypeReferenceCollection refs)
|
|
{
|
|
ArrayList orderedTypeRefs = new ArrayList (refs.Count);
|
|
foreach (TypeReference tr in refs)
|
|
orderedTypeRefs.Add (tr);
|
|
|
|
orderedTypeRefs.Sort (TableComparers.TypeRef.Instance);
|
|
|
|
TypeRefTable trTable = m_tableWriter.GetTypeRefTable ();
|
|
foreach (TypeReference t in orderedTypeRefs) {
|
|
MetadataToken scope;
|
|
|
|
if (t.Module.Assembly != m_mod.Assembly)
|
|
throw new ReflectionException ("A type as not been correctly imported");
|
|
|
|
if (t.Scope == null)
|
|
continue;
|
|
|
|
if (t.DeclaringType != null)
|
|
scope = new MetadataToken (TokenType.TypeRef, GetRidFor (t.DeclaringType));
|
|
else if (t.Scope is AssemblyNameReference)
|
|
scope = new MetadataToken (TokenType.AssemblyRef,
|
|
GetRidFor ((AssemblyNameReference) t.Scope));
|
|
else if (t.Scope is ModuleDefinition)
|
|
scope = new MetadataToken (TokenType.Module,
|
|
GetRidFor ((ModuleDefinition) t.Scope));
|
|
else if (t.Scope is ModuleReference)
|
|
scope = new MetadataToken (TokenType.ModuleRef,
|
|
GetRidFor ((ModuleReference) t.Scope));
|
|
else
|
|
scope = new MetadataToken (TokenType.ExportedType, 0);
|
|
|
|
TypeRefRow trRow = m_rowWriter.CreateTypeRefRow (
|
|
scope,
|
|
m_mdWriter.AddString (t.Name),
|
|
m_mdWriter.AddString (t.Namespace));
|
|
|
|
trTable.Rows.Add (trRow);
|
|
t.MetadataToken = new MetadataToken (TokenType.TypeRef, (uint) trTable.Rows.Count);
|
|
}
|
|
}
|
|
|
|
public override void VisitGenericParameterCollection (GenericParameterCollection parameters)
|
|
{
|
|
if (parameters.Count == 0)
|
|
return;
|
|
|
|
foreach (GenericParameter gp in parameters)
|
|
m_genericParamStack.Add (gp);
|
|
}
|
|
|
|
public override void VisitInterfaceCollection (InterfaceCollection interfaces)
|
|
{
|
|
if (interfaces.Count == 0)
|
|
return;
|
|
|
|
InterfaceImplTable iiTable = m_tableWriter.GetInterfaceImplTable ();
|
|
foreach (TypeReference interf in interfaces) {
|
|
InterfaceImplRow iiRow = m_rowWriter.CreateInterfaceImplRow (
|
|
GetRidFor (interfaces.Container),
|
|
GetTypeDefOrRefToken (interf));
|
|
|
|
iiTable.Rows.Add (iiRow);
|
|
}
|
|
}
|
|
|
|
public override void VisitExternTypeCollection (ExternTypeCollection externs)
|
|
{
|
|
if (externs.Count == 0)
|
|
return;
|
|
|
|
ExportedTypeTable etTable = m_tableWriter.GetExportedTypeTable ();
|
|
foreach (TypeReference ext in externs) {
|
|
TypeDefinition td = ext.Resolve ();
|
|
if (td == null)
|
|
continue;
|
|
|
|
MetadataToken scope = GetExportedTypeScope (td);
|
|
|
|
ExportedTypeRow etRow = m_rowWriter.CreateExportedTypeRow (
|
|
td.Attributes,
|
|
0,
|
|
m_mdWriter.AddString (td.Name),
|
|
m_mdWriter.AddString (td.Namespace),
|
|
scope);
|
|
|
|
etTable.Rows.Add (etRow);
|
|
ext.MetadataToken = new MetadataToken (TokenType.ExportedType, (uint) etTable.Rows.Count);
|
|
}
|
|
}
|
|
|
|
MetadataToken GetExportedTypeScope (TypeDefinition t)
|
|
{
|
|
if (t.DeclaringType != null)
|
|
return t.DeclaringType.MetadataToken;
|
|
|
|
if (t.Scope is AssemblyNameReference)
|
|
return new MetadataToken (TokenType.AssemblyRef, GetRidFor ((AssemblyNameReference) t.Scope));
|
|
|
|
if (t.Scope is ModuleDefinition)
|
|
return new MetadataToken (TokenType.Module, GetRidFor ((ModuleDefinition) t.Scope));
|
|
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
public override void VisitOverrideCollection (OverrideCollection meths)
|
|
{
|
|
if (meths.Count == 0)
|
|
return;
|
|
|
|
MethodImplTable miTable = m_tableWriter.GetMethodImplTable ();
|
|
foreach (MethodReference ov in meths) {
|
|
MethodImplRow miRow = m_rowWriter.CreateMethodImplRow (
|
|
GetRidFor (meths.Container.DeclaringType as TypeDefinition),
|
|
new MetadataToken (TokenType.Method, GetRidFor (meths.Container)),
|
|
GetMemberRefToken (ov));
|
|
|
|
miTable.Rows.Add (miRow);
|
|
}
|
|
}
|
|
|
|
public override void VisitNestedTypeCollection (NestedTypeCollection nestedTypes)
|
|
{
|
|
if (nestedTypes.Count == 0)
|
|
return;
|
|
|
|
NestedClassTable ncTable = m_tableWriter.GetNestedClassTable ();
|
|
foreach (TypeDefinition nested in nestedTypes) {
|
|
NestedClassRow ncRow = m_rowWriter.CreateNestedClassRow (
|
|
nested.MetadataToken.RID,
|
|
GetRidFor (nestedTypes.Container));
|
|
|
|
ncTable.Rows.Add (ncRow);
|
|
}
|
|
}
|
|
|
|
public override void VisitParameterDefinitionCollection (ParameterDefinitionCollection parameters)
|
|
{
|
|
if (parameters.Count == 0)
|
|
return;
|
|
|
|
ushort seq = 1;
|
|
ParamTable pTable = m_tableWriter.GetParamTable ();
|
|
foreach (ParameterDefinition param in parameters)
|
|
InsertParameter (pTable, param, seq++);
|
|
}
|
|
|
|
void InsertParameter (ParamTable pTable, ParameterDefinition param, ushort seq)
|
|
{
|
|
ParamRow pRow = m_rowWriter.CreateParamRow (
|
|
param.Attributes,
|
|
seq,
|
|
m_mdWriter.AddString (param.Name));
|
|
|
|
pTable.Rows.Add (pRow);
|
|
param.MetadataToken = new MetadataToken (TokenType.Param, (uint) pTable.Rows.Count);
|
|
|
|
if (param.MarshalSpec != null)
|
|
param.MarshalSpec.Accept (this);
|
|
|
|
if (param.HasConstant)
|
|
WriteConstant (param, param.ParameterType);
|
|
|
|
m_paramIndex++;
|
|
}
|
|
|
|
static bool RequiresParameterRow (MethodReturnType mrt)
|
|
{
|
|
return mrt.HasConstant || mrt.MarshalSpec != null ||
|
|
mrt.CustomAttributes.Count > 0 || mrt.Parameter.Attributes != (ParameterAttributes) 0;
|
|
}
|
|
|
|
public override void VisitMethodDefinition (MethodDefinition method)
|
|
{
|
|
MethodTable mTable = m_tableWriter.GetMethodTable ();
|
|
MethodRow mRow = m_rowWriter.CreateMethodRow (
|
|
RVA.Zero,
|
|
method.ImplAttributes,
|
|
method.Attributes,
|
|
m_mdWriter.AddString (method.Name),
|
|
m_sigWriter.AddMethodDefSig (GetMethodDefSig (method)),
|
|
m_paramIndex);
|
|
|
|
mTable.Rows.Add (mRow);
|
|
m_methodStack.Add (method);
|
|
method.MetadataToken = new MetadataToken (TokenType.Method, (uint) mTable.Rows.Count);
|
|
m_methodIndex++;
|
|
|
|
if (RequiresParameterRow (method.ReturnType))
|
|
InsertParameter (m_tableWriter.GetParamTable (), method.ReturnType.Parameter, 0);
|
|
|
|
VisitParameterDefinitionCollection (method.Parameters);
|
|
}
|
|
|
|
public override void VisitPInvokeInfo (PInvokeInfo pinvk)
|
|
{
|
|
ImplMapTable imTable = m_tableWriter.GetImplMapTable ();
|
|
ImplMapRow imRow = m_rowWriter.CreateImplMapRow (
|
|
pinvk.Attributes,
|
|
new MetadataToken (TokenType.Method, GetRidFor (pinvk.Method)),
|
|
m_mdWriter.AddString (pinvk.EntryPoint),
|
|
GetRidFor (pinvk.Module));
|
|
|
|
imTable.Rows.Add (imRow);
|
|
}
|
|
|
|
public override void VisitEventDefinitionCollection (EventDefinitionCollection events)
|
|
{
|
|
if (events.Count == 0)
|
|
return;
|
|
|
|
EventMapTable emTable = m_tableWriter.GetEventMapTable ();
|
|
EventMapRow emRow = m_rowWriter.CreateEventMapRow (
|
|
GetRidFor (events.Container),
|
|
m_eventIndex);
|
|
|
|
emTable.Rows.Add (emRow);
|
|
VisitCollection (events);
|
|
}
|
|
|
|
public override void VisitEventDefinition (EventDefinition evt)
|
|
{
|
|
EventTable eTable = m_tableWriter.GetEventTable ();
|
|
EventRow eRow = m_rowWriter.CreateEventRow (
|
|
evt.Attributes,
|
|
m_mdWriter.AddString (evt.Name),
|
|
GetTypeDefOrRefToken (evt.EventType));
|
|
|
|
eTable.Rows.Add (eRow);
|
|
evt.MetadataToken = new MetadataToken (TokenType.Event, (uint) eTable.Rows.Count);
|
|
|
|
if (evt.AddMethod != null)
|
|
WriteSemantic (MethodSemanticsAttributes.AddOn, evt, evt.AddMethod);
|
|
|
|
if (evt.InvokeMethod != null)
|
|
WriteSemantic (MethodSemanticsAttributes.Fire, evt, evt.InvokeMethod);
|
|
|
|
if (evt.RemoveMethod != null)
|
|
WriteSemantic (MethodSemanticsAttributes.RemoveOn, evt, evt.RemoveMethod);
|
|
|
|
m_eventIndex++;
|
|
}
|
|
|
|
public override void VisitFieldDefinition (FieldDefinition field)
|
|
{
|
|
FieldTable fTable = m_tableWriter.GetFieldTable ();
|
|
FieldRow fRow = m_rowWriter.CreateFieldRow (
|
|
field.Attributes,
|
|
m_mdWriter.AddString (field.Name),
|
|
m_sigWriter.AddFieldSig (GetFieldSig (field)));
|
|
|
|
fTable.Rows.Add (fRow);
|
|
field.MetadataToken = new MetadataToken (TokenType.Field, (uint) fTable.Rows.Count);
|
|
m_fieldIndex++;
|
|
|
|
if (field.HasConstant)
|
|
WriteConstant (field, field.FieldType);
|
|
|
|
if (field.HasLayoutInfo)
|
|
WriteLayout (field);
|
|
|
|
m_fieldStack.Add (field);
|
|
}
|
|
|
|
public override void VisitPropertyDefinitionCollection (PropertyDefinitionCollection properties)
|
|
{
|
|
if (properties.Count == 0)
|
|
return;
|
|
|
|
PropertyMapTable pmTable = m_tableWriter.GetPropertyMapTable ();
|
|
PropertyMapRow pmRow = m_rowWriter.CreatePropertyMapRow (
|
|
GetRidFor (properties.Container),
|
|
m_propertyIndex);
|
|
|
|
pmTable.Rows.Add (pmRow);
|
|
VisitCollection (properties);
|
|
}
|
|
|
|
public override void VisitPropertyDefinition (PropertyDefinition property)
|
|
{
|
|
PropertyTable pTable = m_tableWriter.GetPropertyTable ();
|
|
PropertyRow pRow = m_rowWriter.CreatePropertyRow (
|
|
property.Attributes,
|
|
m_mdWriter.AddString (property.Name),
|
|
m_sigWriter.AddPropertySig (GetPropertySig (property)));
|
|
|
|
pTable.Rows.Add (pRow);
|
|
property.MetadataToken = new MetadataToken (TokenType.Property, (uint) pTable.Rows.Count);
|
|
|
|
if (property.GetMethod != null)
|
|
WriteSemantic (MethodSemanticsAttributes.Getter, property, property.GetMethod);
|
|
|
|
if (property.SetMethod != null)
|
|
WriteSemantic (MethodSemanticsAttributes.Setter, property, property.SetMethod);
|
|
|
|
if (property.HasConstant)
|
|
WriteConstant (property, property.PropertyType);
|
|
|
|
m_propertyIndex++;
|
|
}
|
|
|
|
public override void VisitSecurityDeclarationCollection (SecurityDeclarationCollection secDecls)
|
|
{
|
|
if (secDecls.Count == 0)
|
|
return;
|
|
|
|
DeclSecurityTable dsTable = m_tableWriter.GetDeclSecurityTable ();
|
|
foreach (SecurityDeclaration secDec in secDecls) {
|
|
DeclSecurityRow dsRow = m_rowWriter.CreateDeclSecurityRow (
|
|
secDec.Action,
|
|
secDecls.Container.MetadataToken,
|
|
m_mdWriter.AddBlob (secDec.Resolved ?
|
|
m_mod.GetAsByteArray (secDec) : secDec.Blob));
|
|
|
|
dsTable.Rows.Add (dsRow);
|
|
}
|
|
}
|
|
|
|
public override void VisitCustomAttributeCollection (CustomAttributeCollection customAttrs)
|
|
{
|
|
if (customAttrs.Count == 0)
|
|
return;
|
|
|
|
CustomAttributeTable caTable = m_tableWriter.GetCustomAttributeTable ();
|
|
foreach (CustomAttribute ca in customAttrs) {
|
|
MetadataToken parent;
|
|
if (customAttrs.Container is AssemblyDefinition)
|
|
parent = new MetadataToken (TokenType.Assembly, 1);
|
|
else if (customAttrs.Container is ModuleDefinition)
|
|
parent = new MetadataToken (TokenType.Module, 1);
|
|
else if (customAttrs.Container is IMetadataTokenProvider)
|
|
parent = ((IMetadataTokenProvider) customAttrs.Container).MetadataToken;
|
|
else
|
|
throw new ReflectionException ("Unknown Custom Attribute parent");
|
|
|
|
uint value = ca.Resolved ?
|
|
m_sigWriter.AddCustomAttribute (GetCustomAttributeSig (ca), ca.Constructor) :
|
|
m_mdWriter.AddBlob (m_mod.GetAsByteArray (ca));
|
|
CustomAttributeRow caRow = m_rowWriter.CreateCustomAttributeRow (
|
|
parent,
|
|
GetMemberRefToken (ca.Constructor),
|
|
value);
|
|
|
|
caTable.Rows.Add (caRow);
|
|
}
|
|
}
|
|
|
|
public override void VisitMarshalSpec (MarshalSpec marshalSpec)
|
|
{
|
|
FieldMarshalTable fmTable = m_tableWriter.GetFieldMarshalTable ();
|
|
FieldMarshalRow fmRow = m_rowWriter.CreateFieldMarshalRow (
|
|
marshalSpec.Container.MetadataToken,
|
|
m_sigWriter.AddMarshalSig (GetMarshalSig (marshalSpec)));
|
|
|
|
fmTable.Rows.Add (fmRow);
|
|
}
|
|
|
|
void WriteConstant (IHasConstant hc, TypeReference type)
|
|
{
|
|
ConstantTable cTable = m_tableWriter.GetConstantTable ();
|
|
ElementType et;
|
|
if (type is TypeDefinition && (type as TypeDefinition).IsEnum) {
|
|
Type t = hc.Constant.GetType ();
|
|
if (t.IsEnum)
|
|
t = Enum.GetUnderlyingType (t);
|
|
|
|
et = GetCorrespondingType (string.Concat (t.Namespace, '.', t.Name));
|
|
} else
|
|
et = GetCorrespondingType (type.FullName);
|
|
|
|
if (et == ElementType.Object || et == ElementType.Type || et == ElementType.String)
|
|
et = hc.Constant == null ?
|
|
ElementType.Class :
|
|
GetCorrespondingType (hc.Constant.GetType ().FullName);
|
|
|
|
ConstantRow cRow = m_rowWriter.CreateConstantRow (
|
|
et,
|
|
hc.MetadataToken,
|
|
m_mdWriter.AddBlob (EncodeConstant (et, hc.Constant)));
|
|
|
|
cTable.Rows.Add (cRow);
|
|
}
|
|
|
|
void WriteLayout (FieldDefinition field)
|
|
{
|
|
FieldLayoutTable flTable = m_tableWriter.GetFieldLayoutTable ();
|
|
FieldLayoutRow flRow = m_rowWriter.CreateFieldLayoutRow (
|
|
field.Offset,
|
|
GetRidFor (field));
|
|
|
|
flTable.Rows.Add (flRow);
|
|
}
|
|
|
|
void WriteLayout (TypeDefinition type)
|
|
{
|
|
ClassLayoutTable clTable = m_tableWriter.GetClassLayoutTable ();
|
|
ClassLayoutRow clRow = m_rowWriter.CreateClassLayoutRow (
|
|
type.PackingSize,
|
|
type.ClassSize,
|
|
GetRidFor (type));
|
|
|
|
clTable.Rows.Add (clRow);
|
|
}
|
|
|
|
void WriteSemantic (MethodSemanticsAttributes attrs,
|
|
IMetadataTokenProvider member, MethodDefinition meth)
|
|
{
|
|
MethodSemanticsTable msTable = m_tableWriter.GetMethodSemanticsTable ();
|
|
MethodSemanticsRow msRow = m_rowWriter.CreateMethodSemanticsRow (
|
|
attrs,
|
|
GetRidFor (meth),
|
|
member.MetadataToken);
|
|
|
|
msTable.Rows.Add (msRow);
|
|
}
|
|
|
|
void SortTables ()
|
|
{
|
|
TablesHeap th = m_mdWriter.GetMetadataRoot ().Streams.TablesHeap;
|
|
th.Sorted = 0;
|
|
|
|
if (th.HasTable (NestedClassTable.RId))
|
|
m_tableWriter.GetNestedClassTable ().Rows.Sort (
|
|
TableComparers.NestedClass.Instance);
|
|
th.Sorted |= ((long) 1 << NestedClassTable.RId);
|
|
|
|
if (th.HasTable (InterfaceImplTable.RId))
|
|
m_tableWriter.GetInterfaceImplTable ().Rows.Sort (
|
|
TableComparers.InterfaceImpl.Instance);
|
|
th.Sorted |= ((long) 1 << InterfaceImplTable.RId);
|
|
|
|
if (th.HasTable (ConstantTable.RId))
|
|
m_tableWriter.GetConstantTable ().Rows.Sort (
|
|
TableComparers.Constant.Instance);
|
|
th.Sorted |= ((long) 1 << ConstantTable.RId);
|
|
|
|
if (th.HasTable (MethodSemanticsTable.RId))
|
|
m_tableWriter.GetMethodSemanticsTable ().Rows.Sort (
|
|
TableComparers.MethodSem.Instance);
|
|
th.Sorted |= ((long) 1 << MethodSemanticsTable.RId);
|
|
|
|
if (th.HasTable (FieldMarshalTable.RId))
|
|
m_tableWriter.GetFieldMarshalTable ().Rows.Sort (
|
|
TableComparers.FieldMarshal.Instance);
|
|
th.Sorted |= ((long) 1 << FieldMarshalTable.RId);
|
|
|
|
if (th.HasTable (ClassLayoutTable.RId))
|
|
m_tableWriter.GetClassLayoutTable ().Rows.Sort (
|
|
TableComparers.TypeLayout.Instance);
|
|
th.Sorted |= ((long) 1 << ClassLayoutTable.RId);
|
|
|
|
if (th.HasTable (FieldLayoutTable.RId))
|
|
m_tableWriter.GetFieldLayoutTable ().Rows.Sort (
|
|
TableComparers.FieldLayout.Instance);
|
|
th.Sorted |= ((long) 1 << FieldLayoutTable.RId);
|
|
|
|
if (th.HasTable (ImplMapTable.RId))
|
|
m_tableWriter.GetImplMapTable ().Rows.Sort (
|
|
TableComparers.PInvoke.Instance);
|
|
th.Sorted |= ((long) 1 << ImplMapTable.RId);
|
|
|
|
if (th.HasTable (FieldRVATable.RId))
|
|
m_tableWriter.GetFieldRVATable ().Rows.Sort (
|
|
TableComparers.FieldRVA.Instance);
|
|
th.Sorted |= ((long) 1 << FieldRVATable.RId);
|
|
|
|
if (th.HasTable (MethodImplTable.RId))
|
|
m_tableWriter.GetMethodImplTable ().Rows.Sort (
|
|
TableComparers.Override.Instance);
|
|
th.Sorted |= ((long) 1 << MethodImplTable.RId);
|
|
|
|
if (th.HasTable (CustomAttributeTable.RId))
|
|
m_tableWriter.GetCustomAttributeTable ().Rows.Sort (
|
|
TableComparers.CustomAttribute.Instance);
|
|
th.Sorted |= ((long) 1 << CustomAttributeTable.RId);
|
|
|
|
if (th.HasTable (DeclSecurityTable.RId))
|
|
m_tableWriter.GetDeclSecurityTable ().Rows.Sort (
|
|
TableComparers.SecurityDeclaration.Instance);
|
|
th.Sorted |= ((long) 1 << DeclSecurityTable.RId);
|
|
}
|
|
|
|
void CompleteGenericTables ()
|
|
{
|
|
if (m_genericParamStack.Count == 0)
|
|
return;
|
|
|
|
TablesHeap th = m_mdWriter.GetMetadataRoot ().Streams.TablesHeap;
|
|
GenericParamTable gpTable = m_tableWriter.GetGenericParamTable ();
|
|
|
|
m_genericParamStack.Sort (TableComparers.GenericParam.Instance);
|
|
|
|
foreach (GenericParameter gp in m_genericParamStack) {
|
|
GenericParamRow gpRow = m_rowWriter.CreateGenericParamRow (
|
|
(ushort) gp.Owner.GenericParameters.IndexOf (gp),
|
|
gp.Attributes,
|
|
gp.Owner.MetadataToken,
|
|
m_mdWriter.AddString (gp.Name));
|
|
|
|
gpTable.Rows.Add (gpRow);
|
|
gp.MetadataToken = new MetadataToken (TokenType.GenericParam, (uint) gpTable.Rows.Count);
|
|
|
|
if (gp.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (gp.CustomAttributes);
|
|
|
|
if (!gp.HasConstraints)
|
|
continue;
|
|
|
|
GenericParamConstraintTable gpcTable = m_tableWriter.GetGenericParamConstraintTable ();
|
|
|
|
foreach (TypeReference constraint in gp.Constraints) {
|
|
GenericParamConstraintRow gpcRow = m_rowWriter.CreateGenericParamConstraintRow (
|
|
(uint) gpTable.Rows.Count,
|
|
GetTypeDefOrRefToken (constraint));
|
|
|
|
gpcTable.Rows.Add (gpcRow);
|
|
}
|
|
}
|
|
|
|
th.Sorted |= ((long) 1 << GenericParamTable.RId);
|
|
th.Sorted |= ((long) 1 << GenericParamConstraintTable.RId);
|
|
}
|
|
|
|
public override void TerminateModuleDefinition (ModuleDefinition module)
|
|
{
|
|
if (module.Assembly.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (module.Assembly.CustomAttributes);
|
|
if (module.Assembly.HasSecurityDeclarations)
|
|
VisitSecurityDeclarationCollection (module.Assembly.SecurityDeclarations);
|
|
if (module.HasCustomAttributes)
|
|
VisitCustomAttributeCollection (module.CustomAttributes);
|
|
|
|
if (module.ExternTypes.Count > 0)
|
|
VisitExternTypeCollection (module.ExternTypes);
|
|
|
|
CompleteGenericTables ();
|
|
SortTables ();
|
|
|
|
MethodTable mTable = m_tableWriter.GetMethodTable ();
|
|
for (int i = 0; i < m_methodStack.Count; i++) {
|
|
MethodDefinition meth = (MethodDefinition) m_methodStack [i];
|
|
if (meth.HasBody)
|
|
mTable [i].RVA = m_codeWriter.WriteMethodBody (meth);
|
|
}
|
|
|
|
if (m_fieldStack.Count > 0) {
|
|
FieldRVATable frTable = null;
|
|
foreach (FieldDefinition field in m_fieldStack) {
|
|
if (field.InitialValue != null && field.InitialValue.Length > 0) {
|
|
if (frTable == null)
|
|
frTable = m_tableWriter.GetFieldRVATable ();
|
|
|
|
FieldRVARow frRow = m_rowWriter.CreateFieldRVARow (
|
|
m_mdWriter.GetDataCursor (),
|
|
field.MetadataToken.RID);
|
|
|
|
m_mdWriter.AddData (field.InitialValue.Length + 3 & (~3));
|
|
m_mdWriter.AddFieldInitData (field.InitialValue);
|
|
|
|
frTable.Rows.Add (frRow);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_symbolWriter != null)
|
|
m_symbolWriter.Dispose ();
|
|
|
|
if (m_mod.Assembly.EntryPoint != null)
|
|
m_mdWriter.EntryPointToken =
|
|
((uint) TokenType.Method) | GetRidFor (m_mod.Assembly.EntryPoint);
|
|
|
|
m_mod.Image.MetadataRoot.Accept (m_mdWriter);
|
|
}
|
|
|
|
public static ElementType GetCorrespondingType (string fullName)
|
|
{
|
|
switch (fullName) {
|
|
case Constants.Boolean :
|
|
return ElementType.Boolean;
|
|
case Constants.Char :
|
|
return ElementType.Char;
|
|
case Constants.SByte :
|
|
return ElementType.I1;
|
|
case Constants.Int16 :
|
|
return ElementType.I2;
|
|
case Constants.Int32 :
|
|
return ElementType.I4;
|
|
case Constants.Int64 :
|
|
return ElementType.I8;
|
|
case Constants.Byte :
|
|
return ElementType.U1;
|
|
case Constants.UInt16 :
|
|
return ElementType.U2;
|
|
case Constants.UInt32 :
|
|
return ElementType.U4;
|
|
case Constants.UInt64 :
|
|
return ElementType.U8;
|
|
case Constants.Single :
|
|
return ElementType.R4;
|
|
case Constants.Double :
|
|
return ElementType.R8;
|
|
case Constants.String :
|
|
return ElementType.String;
|
|
case Constants.Type :
|
|
return ElementType.Type;
|
|
case Constants.Object :
|
|
return ElementType.Object;
|
|
default:
|
|
return ElementType.Class;
|
|
}
|
|
}
|
|
|
|
byte [] EncodeConstant (ElementType et, object value)
|
|
{
|
|
m_constWriter.Empty ();
|
|
|
|
if (value == null)
|
|
et = ElementType.Class;
|
|
|
|
IConvertible ic = value as IConvertible;
|
|
IFormatProvider fp = CultureInfo.CurrentCulture.NumberFormat;
|
|
|
|
switch (et) {
|
|
case ElementType.Boolean :
|
|
m_constWriter.Write ((byte) (ic.ToBoolean (fp) ? 1 : 0));
|
|
break;
|
|
case ElementType.Char :
|
|
m_constWriter.Write ((ushort) ic.ToChar (fp));
|
|
break;
|
|
case ElementType.I1 :
|
|
m_constWriter.Write (ic.ToSByte (fp));
|
|
break;
|
|
case ElementType.I2 :
|
|
m_constWriter.Write (ic.ToInt16 (fp));
|
|
break;
|
|
case ElementType.I4 :
|
|
m_constWriter.Write (ic.ToInt32 (fp));
|
|
break;
|
|
case ElementType.I8 :
|
|
m_constWriter.Write (ic.ToInt64 (fp));
|
|
break;
|
|
case ElementType.U1 :
|
|
m_constWriter.Write (ic.ToByte (fp));
|
|
break;
|
|
case ElementType.U2 :
|
|
m_constWriter.Write (ic.ToUInt16 (fp));
|
|
break;
|
|
case ElementType.U4 :
|
|
m_constWriter.Write (ic.ToUInt32 (fp));
|
|
break;
|
|
case ElementType.U8 :
|
|
m_constWriter.Write (ic.ToUInt64 (fp));
|
|
break;
|
|
case ElementType.R4 :
|
|
m_constWriter.Write (ic.ToSingle (fp));
|
|
break;
|
|
case ElementType.R8 :
|
|
m_constWriter.Write (ic.ToDouble (fp));
|
|
break;
|
|
case ElementType.String :
|
|
m_constWriter.Write (Encoding.Unicode.GetBytes ((string) value));
|
|
break;
|
|
case ElementType.Class :
|
|
m_constWriter.Write (new byte [4]);
|
|
break;
|
|
default :
|
|
throw new ArgumentException ("Non valid element for a constant");
|
|
}
|
|
|
|
return m_constWriter.ToArray ();
|
|
}
|
|
|
|
public SigType GetSigType (TypeReference type)
|
|
{
|
|
string name = type.FullName;
|
|
|
|
switch (name) {
|
|
case Constants.Void :
|
|
return new SigType (ElementType.Void);
|
|
case Constants.Object :
|
|
return new SigType (ElementType.Object);
|
|
case Constants.Boolean :
|
|
return new SigType (ElementType.Boolean);
|
|
case Constants.String :
|
|
return new SigType (ElementType.String);
|
|
case Constants.Char :
|
|
return new SigType (ElementType.Char);
|
|
case Constants.SByte :
|
|
return new SigType (ElementType.I1);
|
|
case Constants.Byte :
|
|
return new SigType (ElementType.U1);
|
|
case Constants.Int16 :
|
|
return new SigType (ElementType.I2);
|
|
case Constants.UInt16 :
|
|
return new SigType (ElementType.U2);
|
|
case Constants.Int32 :
|
|
return new SigType (ElementType.I4);
|
|
case Constants.UInt32 :
|
|
return new SigType (ElementType.U4);
|
|
case Constants.Int64 :
|
|
return new SigType (ElementType.I8);
|
|
case Constants.UInt64 :
|
|
return new SigType (ElementType.U8);
|
|
case Constants.Single :
|
|
return new SigType (ElementType.R4);
|
|
case Constants.Double :
|
|
return new SigType (ElementType.R8);
|
|
case Constants.IntPtr :
|
|
return new SigType (ElementType.I);
|
|
case Constants.UIntPtr :
|
|
return new SigType (ElementType.U);
|
|
case Constants.TypedReference :
|
|
return new SigType (ElementType.TypedByRef);
|
|
}
|
|
|
|
if (type is GenericParameter) {
|
|
GenericParameter gp = type as GenericParameter;
|
|
int pos = gp.Owner.GenericParameters.IndexOf (gp);
|
|
if (gp.Owner is TypeReference)
|
|
return new VAR (pos);
|
|
else if (gp.Owner is MethodReference)
|
|
return new MVAR (pos);
|
|
else
|
|
throw new ReflectionException ("Unkown generic parameter type");
|
|
} else if (type is GenericInstanceType) {
|
|
GenericInstanceType git = type as GenericInstanceType;
|
|
GENERICINST gi = new GENERICINST ();
|
|
gi.ValueType = git.IsValueType;
|
|
gi.Type = GetTypeDefOrRefToken (git.ElementType);
|
|
gi.Signature = new GenericInstSignature ();
|
|
gi.Signature.Arity = git.GenericArguments.Count;
|
|
gi.Signature.Types = new GenericArg [gi.Signature.Arity];
|
|
for (int i = 0; i < git.GenericArguments.Count; i++)
|
|
gi.Signature.Types [i] = GetGenericArgSig (git.GenericArguments [i]);
|
|
|
|
return gi;
|
|
} else if (type is ArrayType) {
|
|
ArrayType aryType = type as ArrayType;
|
|
if (aryType.IsSizedArray) {
|
|
SZARRAY szary = new SZARRAY ();
|
|
szary.CustomMods = GetCustomMods (aryType.ElementType);
|
|
szary.Type = GetSigType (aryType.ElementType);
|
|
return szary;
|
|
}
|
|
|
|
// not optimized
|
|
ArrayShape shape = new ArrayShape ();
|
|
shape.Rank = aryType.Dimensions.Count;
|
|
shape.NumSizes = 0;
|
|
|
|
for (int i = 0; i < shape.Rank; i++) {
|
|
ArrayDimension dim = aryType.Dimensions [i];
|
|
if (dim.UpperBound > 0)
|
|
shape.NumSizes++;
|
|
}
|
|
|
|
shape.Sizes = new int [shape.NumSizes];
|
|
shape.NumLoBounds = shape.Rank;
|
|
shape.LoBounds = new int [shape.NumLoBounds];
|
|
|
|
for (int i = 0; i < shape.Rank; i++) {
|
|
ArrayDimension dim = aryType.Dimensions [i];
|
|
shape.LoBounds [i] = dim.LowerBound;
|
|
if (dim.UpperBound > 0)
|
|
shape.Sizes [i] = dim.UpperBound - dim.LowerBound + 1;
|
|
}
|
|
|
|
ARRAY ary = new ARRAY ();
|
|
ary.Shape = shape;
|
|
ary.CustomMods = GetCustomMods (aryType.ElementType);
|
|
ary.Type = GetSigType (aryType.ElementType);
|
|
return ary;
|
|
} else if (type is PointerType) {
|
|
PTR p = new PTR ();
|
|
TypeReference elementType = (type as PointerType).ElementType;
|
|
p.Void = elementType.FullName == Constants.Void;
|
|
if (!p.Void) {
|
|
p.CustomMods = GetCustomMods (elementType);
|
|
p.PtrType = GetSigType (elementType);
|
|
}
|
|
return p;
|
|
} else if (type is FunctionPointerType) {
|
|
FNPTR fp = new FNPTR ();
|
|
FunctionPointerType fptr = type as FunctionPointerType;
|
|
|
|
int sentinel = fptr.GetSentinel ();
|
|
if (sentinel < 0)
|
|
fp.Method = GetMethodDefSig (fptr);
|
|
else
|
|
fp.Method = GetMethodRefSig (fptr);
|
|
|
|
return fp;
|
|
} else if (type is TypeSpecification) {
|
|
return GetSigType ((type as TypeSpecification).ElementType);
|
|
} else if (type.IsValueType) {
|
|
VALUETYPE vt = new VALUETYPE ();
|
|
vt.Type = GetTypeDefOrRefToken (type);
|
|
return vt;
|
|
} else {
|
|
CLASS c = new CLASS ();
|
|
c.Type = GetTypeDefOrRefToken (type);
|
|
return c;
|
|
}
|
|
}
|
|
|
|
public GenericArg GetGenericArgSig (TypeReference type)
|
|
{
|
|
GenericArg arg = new GenericArg (GetSigType (type));
|
|
arg.CustomMods = GetCustomMods (type);
|
|
return arg;
|
|
}
|
|
|
|
public CustomMod [] GetCustomMods (TypeReference type)
|
|
{
|
|
ModType modifier = type as ModType;
|
|
if (modifier == null)
|
|
return CustomMod.EmptyCustomMod;
|
|
|
|
ArrayList cmods = new ArrayList ();
|
|
do {
|
|
CustomMod cmod = new CustomMod ();
|
|
cmod.TypeDefOrRef = GetTypeDefOrRefToken (modifier.ModifierType);
|
|
|
|
if (modifier is ModifierOptional)
|
|
cmod.CMOD = CustomMod.CMODType.OPT;
|
|
else if (modifier is ModifierRequired)
|
|
cmod.CMOD = CustomMod.CMODType.REQD;
|
|
|
|
cmods.Add (cmod);
|
|
modifier = modifier.ElementType as ModType;
|
|
} while (modifier != null);
|
|
|
|
return cmods.ToArray (typeof (CustomMod)) as CustomMod [];
|
|
}
|
|
|
|
public Signature GetMemberRefSig (MemberReference member)
|
|
{
|
|
if (member is FieldReference)
|
|
return GetFieldSig (member as FieldReference);
|
|
else
|
|
return GetMemberRefSig (member as MethodReference);
|
|
}
|
|
|
|
public FieldSig GetFieldSig (FieldReference field)
|
|
{
|
|
FieldSig sig = new FieldSig ();
|
|
sig.CallingConvention |= 0x6;
|
|
sig.Field = true;
|
|
sig.CustomMods = GetCustomMods (field.FieldType);
|
|
sig.Type = GetSigType (field.FieldType);
|
|
return sig;
|
|
}
|
|
|
|
Param [] GetParametersSig (ParameterDefinitionCollection parameters)
|
|
{
|
|
Param [] ret = new Param [parameters.Count];
|
|
for (int i = 0; i < ret.Length; i++) {
|
|
ParameterDefinition pDef = parameters [i];
|
|
Param p = new Param ();
|
|
p.CustomMods = GetCustomMods (pDef.ParameterType);
|
|
if (pDef.ParameterType.FullName == Constants.TypedReference)
|
|
p.TypedByRef = true;
|
|
else if (IsByReferenceType (pDef.ParameterType)) {
|
|
p.ByRef = true;
|
|
p.Type = GetSigType (pDef.ParameterType);
|
|
} else
|
|
p.Type = GetSigType (pDef.ParameterType);
|
|
ret [i] = p;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void CompleteMethodSig (IMethodSignature meth, MethodSig sig)
|
|
{
|
|
sig.HasThis = meth.HasThis;
|
|
sig.ExplicitThis = meth.ExplicitThis;
|
|
if (sig.HasThis)
|
|
sig.CallingConvention |= 0x20;
|
|
if (sig.ExplicitThis)
|
|
sig.CallingConvention |= 0x40;
|
|
|
|
if ((meth.CallingConvention & MethodCallingConvention.VarArg) != 0)
|
|
sig.CallingConvention |= 0x5;
|
|
|
|
sig.ParamCount = meth.Parameters.Count;
|
|
sig.Parameters = GetParametersSig (meth.Parameters);
|
|
|
|
RetType rtSig = new RetType ();
|
|
rtSig.CustomMods = GetCustomMods (meth.ReturnType.ReturnType);
|
|
|
|
if (meth.ReturnType.ReturnType.FullName == Constants.Void)
|
|
rtSig.Void = true;
|
|
else if (meth.ReturnType.ReturnType.FullName == Constants.TypedReference)
|
|
rtSig.TypedByRef = true;
|
|
else if (IsByReferenceType (meth.ReturnType.ReturnType)) {
|
|
rtSig.ByRef = true;
|
|
rtSig.Type = GetSigType (meth.ReturnType.ReturnType);
|
|
} else
|
|
rtSig.Type = GetSigType (meth.ReturnType.ReturnType);
|
|
|
|
sig.RetType = rtSig;
|
|
}
|
|
|
|
static bool IsByReferenceType (TypeReference type)
|
|
{
|
|
TypeSpecification ts = type as TypeSpecification;
|
|
while (ts != null) {
|
|
if (ts is ReferenceType)
|
|
return true;
|
|
ts = ts.ElementType as TypeSpecification;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public MethodRefSig GetMethodRefSig (IMethodSignature meth)
|
|
{
|
|
MethodReference methodRef = meth as MethodReference;
|
|
if (methodRef != null && methodRef.GenericParameters.Count > 0)
|
|
return GetMethodDefSig (meth);
|
|
|
|
MethodRefSig methSig = new MethodRefSig ();
|
|
|
|
CompleteMethodSig (meth, methSig);
|
|
|
|
int sentinel = meth.GetSentinel ();
|
|
if (sentinel >= 0)
|
|
methSig.Sentinel = sentinel;
|
|
|
|
if ((meth.CallingConvention & MethodCallingConvention.C) != 0)
|
|
methSig.CallingConvention |= 0x1;
|
|
else if ((meth.CallingConvention & MethodCallingConvention.StdCall) != 0)
|
|
methSig.CallingConvention |= 0x2;
|
|
else if ((meth.CallingConvention & MethodCallingConvention.ThisCall) != 0)
|
|
methSig.CallingConvention |= 0x3;
|
|
else if ((meth.CallingConvention & MethodCallingConvention.FastCall) != 0)
|
|
methSig.CallingConvention |= 0x4;
|
|
|
|
return methSig;
|
|
}
|
|
|
|
public MethodDefSig GetMethodDefSig (IMethodSignature meth)
|
|
{
|
|
MethodDefSig sig = new MethodDefSig ();
|
|
|
|
CompleteMethodSig (meth, sig);
|
|
|
|
MethodReference methodRef = meth as MethodReference;
|
|
if (methodRef != null && methodRef.GenericParameters.Count > 0) {
|
|
sig.CallingConvention |= 0x10;
|
|
sig.GenericParameterCount = methodRef.GenericParameters.Count;
|
|
}
|
|
|
|
return sig;
|
|
}
|
|
|
|
public PropertySig GetPropertySig (PropertyDefinition prop)
|
|
{
|
|
PropertySig ps = new PropertySig ();
|
|
ps.CallingConvention |= 0x8;
|
|
|
|
bool hasThis;
|
|
bool explicitThis;
|
|
MethodCallingConvention mcc;
|
|
ParameterDefinitionCollection parameters = prop.Parameters;
|
|
|
|
MethodDefinition meth;
|
|
if (prop.GetMethod != null)
|
|
meth = prop.GetMethod;
|
|
else if (prop.SetMethod != null)
|
|
meth = prop.SetMethod;
|
|
else
|
|
meth = null;
|
|
|
|
if (meth != null) {
|
|
hasThis = meth.HasThis;
|
|
explicitThis = meth.ExplicitThis;
|
|
mcc = meth.CallingConvention;
|
|
} else {
|
|
hasThis = explicitThis = false;
|
|
mcc = MethodCallingConvention.Default;
|
|
}
|
|
|
|
if (hasThis)
|
|
ps.CallingConvention |= 0x20;
|
|
if (explicitThis)
|
|
ps.CallingConvention |= 0x40;
|
|
|
|
if ((mcc & MethodCallingConvention.VarArg) != 0)
|
|
ps.CallingConvention |= 0x5;
|
|
|
|
int paramCount = parameters != null ? parameters.Count : 0;
|
|
|
|
ps.ParamCount = paramCount;
|
|
ps.Parameters = GetParametersSig (parameters);
|
|
ps.CustomMods = GetCustomMods (prop.PropertyType);
|
|
ps.Type = GetSigType (prop.PropertyType);
|
|
|
|
return ps;
|
|
}
|
|
|
|
public TypeSpec GetTypeSpecSig (TypeReference type)
|
|
{
|
|
TypeSpec ts = new TypeSpec ();
|
|
ts.CustomMods = GetCustomMods (type);
|
|
ts.Type = GetSigType (type);
|
|
return ts;
|
|
}
|
|
|
|
public MethodSpec GetMethodSpecSig (GenericInstanceMethod gim)
|
|
{
|
|
GenericInstSignature gis = new GenericInstSignature ();
|
|
gis.Arity = gim.GenericArguments.Count;
|
|
gis.Types = new GenericArg [gis.Arity];
|
|
for (int i = 0; i < gis.Arity; i++)
|
|
gis.Types [i] = GetGenericArgSig (gim.GenericArguments [i]);
|
|
|
|
return new MethodSpec (gis);
|
|
}
|
|
|
|
static string GetObjectTypeName (object o)
|
|
{
|
|
Type t = o.GetType ();
|
|
return string.Concat (t.Namespace, ".", t.Name);
|
|
}
|
|
|
|
static CustomAttrib.Elem CreateElem (TypeReference type, object value)
|
|
{
|
|
CustomAttrib.Elem elem = new CustomAttrib.Elem ();
|
|
elem.Value = value;
|
|
elem.ElemType = type;
|
|
elem.FieldOrPropType = GetCorrespondingType (type.FullName);
|
|
|
|
switch (elem.FieldOrPropType) {
|
|
case ElementType.Boolean :
|
|
case ElementType.Char :
|
|
case ElementType.R4 :
|
|
case ElementType.R8 :
|
|
case ElementType.I1 :
|
|
case ElementType.I2 :
|
|
case ElementType.I4 :
|
|
case ElementType.I8 :
|
|
case ElementType.U1 :
|
|
case ElementType.U2 :
|
|
case ElementType.U4 :
|
|
case ElementType.U8 :
|
|
elem.Simple = true;
|
|
break;
|
|
case ElementType.String:
|
|
elem.String = true;
|
|
break;
|
|
case ElementType.Type:
|
|
elem.Type = true;
|
|
break;
|
|
case ElementType.Object:
|
|
elem.BoxedValueType = true;
|
|
if (value == null)
|
|
elem.FieldOrPropType = ElementType.String;
|
|
else
|
|
elem.FieldOrPropType = GetCorrespondingType (
|
|
GetObjectTypeName (value));
|
|
break;
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
static CustomAttrib.FixedArg CreateFixedArg (TypeReference type, object value)
|
|
{
|
|
CustomAttrib.FixedArg fa = new CustomAttrib.FixedArg ();
|
|
if (value is object []) {
|
|
fa.SzArray = true;
|
|
object [] values = value as object [];
|
|
TypeReference obj = ((ArrayType) type).ElementType;
|
|
fa.NumElem = (uint) values.Length;
|
|
fa.Elems = new CustomAttrib.Elem [values.Length];
|
|
for (int i = 0; i < values.Length; i++)
|
|
fa.Elems [i] = CreateElem (obj, values [i]);
|
|
} else {
|
|
fa.Elems = new CustomAttrib.Elem [1];
|
|
fa.Elems [0] = CreateElem (type, value);
|
|
}
|
|
|
|
return fa;
|
|
}
|
|
|
|
static CustomAttrib.NamedArg CreateNamedArg (TypeReference type, string name,
|
|
object value, bool field)
|
|
{
|
|
CustomAttrib.NamedArg na = new CustomAttrib.NamedArg ();
|
|
na.Field = field;
|
|
na.Property = !field;
|
|
|
|
na.FieldOrPropName = name;
|
|
na.FieldOrPropType = GetCorrespondingType (type.FullName);
|
|
na.FixedArg = CreateFixedArg (type, value);
|
|
|
|
return na;
|
|
}
|
|
|
|
public static CustomAttrib GetCustomAttributeSig (CustomAttribute ca)
|
|
{
|
|
CustomAttrib cas = new CustomAttrib (ca.Constructor);
|
|
cas.Prolog = CustomAttrib.StdProlog;
|
|
|
|
cas.FixedArgs = new CustomAttrib.FixedArg [ca.Constructor.Parameters.Count];
|
|
|
|
for (int i = 0; i < cas.FixedArgs.Length; i++)
|
|
cas.FixedArgs [i] = CreateFixedArg (
|
|
ca.Constructor.Parameters [i].ParameterType, ca.ConstructorParameters [i]);
|
|
|
|
int nn = ca.Fields.Count + ca.Properties.Count;
|
|
cas.NumNamed = (ushort) nn;
|
|
cas.NamedArgs = new CustomAttrib.NamedArg [nn];
|
|
|
|
if (cas.NamedArgs.Length > 0) {
|
|
int curs = 0;
|
|
foreach (DictionaryEntry entry in ca.Fields) {
|
|
string field = (string) entry.Key;
|
|
cas.NamedArgs [curs++] = CreateNamedArg (
|
|
ca.GetFieldType (field), field, entry.Value, true);
|
|
}
|
|
|
|
foreach (DictionaryEntry entry in ca.Properties) {
|
|
string property = (string) entry.Key;
|
|
cas.NamedArgs [curs++] = CreateNamedArg (
|
|
ca.GetPropertyType (property), property, entry.Value, false);
|
|
}
|
|
}
|
|
|
|
return cas;
|
|
}
|
|
|
|
static MarshalSig GetMarshalSig (MarshalSpec mSpec)
|
|
{
|
|
MarshalSig ms = new MarshalSig (mSpec.NativeIntrinsic);
|
|
|
|
if (mSpec is ArrayMarshalSpec) {
|
|
ArrayMarshalSpec amd = mSpec as ArrayMarshalSpec;
|
|
MarshalSig.Array ar = new MarshalSig.Array ();
|
|
ar.ArrayElemType = amd.ElemType;
|
|
ar.NumElem = amd.NumElem;
|
|
ar.ParamNum = amd.ParamNum;
|
|
ar.ElemMult = amd.ElemMult;
|
|
ms.Spec = ar;
|
|
} else if (mSpec is CustomMarshalerSpec) {
|
|
CustomMarshalerSpec cmd = mSpec as CustomMarshalerSpec;
|
|
MarshalSig.CustomMarshaler cm = new MarshalSig.CustomMarshaler ();
|
|
cm.Guid = cmd.Guid.ToString ();
|
|
cm.UnmanagedType = cmd.UnmanagedType;
|
|
cm.ManagedType = cmd.ManagedType;
|
|
cm.Cookie = cmd.Cookie;
|
|
ms.Spec = cm;
|
|
} else if (mSpec is FixedArraySpec) {
|
|
FixedArraySpec fad = mSpec as FixedArraySpec;
|
|
MarshalSig.FixedArray fa = new MarshalSig.FixedArray ();
|
|
fa.ArrayElemType = fad.ElemType;
|
|
fa.NumElem = fad.NumElem;
|
|
ms.Spec = fa;
|
|
} else if (mSpec is FixedSysStringSpec) {
|
|
MarshalSig.FixedSysString fss = new MarshalSig.FixedSysString ();
|
|
fss.Size = (mSpec as FixedSysStringSpec).Size;
|
|
ms.Spec = fss;
|
|
} else if (mSpec is SafeArraySpec) {
|
|
MarshalSig.SafeArray sa = new MarshalSig.SafeArray ();
|
|
sa.ArrayElemType = (mSpec as SafeArraySpec).ElemType;
|
|
ms.Spec = sa;
|
|
}
|
|
|
|
return ms;
|
|
}
|
|
|
|
public void WriteSymbols (ModuleDefinition module)
|
|
{
|
|
if (!m_saveSymbols)
|
|
return;
|
|
|
|
if (m_asmOutput == null)
|
|
m_asmOutput = module.Assembly.Name.Name + "." + (module.Assembly.Kind == AssemblyKind.Dll ? "dll" : "exe");
|
|
|
|
if (m_symbolWriter == null)
|
|
m_symbolWriter = SymbolStoreHelper.GetWriter (module, m_asmOutput);
|
|
|
|
foreach (TypeDefinition type in module.Types) {
|
|
if (type.HasMethods) {
|
|
foreach (MethodDefinition method in type.Methods)
|
|
WriteSymbols (method);
|
|
}
|
|
if (type.HasConstructors) {
|
|
foreach (MethodDefinition ctor in type.Constructors)
|
|
WriteSymbols (ctor);
|
|
}
|
|
}
|
|
|
|
m_symbolWriter.Dispose ();
|
|
}
|
|
|
|
void WriteSymbols (MethodDefinition meth)
|
|
{
|
|
if (!meth.HasBody)
|
|
return;
|
|
|
|
m_symbolWriter.Write (meth.Body);
|
|
}
|
|
}
|
|
}
|