// // 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 // 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); } } }