// Copyright © Microsoft Corporation. // This source file is subject to the Microsoft Permissive License. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. // All other rights reserved. #if !NoWriter using System; using System.Collections; #if CCINamespace using Microsoft.Cci.Metadata; #else using System.Compiler.Metadata; #endif using System.Diagnostics; using System.IO; using System.Globalization; using System.Runtime.InteropServices; using System.Security; #if !ROTOR using System.Security.Cryptography; #endif using System.Text; #if CCINamespace namespace Microsoft.Cci{ #else namespace System.Compiler { #endif #if !ROTOR [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B01FAFEB-C450-3A4D-BEEC-B4CEEC01E006"), SuppressUnmanagedCodeSecurity] interface ISymUnmanagedDocumentWriter { void SetSource(uint sourceSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] source); void SetCheckSum(ref Guid algorithmId, uint checkSumSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] checkSum); }; [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2DE91396-3844-3B1D-8E91-41C24FD672EA"), SuppressUnmanagedCodeSecurity] interface ISymUnmanagedWriter { ISymUnmanagedDocumentWriter DefineDocument(string url, ref Guid language, ref Guid languageVendor, ref Guid documentType); void SetUserEntryPoint(uint entryMethod); void OpenMethod(uint method); void CloseMethod(); uint OpenScope(uint startOffset); void CloseScope(uint endOffset); void SetScopeRange(uint scopeID, uint startOffset, uint endOffset); void DefineLocalVariable(string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint startOffset, uint endOffset); void DefineParameter(string name, uint attributes, uint sequence, uint addrKind, uint addr1, uint addr2, uint addr3); void DefineField(uint parent, string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint addr3); void DefineGlobalVariable(string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint addr3); void Close(); void SetSymAttribute(uint parent, string name, uint cData, IntPtr signature); void OpenNamespace(string name); void CloseNamespace(); void UsingNamespace(string fullName); void SetMethodSourceRange(ISymUnmanagedDocumentWriter startDoc, uint startLine, uint startColumn, object endDoc, uint endLine, uint endColumn); void Initialize([MarshalAs(UnmanagedType.IUnknown)]object emitter, string filename, [MarshalAs(UnmanagedType.IUnknown)]object pIStream, bool fFullBuild); void GetDebugInfo(ref ImageDebugDirectory pIDD, uint cData, out uint pcData, IntPtr data); void DefineSequencePoints(ISymUnmanagedDocumentWriter document, uint spCount, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] offsets, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] lines, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] columns, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] endLines, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] endColumns); void RemapToken(uint oldToken, uint newToken); void Initialize2([MarshalAs(UnmanagedType.IUnknown)]object emitter, string tempfilename, [MarshalAs(UnmanagedType.IUnknown)]object pIStream, bool fFullBuild, string finalfilename); void DefineConstant(string name, object value, uint cSig, IntPtr signature); } struct ImageDebugDirectory { internal int Characteristics; internal int TimeDateStamp; internal short MajorVersion; internal short MinorVersion; internal int Type; internal int SizeOfData; internal int AddressOfRawData; internal int PointerToRawData; public ImageDebugDirectory(bool zeroFill) { this.Characteristics = 0; this.TimeDateStamp = 0; this.MajorVersion = 0; this.MinorVersion = 0; this.Type = 0; this.SizeOfData = 0; this.AddressOfRawData = 0; this.PointerToRawData = 0; } } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("BA3FEE4C-ECB9-4e41-83B7-183FA41CD859")] unsafe public interface IMetaDataEmit { void SetModuleProps(string szName); void Save(string szFile, uint dwSaveFlags); void SaveToStream(void* pIStream, uint dwSaveFlags); uint GetSaveSize(uint fSave); uint DefineTypeDef(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements); uint DefineNestedType(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements, uint tdEncloser); void SetHandler([MarshalAs(UnmanagedType.IUnknown), In]object pUnk); uint DefineMethod(uint td, char* zName, uint dwMethodFlags, byte* pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags); void DefineMethodImpl(uint td, uint tkBody, uint tkDecl); uint DefineTypeRefByName(uint tkResolutionScope, char* szName); uint DefineImportType(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint tdImport, IntPtr pAssemEmit); uint DefineMemberRef(uint tkImport, string szName, byte* pvSigBlob, uint cbSigBlob); uint DefineImportMember(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent); uint DefineEvent(uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods); void SetClassLayout(uint td, uint dwPackSize, COR_FIELD_OFFSET* rFieldOffsets, uint ulClassSize); void DeleteClassLayout(uint td); void SetFieldMarshal(uint tk, byte* pvNativeType, uint cbNativeType); void DeleteFieldMarshal(uint tk); uint DefinePermissionSet(uint tk, uint dwAction, void* pvPermission, uint cbPermission); void SetRVA(uint md, uint ulRVA); uint GetTokenFromSig(byte* pvSig, uint cbSig); uint DefineModuleRef(string szName); void SetParent(uint mr, uint tk); uint GetTokenFromTypeSpec(byte* pvSig, uint cbSig); void SaveToMemory(void* pbData, uint cbData); uint DefineUserString(string szString, uint cchString); void DeleteToken(uint tkObj); void SetMethodProps(uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags); void SetTypeDefProps(uint td, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements); void SetEventProps(uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods); uint SetPermissionSetProps(uint tk, uint dwAction, void* pvPermission, uint cbPermission); void DefinePinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL); void SetPinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL); void DeletePinvokeMap(uint tk); uint DefineCustomAttribute(uint tkObj, uint tkType, void* pCustomAttribute, uint cbCustomAttribute); void SetCustomAttributeValue(uint pcv, void* pCustomAttribute, uint cbCustomAttribute); uint DefineField(uint td, string szName, uint dwFieldFlags, byte* pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, void* pValue, uint cchValue); uint DefineProperty(uint td, string szProperty, uint dwPropFlags, byte* pvSig, uint cbSig, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods); uint DefineParam(uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue); void SetFieldProps(uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue); void SetPropertyProps(uint pr, uint dwPropFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods); void SetParamProps(uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue); uint DefineSecurityAttributeSet(uint tkObj, IntPtr rSecAttrs, uint cSecAttrs); void ApplyEditAndContinue([MarshalAs(UnmanagedType.IUnknown)]object pImport); uint TranslateSigWithScope(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport import, byte* pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, byte* pvTranslatedSig, uint cbTranslatedSigMax); void SetMethodImplFlags(uint md, uint dwImplFlags); void SetFieldRVA(uint fd, uint ulRVA); void Merge(IMetaDataImport pImport, IntPtr pHostMapToken, [MarshalAs(UnmanagedType.IUnknown)]object pHandler); void MergeEnd(); } public struct COR_FIELD_OFFSET { public uint ridOfField; public uint ulOffset; } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")] unsafe public interface IMetaDataImport { [PreserveSig] void CloseEnum(uint hEnum); uint CountEnum(uint hEnum); void ResetEnum(uint hEnum, uint ulPos); uint EnumTypeDefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeDefs, uint cMax); uint EnumInterfaceImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rImpls, uint cMax); uint EnumTypeRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeRefs, uint cMax); uint FindTypeDefByName(string szTypeDef, uint tkEnclosingClass); Guid GetScopeProps(StringBuilder szName, uint cchName, out uint pchName); uint GetModuleFromScope(); uint GetTypeDefProps(uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, IntPtr pdwTypeDefFlags); uint GetInterfaceImplProps(uint iiImpl, out uint pClass); uint GetTypeRefProps(uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName); uint ResolveTypeRef(uint tr, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIScope); uint EnumMembers(ref uint phEnum, uint cl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMembers, uint cMax); uint EnumMembersWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMembers, uint cMax); uint EnumMethods(ref uint phEnum, uint cl, uint* rMethods, uint cMax); uint EnumMethodsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethods, uint cMax); uint EnumFields(ref uint phEnum, uint cl, uint* rFields, uint cMax); uint EnumFieldsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rFields, uint cMax); uint EnumParams(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rParams, uint cMax); uint EnumMemberRefs(ref uint phEnum, uint tkParent, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMemberRefs, uint cMax); uint EnumMethodImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodBody, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodDecl, uint cMax); uint EnumPermissionSets(ref uint phEnum, uint tk, uint dwActions, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rPermission, uint cMax); uint FindMember(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob); uint FindMethod(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob); uint FindField(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob); uint FindMemberRef(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob); uint GetMethodProps(uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA); unsafe uint GetMemberRefProps(uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out byte* ppvSigBlob); uint EnumProperties(ref uint phEnum, uint td, uint* rProperties, uint cMax); uint EnumEvents(ref uint phEnum, uint td, uint* rEvents, uint cMax); uint GetEventProps(uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 11)] uint[] rmdOtherMethod, uint cMax); uint EnumMethodSemantics(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rEventProp, uint cMax); uint GetMethodSemantics(uint mb, uint tkEventProp); uint GetClassLayout(uint td, out uint pdwPackSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] COR_FIELD_OFFSET[] rFieldOffset, uint cMax, out uint pcFieldOffset); unsafe uint GetFieldMarshal(uint tk, out byte* ppvNativeType); uint GetRVA(uint tk, out uint pulCodeRVA); unsafe uint GetPermissionSetProps(uint pm, out uint pdwAction, out void* ppvPermission); unsafe uint GetSigFromToken(uint mdSig, out byte* ppvSig); uint GetModuleRefProps(uint mur, StringBuilder szName, uint cchName); uint EnumModuleRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rModuleRefs, uint cmax); unsafe uint GetTypeSpecFromToken(uint typespec, out byte* ppvSig); uint GetNameFromToken(uint tk); uint EnumUnresolvedMethods(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rMethods, uint cMax); uint GetUserString(uint stk, StringBuilder szString, uint cchString); uint GetPinvokeMap(uint tk, out uint pdwMappingFlags, StringBuilder szImportName, uint cchImportName, out uint pchImportName); uint EnumSignatures(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rSignatures, uint cmax); uint EnumTypeSpecs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeSpecs, uint cmax); uint EnumUserStrings(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rStrings, uint cmax); [PreserveSig] int GetParamForMethodIndex(uint md, uint ulParamSeq, out uint pParam); uint EnumCustomAttributes(ref uint phEnum, uint tk, uint tkType, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rCustomAttributes, uint cMax); uint GetCustomAttributeProps(uint cv, out uint ptkObj, out uint ptkType, out void* ppBlob); uint FindTypeRef(uint tkResolutionScope, string szName); uint GetMemberProps(uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, out byte* ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out void* ppValue); uint GetFieldProps(uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, out byte* ppvSigBlob, out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out void* ppValue); uint GetPropertyProps(uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, out byte* ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out void* ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, out uint pmdGetter, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 14)] uint[] rmdOtherMethod, uint cMax); uint GetParamProps(uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, out uint pdwAttr, out uint pdwCPlusTypeFlag, out void* ppValue); uint GetCustomAttributeByName(uint tkObj, string szName, out void* ppData); [PreserveSig] [return: MarshalAs(UnmanagedType.Bool)] bool IsValidToken(uint tk); uint GetNestedClassProps(uint tdNestedClass); uint GetNativeCallConvFromSig(void* pvSig, uint cbSig); int IsGlobal(uint pd); } [SuppressUnmanagedCodeSecurity] internal sealed class Ir2md : IMetaDataEmit, IMetaDataImport { #else internal sealed class Ir2md{ #endif private AssemblyNode assembly; private Module/*!*/ module; private MetadataWriter/*!*/ writer; private bool UseGenerics = false; private bool StripOptionalModifiersFromLocals { get { return this.module.StripOptionalModifiersFromLocals; } } private BinaryWriter/*!*/ blobHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode); #if WHIDBEYwithGenerics || WHIDBEYwithGenericsAndIEqualityComparer private Hashtable/*!*/ blobHeapIndex = new Hashtable(new ByteArrayKeyComparer()); #else private Hashtable/*!*/ blobHeapIndex = new Hashtable(new ByteArrayHasher(), new ByteArrayComparer()); #endif private Hashtable/*!*/ blobHeapStringIndex = new Hashtable(); private NodeList/*!*/ nodesWithCustomAttributes = new NodeList(); private int customAttributeCount = 0; private NodeList/*!*/ nodesWithSecurityAttributes = new NodeList(); private int securityAttributeCount = 0; private NodeList/*!*/ constantTableEntries = new NodeList(); private TrivialHashtable/*!*/ assemblyRefIndex = new TrivialHashtable(); private AssemblyReferenceList/*!*/ assemblyRefEntries = new AssemblyReferenceList(); private TypeNodeList/*!*/ classLayoutEntries = new TypeNodeList(); private TrivialHashtable/*!*/ documentMap = new TrivialHashtable(); private TrivialHashtable/*!*/ eventIndex = new TrivialHashtable(); private EventList/*!*/ eventEntries = new EventList(); private TrivialHashtable/*!*/ eventMapIndex = new TrivialHashtable(); private EventList/*!*/ eventMapEntries = new EventList(); private TrivialHashtable/*!*/ exceptionBlock = new TrivialHashtable(); private TrivialHashtable/*!*/ fieldIndex = new TrivialHashtable(); private FieldList/*!*/ fieldEntries = new FieldList(); private FieldList/*!*/ fieldLayoutEntries = new FieldList(); private FieldList/*!*/ fieldRvaEntries = new FieldList(); private Hashtable/*!*/ fileTableIndex = new Hashtable(); private ModuleList/*!*/ fileTableEntries = new ModuleList(); private Hashtable/*!*/ genericParamIndex = new Hashtable(); private MemberList/*!*/ genericParamEntries = new MemberList(); private TypeNodeList/*!*/ genericParameters = new TypeNodeList(); private TypeNodeList/*!*/ genericParamConstraintEntries = new TypeNodeList(); private ArrayList/*!*/ guidEntries = new ArrayList(); private Hashtable/*!*/ guidIndex = new Hashtable(); private MethodList/*!*/ implMapEntries = new MethodList(); private TypeNodeList/*!*/ interfaceEntries = new TypeNodeList(); private NodeList/*!*/ marshalEntries = new NodeList(); private TrivialHashtable/*!*/ memberRefIndex = new TrivialHashtable(); private MemberList/*!*/ memberRefEntries = new MemberList(); private TrivialHashtable/*!*/ methodBodiesHeapIndex = new TrivialHashtable(); private BinaryWriter/*!*/ methodBodiesHeap = new BinaryWriter(new MemoryStream()); private BinaryWriter/*!*/ methodBodyHeap; private MethodList/*!*/ methodEntries = new MethodList(); private TrivialHashtable/*!*/ methodIndex = new TrivialHashtable(); private MethodList/*!*/ methodImplEntries = new MethodList(); private MethodInfo/*!*/ methodInfo; private Method currentMethod; private MemberList/*!*/ methodSemanticsEntries = new MemberList(); private MethodList/*!*/ methodSpecEntries = new MethodList(); private Hashtable/*!*/ methodSpecIndex = new Hashtable(); private ModuleReferenceList/*!*/ moduleRefEntries = new ModuleReferenceList(); private Hashtable/*!*/ moduleRefIndex = new Hashtable(); private TypeNodeList/*!*/ nestedClassEntries = new TypeNodeList(); private TrivialHashtable/*!*/ paramIndex = new TrivialHashtable(); private ParameterList/*!*/ paramEntries = new ParameterList(); private TrivialHashtable/*!*/ propertyIndex = new TrivialHashtable(); private PropertyList/*!*/ propertyEntries = new PropertyList(); private TrivialHashtable/*!*/ propertyMapIndex = new TrivialHashtable(); private PropertyList/*!*/ propertyMapEntries = new PropertyList(); private BinaryWriter/*!*/ resourceDataHeap = new BinaryWriter(new MemoryStream()); private BinaryWriter/*!*/ sdataHeap = new BinaryWriter(new MemoryStream()); #if !ROTOR private ISymUnmanagedWriter symWriter = null; #endif private int stackHeight; private int stackHeightMax; private int stackHeightExitTotal; private ArrayList/*!*/ standAloneSignatureEntries = new ArrayList(); private BinaryWriter/*!*/ stringHeap = new BinaryWriter(new MemoryStream()); private Hashtable/*!*/ stringHeapIndex = new Hashtable(); private BinaryWriter/*!*/ tlsHeap = new BinaryWriter(new MemoryStream()); private TrivialHashtable/*!*/ typeDefIndex = new TrivialHashtable(); private TypeNodeList/*!*/ typeDefEntries = new TypeNodeList(); private TrivialHashtable/*!*/ typeRefIndex = new TrivialHashtable(); private TypeNodeList/*!*/ typeRefEntries = new TypeNodeList(); private TrivialHashtable/*!*/ typeSpecIndex = new TrivialHashtable(); private TypeNodeList/*!*/ typeSpecEntries = new TypeNodeList(); private TrivialHashtable/*!*/ typeParameterNumber = new TrivialHashtable(); private BinaryWriter/*!*/ userStringHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode); private Hashtable/*!*/ userStringHeapIndex = new Hashtable(); private byte[] PublicKey; internal Ir2md(Module/*!*/ module) { this.assembly = module as AssemblyNode; this.module = module; //^ base(); this.blobHeap.Write((byte)0); this.stringHeap.Write((byte)0); this.userStringHeap.Write((byte)0); if (this.assembly != null) this.PublicKey = this.assembly.PublicKeyOrToken; } internal static void WritePE(Module/*!*/ module, string debugSymbolsLocation, BinaryWriter/*!*/ writer) { Ir2md ir2md = new Ir2md(module); try { ir2md.SetupMetadataWriter(debugSymbolsLocation); MetadataWriter mdWriter = ir2md.writer; mdWriter.WritePE(writer); } finally { #if !ROTOR if (ir2md.symWriter != null) ir2md.symWriter.Close(); #endif ir2md.assembly = null; ir2md.assemblyRefEntries = null; ir2md.assemblyRefIndex = null; ir2md.blobHeap = null; ir2md.blobHeapIndex = null; ir2md.blobHeapStringIndex = null; ir2md.classLayoutEntries = null; ir2md.constantTableEntries = null; ir2md.documentMap = null; ir2md.eventEntries = null; ir2md.eventIndex = null; ir2md.eventMapEntries = null; ir2md.eventMapIndex = null; ir2md.exceptionBlock = null; ir2md.fieldEntries = null; ir2md.fieldIndex = null; ir2md.fieldLayoutEntries = null; ir2md.fieldRvaEntries = null; ir2md.fileTableEntries = null; ir2md.fileTableIndex = null; ir2md.genericParamConstraintEntries = null; ir2md.genericParamEntries = null; ir2md.genericParameters = null; ir2md.genericParamIndex = null; ir2md.guidEntries = null; ir2md.guidIndex = null; ir2md.implMapEntries = null; ir2md.interfaceEntries = null; ir2md.marshalEntries = null; ir2md.memberRefEntries = null; ir2md.memberRefIndex = null; ir2md.methodBodiesHeap = null; ir2md.methodBodiesHeapIndex = null; ir2md.methodBodyHeap = null; ir2md.methodEntries = null; ir2md.methodImplEntries = null; ir2md.methodIndex = null; ir2md.methodInfo = null; ir2md.currentMethod = null; ir2md.methodSemanticsEntries = null; ir2md.methodSpecEntries = null; ir2md.methodSpecIndex = null; ir2md.module = null; ir2md.moduleRefEntries = null; ir2md.moduleRefIndex = null; ir2md.nestedClassEntries = null; ir2md.nodesWithCustomAttributes = null; ir2md.nodesWithSecurityAttributes = null; ir2md.paramEntries = null; ir2md.paramIndex = null; ir2md.propertyEntries = null; ir2md.propertyIndex = null; ir2md.propertyMapEntries = null; ir2md.propertyMapIndex = null; ir2md.PublicKey = null; ir2md.resourceDataHeap = null; ir2md.sdataHeap = null; ir2md.standAloneSignatureEntries = null; ir2md.stringHeap = null; ir2md.stringHeapIndex = null; #if !ROTOR ir2md.symWriter = null; #endif ir2md.tlsHeap = null; ir2md.typeDefEntries = null; ir2md.typeDefIndex = null; ir2md.typeParameterNumber = null; ir2md.typeRefEntries = null; ir2md.typeRefIndex = null; ir2md.typeSpecEntries = null; ir2md.typeSpecIndex = null; ir2md.unspecializedFieldFor = null; ir2md.unspecializedMethodFor = null; ir2md.userStringHeap = null; ir2md.userStringHeapIndex = null; ir2md.writer = null; ir2md = null; } } private static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); private static Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046"); [ComImport(), Guid("00000001-0000-0000-C000-000000000046"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] interface IClassFactory { int CreateInstance( [In, MarshalAs(UnmanagedType.Interface)] object unused, [In] ref Guid refiid, [MarshalAs(UnmanagedType.Interface)] out Object ppunk); int LockServer( int fLock); } delegate int GetClassObjectDelegate([In] ref Guid refclsid, [In] ref Guid refiid, [MarshalAs(UnmanagedType.Interface)] out IClassFactory ppUnk); [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] private static extern int LoadLibrary(string lpFileName); [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] private static extern GetClassObjectDelegate GetProcAddress(int hModule, string lpProcName); private object CrossCompileActivate(string server, Guid guid) { // Poor man's version of Activator.CreateInstance or CoCreate object o = null; int hmod = LoadLibrary(server); if (hmod != 0) { GetClassObjectDelegate del = GetProcAddress(hmod, "DllGetClassObject"); if (del != null) { IClassFactory icf; int hr = del(ref guid, ref IID_IClassFactory, out icf); if (hr == 0 && icf != null) { object temp = null; hr = icf.CreateInstance(null, ref IID_IUnknown, out temp); if (hr == 0) o = temp; } } } return o; } private void SetupMetadataWriter(string debugSymbolsLocation) { Version v = TargetPlatform.TargetVersion; this.UseGenerics = TargetPlatform.UseGenerics; #if !ROTOR if (debugSymbolsLocation != null) { // If targeting RTM (Version.Major = 1 and Version.Minor = 0) // then use Symwriter.pdb as ProgID else use CorSymWriter_SxS // (Note that RTM version 1.0.3705 has Assembly version 1.0.3300, // hence the <= 3705 expression. This also leaves room for RTM SP releases // with slightly different build numbers). Type t = null; if (v.Major == 1 && v.Minor == 0 && v.Build <= 3705) { try { t = Type.GetTypeFromProgID("Symwriter.pdb", false); this.symWriter = (ISymUnmanagedWriter)Activator.CreateInstance(t); if (this.symWriter != null) this.symWriter.Initialize(this, debugSymbolsLocation, null, true); } catch (Exception) { t = null; this.symWriter = null; } } if (t == null) { Debug.Assert(this.symWriter == null); t = Type.GetTypeFromProgID("CorSymWriter_SxS", false); if (t != null) { Guid guid = t.GUID; // If the compiler was built with Whidbey, then mscoree will pick a matching // diasymreader.dll out of the Whidbey directory. But if we are cross- // compiling, this is *NOT* what we want. Instead, we want to override // the shim's logic and explicitly pick a diasymreader.dll from the place // that matches the version of the output file we are emitting. This is // strictly illegal by the CLR's rules. However, the CLR does not yet // support cross-compilation, so we have little choice. if (!UseGenerics) { Version vcompiler = typeof(object).Assembly.GetName().Version; if (vcompiler.Major >= 2) { // This is the only cross-compilation case we currently support. string server = Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "..\\v1.1.4322\\diasymreader.dll"); object o = CrossCompileActivate(server, guid); this.symWriter = (ISymUnmanagedWriter)o; } } if (this.symWriter == null) { this.symWriter = (ISymUnmanagedWriter)Activator.CreateInstance(t); } if (this.symWriter != null) this.symWriter.Initialize(this, debugSymbolsLocation, null, true); } else { throw new DebugSymbolsCouldNotBeWrittenException(); } } } #endif //Visit the module, building lists etc. this.VisitModule(this.module); //Use the lists to populate the tables in the metadata writer #if !ROTOR MetadataWriter writer = this.writer = new MetadataWriter(this.symWriter); #else MetadataWriter writer = this.writer = new MetadataWriter(); #endif writer.UseGenerics = this.UseGenerics; if (module.EntryPoint != null) { writer.entryPointToken = this.GetMethodToken(module.EntryPoint); #if !ROTOR if (this.symWriter != null) this.symWriter.SetUserEntryPoint((uint)writer.entryPointToken); #endif } writer.moduleKind = module.Kind; writer.peKind = module.PEKind; writer.TrackDebugData = module.TrackDebugData; writer.fileAlignment = module.FileAlignment; if (writer.fileAlignment < 512) writer.fileAlignment = 512; writer.PublicKey = this.PublicKey; if (this.assembly != null) this.PopulateAssemblyTable(); this.PopulateClassLayoutTable(); this.PopulateConstantTable(); this.PopulateGenericParamTable(); //Needs to happen before PopulateCustomAttributeTable since it the latter refers to indices in the sorted table this.PopulateCustomAttributeTable(); this.PopulateDeclSecurityTable(); this.PopulateEventMapTable(); this.PopulateEventTable(); this.PopulateExportedTypeTable(); this.PopulateFieldTable(); this.PopulateFieldLayoutTable(); this.PopulateFieldRVATable(); this.PopulateManifestResourceTable(); //This needs to happen before PopulateFileTable because resources are not visited separately this.PopulateFileTable(); this.PopulateGenericParamConstraintTable(); this.PopulateImplMapTable(); this.PopulateInterfaceImplTable(); this.PopulateMarshalTable(); this.PopulateMethodTable(); this.PopulateMethodImplTable(); this.PopulateMemberRefTable(); this.PopulateMethodSemanticsTable(); this.PopulateMethodSpecTable(); this.PopulateModuleTable(); this.PopulateModuleRefTable(); this.PopulateNestedClassTable(); this.PopulateParamTable(); this.PopulatePropertyTable(); this.PopulatePropertyMapTable(); this.PopulateStandAloneSigTable(); this.PopulateTypeDefTable(); this.PopulateTypeRefTable(); this.PopulateTypeSpecTable(); this.PopulateGuidTable(); this.PopulateAssemblyRefTable(); this.writer.BlobHeap = (MemoryStream)this.blobHeap.BaseStream; //this.blobHeap = null; this.writer.SdataHeap = (MemoryStream)this.sdataHeap.BaseStream; //this.sdataHeap = null; this.writer.TlsHeap = (MemoryStream)this.tlsHeap.BaseStream; //this.tlsHeap = null; this.writer.StringHeap = (MemoryStream)this.stringHeap.BaseStream; //this.stringHeap = null; this.writer.UserstringHeap = (MemoryStream)this.userStringHeap.BaseStream; //this.userStringHeap = null; this.writer.MethodBodiesHeap = (MemoryStream)this.methodBodiesHeap.BaseStream; //this.methodBodiesHeap = null; this.writer.ResourceDataHeap = (MemoryStream)this.resourceDataHeap.BaseStream; //this.resourceDataHeap = null; this.writer.Win32Resources = this.module.Win32Resources; } int GetAssemblyRefIndex(AssemblyNode/*!*/ assembly) { if (assembly.Location == "unknown:location") throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.UnresolvedAssemblyReferenceNotAllowed, assembly.Name)); Object index = this.assemblyRefIndex[assembly.UniqueKey]; if (index == null) { index = this.assemblyRefEntries.Count + 1; AssemblyReference aref = new AssemblyReference(assembly); if (this.module.UsePublicKeyTokensForAssemblyReferences) { aref.PublicKeyOrToken = aref.PublicKeyToken; aref.HashValue = null; aref.Flags = aref.Flags & ~AssemblyFlags.PublicKey; } this.assemblyRefEntries.Add(aref); this.assemblyRefIndex[assembly.UniqueKey] = index; } return (int)index; } int GetBlobIndex(ExpressionList expressions, ParameterList parameters) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); this.WriteCustomAttributeSignature(expressions, parameters, false, signature); byte[] sigBytes = sig.ToArray(); int length = sigBytes.Length; int index = (int)this.blobHeap.BaseStream.Position; Ir2md.WriteCompressedInt(this.blobHeap, length); this.blobHeap.BaseStream.Write(sigBytes, 0, length); return index; } void WriteCustomAttributeSignature(ExpressionList expressions, ParameterList parameters, bool onlyWriteNamedArguments, BinaryWriter signature) { int n = parameters == null ? 0 : parameters.Count; int m = expressions == null ? 0 : expressions.Count; Debug.Assert(m >= n); int numNamed = m > n ? m - n : 0; if (onlyWriteNamedArguments) { Ir2md.WriteCompressedInt(signature, numNamed); } else { signature.Write((short)1); if (parameters != null && expressions != null) { for (int i = 0; i < n; i++) { Parameter p = parameters[i]; Expression e = expressions[i]; if (p == null || e == null) continue; Literal l = e as Literal; if (l == null) { Debug.Assert(false); continue; } this.WriteCustomAttributeLiteral(signature, l, p.Type == CoreSystemTypes.Object); } } signature.Write((short)numNamed); } if (expressions != null) { for (int i = n; i < m; i++) { Expression e = expressions[i]; NamedArgument narg = e as NamedArgument; if (narg == null) { Debug.Assert(false); continue; } signature.Write((byte)(narg.IsCustomAttributeProperty ? 0x54 : 0x53)); if (narg.ValueIsBoxed) signature.Write((byte)ElementType.BoxedEnum); else if (narg.Value.Type is EnumNode) { signature.Write((byte)ElementType.Enum); this.WriteSerializedTypeName(signature, narg.Value.Type); } else if (narg.Value.Type == CoreSystemTypes.Type) signature.Write((byte)ElementType.Type); else if (narg.Value.Type is ArrayType) { ArrayType arrT = (ArrayType)narg.Value.Type; if (arrT.ElementType == CoreSystemTypes.Type) { signature.Write((byte)ElementType.SzArray); signature.Write((byte)ElementType.Type); } else this.WriteTypeSignature(signature, narg.Value.Type); } else this.WriteTypeSignature(signature, narg.Value.Type); signature.Write(narg.Name.Name, false); this.WriteCustomAttributeLiteral(signature, (Literal)narg.Value, narg.ValueIsBoxed); } } } int GetBlobIndex(byte[]/*!*/ blob) { object indexOb = this.blobHeapIndex[blob]; if (indexOb != null) return (int)indexOb; int index = (int)this.blobHeap.BaseStream.Position; int length = blob.Length; Ir2md.WriteCompressedInt(this.blobHeap, length); this.blobHeap.BaseStream.Write(blob, 0, length); this.blobHeapIndex[blob] = index; return index; } int GetBlobIndex(string/*!*/ str) { object indexOb = this.blobHeapStringIndex[str]; if (indexOb != null) return (int)indexOb; int index = (int)this.blobHeap.BaseStream.Position; this.blobHeap.Write((string)str); this.blobHeapStringIndex[str] = index; return index; } int GetBlobIndex(Field/*!*/ field) { if (field != null && field.DeclaringType != null && field.DeclaringType.Template != null && field.DeclaringType.Template.IsGeneric) field = this.GetUnspecializedField(field); MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); signature.Write((byte)0x6); TypeNode fieldType = field.Type; #if ExtendedRuntime if (field.HasOutOfBandContract) fieldType = TypeNode.DeepStripModifiers(fieldType, null, SystemTypes.NonNullType); #endif if (fieldType == null) { Debug.Fail(""); fieldType = SystemTypes.Object; } this.WriteTypeSignature(signature, fieldType, true); return this.GetBlobIndex(sig.ToArray()); } int GetBlobIndex(MarshallingInformation/*!*/ marshallingInformation) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); signature.Write((byte)marshallingInformation.NativeType); switch (marshallingInformation.NativeType) { case NativeType.SafeArray: signature.Write((byte)marshallingInformation.ElementType); if (marshallingInformation.Class != null && marshallingInformation.Class.Length > 0) signature.Write(marshallingInformation.Class, false); break; case NativeType.LPArray: signature.Write((byte)marshallingInformation.ElementType); if (marshallingInformation.ParamIndex >= 0 || marshallingInformation.ElementSize > 0) { if (marshallingInformation.ParamIndex < 0) { Debug.Fail("MarshallingInformation.ElementSize > 0 should imply that ParamIndex >= 0"); marshallingInformation.ParamIndex = 0; } Ir2md.WriteCompressedInt(signature, marshallingInformation.ParamIndex); } if (marshallingInformation.ElementSize > 0) { Ir2md.WriteCompressedInt(signature, marshallingInformation.ElementSize); if (marshallingInformation.NumberOfElements > 0) Ir2md.WriteCompressedInt(signature, marshallingInformation.NumberOfElements); } break; case NativeType.ByValArray: Ir2md.WriteCompressedInt(signature, marshallingInformation.Size); if (marshallingInformation.ElementType != NativeType.NotSpecified) signature.Write((byte)marshallingInformation.ElementType); break; case NativeType.ByValTStr: Ir2md.WriteCompressedInt(signature, marshallingInformation.Size); break; case NativeType.CustomMarshaler: signature.Write((short)0); signature.Write(marshallingInformation.Class); signature.Write(marshallingInformation.Cookie); break; } return this.GetBlobIndex(sig.ToArray()); } int GetBlobIndex(Literal/*!*/ literal) { int index = (int)this.blobHeap.BaseStream.Position; TypeNode lType = literal.Type; EnumNode eType = lType as EnumNode; if (eType != null) lType = eType.UnderlyingType; IConvertible ic = literal.Value as IConvertible; if (ic == null) ic = ""; switch (lType.typeCode) { case ElementType.Boolean: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToBoolean(null)); break; case ElementType.Char: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToChar(null)); break; case ElementType.Int8: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToSByte(null)); break; case ElementType.UInt8: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToByte(null)); break; case ElementType.Int16: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToInt16(null)); break; case ElementType.UInt16: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToUInt16(null)); break; case ElementType.Int32: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToInt32(null)); break; case ElementType.UInt32: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToUInt32(null)); break; case ElementType.Int64: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToInt64(null)); break; case ElementType.UInt64: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToUInt64(null)); break; case ElementType.Single: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToSingle(null)); break; case ElementType.Double: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToDouble(null)); break; case ElementType.String: this.blobHeap.Write((string)literal.Value, false); break; case ElementType.Array: case ElementType.Class: case ElementType.Object: case ElementType.Reference: case ElementType.SzArray: this.blobHeap.Write((byte)4); this.blobHeap.Write((int)0); break; //REVIEW: standard implies this should be 0, peverify thinks otherwise. default: Debug.Assert(false, "Unexpected Literal type"); return 0; } return index; } int GetBlobIndex(FunctionPointer/*!*/ fp) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); this.WriteMethodSignature(signature, fp); return this.GetBlobIndex(sig.ToArray()); } int GetBlobIndex(Method/*!*/ method, bool methodSpecSignature) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); if (methodSpecSignature) this.WriteMethodSpecSignature(signature, method); else this.WriteMethodSignature(signature, method); return this.GetBlobIndex(sig.ToArray()); } int GetBlobIndex(AttributeList/*!*/ securityAttributes) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); signature.Write((byte)'.'); Ir2md.WriteCompressedInt(signature, securityAttributes.Count); foreach (AttributeNode attr in securityAttributes) this.WriteSecurityAttribute(signature, attr); return this.GetBlobIndex(sig.ToArray()); } private void WriteSecurityAttribute(BinaryWriter signature, AttributeNode attr) { this.WriteSerializedTypeName(signature, attr.Type); MemoryStream sig = new MemoryStream(); BinaryWriter casig = new BinaryWriter(sig); MemberBinding mb = attr.Constructor as MemberBinding; if (mb == null) return; InstanceInitializer constructor = mb.BoundMember as InstanceInitializer; if (constructor == null) return; this.WriteCustomAttributeSignature(attr.Expressions, constructor.Parameters, true, casig); byte[] sigBytes = sig.ToArray(); int length = sigBytes.Length; Ir2md.WriteCompressedInt(signature, length); signature.BaseStream.Write(sigBytes, 0, length); } int GetBlobIndex(Property/*!*/ prop) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); this.WritePropertySignature(signature, prop); return this.GetBlobIndex(sig.ToArray()); } int GetBlobIndex(TypeNode/*!*/ type) { MemoryStream sig = new MemoryStream(); BinaryWriter signature = new BinaryWriter(sig); this.WriteTypeSignature(signature, type, true); return this.GetBlobIndex(sig.ToArray()); } int GetCustomAttributeParentCodedIndex(Node/*!*/ node) { switch (node.NodeType) { case NodeType.InstanceInitializer: case NodeType.StaticInitializer: case NodeType.Method: return this.GetMethodIndex((Method)node) << 5; case NodeType.Field: return (this.GetFieldIndex((Field)node) << 5) | 1; case NodeType.Parameter: return (this.GetParamIndex((Parameter)node) << 5) | 4; case NodeType.Class: case NodeType.DelegateNode: case NodeType.EnumNode: case NodeType.Interface: case NodeType.Struct: #if !MinimalReader case NodeType.TupleType: case NodeType.TypeAlias: case NodeType.TypeIntersection: case NodeType.TypeUnion: #endif TypeNode t = (TypeNode)node; if (this.IsStructural(t) && (!t.IsGeneric || (t.Template != null && t.ConsolidatedTemplateArguments != null && t.ConsolidatedTemplateArguments.Count > 0))) return (this.GetTypeSpecIndex(t) << 5) | 13; else return (this.GetTypeDefIndex(t) << 5) | 3; case NodeType.ClassParameter: case NodeType.TypeParameter: if (!this.UseGenerics) goto case NodeType.Class; return (this.GetGenericParamIndex((TypeNode)node) << 5) | 19; case NodeType.Property: return (this.GetPropertyIndex((Property)node) << 5) | 9; case NodeType.Event: return (this.GetEventIndex((Event)node) << 5) | 10; case NodeType.Module: return (1 << 5) | 7; case NodeType.Assembly: return (1 << 5) | 14; default: Debug.Assert(false, "Unexpect custom attribute parent"); return 0; } } #if !ROTOR ISymUnmanagedDocumentWriter GetDocumentWriter(Document/*!*/ doc) //^ requires this.symWriter != null; { int key = Identifier.For(doc.Name).UniqueIdKey; object writer = this.documentMap[key]; if (writer == null) { writer = this.symWriter.DefineDocument(doc.Name, ref doc.Language, ref doc.LanguageVendor, ref doc.DocumentType); this.documentMap[key] = writer; } return (ISymUnmanagedDocumentWriter)writer; } #endif int GetEventIndex(Event/*!*/ e) { return (int)this.eventIndex[e.UniqueKey]; } int GetFieldIndex(Field/*!*/ f) { Object index = this.fieldIndex[f.UniqueKey]; if (index == null) { if (this.fieldEntries == null) return 1; index = this.fieldEntries.Count + 1; this.fieldEntries.Add(f); this.fieldIndex[f.UniqueKey] = index; if (f.DefaultValue != null && !(f.DefaultValue.Value is Parameter)) this.constantTableEntries.Add(f); if (!f.IsStatic && f.DeclaringType != null && (f.DeclaringType.Flags & TypeFlags.ExplicitLayout) != 0) this.fieldLayoutEntries.Add(f); if ((f.Flags & FieldFlags.HasFieldRVA) != 0) this.fieldRvaEntries.Add(f); if (f.MarshallingInformation != null) this.marshalEntries.Add(f); } return (int)index; } int GetGenericParamIndex(TypeNode/*!*/ gp) { return (int)this.genericParamIndex[gp.UniqueKey]; } int GetFieldToken(Field/*!*/ f) { if (f.DeclaringType == null || (f.DeclaringType.DeclaringModule == this.module && !this.IsStructural(f.DeclaringType))) return 0x04000000 | this.GetFieldIndex(f); else return 0x0a000000 | this.GetMemberRefIndex(f); } bool IsStructural(TypeNode type) { if (type == null) return false; if (this.UseGenerics && (type.IsGeneric || type.Template != null && type.Template.IsGeneric)) return true; switch (type.NodeType) { case NodeType.ArrayType: case NodeType.Pointer: case NodeType.Reference: case NodeType.OptionalModifier: case NodeType.RequiredModifier: return true; case NodeType.ClassParameter: case NodeType.TypeParameter: return this.UseGenerics; } return false; } int GetFileTableIndex(Module/*!*/ module) { Object index = this.fileTableIndex[module]; if (index == null) { index = this.fileTableEntries.Count + 1; this.fileTableEntries.Add(module); this.fileTableIndex[module] = index; } return (int)index; } int GetGuidIndex(Guid guid) { Object index = this.guidIndex[guid]; if (index == null) { index = this.guidEntries.Count + 1; this.guidEntries.Add(guid); this.guidIndex[guid] = index; } return (int)index; } internal int GetLocalVarIndex(Local/*!*/ loc) { #if !MinimalReader LocalBinding lb = loc as LocalBinding; if (lb != null) loc = lb.BoundLocal; #endif if (this.StripOptionalModifiersFromLocals) loc.Type = TypeNode.StripModifiers(loc.Type); MethodInfo methInfo = this.methodInfo; if (methInfo.localVarSignature == null) { methInfo.localVarSignature = new BinaryWriter(new MemoryStream()); methInfo.localVarSignature.Write((short)0); methInfo.localVarIndex = new TrivialHashtable(); methInfo.localVarSigTok = 0x11000000 | this.GetStandAloneSignatureIndex(methInfo.localVarSignature); } object index = methInfo.localVarIndex[loc.UniqueKey]; if (index == null) { methInfo.localVarIndex[loc.UniqueKey] = index = methInfo.localVarIndex.Count; #if !ROTOR int startPosition = 0; if (this.symWriter != null && loc.Name != null && loc.Name.UniqueIdKey != Identifier.Empty.UniqueIdKey) { methInfo.debugLocals.Add(loc); methInfo.signatureOffsets.Add(startPosition = methInfo.localVarSignature.BaseStream.Position); if (loc.Pinned) methInfo.localVarSignature.Write((byte)ElementType.Pinned); this.WriteTypeSignature(methInfo.localVarSignature, loc.Type, true); methInfo.signatureLengths.Add(methInfo.localVarSignature.BaseStream.Position - startPosition); } else { #endif if (loc.Pinned) methInfo.localVarSignature.Write((byte)ElementType.Pinned); this.WriteTypeSignature(methInfo.localVarSignature, loc.Type, true); #if !ROTOR } #endif } return (int)index; } int GetMemberRefParentEncoded(TypeNode type) { if (type == null) return 0; if (this.IsStructural(type)) return (this.GetTypeSpecIndex(type) << 3) | 4; if (type.DeclaringModule == this.module) return this.GetTypeDefIndex(type) << 3; if (type.DeclaringModule != null) return (this.GetTypeRefIndex(type) << 3) | 1; if (type.typeCode == ElementType.Class || type.typeCode == ElementType.ValueType) return this.GetTypeDefIndex(type) << 3; //REVIEW: when does this happen? Debug.Assert(false); return 0; } int GetMemberRefIndex(Member/*!*/ m) { Object index = this.memberRefIndex[m.UniqueKey]; if (index == null) { index = this.memberRefEntries.Count + 1; this.memberRefEntries.Add(m); this.memberRefIndex[m.UniqueKey] = index; TypeNode type = m.DeclaringType; this.VisitReferencedType(type); } return (int)index; } class VarargMethodCallSignature : FunctionPointer { internal Method method; internal VarargMethodCallSignature(Method/*!*/ method, TypeNodeList/*!*/ parameterTypes) : base(parameterTypes, method.ReturnType, method.Name) { this.method = method; this.DeclaringType = method.DeclaringType; } } int GetMemberRefToken(Method/*!*/ m, ExpressionList arguments) { int numArgs = arguments == null ? 0 : arguments.Count; TypeNodeList parTypes = new TypeNodeList(numArgs); int varArgStart = m.Parameters.Count; for (int i = 0; i < varArgStart; i++) parTypes.Add(m.Parameters[i].Type); for (int i = varArgStart; i < numArgs; i++) { //^ assert arguments != null; parTypes.Add(arguments[i].Type); } VarargMethodCallSignature sig = new VarargMethodCallSignature(m, parTypes); sig.VarArgStart = varArgStart; sig.CallingConvention = m.CallingConvention; return 0x0a000000 | this.GetMemberRefIndex(sig); } int GetMethodDefOrRefEncoded(Method/*!*/ m) { if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType)) return this.GetMethodIndex(m) << 1; else return (this.GetMemberRefIndex(m) << 1) | 0x1; } int GetMethodIndex(Method/*!*/ m) { Object index = this.methodIndex[m.UniqueKey]; if (index == null) { if (this.methodEntries == null) return 1; index = this.methodEntries.Count + 1; this.methodEntries.Add(m); this.methodIndex[m.UniqueKey] = index; if (m.ReturnTypeMarshallingInformation != null || (m.ReturnAttributes != null && m.ReturnAttributes.Count > 0)) { Parameter p = new Parameter(); p.ParameterListIndex = -1; p.Attributes = m.ReturnAttributes; if (m.ReturnTypeMarshallingInformation != null) { p.MarshallingInformation = m.ReturnTypeMarshallingInformation; p.Flags = ParameterFlags.HasFieldMarshal; this.marshalEntries.Add(p); } this.paramEntries.Add(p); this.paramIndex[m.UniqueKey] = this.paramEntries.Count; this.paramIndex[p.UniqueKey] = this.paramEntries.Count; this.VisitAttributeList(p.Attributes, p); } int offset = m.IsStatic ? 0 : 1; if (m.Parameters != null) { for (int i = 0, n = m.Parameters.Count; i < n; i++) { Parameter p = m.Parameters[i]; if (p == null) continue; if (p == null) continue; if (p.DeclaringMethod == null) p.DeclaringMethod = m; p.ParameterListIndex = i; p.ArgumentListIndex = i + offset; int j = this.paramEntries.Count + 1; this.paramEntries.Add(p); //TODO: provide a way to suppress the param table entries unless param has custom attributes or flags this.paramIndex[p.UniqueKey] = j; if (p.DefaultValue != null) this.constantTableEntries.Add(p); if (p.MarshallingInformation != null) this.marshalEntries.Add(p); } } if (m.IsGeneric) this.VisitGenericParameterList(m, m.TemplateParameters); } return (int)index; } int GetMethodSpecIndex(Method/*!*/ m) { int structuralKey = m.UniqueKey; int blobIndex = this.GetBlobIndex(m, true); if (m.Template != null) structuralKey = (m.Template.UniqueKey << 8) + blobIndex; else Debug.Assert(false); Object index = this.methodSpecIndex[m.UniqueKey]; if (index == null) { index = this.methodSpecIndex[structuralKey]; if (index is int) { Method otherMethod = this.methodSpecEntries[((int)index) - 1]; if (otherMethod != null && otherMethod.Template == m.Template && blobIndex == this.GetBlobIndex(otherMethod, true)) return (int)index; } index = this.methodSpecEntries.Count + 1; this.methodSpecEntries.Add(m); this.methodSpecIndex[m.UniqueKey] = index; this.methodSpecIndex[structuralKey] = index; this.GetMemberRefIndex(m.Template); Method templ = m.Template; if (templ != null) { while (templ.Template != null) templ = templ.Template; TypeNodeList templParams = templ.TemplateParameters; if (templParams != null) { for (int i = 0, n = templParams.Count; i < n; i++) { TypeNode templParam = templParams[i]; if (templParam == null) continue; this.typeParameterNumber[templParam.UniqueKey] = -(i + 1); } } } } return (int)index; } int GetMethodToken(Method/*!*/ m) { if (this.UseGenerics && m.Template != null && m.Template.IsGeneric) return 0x2b000000 | this.GetMethodSpecIndex(m); else if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType)) return 0x06000000 | this.GetMethodIndex(m); else return 0x0a000000 | this.GetMemberRefIndex(m); } int GetMethodDefToken(Method/*!*/ m) { if (m.DeclaringType.DeclaringModule == this.module) return 0x06000000 | this.GetMethodIndex(m); else return 0x0a000000 | this.GetMemberRefIndex(m); } int GetMethodBodiesHeapIndex(Method/*!*/ m) { return (int)this.methodBodiesHeapIndex[m.UniqueKey]; } int GetModuleRefIndex(Module/*!*/ module) { if (module.Location == "unknown:location") throw new InvalidOperationException(ExceptionStrings.UnresolvedModuleReferenceNotAllowed); Object index = this.moduleRefIndex[module.Name]; if (index == null) { index = this.moduleRefEntries.Count + 1; this.moduleRefEntries.Add(new ModuleReference(module.Name, module)); this.moduleRefIndex[module.Name] = index; if (module.HashValue != null && module.HashValue.Length > 0) this.GetFileTableIndex(module); } return (int)index; } int GetOffset(Block target, int addressOfNextInstruction) { if (target == null) return 0; int fixupLocation = (int)(this.methodBodyHeap.BaseStream.Position); Object ob = this.methodInfo.fixupIndex[target.UniqueKey]; if (ob is int) return ((int)ob) - addressOfNextInstruction; Fixup fixup = new Fixup(); fixup.addressOfNextInstruction = addressOfNextInstruction; fixup.fixupLocation = fixupLocation; fixup.shortOffset = false; fixup.nextFixUp = (Fixup)ob; this.methodInfo.fixupIndex[target.UniqueKey] = fixup; return 0; } int GetOffset(Block target, ref bool shortOffset) { if (target == null) return 0; int fixupLocation = (int)(this.methodBodyHeap.BaseStream.Position + 1); Object ob = this.methodInfo.fixupIndex[target.UniqueKey]; if (ob is int) { int targetAddress = (int)ob; int offset = targetAddress - (fixupLocation + 1); if (-128 > offset || offset > 127) { offset = targetAddress - (fixupLocation + 4); Debug.Assert(offset < -128, "Forward short branch out of range"); shortOffset = false; } else shortOffset = true; return offset; } Fixup fixup = new Fixup(); fixup.fixupLocation = fixup.addressOfNextInstruction = fixupLocation; if (shortOffset) fixup.addressOfNextInstruction += 1; else fixup.addressOfNextInstruction += 4; fixup.shortOffset = shortOffset; fixup.nextFixUp = (Fixup)ob; this.methodInfo.fixupIndex[target.UniqueKey] = fixup; return 0; } int GetParamIndex(Parameter p) { if (p == null) return 0; #if !MinimalReader ParameterBinding pb = p as ParameterBinding; if (pb != null) p = pb.BoundParameter; #endif return (int)this.paramIndex[p.UniqueKey]; } int GetPropertyIndex(Property/*!*/ p) { return (int)this.propertyIndex[p.UniqueKey]; } int GetSecurityAttributeParentCodedIndex(Node/*!*/ node) { switch (node.NodeType) { case NodeType.InstanceInitializer: case NodeType.StaticInitializer: case NodeType.Method: return (this.GetMethodIndex((Method)node) << 2) | 1; case NodeType.Class: case NodeType.Interface: case NodeType.DelegateNode: case NodeType.EnumNode: case NodeType.Struct: return (this.GetTypeDefIndex((TypeNode)node) << 2) | 0; case NodeType.Assembly: return (1 << 2) | 2; default: Debug.Assert(false, "Unexpected security attribute parent"); return 0; } } int GetStandAloneSignatureIndex(BinaryWriter signatureWriter) { this.standAloneSignatureEntries.Add(signatureWriter); return this.standAloneSignatureEntries.Count; } int GetStaticDataIndex(byte[] data, PESection targetSection) { int result = 0; switch (targetSection) { case PESection.SData: result = (int)this.sdataHeap.BaseStream.Position; this.sdataHeap.Write(data); break; case PESection.Text: result = (int)this.methodBodiesHeap.BaseStream.Position; this.methodBodiesHeap.Write(data); break; case PESection.TLS: result = (int)this.tlsHeap.BaseStream.Position; this.tlsHeap.Write(data); break; } return result; } int GetResourceDataIndex(byte[]/*!*/ data) { int index = (int)this.resourceDataHeap.BaseStream.Position; this.resourceDataHeap.Write((int)data.Length); this.resourceDataHeap.Write(data); return index; } int GetStringIndex(string str) { if (str == null || str.Length == 0) return 0; Object index = this.stringHeapIndex[str]; if (index == null) { index = (int)this.stringHeap.BaseStream.Position; this.stringHeap.Write(str, true); this.stringHeapIndex[str] = index; } return (int)index; } int GetUserStringIndex(string/*!*/ str) { Object index = this.userStringHeapIndex[str]; if (index == null) { index = (int)this.userStringHeap.BaseStream.Position; Ir2md.WriteCompressedInt(this.userStringHeap, str.Length * 2 + 1); this.userStringHeap.Write(str.ToCharArray()); this.userStringHeapIndex[str] = index; //Write out a trailing byte indicating if the string is really quite simple ulong stringKind = 0; //no funny business foreach (char ch in str) { if (ch >= 0x7F) stringKind += 1; else switch ((int)ch) { case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0xE: case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: case 0x27: case 0x2D: stringKind += 1; break; default: break; } } if (stringKind > 0) stringKind = 1; this.userStringHeap.Write((byte)stringKind); } return (int)index; } int GetTypeDefIndex(TypeNode/*!*/ type) { Object index = this.typeDefIndex[type.UniqueKey]; if (index == null) { if (this.typeDefEntries == null) return 0; index = this.typeDefEntries.Count + 1; this.typeDefEntries.Add(type); this.typeDefIndex[type.UniqueKey] = index; if (type.IsGeneric && type.Template == null) this.VisitGenericParameterList(type, type.ConsolidatedTemplateParameters); } return (int)index; } int GetTypeDefOrRefOrSpecEncoded(TypeNode type) { if (type == null) return 0; if (!this.UseGenerics) { ClassParameter cp = type as ClassParameter; if (cp != null) { Debug.Assert(!cp.IsGeneric); return this.GetTypeDefOrRefOrSpecEncoded(cp.BaseClass); } //REVIEW: why??? } if (this.IsStructural(type)) return (this.GetTypeSpecIndex(type) << 2) | 2; if (type.DeclaringModule == this.module) return this.GetTypeDefIndex(type) << 2; return (this.GetTypeRefIndex(type) << 2) | 1; } int GetTypeToken(TypeNode/*!*/ type) { if (this.IsStructural(type) && (!type.IsGeneric || (type.ConsolidatedTemplateArguments != null && type.ConsolidatedTemplateArguments.Count > 0))) return 0x1b000000 | this.GetTypeSpecIndex(type); if (type.IsGeneric) { TypeNode foundType = type.GetTemplateInstance(type, type.TemplateParameters); Debug.Assert(foundType != type); return this.GetTypeToken(foundType); } if (type.DeclaringModule == this.module) return 0x02000000 | this.GetTypeDefIndex(type); else if (type.DeclaringModule != null) return 0x01000000 | this.GetTypeRefIndex(type); else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class) { type.DeclaringModule = this.module; return 0x02000000 | this.GetTypeDefIndex(type); } Debug.Assert(false); return 0; } int GetTypeDefToken(TypeNode/*!*/ type) { if (this.IsStructural(type) && (!type.IsGeneric || (type.Template != null && type.ConsolidatedTemplateArguments != null && type.ConsolidatedTemplateArguments.Count > 0))) return 0x1b000000 | this.GetTypeSpecIndex(type); if (type.DeclaringModule == this.module) return 0x02000000 | this.GetTypeDefIndex(type); else if (type.DeclaringModule != null) return 0x01000000 | this.GetTypeRefIndex(type); else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class) { type.DeclaringModule = this.module; return 0x02000000 | this.GetTypeDefIndex(type); } Debug.Assert(false); return 0; } int GetTypeRefIndex(TypeNode/*!*/ type) { Object index = this.typeRefIndex[type.UniqueKey]; if (index == null) { index = this.typeRefEntries.Count + 1; this.typeRefEntries.Add(type); this.typeRefIndex[type.UniqueKey] = index; Module module = type.DeclaringModule; AssemblyNode assembly = module as AssemblyNode; if (assembly != null) this.GetAssemblyRefIndex(assembly); else this.GetModuleRefIndex(module); if (type.DeclaringType != null) this.GetTypeRefIndex(type.DeclaringType); } return (int)index; } int GetTypeSpecIndex(TypeNode/*!*/ type) { int structuralKey = type.UniqueKey; int blobIndex = 0; if (type.Template != null) { blobIndex = this.GetBlobIndex(type); structuralKey = ((type.Template.UniqueKey << 8) & int.MaxValue) + blobIndex; } Object index = this.typeSpecIndex[type.UniqueKey]; if (index == null) { if (type.Template != null) { index = this.typeSpecIndex[structuralKey]; if (index is int) { TypeNode otherType = this.typeSpecEntries[((int)index) - 1]; if (otherType != null && otherType.Template == type.Template && blobIndex == this.GetBlobIndex(otherType)) return (int)index; } } index = this.typeSpecEntries.Count + 1; this.typeSpecEntries.Add(type); this.typeSpecIndex[type.UniqueKey] = index; if (type.Template != null) this.typeSpecIndex[structuralKey] = index; if (type.Template != null) { if (type.Template.DeclaringModule != this.module) this.GetTypeRefIndex(type.Template); TypeNodeList templArgs = type.ConsolidatedTemplateArguments; for (int i = 0, n = templArgs == null ? 0 : templArgs.Count; i < n; i++) { this.VisitReferencedType(templArgs[i]); } } else { TypeNodeList telems = type.StructuralElementTypes; for (int i = 0, n = telems == null ? 0 : telems.Count; i < n; i++) this.VisitReferencedType(telems[i]); } } return (int)index; } TrivialHashtable/*!*/ unspecializedFieldFor = new TrivialHashtable(); Field/*!*/ GetUnspecializedField(Field/*!*/ field) { if (field == null || field.DeclaringType == null || !field.DeclaringType.IsGeneric) { Debug.Fail(""); return field; } Field unspecializedField = (Field)this.unspecializedFieldFor[field.UniqueKey]; if (unspecializedField != null) return unspecializedField; TypeNode template = field.DeclaringType; if (template == null) { Debug.Assert(false); return field; } while (template.Template != null) template = template.Template; MemberList specializedMembers = field.DeclaringType.Members; MemberList unspecializedMembers = template.Members; for (int i = 0, n = specializedMembers.Count; i < n; i++) { if (specializedMembers[i] != field) continue; unspecializedField = (Field)unspecializedMembers[i]; if (unspecializedField == null) { Debug.Fail(""); unspecializedField = field; } this.unspecializedFieldFor[field.UniqueKey] = unspecializedField; this.VisitReferencedType(unspecializedField.DeclaringType); return unspecializedField; } Debug.Fail(""); return field; } TrivialHashtable/*!*/ unspecializedMethodFor = new TrivialHashtable(); Method/*!*/ GetUnspecializedMethod(Method/*!*/ method) { Debug.Assert(method != null && method.DeclaringType != null && method.DeclaringType.IsGeneric); Method unspecializedMethod = (Method)this.unspecializedMethodFor[method.UniqueKey]; if (unspecializedMethod != null) return unspecializedMethod; TypeNode template = method.DeclaringType; if (template == null) { Debug.Assert(false); return method; } while (template.Template != null) template = template.Template; MemberList specializedMembers = method.DeclaringType.Members; MemberList unspecializedMembers = template.Members; for (int i = 0, n = specializedMembers.Count; i < n; i++) { if (specializedMembers[i] != method) continue; unspecializedMethod = unspecializedMembers[i] as Method; if (unspecializedMethod == null) break; this.unspecializedMethodFor[method.UniqueKey] = unspecializedMethod; template = unspecializedMethod.DeclaringType; while (template.Template != null) template = template.Template; this.VisitReferencedType(template); for (int j = 0, m = unspecializedMethod.TemplateParameters == null ? 0 : unspecializedMethod.TemplateParameters.Count; j < m; j++) { TypeNode p = unspecializedMethod.TemplateParameters[j]; if (p == null) continue; this.typeParameterNumber[p.UniqueKey] = -(j + 1); } return unspecializedMethod; } Debug.Assert(false); return method; } internal void IncrementStackHeight() { this.stackHeight++; if (this.stackHeight > this.stackHeightMax) this.stackHeightMax = this.stackHeight; } void PopulateAssemblyTable() //^ requires this.assembly != null; { AssemblyNode assembly = this.assembly; AssemblyRow[] assemblyTable = this.writer.assemblyTable = new AssemblyRow[1]; assemblyTable[0].HashAlgId = (int)AssemblyHashAlgorithm.SHA1; assemblyTable[0].Flags = (int)assembly.Flags; if (assembly.Version == null) assembly.Version = new Version(1, 0, 0, 0); assemblyTable[0].MajorVersion = assembly.Version.Major; assemblyTable[0].MinorVersion = assembly.Version.Minor; assemblyTable[0].RevisionNumber = assembly.Version.Revision; assemblyTable[0].BuildNumber = assembly.Version.Build; if (assembly.PublicKeyOrToken != null && 0 < assembly.PublicKeyOrToken.Length) assemblyTable[0].PublicKey = this.GetBlobIndex(assembly.PublicKeyOrToken); if (assembly.Name != null) assemblyTable[0].Name = this.GetStringIndex(assembly.Name); else Debug.Assert(false, "Assembly must have a name"); if (assembly.Culture != null && assembly.Culture.Length > 0) assemblyTable[0].Culture = this.GetStringIndex(assembly.Culture); this.writer.assemblyTable = assemblyTable; } void PopulateAssemblyRefTable() { AssemblyReferenceList arList = this.module.AssemblyReferences = this.assemblyRefEntries; if (arList == null) return; int n = arList.Count; AssemblyRefRow[] arRows = this.writer.assemblyRefTable = new AssemblyRefRow[n]; for (int i = 0; i < n; i++) { AssemblyReference ar = arList[i]; if (ar.Version == null) Debug.Assert(false, "assembly reference without a version"); else { arRows[i].MajorVersion = ar.Version.Major; arRows[i].MinorVersion = ar.Version.Minor; arRows[i].RevisionNumber = ar.Version.Revision; arRows[i].BuildNumber = ar.Version.Build; arRows[i].Flags = (int)ar.Flags; } if (ar.PublicKeyOrToken != null && 0 < ar.PublicKeyOrToken.Length) arRows[i].PublicKeyOrToken = this.GetBlobIndex(ar.PublicKeyOrToken); if (ar.Name == null) Debug.Assert(false, "assembly reference without a name"); else arRows[i].Name = this.GetStringIndex(ar.Name); if (ar.Culture != null && ar.Culture.Length > 0) arRows[i].Culture = this.GetStringIndex(ar.Culture); if (ar.HashValue != null) arRows[i].HashValue = this.GetBlobIndex(ar.HashValue); } //this.assemblyRefEntries = null; } void PopulateClassLayoutTable() { int n = this.classLayoutEntries.Count; if (n == 0) return; ClassLayoutRow[] clr = this.writer.classLayoutTable = new ClassLayoutRow[n]; for (int i = 0; i < n; i++) { TypeNode t = this.classLayoutEntries[i]; clr[i].ClassSize = t.ClassSize; clr[i].PackingSize = t.PackingSize; clr[i].Parent = this.GetTypeDefIndex(t); } //this.classLayoutEntries = null; } void PopulateConstantTable() { int n = this.constantTableEntries.Count; if (n == 0) return; ConstantRow[] cr = this.writer.constantTable = new ConstantRow[n]; for (int i = 0; i < n; i++) { Parameter p = this.constantTableEntries[i] as Parameter; if (p != null) { cr[i].Parent = (this.GetParamIndex(p) << 2) | 1; cr[i].Value = this.GetBlobIndex((Literal)p.DefaultValue); TypeNode t = p.DefaultValue.Type; if (t.NodeType == NodeType.EnumNode) t = ((EnumNode)t).UnderlyingType; cr[i].Type = (int)t.typeCode; if (t is Reference || (t != p.Type && Literal.IsNullLiteral(p.DefaultValue))) cr[i].Type = (int)ElementType.Class; } else { Field f = (Field)this.constantTableEntries[i]; cr[i].Parent = (this.GetFieldIndex(f) << 2); cr[i].Value = this.GetBlobIndex(f.DefaultValue); TypeNode t = f.DefaultValue.Type; if (t.NodeType == NodeType.EnumNode) t = ((EnumNode)t).UnderlyingType; cr[i].Type = (int)t.typeCode; if (t is Reference || (t != f.Type && Literal.IsNullLiteral(f.DefaultValue))) cr[i].Type = (int)ElementType.Class; } ConstantRow temp = cr[i]; int parent = temp.Parent; for (int j = i - 1; j >= 0; j--) { if (cr[j].Parent > parent) { cr[j + 1] = cr[j]; if (j == 0) { cr[0] = temp; break; } } else { if (j < i - 1) cr[j + 1] = temp; break; } } } //TODO: more efficient sort //this.constantTableEntries = null; } void PopulateCustomAttributeTable() { if (this.customAttributeCount == 0) return; CustomAttributeRow[] table = this.writer.customAttributeTable = new CustomAttributeRow[this.customAttributeCount]; int k = 0; int prevCodedIndex = 0; for (int i = 0, n = this.nodesWithCustomAttributes.Count; i < n; i++) { AttributeList attrs = null; Node node = this.nodesWithCustomAttributes[i]; int codedIndex = 0; switch (node.NodeType) { case NodeType.Method: case NodeType.InstanceInitializer: case NodeType.StaticInitializer: Method m = (Method)node; codedIndex = this.GetMethodIndex(m) << 5; attrs = m.Attributes; break; case NodeType.Field: Field f = (Field)node; codedIndex = (this.GetFieldIndex(f) << 5) | 1; attrs = f.Attributes; break; case NodeType.Parameter: Parameter par = (Parameter)node; codedIndex = (this.GetParamIndex(par) << 5) | 4; attrs = par.Attributes; break; case NodeType.Class: case NodeType.DelegateNode: case NodeType.EnumNode: case NodeType.Interface: case NodeType.Struct: #if !MinimalReader case NodeType.TupleType: case NodeType.TypeAlias: case NodeType.TypeIntersection: case NodeType.TypeUnion: #endif TypeNode t = (TypeNode)node; if (this.IsStructural(t) && (!t.IsGeneric || (t.Template != null && t.ConsolidatedTemplateArguments != null && t.ConsolidatedTemplateArguments.Count > 0))) codedIndex = (this.GetTypeSpecIndex(t) << 5) | 13; else codedIndex = (this.GetTypeDefIndex(t) << 5) | 3; attrs = t.Attributes; break; case NodeType.ClassParameter: case NodeType.TypeParameter: if (!this.UseGenerics) goto case NodeType.Class; t = (TypeNode)node; codedIndex = (this.GetGenericParamIndex(t) << 5) | 19; attrs = t.Attributes; break; case NodeType.Property: Property p = (Property)node; codedIndex = (this.GetPropertyIndex(p) << 5) | 9; attrs = p.Attributes; break; case NodeType.Event: Event e = (Event)node; codedIndex = (this.GetEventIndex(e) << 5) | 10; attrs = e.Attributes; break; case NodeType.Module: case NodeType.Assembly: codedIndex = (1 << 5) | (node.NodeType == NodeType.Module ? 7 : 14); attrs = ((Module)node).Attributes; break; default: Debug.Assert(false); break; } if (attrs == null) continue; if (UseGenerics) { Debug.Assert(codedIndex > prevCodedIndex); } prevCodedIndex = codedIndex; for (int j = 0, m = attrs.Count; j < m; j++) { AttributeNode a = attrs[j]; if (a == null) continue; table[k].Parent = codedIndex; Debug.Assert(a.Constructor is MemberBinding); Method cons = (Method)((MemberBinding)a.Constructor).BoundMember; if (cons.DeclaringType.DeclaringModule == this.module && !this.IsStructural(cons.DeclaringType)) table[k].Constructor = (this.GetMethodIndex(cons) << 3) | 2; else table[k].Constructor = (this.GetMemberRefIndex(cons) << 3) | 3; table[k].Value = this.GetBlobIndex(a.Expressions, cons.Parameters); k++; } } } void PopulateDeclSecurityTable() { if (this.securityAttributeCount == 0) return; DeclSecurityRow[] table = this.writer.declSecurityTable = new DeclSecurityRow[this.securityAttributeCount]; int k = 0; int prevCodedIndex = 0; for (int i = 0, n = this.nodesWithSecurityAttributes.Count; i < n; i++) { SecurityAttributeList attrs = null; Node node = this.nodesWithSecurityAttributes[i]; int codedIndex = 0; switch (node.NodeType) { case NodeType.Method: case NodeType.InstanceInitializer: case NodeType.StaticInitializer: Method m = (Method)node; codedIndex = (this.GetMethodIndex(m) << 2) | 1; attrs = m.SecurityAttributes; break; case NodeType.Class: case NodeType.Interface: case NodeType.DelegateNode: case NodeType.EnumNode: case NodeType.Struct: TypeNode t = (TypeNode)node; codedIndex = (this.GetTypeDefIndex(t) << 2) | 0; attrs = t.SecurityAttributes; break; case NodeType.Assembly: codedIndex = (1 << 2) | 2; attrs = ((AssemblyNode)node).SecurityAttributes; break; default: Debug.Assert(false); break; } if (attrs == null) continue; Debug.Assert(codedIndex > prevCodedIndex); prevCodedIndex = codedIndex; for (int j = 0, m = attrs.Count; j < m; j++) { SecurityAttribute a = attrs[j]; if (a == null) continue; this.VisitReferencedType(CoreSystemTypes.SecurityAction); table[k].Action = (int)a.Action; table[k].Parent = codedIndex; if (CoreSystemTypes.SystemAssembly.MetadataFormatMajorVersion == 1 && CoreSystemTypes.SystemAssembly.MetadataFormatMinorVersion < 1) table[k].PermissionSet = this.GetBlobIndex(a.SerializedPermissions); else { if (a.PermissionAttributes != null) { table[k].PermissionSet = this.GetBlobIndex(a.PermissionAttributes); } else { // Came across some assemblies that had a metadata version > 1.0, but still used // serialized security attributes. So might as well try to see if this is the case // if the PermissionAttributes are null. table[k].PermissionSet = this.GetBlobIndex(a.SerializedPermissions); } } k++; } } } void PopulateEventMapTable() { int n = this.eventMapEntries.Count; if (n == 0) return; EventMapRow[] emr = this.writer.eventMapTable = new EventMapRow[n]; for (int i = 0; i < n; i++) { Event e = this.eventMapEntries[i]; emr[i].Parent = this.GetTypeDefIndex(e.DeclaringType); emr[i].EventList = this.GetEventIndex(e); } //this.eventMapEntries = null; } void PopulateEventTable() { int n = this.eventEntries.Count; if (n == 0) return; EventRow[] er = this.writer.eventTable = new EventRow[n]; for (int i = 0; i < n; i++) { Event e = this.eventEntries[i]; if (e == null || e.Name == null) continue; er[i].Flags = (int)e.Flags; er[i].Name = this.GetStringIndex(e.Name.ToString()); er[i].EventType = this.GetTypeDefOrRefOrSpecEncoded(e.HandlerType); } //this.eventEntries = null; } void PopulateExportedTypeTable() { if (this.assembly == null) return; TypeNodeList exportedTypes = this.assembly.ExportedTypes; int n = exportedTypes == null ? 0 : exportedTypes.Count; if (n == 0) return; ExportedTypeRow[] ett = this.writer.exportedTypeTable = new ExportedTypeRow[n]; for (int i = 0; i < n; i++) { TypeNode et = exportedTypes[i]; if (et == null || et.Namespace == null || et.Name == null) continue; ett[i].TypeDefId = 0; ett[i].TypeNamespace = this.GetStringIndex(et.Namespace.ToString()); ett[i].TypeName = this.GetStringIndex(et.Name.ToString()); ett[i].Flags = (int)(et.Flags & TypeFlags.VisibilityMask); if (et.DeclaringType != null) { for (int j = 0; j < i; j++) { if (exportedTypes[j] == et.DeclaringType) { ett[i].Implementation = (j << 2) | 2; break; } } } else if (et.DeclaringModule != this.module && et.DeclaringModule is AssemblyNode) { ett[i].Implementation = (this.GetAssemblyRefIndex((AssemblyNode)et.DeclaringModule) << 2) | 1; ett[i].Flags = (int)TypeFlags.Forwarder; } else ett[i].Implementation = (this.GetFileTableIndex(et.DeclaringModule) << 2) | 0; } } void PopulateFieldTable() { int n = this.fieldEntries.Count; if (n == 0) return; FieldRow[] fr = this.writer.fieldTable = new FieldRow[n]; for (int i = 0; i < n; i++) { Field f = this.fieldEntries[i]; fr[i].Flags = (int)f.Flags; fr[i].Name = this.GetStringIndex(f.Name.Name); // we don't store prefixes in field names. fr[i].Signature = this.GetBlobIndex(f); } //this.fieldEntries = null; } void PopulateFieldLayoutTable() { int n = this.fieldLayoutEntries.Count; if (n == 0) return; FieldLayoutRow[] flr = this.writer.fieldLayoutTable = new FieldLayoutRow[n]; for (int i = 0; i < n; i++) { Field f = this.fieldLayoutEntries[i]; flr[i].Field = this.GetFieldIndex(f); flr[i].Offset = f.Offset; } //this.fieldLayoutEntries = null; } void PopulateFieldRVATable() { int n = this.fieldRvaEntries.Count; if (n == 0) return; FieldRvaRow[] frr = this.writer.fieldRvaTable = new FieldRvaRow[n]; for (int i = 0; i < n; i++) { Field f = this.fieldRvaEntries[i]; frr[i].Field = this.GetFieldIndex(f); if (f.InitialData != null) frr[i].RVA = this.GetStaticDataIndex(f.InitialData, f.Section); //Fixed up to be an RVA inside MetadataWriter. else frr[i].RVA = f.Offset; frr[i].TargetSection = f.Section; } //this.fieldRvaEntries = null; } void PopulateFileTable() { int n = this.fileTableEntries.Count; if (n == 0) return; bool readContents = false; FileRow[] ftr = this.writer.fileTable = new FileRow[n]; for (int i = 0; i < n; i++) { Module module = this.fileTableEntries[i]; switch (module.Kind) { case ModuleKindFlags.ConsoleApplication: case ModuleKindFlags.DynamicallyLinkedLibrary: case ModuleKindFlags.WindowsApplication: ftr[i].Flags = (int)FileFlags.ContainsMetaData; break; case ModuleKindFlags.ManifestResourceFile: readContents = true; ftr[i].Flags = (int)FileFlags.ContainsNoMetaData; break; case ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary: ftr[i].Flags = (int)FileFlags.ContainsNoMetaData; break; } if (module.HashValue != null) ftr[i].HashValue = this.GetBlobIndex(module.HashValue); else ftr[i].HashValue = 0; ftr[i].Name = this.GetStringIndex(module.Name); if (readContents) { try { FileStream fs = File.OpenRead(module.Location); long size = fs.Length; byte[] buffer = new byte[size]; fs.Read(buffer, 0, (int)size); System.Security.Cryptography.SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider(); byte[] hash = sha1.ComputeHash(buffer); ftr[i].HashValue = this.GetBlobIndex(hash); } catch { } } } //this.fileTableEntries = null; } void PopulateGuidTable() { int n = this.guidEntries.Count; Guid[] guids = this.writer.GuidHeap = new Guid[n]; for (int i = 0; i < n; i++) guids[i] = (Guid)this.guidEntries[i]; //this.guidEntries = null; } void PopulateGenericParamTable() { int n = this.genericParamEntries.Count; if (n == 0) return; GenericParamRow[] gpr = this.writer.genericParamTable = new GenericParamRow[n]; Member lastMember = null; int number = 0; for (int i = 0; i < n; i++) { Member m = this.genericParamEntries[i]; TypeNode paramType = this.genericParameters[i]; if (paramType == null || paramType.Name == null) continue; Method meth = m as Method; TypeNode type = m as TypeNode; if (m != lastMember) number = 0; gpr[i].GenericParameter = paramType; gpr[i].Number = number++; if (type != null) { gpr[i].Name = this.GetStringIndex(paramType.Name.ToString()); gpr[i].Owner = (this.GetTypeDefIndex(type) << 1) | 0; } else { //^ assert meth != null; gpr[i].Name = this.GetStringIndex(paramType.Name.ToString()); gpr[i].Owner = (this.GetMethodIndex(meth) << 1) | 1; } ITypeParameter tp = paramType as ITypeParameter; if (tp != null) gpr[i].Flags = (int)tp.TypeParameterFlags; else { Debug.Assert(false); gpr[i].Flags = 0; } lastMember = m; GenericParamRow temp = gpr[i]; int owner = temp.Owner; for (int j = i - 1; j >= 0; j--) { if (gpr[j].Owner > owner) { gpr[j + 1] = gpr[j]; if (j == 0) { gpr[0] = temp; break; } } else { if (j < i - 1) gpr[j + 1] = temp; break; } } } for (int i = 0; i < n; i++) { Member genPar = gpr[i].GenericParameter; if (genPar == null) continue; this.genericParamIndex[genPar.UniqueKey] = i + 1; } for (int i = 0; i < n; i++) { Member genPar = gpr[i].GenericParameter; if (genPar == null) continue; this.VisitAttributeList(genPar.Attributes, genPar); } //this.genericParamEntries = null; //this.genericParameters = null; } void PopulateGenericParamConstraintTable() { int n = this.genericParamConstraintEntries.Count; if (n == 0) return; GenericParamConstraintRow[] gpcr = this.writer.genericParamConstraintTable = new GenericParamConstraintRow[n]; TypeNode lastParameter = null; int paramIndex = 0; int constraintIndex = 0; int indexOffset = 0; for (int i = 0; i < n; i++) { TypeNode t = this.genericParamConstraintEntries[i]; if (t != lastParameter) { paramIndex = this.GetGenericParamIndex(t); constraintIndex = 0; indexOffset = 0; } gpcr[i].Param = paramIndex; TypeNode constraint; if (constraintIndex == 0 && t.BaseType != null && t.BaseType != CoreSystemTypes.Object) { constraint = t.BaseType; indexOffset = 1; } else constraint = t.Interfaces[constraintIndex - indexOffset]; gpcr[i].Constraint = this.GetTypeDefOrRefOrSpecEncoded(constraint); lastParameter = t; constraintIndex++; GenericParamConstraintRow temp = gpcr[i]; int param = temp.Param; for (int j = i - 1; j >= 0; j--) { if (gpcr[j].Param > param) { gpcr[j + 1] = gpcr[j]; if (j == 0) { gpcr[0] = temp; break; } } else { if (j < i - 1) gpcr[j + 1] = temp; break; } } } //this.genericParamConstraintEntries = null; } void PopulateImplMapTable() { int n = this.implMapEntries.Count; if (n == 0) return; ImplMapRow[] imr = this.writer.implMapTable = new ImplMapRow[n]; for (int i = 0; i < n; i++) { Method m = this.implMapEntries[i]; imr[i].ImportName = this.GetStringIndex(m.PInvokeImportName); imr[i].ImportScope = this.GetModuleRefIndex(m.PInvokeModule); imr[i].MappingFlags = (int)m.PInvokeFlags; imr[i].MemberForwarded = (this.GetMethodIndex(m) << 1) | 1; } //this.implMapEntries = null; } void PopulateInterfaceImplTable() { int n = this.interfaceEntries.Count; if (n == 0) return; InterfaceImplRow[] iir = this.writer.interfaceImplTable = new InterfaceImplRow[n]; TypeNode prevT = null; for (int i = 0, j = 0; i < n; i++) { TypeNode t = this.interfaceEntries[i]; if (t == prevT) j++; else { j = 0; prevT = t; } int ti = iir[i].Class = this.GetTypeDefIndex(t); Interface iface = null; #if ExtendedRuntime if (t is ITypeParameter){ int numIfaces = t.Interfaces == null ? 0 : t.Interfaces.Count; if (j == numIfaces) iface = SystemTypes.ITemplateParameter; else iface = t.Interfaces[j]; }else #endif iface = t.Interfaces[j]; if (iface == null) { i--; continue; } int ii = iir[i].Interface = this.GetTypeDefOrRefOrSpecEncoded(iface); for (int k = 0; k < i; k++) { //REVIEW: is a more efficient sort worthwhile? if (iir[k].Class > ti) { for (int kk = i; kk > k; kk--) { iir[kk].Class = iir[kk - 1].Class; iir[kk].Interface = iir[kk - 1].Interface; } iir[k].Class = ti; iir[k].Interface = ii; break; } } } //this.interfaceEntries = null; } void PopulateManifestResourceTable() { ResourceList resources = this.module.Resources; int n = resources == null ? 0 : resources.Count; if (n == 0) return; ManifestResourceRow[] mresources = this.writer.manifestResourceTable = new ManifestResourceRow[n]; for (int i = 0; i < n; i++) { Resource r = resources[i]; mresources[i].Flags = r.IsPublic ? 1 : 2; mresources[i].Name = this.GetStringIndex(r.Name); if (r.Data != null) mresources[i].Offset = this.GetResourceDataIndex(r.Data); else if (r.DefiningModule is AssemblyNode) mresources[i].Implementation = (this.GetAssemblyRefIndex((AssemblyNode)r.DefiningModule) << 2) | 1; else mresources[i].Implementation = (this.GetFileTableIndex(r.DefiningModule) << 2) | 0; } } void PopulateMarshalTable() { int n = this.marshalEntries.Count; if (n == 0) return; FieldMarshalRow[] fmr = this.writer.fieldMarshalTable = new FieldMarshalRow[n]; for (int i = 0; i < n; i++) { MarshallingInformation mi; Field f = this.marshalEntries[i] as Field; if (f != null) { fmr[i].Parent = (this.GetFieldIndex(f) << 1) | 0; mi = f.MarshallingInformation; } else { Parameter p = (Parameter)this.marshalEntries[i]; fmr[i].Parent = (this.GetParamIndex(p) << 1) | 1; mi = p.MarshallingInformation; } int nt = fmr[i].NativeType = this.GetBlobIndex(mi); int pi = fmr[i].Parent; for (int k = 0; k < i; k++) { //REVIEW: is a more efficient sort worthwhile? if (fmr[k].Parent > pi) { for (int kk = i; kk > k; kk--) { fmr[kk].Parent = fmr[kk - 1].Parent; fmr[kk].NativeType = fmr[kk - 1].NativeType; } fmr[k].Parent = pi; fmr[k].NativeType = nt; break; } } } //this.marshalEntries = null; } void PopulateMemberRefTable() { int n = this.memberRefEntries.Count; if (n == 0) return; MemberRefRow[] mr = this.writer.memberRefTable = new MemberRefRow[n]; for (int i = 0; i < n; i++) { Member member = this.memberRefEntries[i]; if (member == null || member.Name == null) continue; mr[i].Name = this.GetStringIndex(member.Name.ToString()); Field f = member as Field; if (f != null) mr[i].Signature = this.GetBlobIndex(f); else { FunctionPointer fp = member as FunctionPointer; if (fp != null) { mr[i].Signature = this.GetBlobIndex(fp); if (fp is VarargMethodCallSignature) { Method m = ((VarargMethodCallSignature)member).method; if (m != null && m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType)) { mr[i].Class = (this.GetMethodIndex(m) << 3) | 3; continue; } } } else { Method m = (Method)member; if (m.IsGeneric && m.Template != null) m = this.GetUnspecializedMethod(m); mr[i].Signature = this.GetBlobIndex(m, false); if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType) && !m.IsGeneric) { mr[i].Class = (this.GetMethodIndex(m) << 3) | 3; continue; } //TODO: if the declaring type is the special global members type of another module, set class to a module ref } } int j = mr[i].Class = this.GetMemberRefParentEncoded(member.DeclaringType); if ((j & 0x3) == 2) mr[i].Class = (j & ~0x3) | 4; } //this.memberRefEntries = null; } void PopulateMethodTable() { int n = this.methodEntries.Count; if (n == 0) return; MethodRow[] mr = this.writer.methodTable = new MethodRow[n]; for (int i = 0; i < n; i++) { Method m = this.methodEntries[i]; if (m == null || m.Name == null) continue; if (m.IsAbstract || m.Body == null || m.Body.Statements == null || m.Body.Statements.Count == 0) mr[i].RVA = -1; else mr[i].RVA = this.GetMethodBodiesHeapIndex(m); //Fixed up to be an RVA inside MetadataWriter. mr[i].Flags = (int)m.Flags; mr[i].ImplFlags = (int)m.ImplFlags; mr[i].Name = this.GetStringIndex(m.Name.ToString()); mr[i].Signature = this.GetBlobIndex(m, false); if (m.ReturnTypeMarshallingInformation != null || (m.ReturnAttributes != null && m.ReturnAttributes.Count > 0)) mr[i].ParamList = (int)this.paramIndex[m.UniqueKey]; else { ParameterList pars = m.Parameters; if (pars != null && pars.Count > 0) { Debug.Assert(pars[0] != null && pars[0].DeclaringMethod == m); mr[i].ParamList = this.GetParamIndex(pars[0]); } else mr[i].ParamList = 0; } } //this.methodEntries = null; } void PopulateMethodImplTable() { int n = this.methodImplEntries.Count; if (n == 0) return; MethodImplRow[] mir = this.writer.methodImplTable = new MethodImplRow[n]; int j = 0; Method lastMethod = null; for (int i = 0; i < n; i++) { Method m = this.methodImplEntries[i]; if (lastMethod != m) j = 0; mir[i].Class = this.GetTypeDefIndex(m.DeclaringType); if (m.DeclaringType.DeclaringModule == this.module) mir[i].MethodBody = this.GetMethodIndex(m) << 1; else mir[i].MethodBody = (this.GetMemberRefIndex(m) << 1) | 0x1; Method im = m.ImplementedInterfaceMethods[j++]; while (im == null) im = m.ImplementedInterfaceMethods[j++]; mir[i].MethodDeclaration = this.GetMethodDefOrRefEncoded(im); lastMethod = m; } //this.methodImplEntries = null; } void PopulateMethodSpecTable() { int n = this.methodSpecEntries.Count; if (n == 0) return; MethodSpecRow[] msr = this.writer.methodSpecTable = new MethodSpecRow[n]; for (int i = 0; i < n; i++) { Method m = this.methodSpecEntries[i]; msr[i].Method = this.GetMethodDefOrRefEncoded(m.Template); msr[i].Instantiation = this.GetBlobIndex(m, true); //TODO: sort this and eliminate duplicates. //Duplicates can arise when methods are instantiated with method parameters from different methods. //TODO: perhaps this duplication should be prevented by Method.GetTemplateInstance? } //this.methodEntries = null; } void PopulateMethodSemanticsTable() { int n = this.methodSemanticsEntries.Count; if (n == 0) return; MethodSemanticsRow[] msr = this.writer.methodSemanticsTable = new MethodSemanticsRow[n]; Member previousOwner = null; int index = -1; for (int i = 0; i < n; i++) { Member owner = this.methodSemanticsEntries[i]; Property ownerProperty = owner as Property; if (ownerProperty != null) { msr[i].Association = (this.GetPropertyIndex(ownerProperty) << 1) | 1; if (owner != previousOwner) { previousOwner = owner; index = -1; if (ownerProperty.Getter != null) { msr[i].Method = this.GetMethodIndex(ownerProperty.Getter); msr[i].Semantics = 0x0002; continue; } } if (index == -1) { index = 0; if (ownerProperty.Setter != null) { msr[i].Method = this.GetMethodIndex(ownerProperty.Setter); msr[i].Semantics = 0x0001; continue; } } msr[i].Method = this.GetMethodIndex(ownerProperty.OtherMethods[index]); msr[i].Semantics = 0x0004; index++; continue; } Event ownerEvent = owner as Event; if (ownerEvent == null) { Debug.Fail(""); continue; } msr[i].Association = this.GetEventIndex(ownerEvent) << 1; if (owner != previousOwner) { previousOwner = owner; index = -2; if (ownerEvent.HandlerAdder != null) { msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerAdder); msr[i].Semantics = 0x0008; continue; } } if (index == -2) { index = -1; if (ownerEvent.HandlerRemover != null) { msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerRemover); msr[i].Semantics = 0x0010; continue; } } if (index == -1) { index = 0; if (ownerEvent.HandlerCaller != null) { msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerCaller); msr[i].Semantics = 0x0020; continue; } } msr[i].Method = this.GetMethodIndex(ownerEvent.OtherMethods[i]); msr[i].Semantics = 0x0004; index++; continue; } System.Array.Sort(msr, new MethodSemanticsRowComparer()); //this.methodSemanticsEntries = null; } class MethodSemanticsRowComparer : IComparer { int IComparer.Compare(object x, object y) { MethodSemanticsRow xr = (MethodSemanticsRow)x; MethodSemanticsRow yr = (MethodSemanticsRow)y; int result = xr.Association - yr.Association; if (result == 0) result = xr.Method - yr.Method; return result; } } void PopulateModuleTable() { ModuleRow[] mr = this.writer.moduleTable = new ModuleRow[1]; string name = this.module.Name; if (this.assembly != null) { if (this.assembly.ModuleName != null) name = this.assembly.ModuleName; else { string extension = ".exe"; if (this.module.Kind == ModuleKindFlags.DynamicallyLinkedLibrary) extension = ".dll"; name = name + extension; } } mr[0].Name = this.GetStringIndex(name); mr[0].Mvid = this.GetGuidIndex(Guid.NewGuid()); } void PopulateModuleRefTable() { int n = this.moduleRefEntries.Count; if (n == 0) return; ModuleRefRow[] mrr = this.writer.moduleRefTable = new ModuleRefRow[n]; for (int i = 0; i < n; i++) { ModuleReference moduleRef = this.moduleRefEntries[i]; mrr[i].Name = this.GetStringIndex(moduleRef.Name); } //this.moduleRefEntries = null; } void PopulateNestedClassTable() { int n = this.nestedClassEntries.Count; if (n == 0) return; NestedClassRow[] ncr = this.writer.nestedClassTable = new NestedClassRow[n]; for (int i = 0; i < n; i++) { TypeNode nt = this.nestedClassEntries[i]; ncr[i].NestedClass = this.GetTypeDefIndex(nt); ncr[i].EnclosingClass = this.GetTypeDefIndex(nt.DeclaringType); } //this.nestedClassEntries = null; } void PopulateParamTable() { int n = this.paramEntries.Count; if (n == 0) return; ParamRow[] pr = this.writer.paramTable = new ParamRow[n]; for (int i = 0; i < n; i++) { Parameter p = this.paramEntries[i]; if (p == null) continue; pr[i].Flags = (int)p.Flags; pr[i].Sequence = p.ParameterListIndex + 1; pr[i].Name = p.Name == null ? 0 : this.GetStringIndex(p.Name.ToString()); } //this.paramEntries = null; } void PopulatePropertyTable() { int n = this.propertyEntries.Count; if (n == 0) return; PropertyRow[] pr = this.writer.propertyTable = new PropertyRow[n]; for (int i = 0; i < n; i++) { Property p = this.propertyEntries[i]; if (p == null || p.Name == null) continue; pr[i].Flags = (int)p.Flags; pr[i].Name = this.GetStringIndex(p.Name.ToString()); pr[i].Signature = this.GetBlobIndex(p); } //this.propertyEntries = null; } void PopulatePropertyMapTable() { int n = this.propertyMapEntries.Count; if (n == 0) return; PropertyMapRow[] pmr = this.writer.propertyMapTable = new PropertyMapRow[n]; for (int i = 0; i < n; i++) { Property p = this.propertyMapEntries[i]; pmr[i].Parent = this.GetTypeDefIndex(p.DeclaringType); pmr[i].PropertyList = this.GetPropertyIndex(p); } //this.propertyMapEntries = null; } void PopulateStandAloneSigTable() { int n = this.standAloneSignatureEntries.Count; if (n == 0) return; StandAloneSigRow[] sasr = this.writer.standAloneSigTable = new StandAloneSigRow[n]; for (int i = 0; i < n; i++) { BinaryWriter sigWriter = (BinaryWriter)this.standAloneSignatureEntries[i]; sasr[i].Signature = this.GetBlobIndex(((MemoryStream)sigWriter.BaseStream).ToArray()); } } void PopulateTypeDefTable() { int n = this.typeDefEntries.Count; if (n == 0) return; TypeDefRow[] tdr = this.writer.typeDefTable = new TypeDefRow[n]; for (int i = 0; i < n; i++) { TypeNode t = this.typeDefEntries[i]; if (t == null) continue; tdr[i].Flags = (int)t.Flags; tdr[i].Name = this.GetStringIndex(t.Name == null ? "" : t.Name.ToString()); tdr[i].Namespace = t.Namespace == null ? 0 : this.GetStringIndex(t.Namespace == null ? "" : t.Namespace.ToString()); tdr[i].Extends = this.GetTypeDefOrRefOrSpecEncoded(t.BaseType); MemberList members = t.Members; int m = members.Count; for (int j = 0; j < m; j++) { Member mem = members[j]; if (mem == null) continue; if (mem.NodeType == NodeType.Field) { tdr[i].FieldList = this.GetFieldIndex((Field)mem); break; } } for (int j = 0; j < m; j++) { Member mem = members[j]; if (mem == null) continue; switch (mem.NodeType) { case NodeType.Method: case NodeType.InstanceInitializer: case NodeType.StaticInitializer: tdr[i].MethodList = this.GetMethodIndex((Method)mem); goto done; } } done: continue; } //this.typeDefEntries = null; } void PopulateTypeRefTable() { int n = this.typeRefEntries.Count; if (n == 0) return; TypeRefRow[] trr = this.writer.typeRefTable = new TypeRefRow[n]; for (int i = 0; i < n; i++) { TypeNode t = this.typeRefEntries[i]; if (t == null || t.Name == null || t.Namespace == null) continue; trr[i].Name = this.GetStringIndex(t.Name.ToString()); trr[i].Namespace = this.GetStringIndex(t.Namespace.ToString()); if (t.DeclaringType == null) if (t.DeclaringModule is AssemblyNode) trr[i].ResolutionScope = (this.GetAssemblyRefIndex((AssemblyNode)t.DeclaringModule) << 2) | 2; else trr[i].ResolutionScope = (this.GetModuleRefIndex(t.DeclaringModule) << 2) | 1; else trr[i].ResolutionScope = (this.GetTypeRefIndex(t.DeclaringType) << 2) | 3; } //this.typeRefEntries = null; } void PopulateTypeSpecTable() { int n = this.typeSpecEntries.Count; if (n == 0) return; TypeSpecRow[] tsr = this.writer.typeSpecTable = new TypeSpecRow[n]; for (int i = 0; i < n; i++) { TypeNode t = this.typeSpecEntries[i]; tsr[i].Signature = this.GetBlobIndex(t); //TODO: eliminate duplicates } //this.typeSpecEntries = null; } void Visit(Node node) { if (node == null) return; switch (node.NodeType) { case NodeType.AddressDereference: this.VisitAddressDereference((AddressDereference)node); return; case NodeType.Arglist: this.VisitExpression((Expression)node); return; case NodeType.AssignmentStatement: this.VisitAssignmentStatement((AssignmentStatement)node); return; #if !MinimalReader case NodeType.Base: this.VisitBase((Base)node); return; #endif case NodeType.Block: this.VisitBlock((Block)node); return; #if !MinimalReader case NodeType.BlockExpression: this.VisitBlockExpression((BlockExpression)node); return; #endif case NodeType.Branch: this.VisitBranch((Branch)node); return; case NodeType.DebugBreak: this.VisitStatement((Statement)node); return; case NodeType.Call: case NodeType.Calli: case NodeType.Callvirt: case NodeType.Jmp: #if !MinimalReader case NodeType.MethodCall: #endif this.VisitMethodCall((MethodCall)node); return; case NodeType.Class: case NodeType.ClassParameter: this.VisitClass((Class)node); return; case NodeType.Construct: this.VisitConstruct((Construct)node); return; case NodeType.ConstructArray: this.VisitConstructArray((ConstructArray)node); return; case NodeType.DelegateNode: this.VisitDelegateNode((DelegateNode)node); return; case NodeType.Dup: this.VisitExpression((Expression)node); return; case NodeType.EndFilter: this.VisitEndFilter((EndFilter)node); return; case NodeType.EndFinally: this.VisitStatement((Statement)node); return; case NodeType.EnumNode: this.VisitEnumNode((EnumNode)node); return; case NodeType.Event: this.VisitEvent((Event)node); return; case NodeType.ExpressionStatement: this.VisitExpressionStatement((ExpressionStatement)node); return; case NodeType.Field: this.VisitField((Field)node); return; case NodeType.Indexer: this.VisitIndexer((Indexer)node); return; case NodeType.InstanceInitializer: case NodeType.StaticInitializer: case NodeType.Method: this.VisitMethod((Method)node); return; case NodeType.TypeParameter: case NodeType.Interface: this.VisitInterface((Interface)node); return; case NodeType.Literal: this.VisitLiteral((Literal)node); return; case NodeType.Local: this.VisitLocal((Local)node); return; #if !MinimalReader case NodeType.LocalDeclarationsStatement: this.VisitLocalDeclarationsStatement((LocalDeclarationsStatement)node); return; #endif case NodeType.MemberBinding: this.VisitMemberBinding((MemberBinding)node); return; case NodeType.Nop: this.VisitStatement((Statement)node); return; case NodeType.Parameter: this.VisitParameter((Parameter)node); return; case NodeType.Pop: this.VisitExpression((Expression)node); return; case NodeType.Property: this.VisitProperty((Property)node); return; case NodeType.Rethrow: case NodeType.Throw: this.VisitThrow((Throw)node); return; case NodeType.Return: this.VisitReturn((Return)node); return; case NodeType.Struct: #if !MinimalReader case NodeType.TypeAlias: case NodeType.TypeIntersection: case NodeType.TypeUnion: case NodeType.TupleType: #endif this.VisitStruct((Struct)node); return; #if !MinimalReader case NodeType.SwitchCaseBottom: return; #endif case NodeType.SwitchInstruction: this.VisitSwitchInstruction((SwitchInstruction)node); return; case NodeType.This: this.VisitThis((This)node); return; case NodeType.Cpblk: case NodeType.Initblk: this.VisitTernaryExpression((TernaryExpression)node); return; case NodeType.Add: case NodeType.Add_Ovf: case NodeType.Add_Ovf_Un: case NodeType.And: case NodeType.Box: case NodeType.Castclass: case NodeType.Ceq: case NodeType.Cgt: case NodeType.Cgt_Un: case NodeType.Clt: case NodeType.Clt_Un: case NodeType.Div: case NodeType.Div_Un: case NodeType.Eq: case NodeType.Ge: case NodeType.Gt: #if !MinimalReader case NodeType.Is: #endif case NodeType.Isinst: case NodeType.Ldvirtftn: case NodeType.Le: case NodeType.Lt: case NodeType.Mkrefany: case NodeType.Mul: case NodeType.Mul_Ovf: case NodeType.Mul_Ovf_Un: case NodeType.Ne: case NodeType.Or: case NodeType.Refanyval: case NodeType.Rem: case NodeType.Rem_Un: case NodeType.Shl: case NodeType.Shr: case NodeType.Shr_Un: case NodeType.Sub: case NodeType.Sub_Ovf: case NodeType.Sub_Ovf_Un: case NodeType.Unbox: case NodeType.UnboxAny: case NodeType.Xor: this.VisitBinaryExpression((BinaryExpression)node); return; case NodeType.AddressOf: #if !MinimalReader case NodeType.OutAddress: case NodeType.RefAddress: #endif case NodeType.ReadOnlyAddressOf: this.VisitAddressOf((UnaryExpression)node); return; case NodeType.Ckfinite: case NodeType.Conv_I: case NodeType.Conv_I1: case NodeType.Conv_I2: case NodeType.Conv_I4: case NodeType.Conv_I8: case NodeType.Conv_Ovf_I: case NodeType.Conv_Ovf_I1: case NodeType.Conv_Ovf_I1_Un: case NodeType.Conv_Ovf_I2: case NodeType.Conv_Ovf_I2_Un: case NodeType.Conv_Ovf_I4: case NodeType.Conv_Ovf_I4_Un: case NodeType.Conv_Ovf_I8: case NodeType.Conv_Ovf_I8_Un: case NodeType.Conv_Ovf_I_Un: case NodeType.Conv_Ovf_U: case NodeType.Conv_Ovf_U1: case NodeType.Conv_Ovf_U1_Un: case NodeType.Conv_Ovf_U2: case NodeType.Conv_Ovf_U2_Un: case NodeType.Conv_Ovf_U4: case NodeType.Conv_Ovf_U4_Un: case NodeType.Conv_Ovf_U8: case NodeType.Conv_Ovf_U8_Un: case NodeType.Conv_Ovf_U_Un: case NodeType.Conv_R4: case NodeType.Conv_R8: case NodeType.Conv_R_Un: case NodeType.Conv_U: case NodeType.Conv_U1: case NodeType.Conv_U2: case NodeType.Conv_U4: case NodeType.Conv_U8: case NodeType.Ldftn: case NodeType.Ldlen: case NodeType.Ldtoken: case NodeType.Localloc: case NodeType.Neg: case NodeType.Not: case NodeType.Refanytype: case NodeType.Sizeof: this.VisitUnaryExpression((UnaryExpression)node); return; default: // handle type extensions with new NodeType's, that are emitted as ordinary structs and classes Class cl = node as Class; if (cl != null) { this.VisitClass(cl); return; } Struct st = node as Struct; if (st != null) { this.VisitStruct(st); return; } Debug.Assert(false, "invalid node: " + node.NodeType.ToString()); return; } } void VisitAddressDereference(AddressDereference/*!*/ adr) { this.Visit(adr.Address); if (adr.Alignment > 0) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x12); this.methodBodyHeap.Write((byte)adr.Alignment); } if (adr.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } switch (adr.Type.typeCode) { case ElementType.Int8: this.methodBodyHeap.Write((byte)0x46); return; case ElementType.UInt8: this.methodBodyHeap.Write((byte)0x47); return; case ElementType.Int16: this.methodBodyHeap.Write((byte)0x48); return; case ElementType.Char: case ElementType.UInt16: this.methodBodyHeap.Write((byte)0x49); return; case ElementType.Int32: this.methodBodyHeap.Write((byte)0x4a); return; case ElementType.UInt32: this.methodBodyHeap.Write((byte)0x4b); return; case ElementType.Int64: case ElementType.UInt64: this.methodBodyHeap.Write((byte)0x4c); return; //case ElementType.UIntPtr: //case ElementType.IntPtr: this.methodBodyHeap.Write((byte)0x4d); return; case ElementType.Single: this.methodBodyHeap.Write((byte)0x4e); return; case ElementType.Double: this.methodBodyHeap.Write((byte)0x4f); return; default: if (adr.Type.IsValueType || (adr.Type is ITypeParameter && this.UseGenerics)) { this.methodBodyHeap.Write((byte)0x71); this.methodBodyHeap.Write((int)this.GetTypeToken(adr.Type)); return; } else if (TypeNode.StripModifiers(adr.Type) is Pointer) { this.methodBodyHeap.Write((byte)0x4d); return; } this.methodBodyHeap.Write((byte)0x50); return; } } void VisitAttributeList(AttributeList attrs, Node/*!*/ node) { if (attrs == null) return; int n = attrs.Count; if (n == 0) return; int m = n; for (int j = 0; j < n; j++) { AttributeNode a = attrs[j]; if (a == null) m--; } if (m == 0) return; n = m; int codedIndex = this.GetCustomAttributeParentCodedIndex(node); this.customAttributeCount += n; m = this.nodesWithCustomAttributes.Count; this.nodesWithCustomAttributes.Add(node); int i = 0; //after the for loop i will be position where the new node should be in sorted list NodeList nodes = this.nodesWithCustomAttributes; for (i = m; i > 0; i--) { Node other = nodes[i - 1]; int oci = this.GetCustomAttributeParentCodedIndex(other); if (oci < codedIndex) break; if (UseGenerics) { if (oci == codedIndex) Debug.Assert(false); } } if (i == m) return; //node is already where it should be for (int j = m; j > i; j--) nodes[j] = nodes[j - 1]; //Make space at postion i nodes[i] = node; } void VisitAddressOf(UnaryExpression/*!*/ expr) { Expression operand = expr.Operand; if (operand == null) return; switch (operand.NodeType) { case NodeType.Indexer: Indexer indexer = (Indexer)operand; this.Visit(indexer.Object); if (indexer.Operands == null || indexer.Operands.Count < 1) return; this.Visit(indexer.Operands[0]); if (expr.NodeType == NodeType.ReadOnlyAddressOf) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x1e); } this.methodBodyHeap.Write((byte)0x8f); this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType)); this.stackHeight--; return; case NodeType.Local: int li = this.GetLocalVarIndex((Local)operand); if (li < 256) { this.methodBodyHeap.Write((byte)0x12); this.methodBodyHeap.Write((byte)li); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x0d); this.methodBodyHeap.Write((ushort)li); } this.IncrementStackHeight(); return; case NodeType.MemberBinding: MemberBinding mb = (MemberBinding)operand; if (mb.TargetObject != null) { this.Visit(mb.TargetObject); this.methodBodyHeap.Write((byte)0x7c); } else { this.methodBodyHeap.Write((byte)0x7f); this.IncrementStackHeight(); } this.methodBodyHeap.Write((int)this.GetFieldToken((Field)mb.BoundMember)); return; case NodeType.Parameter: #if !MinimalReader ParameterBinding pb = operand as ParameterBinding; if (pb != null) operand = pb.BoundParameter; #endif int pi = ((Parameter)operand).ArgumentListIndex; if (pi < 256) { this.methodBodyHeap.Write((byte)0x0f); this.methodBodyHeap.Write((byte)pi); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x0a); this.methodBodyHeap.Write((ushort)pi); } this.IncrementStackHeight(); return; } } void VisitAssignmentStatement(AssignmentStatement/*!*/ assignment) { this.DefineSequencePoint(assignment); Expression target = assignment.Target; switch (assignment.Target.NodeType) { case NodeType.Local: Local loc = (Local)target; this.Visit(assignment.Source); this.stackHeight--; int li = this.GetLocalVarIndex(loc); switch (li) { case 0: this.methodBodyHeap.Write((byte)0x0a); return; case 1: this.methodBodyHeap.Write((byte)0x0b); return; case 2: this.methodBodyHeap.Write((byte)0x0c); return; case 3: this.methodBodyHeap.Write((byte)0x0d); return; default: if (li < 256) { this.methodBodyHeap.Write((byte)0x13); this.methodBodyHeap.Write((byte)li); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x0e); this.methodBodyHeap.Write((ushort)li); } return; } case NodeType.MemberBinding: MemberBinding mb = (MemberBinding)target; if (mb.TargetObject != null) this.Visit(mb.TargetObject); this.Visit(assignment.Source); if (mb.TargetObject != null) { if (mb.Alignment != -1) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x12); this.methodBodyHeap.Write((byte)mb.Alignment); } if (mb.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } this.methodBodyHeap.Write((byte)0x7d); } else { if (mb.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } this.methodBodyHeap.Write((byte)0x80); } this.methodBodyHeap.Write((int)this.GetFieldToken((Field)mb.BoundMember)); if (mb.TargetObject != null) this.stackHeight -= 2; else this.stackHeight--; return; case NodeType.Parameter: #if !MinimalReader ParameterBinding pb = target as ParameterBinding; if (pb != null) target = pb.BoundParameter; #endif Parameter par = (Parameter)target; this.Visit(assignment.Source); int pi = par.ArgumentListIndex; if (pi < 256) { this.methodBodyHeap.Write((byte)0x10); this.methodBodyHeap.Write((byte)pi); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x0b); this.methodBodyHeap.Write((ushort)pi); } this.stackHeight--; return; case NodeType.Indexer: Indexer indexer = (Indexer)target; this.Visit(indexer.Object); if (indexer.Operands == null || indexer.Operands.Count < 1) return; this.Visit(indexer.Operands[0]); this.Visit(assignment.Source); byte opCode; switch (indexer.ElementType.typeCode) { case ElementType.UIntPtr: case ElementType.IntPtr: opCode = 0x9b; break; case ElementType.Boolean: case ElementType.Int8: case ElementType.UInt8: opCode = 0x9c; break; case ElementType.Char: case ElementType.Int16: case ElementType.UInt16: opCode = 0x9d; break; case ElementType.Int32: case ElementType.UInt32: opCode = 0x9e; break; case ElementType.Int64: case ElementType.UInt64: opCode = 0x9f; break; case ElementType.Single: opCode = 0xa0; break; case ElementType.Double: opCode = 0xa1; break; default: if (this.UseGenerics && (indexer.ElementType is ITypeParameter)) opCode = 0xa4; else if (TypeNode.StripModifiers(indexer.ElementType) is Pointer) opCode = 0x9b; else opCode = 0xa2; break; } this.methodBodyHeap.Write((byte)opCode); if (opCode == 0xa4) this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType)); this.stackHeight -= 3; return; case NodeType.AddressDereference: AddressDereference adr = (AddressDereference)target; this.Visit(adr.Address); if (adr.Type.IsValueType || adr.Type is ITypeParameter) { Literal lit = assignment.Source as Literal; if (lit != null && lit.Value == null) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x15); this.methodBodyHeap.Write((int)this.GetTypeToken(adr.Type)); this.stackHeight--; return; } } this.Visit(assignment.Source); this.stackHeight -= 2; if (adr.Alignment > 0) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x12); this.methodBodyHeap.Write((byte)adr.Alignment); } if (adr.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } TypeNode adrType = TypeNode.StripModifiers(adr.Type); if (adrType == null) return; switch (adrType.typeCode) { case ElementType.Int8: case ElementType.UInt8: this.methodBodyHeap.Write((byte)0x52); return; case ElementType.Int16: case ElementType.UInt16: this.methodBodyHeap.Write((byte)0x53); return; case ElementType.Int32: case ElementType.UInt32: this.methodBodyHeap.Write((byte)0x54); return; case ElementType.Int64: case ElementType.UInt64: this.methodBodyHeap.Write((byte)0x55); return; case ElementType.Single: this.methodBodyHeap.Write((byte)0x56); return; case ElementType.Double: this.methodBodyHeap.Write((byte)0x57); return; case ElementType.UIntPtr: case ElementType.IntPtr: this.methodBodyHeap.Write((byte)0xdf); return; default: if (adrType != null && (adrType.IsValueType || this.UseGenerics && (adrType is ITypeParameter))) { this.methodBodyHeap.Write((byte)0x81); this.methodBodyHeap.Write((int)this.GetTypeToken(adrType)); return; } if (adrType.NodeType == NodeType.Pointer) { this.methodBodyHeap.Write((byte)0xdf); return; } this.methodBodyHeap.Write((byte)0x51); return; } default: Debug.Assert(false, "unexpected assignment target"); return; } } #if !MinimalReader void VisitBase(Base/*!*/ Base) { this.IncrementStackHeight(); this.methodBodyHeap.Write((byte)0x02); } #endif void VisitBinaryExpression(BinaryExpression/*!*/ binaryExpression) { byte opCode = 0; this.Visit(binaryExpression.Operand1); switch (binaryExpression.NodeType) { case NodeType.Castclass: opCode = 0x74; goto writeOpCodeAndToken; case NodeType.Isinst: opCode = 0x75; goto writeOpCodeAndToken; case NodeType.Unbox: opCode = 0x79; goto writeOpCodeAndToken; case NodeType.UnboxAny: opCode = 0xa5; goto writeOpCodeAndToken; case NodeType.Box: opCode = 0x8c; goto writeOpCodeAndToken; case NodeType.Refanyval: opCode = 0xc2; goto writeOpCodeAndToken; case NodeType.Mkrefany: opCode = 0xc6; goto writeOpCodeAndToken; writeOpCodeAndToken: this.methodBodyHeap.Write((byte)opCode); Literal lit = binaryExpression.Operand2 as Literal; if (lit != null) this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)lit.Value)); else { // TODO: Normalized IR should never use a MemberBinding to represent a type this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)((MemberBinding)binaryExpression.Operand2).BoundMember)); } return; case NodeType.Ldvirtftn: opCode = 0x07; this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)opCode); this.methodBodyHeap.Write((int)this.GetMethodToken((Method)((MemberBinding)binaryExpression.Operand2).BoundMember)); return; } this.Visit(binaryExpression.Operand2); switch (binaryExpression.NodeType) { case NodeType.Add: opCode = 0x58; break; case NodeType.Sub: opCode = 0x59; break; case NodeType.Mul: opCode = 0x5a; break; case NodeType.Div: opCode = 0x5b; break; case NodeType.Div_Un: opCode = 0x5c; break; case NodeType.Rem: opCode = 0x5d; break; case NodeType.Rem_Un: opCode = 0x5e; break; case NodeType.And: opCode = 0x5f; break; case NodeType.Or: opCode = 0x60; break; case NodeType.Xor: opCode = 0x61; break; case NodeType.Shl: opCode = 0x62; break; case NodeType.Shr: opCode = 0x63; break; case NodeType.Shr_Un: opCode = 0x64; break; case NodeType.Add_Ovf: opCode = 0xd6; break; case NodeType.Add_Ovf_Un: opCode = 0xd7; break; case NodeType.Mul_Ovf: opCode = 0xd8; break; case NodeType.Mul_Ovf_Un: opCode = 0xd9; break; case NodeType.Sub_Ovf: opCode = 0xda; break; case NodeType.Sub_Ovf_Un: opCode = 0xdb; break; case NodeType.Ceq: opCode = 0x01; this.methodBodyHeap.Write((byte)0xfe); break; case NodeType.Cgt: opCode = 0x02; this.methodBodyHeap.Write((byte)0xfe); break; case NodeType.Cgt_Un: opCode = 0x03; this.methodBodyHeap.Write((byte)0xfe); break; case NodeType.Clt: opCode = 0x04; this.methodBodyHeap.Write((byte)0xfe); break; case NodeType.Clt_Un: opCode = 0x05; this.methodBodyHeap.Write((byte)0xfe); break; } this.methodBodyHeap.Write((byte)opCode); this.stackHeight--; } void VisitBlock(Block/*!*/ block) { MethodInfo mInfo = this.methodInfo; int currentAddress = (int)this.methodBodyHeap.BaseStream.Position; this.VisitFixupList((Fixup)this.methodInfo.fixupIndex[block.UniqueKey], currentAddress); mInfo.fixupIndex[block.UniqueKey] = currentAddress; this.methodBodyHeap.BaseStream.Position = currentAddress; int savedStackHeight = this.stackHeight; if (this.exceptionBlock[block.UniqueKey] != null) this.stackHeight = 1; StatementList statements = block.Statements; if (statements == null) return; #if !ROTOR if (this.symWriter != null && block.HasLocals) { LocalList savedDebugLocals = mInfo.debugLocals; Int32List savedSignatureLengths = mInfo.signatureLengths; Int32List savedSignatureOffsets = mInfo.signatureOffsets; mInfo.debugLocals = new LocalList(); mInfo.signatureLengths = new Int32List(); mInfo.signatureOffsets = new Int32List(); this.symWriter.OpenScope((uint)currentAddress); for (int i = 0, n = statements.Count; i < n; i++) this.Visit(statements[i]); if (this.stackHeight > 0) this.stackHeightExitTotal += this.stackHeight; this.DefineLocalVariables(currentAddress, mInfo.debugLocals); mInfo.debugLocals = savedDebugLocals; mInfo.signatureLengths = savedSignatureLengths; mInfo.signatureOffsets = savedSignatureOffsets; } else { #endif for (int i = 0, n = statements.Count; i < n; i++) this.Visit(statements[i]); if (this.stackHeight > savedStackHeight) this.stackHeightExitTotal += (this.stackHeight - savedStackHeight); #if !ROTOR } #endif this.stackHeight = savedStackHeight; } #if !MinimalReader void VisitBlockExpression(BlockExpression/*!*/ blockExpression) { if (blockExpression.Block == null) return; this.VisitBlock(blockExpression.Block); } #endif void VisitBranch(Branch/*!*/ branch) { this.DefineSequencePoint(branch); BinaryExpression bex = branch.Condition as BinaryExpression; UnaryExpression uex = null; NodeType typeOfCondition = NodeType.Nop; if (bex != null) { switch (bex.NodeType) { case NodeType.Eq: case NodeType.Ge: case NodeType.Gt: case NodeType.Le: case NodeType.Lt: case NodeType.Ne: this.Visit(bex.Operand1); this.Visit(bex.Operand2); typeOfCondition = bex.NodeType; this.stackHeight -= 2; break; case NodeType.And: case NodeType.Or: case NodeType.Xor: case NodeType.Isinst: case NodeType.Castclass: typeOfCondition = bex.NodeType; goto default; default: this.Visit(branch.Condition); this.stackHeight--; break; } } else { uex = branch.Condition as UnaryExpression; if (uex != null && uex.NodeType == NodeType.LogicalNot) { this.Visit(uex.Operand); typeOfCondition = NodeType.LogicalNot; this.stackHeight--; } else if (branch.Condition != null) { // Undefined is used here simply as a sentinel value typeOfCondition = NodeType.Undefined; this.Visit(branch.Condition); this.stackHeight--; } } int target = this.GetOffset(branch.Target, ref branch.shortOffset); if (branch.ShortOffset) { switch (typeOfCondition) { case NodeType.Nop: if (branch.Condition == null) { if (branch.LeavesExceptionBlock) this.methodBodyHeap.Write((byte)0xde); else this.methodBodyHeap.Write((byte)0x2b); break; } else { this.methodBodyHeap.Write((byte)0x2d); break; } case NodeType.And: case NodeType.Or: case NodeType.Xor: case NodeType.Isinst: case NodeType.Castclass: case NodeType.Undefined: this.methodBodyHeap.Write((byte)0x2d); break; case NodeType.LogicalNot: this.methodBodyHeap.Write((byte)0x2c); break; case NodeType.Eq: this.methodBodyHeap.Write((byte)0x2e); break; case NodeType.Ge: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x34); else this.methodBodyHeap.Write((byte)0x2f); break; case NodeType.Gt: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x35); else this.methodBodyHeap.Write((byte)0x30); break; case NodeType.Le: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x36); else this.methodBodyHeap.Write((byte)0x31); break; case NodeType.Lt: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x37); else this.methodBodyHeap.Write((byte)0x32); break; case NodeType.Ne: this.methodBodyHeap.Write((byte)0x33); break; } this.methodBodyHeap.Write((sbyte)target); } else { switch (typeOfCondition) { case NodeType.Nop: if (branch.Condition == null) { if (branch.LeavesExceptionBlock) this.methodBodyHeap.Write((byte)0xdd); else this.methodBodyHeap.Write((byte)0x38); break; } else { this.methodBodyHeap.Write((byte)0x3a); break; } case NodeType.And: case NodeType.Or: case NodeType.Xor: case NodeType.Isinst: case NodeType.Castclass: case NodeType.Undefined: this.methodBodyHeap.Write((byte)0x3a); break; case NodeType.LogicalNot: this.methodBodyHeap.Write((byte)0x39); break; case NodeType.Eq: this.methodBodyHeap.Write((byte)0x3b); break; case NodeType.Ge: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x41); else this.methodBodyHeap.Write((byte)0x3c); break; case NodeType.Gt: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x42); else this.methodBodyHeap.Write((byte)0x3d); break; case NodeType.Le: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x43); else this.methodBodyHeap.Write((byte)0x3e); break; case NodeType.Lt: if (branch.BranchIfUnordered) this.methodBodyHeap.Write((byte)0x44); else this.methodBodyHeap.Write((byte)0x3f); break; case NodeType.Ne: this.methodBodyHeap.Write((byte)0x40); break; } this.methodBodyHeap.Write((int)target); } } void VisitMethodCall(MethodCall/*!*/ call) { MemberBinding mb = (MemberBinding)call.Callee; TypeNode constraint = call.Constraint; this.Visit(mb.TargetObject); ExpressionList arguments = call.Operands; int pops = 0; if (arguments != null) { this.VisitExpressionList(arguments); pops = arguments.Count; } if (call.Type != CoreSystemTypes.Void) { this.VisitReferencedType(call.Type); pops--; } if (pops >= 0) this.stackHeight -= pops; else this.IncrementStackHeight(); //make sure the high water mark moves up if necessary if (call.IsTailCall) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x14); } else if (constraint != null) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x16); this.methodBodyHeap.Write((int)this.GetTypeToken(constraint)); } switch (call.NodeType) { case NodeType.Calli: this.methodBodyHeap.Write((byte)0x29); BinaryWriter sig = new BinaryWriter(new MemoryStream()); this.WriteMethodSignature(sig, (FunctionPointer)mb.BoundMember); this.methodBodyHeap.Write((int)(0x11000000 | this.GetStandAloneSignatureIndex(sig))); return; case NodeType.Callvirt: this.methodBodyHeap.Write((byte)0x6f); break; case NodeType.Jmp: this.methodBodyHeap.Write((byte)0x27); break; default: this.methodBodyHeap.Write((byte)0x28); break; } Method method = (Method)mb.BoundMember; if ((method.CallingConvention & (CallingConventionFlags)7) == CallingConventionFlags.VarArg || (method.CallingConvention & (CallingConventionFlags)7) == CallingConventionFlags.C) { this.methodBodyHeap.Write((int)this.GetMemberRefToken(method, arguments)); } else this.methodBodyHeap.Write((int)this.GetMethodToken(method)); } void VisitClass(Class/*!*/ Class) { if (this.UseGenerics && Class.Template != null && Class.Template.IsGeneric) return; this.VisitAttributeList(Class.Attributes, Class); this.VisitSecurityAttributeList(Class.SecurityAttributes, Class); if (Class.BaseClass != null) this.VisitReferencedType(Class.BaseClass); for (int i = 0, n = Class.Interfaces == null ? 0 : Class.Interfaces.Count; i < n; i++) { this.GetTypeDefOrRefOrSpecEncoded(Class.Interfaces[i]); if (Class.Interfaces[i] != null) this.interfaceEntries.Add(Class); } if (Class.NodeType == NodeType.ClassParameter && !(Class is MethodClassParameter)) this.interfaceEntries.Add(Class); for (int i = 0, n = Class.Members.Count; i < n; i++) { Member mem = Class.Members[i]; if (mem == null || mem is TypeNode) continue; this.Visit(mem); } if ((Class.Flags & (TypeFlags.ExplicitLayout | TypeFlags.SequentialLayout)) != 0 && (Class.PackingSize != 0 || Class.ClassSize != 0)) this.classLayoutEntries.Add(Class); } void VisitConstruct(Construct/*!*/ cons) { int pops = -1; ExpressionList operands = cons.Operands; if (operands != null) { this.VisitExpressionList(cons.Operands); pops = operands.Count - 1; } if (pops >= 0) this.stackHeight -= pops; else this.IncrementStackHeight(); this.methodBodyHeap.Write((byte)0x73); Method method = ((MemberBinding)cons.Constructor).BoundMember as Method; if (method == null) return; this.methodBodyHeap.Write((int)this.GetMethodToken(method)); //REVIEW: varargs? } void VisitConstructArray(ConstructArray/*!*/ consArr) { if (consArr == null || consArr.Operands == null || consArr.Operands.Count < 1) return; this.Visit(consArr.Operands[0]); this.methodBodyHeap.Write((byte)0x8d); this.methodBodyHeap.Write((int)this.GetTypeToken(consArr.ElementType)); } void VisitDelegateNode(DelegateNode/*!*/ delegateNode) { if (this.UseGenerics && delegateNode.Template != null && delegateNode.Template.IsGeneric) return; this.VisitAttributeList(delegateNode.Attributes, delegateNode); this.VisitSecurityAttributeList(delegateNode.SecurityAttributes, delegateNode); this.VisitReferencedType(CoreSystemTypes.MulticastDelegate); for (int i = 0, n = delegateNode.Interfaces == null ? 0 : delegateNode.Interfaces.Count; i < n; i++) { //REVIEW: is this valid? this.GetTypeDefOrRefOrSpecEncoded(delegateNode.Interfaces[i]); if (delegateNode.Interfaces[i] != null) this.interfaceEntries.Add(delegateNode); } for (int i = 0, n = delegateNode.Members.Count; i < n; i++) { Member mem = delegateNode.Members[i]; if (mem == null || mem is TypeNode) continue; this.Visit(mem); } } void VisitEndFilter(EndFilter/*!*/ endFilter) { this.DefineSequencePoint(endFilter); this.Visit(endFilter.Value); this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x11); this.stackHeight--; } void VisitEnumNode(EnumNode/*!*/ enumNode) { this.VisitAttributeList(enumNode.Attributes, enumNode); this.VisitSecurityAttributeList(enumNode.SecurityAttributes, enumNode); this.VisitReferencedType(CoreSystemTypes.Enum); for (int i = 0, n = enumNode.Interfaces == null ? 0 : enumNode.Interfaces.Count; i < n; i++) { this.GetTypeDefOrRefOrSpecEncoded(enumNode.Interfaces[i]); if (enumNode.Interfaces[i] != null) this.interfaceEntries.Add(enumNode); } for (int i = 0, n = enumNode.Members.Count; i < n; i++) this.Visit(enumNode.Members[i]); } void VisitEvent(Event/*!*/ Event) { object eindex = this.eventIndex[Event.UniqueKey]; if (eindex != null) return; int index = this.eventEntries.Count + 1; this.eventEntries.Add(Event); this.eventIndex[Event.UniqueKey] = index; object evindex = this.eventMapIndex[Event.DeclaringType.UniqueKey]; if (evindex == null) { this.eventMapEntries.Add(Event); this.eventMapIndex[Event.DeclaringType.UniqueKey] = this.eventMapEntries.Count; } if (Event.HandlerAdder != null) this.methodSemanticsEntries.Add(Event); if (Event.HandlerRemover != null) this.methodSemanticsEntries.Add(Event); if (Event.HandlerCaller != null) this.methodSemanticsEntries.Add(Event); if (Event.OtherMethods != null) for (int i = 0, n = Event.OtherMethods.Count; i < n; i++) this.methodSemanticsEntries.Add(Event); this.VisitAttributeList(Event.Attributes, Event); } void VisitExpression(Expression/*!*/ expression) { switch (expression.NodeType) { case NodeType.Dup: this.methodBodyHeap.Write((byte)0x25); this.IncrementStackHeight(); return; case NodeType.Pop: UnaryExpression unex = expression as UnaryExpression; if (unex != null) { this.Visit(unex.Operand); this.stackHeight--; this.methodBodyHeap.Write((byte)0x26); } return; case NodeType.Arglist: this.IncrementStackHeight(); this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x00); return; } } void VisitExpressionList(ExpressionList expressions) { if (expressions == null) return; for (int i = 0, n = expressions.Count; i < n; i++) this.Visit(expressions[i]); } void VisitExpressionStatement(ExpressionStatement/*!*/ statement) { #if !MinimalReader if (!(statement.Expression is BlockExpression)) #endif this.DefineSequencePoint(statement); this.Visit(statement.Expression); } void VisitField(Field/*!*/ field) { this.VisitAttributeList(field.Attributes, field); this.GetFieldIndex(field); if (field.IsVolatile) field.Type = RequiredModifier.For(CoreSystemTypes.IsVolatile, field.Type); this.VisitReferencedType(field.Type); } void VisitFixupList(Fixup fixup, int targetAddress) { while (fixup != null) { this.methodBodyHeap.BaseStream.Position = fixup.fixupLocation; if (fixup.shortOffset) { int offset = targetAddress - fixup.addressOfNextInstruction; Debug.Assert(-128 <= offset && offset <= 127, "Invalid short branch"); this.methodBodyHeap.Write((byte)offset); } else this.methodBodyHeap.Write((int)(targetAddress - fixup.addressOfNextInstruction)); fixup = fixup.nextFixUp; } } void VisitGenericParameterList(Member/*!*/ member, TypeNodeList/*!*/ parameters) { if (member == null || parameters == null || !this.UseGenerics) return; int sign = member is Method ? -1 : 1; for (int i = 0, n = parameters.Count; i < n; i++) { TypeNode parameter = parameters[i]; if (parameter == null) continue; this.typeParameterNumber[parameter.UniqueKey] = sign * (i + 1); this.genericParamEntries.Add(member); if (((ITypeParameter)parameter).DeclaringMember != member) parameter = (TypeNode)parameter.Clone(); this.genericParameters.Add(parameter); if (parameter.BaseType is Class && parameter.BaseType != CoreSystemTypes.Object) this.genericParamConstraintEntries.Add(parameter); for (int j = 0, m = parameter.Interfaces == null ? 0 : parameter.Interfaces.Count; j < m; j++) this.genericParamConstraintEntries.Add(parameter); } } void VisitIndexer(Indexer/*!*/ indexer) { this.Visit(indexer.Object); if (indexer.Operands == null || indexer.Operands.Count < 1) return; this.Visit(indexer.Operands[0]); byte opCode; switch (indexer.ElementType.typeCode) { case ElementType.Boolean: case ElementType.Int8: opCode = 0x90; break; case ElementType.UInt8: opCode = 0x91; break; case ElementType.Int16: opCode = 0x92; break; case ElementType.Char: case ElementType.UInt16: opCode = 0x93; break; case ElementType.Int32: opCode = 0x94; break; case ElementType.UInt32: opCode = 0x95; break; case ElementType.Int64: case ElementType.UInt64: opCode = 0x96; break; case ElementType.UIntPtr: case ElementType.IntPtr: opCode = 0x97; break; case ElementType.Single: opCode = 0x98; break; case ElementType.Double: opCode = 0x99; break; default: if (this.UseGenerics && indexer.ElementType is ITypeParameter) opCode = 0xa3; else if (TypeNode.StripModifiers(indexer.ElementType) is Pointer) opCode = 0x97; else opCode = 0x9a; break; } this.methodBodyHeap.Write((byte)opCode); if (opCode == 0xa3) this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType)); this.stackHeight--; } void VisitInterface(Interface/*!*/ Interface) { if (this.UseGenerics && Interface.Template != null && Interface.Template.IsGeneric) return; this.VisitAttributeList(Interface.Attributes, Interface); this.VisitSecurityAttributeList(Interface.SecurityAttributes, Interface); InterfaceList interfaces = Interface.Interfaces; for (int i = 0, n = interfaces == null ? 0 : interfaces.Count; i < n; i++) { this.GetTypeDefOrRefOrSpecEncoded(interfaces[i]); if (interfaces[i] != null) this.interfaceEntries.Add(Interface); } if (Interface.NodeType == NodeType.TypeParameter && !(Interface is MethodTypeParameter)) this.interfaceEntries.Add(Interface); for (int i = 0, n = Interface.Members.Count; i < n; i++) { Member mem = Interface.Members[i]; if (mem == null || mem is TypeNode) continue; this.Visit(mem); } } void VisitLocal(Local/*!*/ local) { this.IncrementStackHeight(); int li = this.GetLocalVarIndex(local); switch (li) { case 0: this.methodBodyHeap.Write((byte)0x06); return; case 1: this.methodBodyHeap.Write((byte)0x07); return; case 2: this.methodBodyHeap.Write((byte)0x08); return; case 3: this.methodBodyHeap.Write((byte)0x09); return; default: if (li < 256) { this.methodBodyHeap.Write((byte)0x11); this.methodBodyHeap.Write((byte)li); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x0c); this.methodBodyHeap.Write((ushort)li); } return; } } #if !MinimalReader /// /// This just gets the local variable index for each local declaration. /// That associates the debug information with the right block because /// it is the block the local is declared in rather than the subblock /// it is first referenced in. (When different, the debugger only knows /// about the local when control is in the subblock.) /// /// The list of locals declared at this statement void VisitLocalDeclarationsStatement(LocalDeclarationsStatement/*!*/ localDeclarations) { if (localDeclarations == null) return; LocalDeclarationList decls = localDeclarations.Declarations; for (int i = 0, n = decls == null ? 0 : decls.Count; i < n; i++) { //^ assert decls != null; LocalDeclaration decl = decls[i]; if (decl == null) continue; Field f = decl.Field; if (f == null) continue; //^ assume this.currentMethod != null; Local loc = this.currentMethod.GetLocalForField(f); loc.Type = localDeclarations.Type; this.GetLocalVarIndex(loc); } } #endif void VisitLiteral(Literal/*!*/ literal) { this.IncrementStackHeight(); IConvertible ic = literal.Value as IConvertible; if (ic == null) { Debug.Assert(literal.Value == null && !literal.Type.IsValueType); this.methodBodyHeap.Write((byte)0x14); return; } TypeCode tc = ic.GetTypeCode(); switch (tc) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Char: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: long n = ic.ToInt64(null); switch (n) { case -1: this.methodBodyHeap.Write((byte)0x15); break; case 0: this.methodBodyHeap.Write((byte)0x16); break; case 1: this.methodBodyHeap.Write((byte)0x17); break; case 2: this.methodBodyHeap.Write((byte)0x18); break; case 3: this.methodBodyHeap.Write((byte)0x19); break; case 4: this.methodBodyHeap.Write((byte)0x1a); break; case 5: this.methodBodyHeap.Write((byte)0x1b); break; case 6: this.methodBodyHeap.Write((byte)0x1c); break; case 7: this.methodBodyHeap.Write((byte)0x1d); break; case 8: this.methodBodyHeap.Write((byte)0x1e); break; default: if (n >= System.SByte.MinValue && n <= System.SByte.MaxValue) { this.methodBodyHeap.Write((byte)0x1f); this.methodBodyHeap.Write((byte)n); } else if (n >= System.Int32.MinValue && n <= System.Int32.MaxValue || n <= System.UInt32.MaxValue && (tc == TypeCode.Char || tc == TypeCode.UInt16 || tc == TypeCode.UInt32)) { if (n == System.UInt32.MaxValue && tc != TypeCode.Int64) this.methodBodyHeap.Write((byte)0x15); else { this.methodBodyHeap.Write((byte)0x20); this.methodBodyHeap.Write((int)n); } } else { this.methodBodyHeap.Write((byte)0x21); this.methodBodyHeap.Write((long)n); tc = TypeCode.Empty; //Suppress conversion to long } break; } if (tc == TypeCode.Int64) this.methodBodyHeap.Write((byte)0x6a); return; case TypeCode.UInt64: this.methodBodyHeap.Write((byte)0x21); this.methodBodyHeap.Write(ic.ToUInt64(null)); return; case TypeCode.Single: this.methodBodyHeap.Write((byte)0x22); this.methodBodyHeap.Write(ic.ToSingle(null)); return; case TypeCode.Double: this.methodBodyHeap.Write((byte)0x23); this.methodBodyHeap.Write(ic.ToDouble(null)); return; case TypeCode.String: this.methodBodyHeap.Write((byte)0x72); this.methodBodyHeap.Write((int)(this.GetUserStringIndex((String)literal.Value) | 0x70000000)); return; } Debug.Assert(false, "Unexpected literal type"); } void VisitMemberBinding(MemberBinding/*!*/ memberBinding) { if (memberBinding.TargetObject != null) { this.Visit(memberBinding.TargetObject); if (memberBinding.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } this.methodBodyHeap.Write((byte)0x7b); } else { this.IncrementStackHeight(); if (memberBinding.Volatile) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x13); } this.methodBodyHeap.Write((byte)0x7e); } this.methodBodyHeap.Write((int)this.GetFieldToken((Field)memberBinding.BoundMember)); return; } void VisitMethod(Method/*!*/ method) { if (this.UseGenerics && method.Template != null && method.Template.IsGeneric) return; this.GetMethodIndex(method); this.VisitAttributeList(method.Attributes, method); this.VisitSecurityAttributeList(method.SecurityAttributes, method); for (int i = 0, n = method.Parameters == null ? 0 : method.Parameters.Count; i < n; i++) { Parameter par = method.Parameters[i]; if (par == null) continue; this.VisitAttributeList(par.Attributes, par); this.VisitReferencedType(par.Type); } if (method.ReturnType != null) this.VisitReferencedType(method.ReturnType); if (!method.IsAbstract && method.Body != null) { if (method.Body.Statements != null && method.Body.Statements.Count > 0) this.VisitMethodBody(method); } MethodList implementedInterfaceMethods = method.ImplementedInterfaceMethods; for (int i = 0, n = implementedInterfaceMethods == null ? 0 : implementedInterfaceMethods.Count; i < n; i++) { Method im = implementedInterfaceMethods[i]; if (im == null) continue; this.methodImplEntries.Add(method); } if ((method.Flags & MethodFlags.PInvokeImpl) != 0 && method.PInvokeImportName != null && method.PInvokeModule != null) { this.implMapEntries.Add(method); this.GetStringIndex(method.PInvokeImportName); this.GetModuleRefIndex(method.PInvokeModule); } } void VisitMethodBody(Method/*!*/ method) { //Visit body, emitting IL bytes and gathering information this.methodBodyHeap = new BinaryWriter(new MemoryStream()); this.methodInfo = new MethodInfo(); this.currentMethod = method; this.stackHeightMax = 0; this.stackHeightExitTotal = 0; #if !ROTOR if (this.symWriter != null) { this.methodInfo.debugLocals = new LocalList(); this.methodInfo.signatureLengths = new Int32List(); this.methodInfo.signatureOffsets = new Int32List(); this.methodInfo.statementNodes = new NodeList(); this.methodInfo.statementOffsets = new Int32List(); this.symWriter.OpenMethod((uint)this.GetMethodDefToken(method)); this.symWriter.OpenScope(0u); #if !MinimalReader MethodScope scope = method.Scope; if (scope != null) { UsedNamespaceList usedNamespaces = scope.UsedNamespaces; for (int i = 0, n = usedNamespaces == null ? 0 : usedNamespaces.Count; i < n; i++) { //^ assert usedNamespaces != null; UsedNamespace uns = usedNamespaces[i]; if (uns == null || uns.Namespace == null) continue; this.symWriter.UsingNamespace(uns.Namespace.ToString()); } } #endif } #endif #if !FxCop int originalAddress = 0; if (method.LocalList != null) { for (int i = 0, n = method.LocalList.Count; i < n; i++) { Local loc = method.LocalList[i]; if (loc == null) continue; this.GetLocalVarIndex(loc); } #if !ROTOR if (this.symWriter != null) { int currentAddress = (int)this.methodBodyHeap.BaseStream.Position; originalAddress = currentAddress; this.symWriter.OpenScope((uint)currentAddress); } #endif } #endif int exceptionHandlersCount = method.ExceptionHandlers == null ? 0 : method.ExceptionHandlers.Count; if (exceptionHandlersCount > 0) { this.exceptionBlock = new TrivialHashtable(); for (int i = 0; i < exceptionHandlersCount; i++) { ExceptionHandler eh = method.ExceptionHandlers[i]; if (eh == null || eh.HandlerStartBlock == null || (eh.HandlerType != NodeType.Catch && eh.HandlerType != NodeType.Filter)) continue; this.exceptionBlock[eh.HandlerStartBlock.UniqueKey] = eh; } } this.VisitBlock(method.Body); #if !FxCop if (method.LocalList != null) { #if !ROTOR if (this.symWriter != null) { DefineLocalVariables(originalAddress, method.LocalList); } #endif } #endif this.methodBodiesHeapIndex[method.UniqueKey] = (int)this.methodBodiesHeap.BaseStream.Position; int maxStack = this.stackHeightExitTotal + this.stackHeightMax; //Wildly pessimistic estimate. Works dandy if BBlocks never leave anything on the stack. if (exceptionHandlersCount > 0 && maxStack == 0) maxStack = 1; int codeSize = (int)this.methodBodyHeap.BaseStream.Position; int localVarSigTok = this.methodInfo.localVarSigTok; bool fatHeader = codeSize >= 64 || exceptionHandlersCount > 0 || maxStack > 8 || localVarSigTok != 0; if (fatHeader) { //Emit fat header byte header = 0x03; if (method.InitLocals) header |= 0x10; if (exceptionHandlersCount > 0) header |= 0x08; this.methodBodiesHeap.Write((byte)header); this.methodBodiesHeap.Write((byte)0x30); //top 4 bits represent length of fat header in dwords. Heaven only knows why. this.methodBodiesHeap.Write((short)maxStack); this.methodBodiesHeap.Write((int)codeSize); if (localVarSigTok != 0) { if (this.methodInfo.localVarIndex.Count > 127) { //Need to make space for the two byte count this.methodInfo.localVarSignature.Write((byte)0); byte[] buf = this.methodInfo.localVarSignature.BaseStream.Buffer; int n = buf.Length; for (int i = n - 2; i > 1; i--) buf[i + 1] = buf[i]; } this.methodInfo.localVarSignature.BaseStream.Position = 0; this.methodInfo.localVarSignature.Write((byte)7); Ir2md.WriteCompressedInt(this.methodInfo.localVarSignature, this.methodInfo.localVarIndex.Count); Debug.Assert(this.methodInfo.localVarIndex.Count <= 0xFFFE); } this.methodBodiesHeap.Write((int)localVarSigTok); } else { //Emit tiny header this.methodBodiesHeap.Write((byte)(codeSize << 2 | 2)); } //Copy body to bodies heap ((MemoryStream)this.methodBodyHeap.BaseStream).WriteTo(this.methodBodiesHeap.BaseStream); int pad = (int)this.methodBodiesHeap.BaseStream.Position; while (pad % 4 != 0) { pad++; this.methodBodiesHeap.Write((byte)0); } if (fatHeader) { //Emit exception handler entries int[] tryOffsets = new int[exceptionHandlersCount]; int[] tryLengths = new int[exceptionHandlersCount]; int[] handlerOffsets = new int[exceptionHandlersCount]; int[] handlerLengths = new int[exceptionHandlersCount]; bool fatFormat = false; for (int i = 0; i < exceptionHandlersCount; i++) { ExceptionHandler eh = method.ExceptionHandlers[i]; int tryOffset = tryOffsets[i] = (int)this.methodInfo.fixupIndex[eh.TryStartBlock.UniqueKey]; int tryLength = tryLengths[i] = ((int)this.methodInfo.fixupIndex[eh.BlockAfterTryEnd.UniqueKey]) - tryOffset; int handlerOffset = handlerOffsets[i] = (int)this.methodInfo.fixupIndex[eh.HandlerStartBlock.UniqueKey]; int handlerLength = handlerLengths[i] = ((int)this.methodInfo.fixupIndex[eh.BlockAfterHandlerEnd.UniqueKey]) - handlerOffset; if (tryOffset > 0xffff || tryLength > 0xff || handlerOffset > 0xffff || handlerLength > 0xff) fatFormat = true; } if (exceptionHandlersCount * 12 > 0xff) fatFormat = true; if (fatFormat) { int dataSize = exceptionHandlersCount * 24 + 4; this.methodBodiesHeap.Write((byte)0x41); this.methodBodiesHeap.Write((byte)(dataSize & 0xff)); this.methodBodiesHeap.Write((short)((dataSize >> 8) & 0xffff)); } else { int dataSize = exceptionHandlersCount * 12 + 4; this.methodBodiesHeap.Write((byte)0x01); this.methodBodiesHeap.Write((byte)dataSize); this.methodBodiesHeap.Write((short)0); } for (int i = 0; i < exceptionHandlersCount; i++) { ExceptionHandler eh = method.ExceptionHandlers[i]; byte flags = 0; switch (eh.HandlerType) { case NodeType.Filter: flags = 0x0001; break; case NodeType.Finally: flags = 0x0002; break; case NodeType.FaultHandler: flags = 0x0004; break; } if (fatFormat) { this.methodBodiesHeap.Write((int)flags); this.methodBodiesHeap.Write((int)tryOffsets[i]); this.methodBodiesHeap.Write((int)tryLengths[i]); this.methodBodiesHeap.Write((int)handlerOffsets[i]); this.methodBodiesHeap.Write((int)handlerLengths[i]); } else { this.methodBodiesHeap.Write((short)flags); this.methodBodiesHeap.Write((ushort)tryOffsets[i]); this.methodBodiesHeap.Write((byte)tryLengths[i]); this.methodBodiesHeap.Write((ushort)handlerOffsets[i]); this.methodBodiesHeap.Write((byte)handlerLengths[i]); } if (eh.FilterType != null) this.methodBodiesHeap.Write((int)this.GetTypeToken(eh.FilterType)); else if (eh.FilterExpression != null) this.methodBodiesHeap.Write((int)this.methodInfo.fixupIndex[eh.FilterExpression.UniqueKey]); else this.methodBodiesHeap.Write((int)0); } } #if !ROTOR if (this.symWriter != null) { MethodInfo mInfo = this.methodInfo; NodeList statementNodes = mInfo.statementNodes; Int32List statementOffsets = mInfo.statementOffsets; int n = statementNodes.Count; int j = 0; int k = 0; Document d = null; ISymUnmanagedDocumentWriter doc = null; for (int i = 0; i < n; i++) { Document e = statementNodes[i].SourceContext.Document; if (e == null) continue; if (e != d) { d = e; if (doc != null) this.DefineSequencePoints(statementNodes, statementOffsets, j, k, doc); doc = this.GetDocumentWriter(d); j = i; k = 0; } k++; } this.DefineSequencePoints(statementNodes, statementOffsets, j, k, doc); this.symWriter.CloseScope((uint)this.methodBodyHeap.BaseStream.Position); this.symWriter.CloseMethod(); } #endif //this.methodBodyHeap = null; //this.methodInfo = null; //this.currentMethod = null; } #if !ROTOR private void DefineLocalVariables(int startAddress, LocalList locals) { MethodInfo mInfo = this.methodInfo; for (int i = 0, n = locals.Count; i < n; i++) { Local loc = locals[i]; string name = loc.Name.ToString(); unsafe { fixed (byte* p = mInfo.localVarSignature.BaseStream.Buffer) { IntPtr sp = (IntPtr)(p + mInfo.signatureOffsets[i]); uint c = (uint)mInfo.signatureLengths[i]; this.symWriter.DefineLocalVariable(name, 0u, c, sp, 1u, (uint)this.GetLocalVarIndex(loc), 0u, 0u, 0u); } } } int posOfFirstInstructionOfNextBlock = this.methodBodyHeap.BaseStream.Position; if (posOfFirstInstructionOfNextBlock > startAddress) this.symWriter.CloseScope((uint)(posOfFirstInstructionOfNextBlock - 1)); else this.symWriter.CloseScope((uint)startAddress); } #endif void DefineSequencePoint(Node node) { #if !ROTOR if (this.symWriter != null && node != null && node.SourceContext.Document != null && !node.SourceContext.Document.Hidden) { this.methodInfo.statementNodes.Add(node); this.methodInfo.statementOffsets.Add(this.methodBodyHeap.BaseStream.Position); } #endif } #if !ROTOR void DefineSequencePoints(NodeList/*!*/ statementNodes, Int32List/*!*/ statementOffsets, int start, int count, ISymUnmanagedDocumentWriter doc) //^ requires this.symWriter != null; { if (count == 0) return; uint[] offsets = new uint[count]; uint[] lines = new uint[count]; uint[] columns = new uint[count]; uint[] endLines = new uint[count]; uint[] endColumns = new uint[count]; for (int i = 0; i < count; i++) { Node n = statementNodes[i + start]; offsets[i] = i + start == 0 ? 0 : (uint)statementOffsets[i + start]; lines[i] = (uint)n.SourceContext.StartLine; columns[i] = (uint)n.SourceContext.StartColumn; endLines[i] = (uint)n.SourceContext.EndLine; endColumns[i] = (uint)n.SourceContext.EndColumn; } this.symWriter.DefineSequencePoints(doc, (uint)count, offsets, lines, columns, endLines, endColumns); } #endif void VisitModule(Module/*!*/ module) { //REVIEW: check that module has no explicit lists of assembly/module references? this.ForceTemplateTypeMethodBodiesToGetSpecialized(module); this.VisitAttributeList(module.Attributes, module); if (this.assembly != null) { Module m = new Module(); m.Attributes = this.assembly.ModuleAttributes; this.VisitAttributeList(m.Attributes, m); this.VisitSecurityAttributeList(this.assembly.SecurityAttributes, this.assembly); } TypeNodeList allTypes = module.Types.Clone(); for (int k = 0; k < allTypes.Count; ) { int typeCount = module.Types.Count; for (int i = k, n = k, m = allTypes.Count; i < (n = allTypes.Count); ) { for (; i < n; i++) { TypeNode t = allTypes[i]; if (t == null) continue; if (this.UseGenerics && t.Template != null && t.Template.IsGeneric) { allTypes[i] = null; continue; } this.GetTypeDefIndex(t); if (i >= m) this.nestedClassEntries.Add(t); MemberList members = t.Members; if (members != null) { for (int j = 0, numMembers = members.Count; j < numMembers; j++) { TypeNode nt = members[j] as TypeNode; if (nt != null) allTypes.Add(nt); } } } } for (int i = k, n = allTypes.Count; i < n; i++) { TypeNode t = allTypes[i]; if (t == null) continue; if (this.UseGenerics && t.Template != null && t.Template.IsGeneric) { allTypes[i] = null; continue; } MemberList mems = t.Members; if (t is EnumNode) { //Work around JIT bug in Beta2 for (int jj = 0, mm = mems.Count; jj < mm; jj++) { Field f = mems[jj] as Field; if (f == null || f.IsStatic) continue; mems[jj] = mems[0]; mems[0] = f; break; } } for (int j = 0, m = mems.Count; j < m; j++) { Member mem = mems[j]; if (mem == null) continue; switch (mem.NodeType) { case NodeType.Field: this.GetFieldIndex((Field)mem); break; case NodeType.Method: case NodeType.InstanceInitializer: case NodeType.StaticInitializer: Method meth = (Method)mem; if (this.UseGenerics && meth.Template != null && meth.Template.IsGeneric) this.GetMethodSpecIndex(meth); else this.GetMethodIndex(meth); break; } } } for (int i = k, n = allTypes.Count; i < n; i++, k++) { TypeNode t = allTypes[i]; if (t == null) continue; this.Visit(t); } for (int i = typeCount, n = module.Types.Count; i < n; i++) { TypeNode t = module.Types[i]; if (t == null) continue; Debug.Assert(t.IsNotFullySpecialized); //allTypes.Add(t); } } } sealed class MethodSpecializer : StandardVisitor { private Module/*!*/ module; internal MethodSpecializer(Module/*!*/ module) { this.module = module; //^ base(); } public override Method VisitMethod(Method method) { if (method == null) return null; if (method.Template == null || method.Template.IsGeneric) return method; TypeNodeList templateParameters = null; TypeNodeList templateArguments = null; if (method.TemplateArguments != null && method.TemplateArguments.Count > 0) { templateParameters = method.Template.TemplateParameters; templateArguments = method.TemplateArguments; } else { TypeNode tdt = method.Template.DeclaringType; TypeNode dt = method.DeclaringType; templateParameters = tdt.ConsolidatedTemplateParameters; templateArguments = dt.ConsolidatedTemplateArguments; if (templateArguments == null) templateArguments = templateParameters; } if (templateParameters == null || templateParameters.Count == 0) return method; TypeNode declaringTemplate = method.DeclaringType == null ? null : method.DeclaringType.Template; bool savedNewTemplateInstanceIsRecursive = false; if (declaringTemplate != null) { savedNewTemplateInstanceIsRecursive = declaringTemplate.NewTemplateInstanceIsRecursive; declaringTemplate.NewTemplateInstanceIsRecursive = method.DeclaringType.IsNotFullySpecialized; } Duplicator duplicator = new Duplicator(this.module, method.DeclaringType); #if !MinimalReader TypeNode closureClone = null; if (method.Template.Scope != null && method.Template.Scope.CapturedForClosure) { duplicator.TypesToBeDuplicated[method.Template.Scope.ClosureClass.UniqueKey] = method.Template.Scope.ClosureClass; duplicator.RecordOriginalAsTemplate = true; closureClone = duplicator.VisitTypeNode(method.Template.Scope.ClosureClass); } #endif int n = method.Parameters == null ? 0 : method.Parameters.Count; int m = method.Template.Parameters == null ? 0 : method.Template.Parameters.Count; if (n != m) { Debug.Assert(false); if (n > m) n = m; } for (int i = 0; i < n; i++) { Parameter par = method.Parameters[i]; Parameter tpar = method.Template.Parameters[i]; if (par == null || tpar == null) continue; duplicator.DuplicateFor[tpar.UniqueKey] = par; } n = method.TemplateParameters == null ? 0 : method.TemplateParameters.Count; m = method.Template.TemplateParameters == null ? 0 : method.Template.TemplateParameters.Count; if (n != m && n > 0) { Debug.Assert(false); if (n > m) n = m; } for (int i = 0; i < n; i++) { TypeNode tpar = method.TemplateParameters[i]; TypeNode ttpar = method.Template.TemplateParameters[i]; if (tpar == null || ttpar == null) continue; duplicator.DuplicateFor[ttpar.UniqueKey] = tpar; } Method dup = duplicator.VisitMethod(method.Template); //^ assume dup != null; Specializer specializer = new Specializer(this.module, templateParameters, templateArguments); specializer.VisitMethod(dup); #if !MinimalReader if (closureClone != null) { specializer.VisitTypeNode(closureClone); if (method.TemplateArguments != null && method.TemplateArguments.Count > 0) closureClone.Name = Identifier.For(closureClone.Name.ToString() + closureClone.UniqueKey); MemberList dtMembers = method.DeclaringType.Members; for (int i = 0, nmems = dtMembers == null ? 0 : dtMembers.Count; i < nmems; i++) { ClosureClass closureRef = dtMembers[i] as ClosureClass; if (closureRef != null && closureRef.Name.UniqueIdKey == closureClone.Name.UniqueIdKey) { //This happens when the declaring type was instantiated after Normalizer has already injected a closure into the template dtMembers[i] = closureClone; closureClone = null; break; } } if (closureClone != null) method.DeclaringType.Members.Add(closureClone); } #endif if (method.Template.DeclaringType.DeclaringModule != this.module) { //Dealing with imported IR that misses important type information if it contains explicit stack operations (push, pop, dup) //Call a helper visitor to remove these stack operations and in the process supply the missing type information. Unstacker unstacker = new Unstacker(); unstacker.Visit(dup); } MethodBodySpecializer mbSpecializer = this.module.GetMethodBodySpecializer(templateParameters, templateArguments); mbSpecializer.methodBeingSpecialized = method; mbSpecializer.dummyMethod = dup; mbSpecializer.VisitMethod(dup); method.Body = dup.Body; // HACK to try to fix parameter declaring method back to the way it was before: method.Parameters = method.Parameters; method.ExceptionHandlers = dup.ExceptionHandlers; if (declaringTemplate != null) declaringTemplate.NewTemplateInstanceIsRecursive = savedNewTemplateInstanceIsRecursive; return method; } } void ForceTemplateTypeMethodBodiesToGetSpecialized(Module/*!*/ module) { MethodSpecializer visitor = new MethodSpecializer(module); if (module == null) return; TypeNodeList types = module.Types; if (types == null) return; for (int i = 0; i < types.Count; i++) this.ForceTemplateTypeMethodBodiesToGetSpecialized(types[i], visitor); } void ForceTemplateTypeMethodBodiesToGetSpecialized(TypeNode/*!*/ type, MethodSpecializer/*!*/ visitor) { if (type == null) return; if (type.IsNotFullySpecialized || type.IsGeneric) return; bool savedNewTemplateInstanceIsRecursive = type.NewTemplateInstanceIsRecursive; type.NewTemplateInstanceIsRecursive = type.IsNotFullySpecialized; MemberList members = type.Members; if (members == null) return; for (int j = 0; j < members.Count; j++) { Member mem = members[j]; if (mem == null) continue; TypeNode t = mem as TypeNode; if (t != null) this.ForceTemplateTypeMethodBodiesToGetSpecialized(t, visitor); else visitor.VisitMethod(mem as Method); } type.NewTemplateInstanceIsRecursive = savedNewTemplateInstanceIsRecursive; } void VisitParameter(Parameter/*!*/ parameter) { this.IncrementStackHeight(); #if !MinimalReader ParameterBinding pb = parameter as ParameterBinding; if (pb != null) parameter = pb.BoundParameter; #endif int pi = parameter.ArgumentListIndex; switch (pi) { case 0: this.methodBodyHeap.Write((byte)0x02); return; case 1: this.methodBodyHeap.Write((byte)0x03); return; case 2: this.methodBodyHeap.Write((byte)0x04); return; case 3: this.methodBodyHeap.Write((byte)0x05); return; default: if (pi < 256) { this.methodBodyHeap.Write((byte)0x0e); this.methodBodyHeap.Write((byte)pi); } else { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x09); this.methodBodyHeap.Write((ushort)pi); } return; } } void VisitProperty(Property/*!*/ property) { object pindex = this.propertyIndex[property.UniqueKey]; if (pindex != null) return; int index = this.propertyEntries.Count + 1; this.propertyEntries.Add(property); this.propertyIndex[property.UniqueKey] = index; object pmindex = this.propertyMapIndex[property.DeclaringType.UniqueKey]; if (pmindex == null) { this.propertyMapEntries.Add(property); this.propertyMapIndex[property.DeclaringType.UniqueKey] = this.propertyMapEntries.Count; } if (property.Getter != null) this.methodSemanticsEntries.Add(property); if (property.Setter != null) this.methodSemanticsEntries.Add(property); if (property.OtherMethods != null) for (int i = 0, n = property.OtherMethods.Count; i < n; i++) this.methodSemanticsEntries.Add(property); this.VisitAttributeList(property.Attributes, property); } void VisitReferencedType(TypeNode type) { if (type == null) return; if (type.IsGeneric && type.Template == null) { TypeNodeList templParams = type.ConsolidatedTemplateParameters; for (int i = 0, n = templParams == null ? 0 : templParams.Count; i < n; i++) this.typeParameterNumber[templParams[i].UniqueKey] = i + 1; } switch (type.typeCode) { case ElementType.Pointer: this.VisitReferencedType(((Pointer)type).ElementType); return; case ElementType.Reference: this.VisitReferencedType(((Reference)type).ElementType); return; case ElementType.Array: case ElementType.SzArray: this.VisitReferencedType(((ArrayType)type).ElementType); return; case ElementType.OptionalModifier: case ElementType.RequiredModifier: TypeModifier tm = (TypeModifier)type; this.VisitReferencedType(tm.Modifier); this.VisitReferencedType(tm.ModifiedType); return; case ElementType.FunctionPointer: FunctionPointer fp = (FunctionPointer)type; this.VisitReferencedType(fp.ReturnType); for (int i = 0, n = fp.ParameterTypes == null ? 0 : fp.ParameterTypes.Count; i < n; i++) this.VisitReferencedType(fp.ParameterTypes[i]); return; case ElementType.ValueType: case ElementType.Class: break; default: return; } if (this.IsStructural(type)) this.GetTypeSpecIndex(type); else if (type.DeclaringModule == this.module) this.GetTypeDefIndex(type); else if (type.DeclaringModule != null) this.GetTypeRefIndex(type); else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class) { //Get here for type parameters if (this.UseGenerics && this.typeParameterNumber[type.UniqueKey] != null) return; type.DeclaringModule = this.module; this.GetTypeDefIndex(type); } else Debug.Assert(false); } void VisitReturn(Return/*!*/ Return) { this.DefineSequencePoint(Return); if (Return.Expression != null) { this.Visit(Return.Expression); this.stackHeight--; } this.methodBodyHeap.Write((byte)0x2a); } void VisitSecurityAttributeList(SecurityAttributeList attrs, Node/*!*/ node) { if (attrs == null) return; int n = attrs.Count; if (n == 0) return; int m = n; for (int j = 0; j < n; j++) { SecurityAttribute a = attrs[j]; if (a == null) m--; } if (m == 0) return; n = m; int codedIndex = this.GetSecurityAttributeParentCodedIndex(node); this.securityAttributeCount += n; m = this.nodesWithSecurityAttributes.Count; this.nodesWithSecurityAttributes.Add(node); int i = 0; //after the for loop i will be position where the new node should be in sorted list NodeList nodes = this.nodesWithSecurityAttributes; for (i = m; i > 0; i--) { Node other = nodes[i - 1]; int oci = this.GetSecurityAttributeParentCodedIndex(other); if (oci < codedIndex) break; } if (i == m) return; //node is already where it should be for (int j = m; j > i; j--) nodes[j] = nodes[j - 1]; //Make space at postion i nodes[i] = node; } void VisitStatement(Statement/*!*/ statement) { this.DefineSequencePoint(statement); switch (statement.NodeType) { case NodeType.Nop: this.methodBodyHeap.Write((byte)0x00); break; case NodeType.DebugBreak: this.methodBodyHeap.Write((byte)0x01); break; case NodeType.EndFinally: this.methodBodyHeap.Write((byte)0xdc); break; } } void VisitStruct(Struct/*!*/ Struct) { if (this.UseGenerics && Struct.Template != null && Struct.Template.IsGeneric) return; this.VisitAttributeList(Struct.Attributes, Struct); this.VisitSecurityAttributeList(Struct.SecurityAttributes, Struct); this.VisitReferencedType(CoreSystemTypes.ValueType); InterfaceList interfaces = Struct.Interfaces; for (int i = 0, n = interfaces == null ? 0 : interfaces.Count; i < n; i++) { this.GetTypeDefOrRefOrSpecEncoded(interfaces[i]); if (interfaces[i] != null) this.interfaceEntries.Add(Struct); } for (int i = 0, n = Struct.Members.Count; i < n; i++) { Member m = Struct.Members[i]; if (m is TypeNode) continue; this.Visit(m); } if ((Struct.Flags & (TypeFlags.ExplicitLayout | TypeFlags.SequentialLayout)) != 0 && (Struct.PackingSize != 0 || Struct.ClassSize != 0)) this.classLayoutEntries.Add(Struct); } void VisitSwitchInstruction(SwitchInstruction/*!*/ switchInstruction) { this.Visit(switchInstruction.Expression); this.stackHeight--; BlockList targets = switchInstruction.Targets; int n = targets != null ? targets.Count : 0; int addressOfNextInstruction = ((int)this.methodBodyHeap.BaseStream.Position) + 5 + 4 * n; this.methodBodyHeap.Write((byte)0x45); this.methodBodyHeap.Write((uint)n); for (int i = 0; i < n; i++) this.methodBodyHeap.Write((int)this.GetOffset(targets[i], addressOfNextInstruction)); } void VisitTernaryExpression(TernaryExpression/*!*/ expression) { this.Visit(expression.Operand1); this.Visit(expression.Operand2); this.Visit(expression.Operand3); this.methodBodyHeap.Write((byte)0xfe); if (expression.NodeType == NodeType.Cpblk) this.methodBodyHeap.Write((byte)0x17); else this.methodBodyHeap.Write((byte)0x18); this.stackHeight -= 3; } void VisitThis(This/*!*/ This) { this.IncrementStackHeight(); this.methodBodyHeap.Write((byte)0x02); } void VisitThrow(Throw/*!*/ Throw) { this.DefineSequencePoint(Throw); if (Throw.NodeType == NodeType.Rethrow) { this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x1a); } else { this.Visit(Throw.Expression); this.methodBodyHeap.Write((byte)0x7a); } this.stackHeight--; } void VisitUnaryExpression(UnaryExpression/*!*/ unaryExpression) { switch (unaryExpression.NodeType) { case NodeType.Ldtoken: this.methodBodyHeap.Write((byte)0xd0); Literal lit = unaryExpression.Operand as Literal; if (lit != null) { if (lit.Value == null) return; this.methodBodyHeap.Write((int)this.GetTypeDefToken((TypeNode)lit.Value)); } else { if (unaryExpression.Operand == null) return; Member m = ((MemberBinding)unaryExpression.Operand).BoundMember; if (m == null) return; Method meth = m as Method; if (meth != null) this.methodBodyHeap.Write((int)this.GetMethodToken(meth)); else this.methodBodyHeap.Write((int)this.GetFieldToken((Field)m)); } this.IncrementStackHeight(); return; case NodeType.Ldftn: this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x06); this.methodBodyHeap.Write((int)this.GetMethodToken((Method)((MemberBinding)unaryExpression.Operand).BoundMember)); this.IncrementStackHeight(); return; case NodeType.Sizeof: this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x1c); this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)((Literal)unaryExpression.Operand).Value)); this.IncrementStackHeight(); return; case NodeType.SkipCheck: this.methodBodyHeap.Write((byte)0xfe); this.methodBodyHeap.Write((byte)0x19); switch (unaryExpression.Operand.NodeType) { case NodeType.Castclass: case NodeType.Unbox: this.methodBodyHeap.Write((byte)0x01); break; default: Debug.Assert(false); this.methodBodyHeap.Write((byte)0x00); break; } this.VisitExpression(unaryExpression.Operand); return; } this.Visit(unaryExpression.Operand); byte opCode = 0; switch (unaryExpression.NodeType) { case NodeType.Neg: opCode = 0x65; break; case NodeType.Not: opCode = 0x66; break; case NodeType.Conv_I1: opCode = 0x67; break; case NodeType.Conv_I2: opCode = 0x68; break; case NodeType.Conv_I4: opCode = 0x69; break; case NodeType.Conv_I8: opCode = 0x6a; break; case NodeType.Conv_R4: opCode = 0x6b; break; case NodeType.Conv_R8: opCode = 0x6c; break; case NodeType.Conv_U4: opCode = 0x6d; break; case NodeType.Conv_U8: opCode = 0x6e; break; case NodeType.Conv_R_Un: opCode = 0x76; break; case NodeType.Conv_Ovf_I1_Un: opCode = 0x82; break; case NodeType.Conv_Ovf_I2_Un: opCode = 0x83; break; case NodeType.Conv_Ovf_I4_Un: opCode = 0x84; break; case NodeType.Conv_Ovf_I8_Un: opCode = 0x85; break; case NodeType.Conv_Ovf_U1_Un: opCode = 0x86; break; case NodeType.Conv_Ovf_U2_Un: opCode = 0x87; break; case NodeType.Conv_Ovf_U4_Un: opCode = 0x88; break; case NodeType.Conv_Ovf_U8_Un: opCode = 0x89; break; case NodeType.Conv_Ovf_I_Un: opCode = 0x8a; break; case NodeType.Conv_Ovf_U_Un: opCode = 0x8b; break; case NodeType.Ldlen: opCode = 0x8e; break; case NodeType.Conv_Ovf_I1: opCode = 0xb3; break; case NodeType.Conv_Ovf_U1: opCode = 0xb4; break; case NodeType.Conv_Ovf_I2: opCode = 0xb5; break; case NodeType.Conv_Ovf_U2: opCode = 0xb6; break; case NodeType.Conv_Ovf_I4: opCode = 0xb7; break; case NodeType.Conv_Ovf_U4: opCode = 0xb8; break; case NodeType.Conv_Ovf_I8: opCode = 0xb9; break; case NodeType.Conv_Ovf_U8: opCode = 0xba; break; case NodeType.Ckfinite: opCode = 0xc3; break; case NodeType.Conv_U2: opCode = 0xd1; break; case NodeType.Conv_U1: opCode = 0xd2; break; case NodeType.Conv_I: opCode = 0xd3; break; case NodeType.Conv_Ovf_I: opCode = 0xd4; break; case NodeType.Conv_Ovf_U: opCode = 0xd5; break; case NodeType.Conv_U: opCode = 0xe0; break; case NodeType.Localloc: opCode = 0x0f; this.methodBodyHeap.Write((byte)0xfe); break; case NodeType.Refanytype: opCode = 0x1d; this.methodBodyHeap.Write((byte)0xfe); break; } this.methodBodyHeap.Write((byte)opCode); } static void WriteArrayShape(BinaryWriter/*!*/ target, ArrayType/*!*/ arrayType) { Ir2md.WriteCompressedInt(target, arrayType.Rank); int n = arrayType.Sizes == null ? 0 : arrayType.Sizes.Length; Ir2md.WriteCompressedInt(target, n); for (int i = 0; i < n; i++) { //^ assert arrayType.Sizes != null; Ir2md.WriteCompressedInt(target, arrayType.Sizes[i]); } n = arrayType.LowerBounds == null ? 0 : arrayType.LowerBounds.Length; Ir2md.WriteCompressedInt(target, n); for (int i = 0; i < n; i++) { //^ assert arrayType.LowerBounds != null; Ir2md.WriteCompressedInt(target, arrayType.LowerBounds[i]); } } internal static void WriteCompressedInt(BinaryWriter/*!*/ target, int val) { if (val <= 0x7f) target.Write((byte)val); else if (val < 0x3fff) { target.Write((byte)((val >> 8) | 0x80)); target.Write((byte)(val & 0xff)); } else if (val < 0x1fffffff) { target.Write((byte)((val >> 24) | 0xc0)); target.Write((byte)((val & 0xff0000) >> 16)); target.Write((byte)((val & 0xff00) >> 8)); target.Write((byte)(val & 0xff)); } else Debug.Assert(false, "index too large for compression"); } TypeNode/*!*/ WriteCustomModifiers(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { switch (type.NodeType) { case NodeType.RequiredModifier: case NodeType.OptionalModifier: TypeModifier tm = (TypeModifier)type; target.Write((byte)tm.typeCode); this.WriteTypeDefOrRefEncoded(target, tm.Modifier); return this.WriteCustomModifiers(target, tm.ModifiedType); } return type; } void WriteCustomAttributeLiteral(BinaryWriter/*!*/ writer, Literal/*!*/ literal, bool needsTag) { if (literal.Type == null) return; ElementType typeCode = literal.Type.typeCode; if (needsTag) { if (typeCode == ElementType.ValueType) { //Boxed enum writer.Write((byte)0x55); this.WriteSerializedTypeName(writer, literal.Type); } else if (typeCode == ElementType.Class) { //a Type value writer.Write((byte)0x50); } else if (typeCode != ElementType.Object) //a primitive writer.Write((byte)typeCode); } Object value = literal.Value; //if (value == null) return; //TODO: nope, find some other way switch (typeCode) { case ElementType.Boolean: writer.Write((bool)value); return; case ElementType.Char: writer.Write((ushort)(char)value); return; case ElementType.Double: writer.Write((double)value); return; case ElementType.Single: writer.Write((float)value); return; case ElementType.Int16: writer.Write((short)value); return; case ElementType.Int32: writer.Write((int)value); return; case ElementType.Int64: writer.Write((long)value); return; case ElementType.Int8: writer.Write((sbyte)value); return; case ElementType.UInt16: writer.Write((ushort)value); return; case ElementType.UInt32: writer.Write((uint)value); return; case ElementType.UInt64: writer.Write((ulong)value); return; case ElementType.UInt8: writer.Write((byte)value); return; case ElementType.String: writer.Write((string)value, false); return; case ElementType.ValueType: this.WriteCustomAttributeLiteral(writer, new Literal(value, ((EnumNode)literal.Type).UnderlyingType), false); return; case ElementType.Class: this.WriteSerializedTypeName(writer, (TypeNode)value); return; case ElementType.SzArray: TypeNode elemType = ((ArrayType)literal.Type).ElementType; if (needsTag) writer.Write((byte)elemType.typeCode); Array array = (Array)value; int numElems = array == null ? -1 : array.Length; writer.Write((int)numElems); for (int i = 0; i < numElems; i++) this.WriteCustomAttributeLiteral(writer, new Literal(array.GetValue(i), elemType), false); return; case ElementType.Object: Literal lit = (Literal)literal.Clone(); TypeNode t = null; switch (Convert.GetTypeCode(lit.Value)) { case TypeCode.Boolean: t = CoreSystemTypes.Boolean; break; case TypeCode.Byte: t = CoreSystemTypes.UInt8; break; case TypeCode.Char: t = CoreSystemTypes.Char; break; case TypeCode.Double: t = CoreSystemTypes.Double; break; case TypeCode.Int16: t = CoreSystemTypes.Int16; break; case TypeCode.Int32: t = CoreSystemTypes.Int32; break; case TypeCode.Int64: t = CoreSystemTypes.Int64; break; case TypeCode.SByte: t = CoreSystemTypes.Int8; break; case TypeCode.Single: t = CoreSystemTypes.Single; break; case TypeCode.String: t = CoreSystemTypes.String; break; case TypeCode.UInt16: t = CoreSystemTypes.UInt16; break; case TypeCode.UInt32: t = CoreSystemTypes.UInt32; break; case TypeCode.UInt64: t = CoreSystemTypes.UInt64; break; case TypeCode.Empty: case TypeCode.Object: Array arr = lit.Value as Array; if (arr != null) { #if !NoReflection t = TypeNode.GetTypeNode(arr.GetType()); #else System.Type reflType = arr.GetType(); System.Type reflElemType = reflType.GetElementType(); AssemblyNode assem = AssemblyNode.GetAssembly(reflType.Assembly.Location); TypeNode cciElemType = assem.GetType(Identifier.For(reflElemType.Namespace), Identifier.For(reflElemType.Name)); t = cciElemType.GetArrayType(reflType.GetArrayRank()); #endif } else t = CoreSystemTypes.Type; break; } if (t == null) break; lit.Type = t; this.WriteCustomAttributeLiteral(writer, lit, true); return; } Debug.Assert(false, "Unexpected type in custom attribute"); } bool AttributesContains(AttributeList al, TypeNode/*!*/ a) { if (al == null) return false; for (int i = 0, n = al.Count; i < n; i++) { if (al[i] != null && al[i].Type == a) return true; } return false; } void WriteMethodSignature(BinaryWriter/*!*/ target, Method/*!*/ method) { if (this.UseGenerics) { if (method.Template != null && method.Template.IsGeneric) { //Signature is being used in MethodDef table TypeNodeList types = method.TemplateArguments; int m = types == null ? 0 : types.Count; target.Write((byte)(method.CallingConvention | CallingConventionFlags.Generic)); Ir2md.WriteCompressedInt(target, m); } else if (method.DeclaringType.Template != null && method.DeclaringType.Template.IsGeneric) { Method unspecializedMethod = this.GetUnspecializedMethod(method); this.WriteMethodSignature(target, unspecializedMethod); return; } else if (method.IsGeneric) { TypeNodeList types = method.TemplateParameters; int m = types == null ? 0 : types.Count; target.Write((byte)(method.CallingConvention | CallingConventionFlags.Generic)); Ir2md.WriteCompressedInt(target, m); } else target.Write((byte)method.CallingConvention); } else target.Write((byte)method.CallingConvention); ParameterList pars = method.Parameters; int n = pars == null ? 0 : pars.Count; Ir2md.WriteCompressedInt(target, n); TypeNode returnType = method.ReturnType; #if ExtendedRuntime if (method.HasOutOfBandContract || this.AttributesContains(method.ReturnAttributes, SystemTypes.NotNullAttribute)) { returnType = TypeNode.DeepStripModifiers(returnType, (method.Template != null) ? method.Template.ReturnType : null, SystemTypes.NonNullType, SystemTypes.NullableType); // returnType = TypeNode.DeepStripModifier(returnType, SystemTypes.NullableType, (method.Template != null) ? returnType.GetTemplateInstance(returnType, returnType.TemplateArguments) : null); } #endif if (returnType == null) returnType = SystemTypes.Object; this.WriteTypeSignature(target, returnType, true); for (int i = 0; i < n; i++) { Parameter p = pars[i]; if (p == null) continue; TypeNode parameterType = p.Type; #if ExtendedRuntime if (method.HasOutOfBandContract || this.AttributesContains(p.Attributes, SystemTypes.NotNullAttribute)) { parameterType = TypeNode.DeepStripModifiers(parameterType, (method.Template != null) ? method.Template.Parameters[i].Type : null, SystemTypes.NonNullType, SystemTypes.NullableType); //parameterType = TypeNode.DeepStripModifier(parameterType, SystemTypes.NullableType, (method.Template != null) ? parameterType.GetTemplateInstance(parameterType, parameterType.TemplateArguments) : null); } #endif if (parameterType == null) parameterType = SystemTypes.Object; this.WriteTypeSignature(target, parameterType); } } void WriteMethodSpecSignature(BinaryWriter/*!*/ target, Method/*!*/ method) //^ requires this.UseGenerics && method.Template != null && method.Template.IsGeneric; { Debug.Assert(this.UseGenerics && method.Template != null && method.Template.IsGeneric); target.Write((byte)0x0a); TypeNodeList types = method.TemplateArguments; int m = types == null ? 0 : types.Count; Ir2md.WriteCompressedInt(target, m); for (int i = 0; i < m; i++) { //^ assert types != null; this.WriteTypeSignature(target, types[i]); } } void WriteMethodSignature(BinaryWriter/*!*/ target, FunctionPointer/*!*/ fp) { target.Write((byte)fp.CallingConvention); TypeNodeList parTypes = fp.ParameterTypes; int n = parTypes == null ? 0 : parTypes.Count; Ir2md.WriteCompressedInt(target, n); if (fp.ReturnType != null) this.WriteTypeSignature(target, fp.ReturnType); int m = fp.VarArgStart; for (int i = 0; i < n; i++) { //^ assert parTypes != null; if (i == m) target.Write((byte)0x41); //Sentinel this.WriteTypeSignature(target, parTypes[i]); } } void WritePropertySignature(BinaryWriter/*!*/ target, Property/*!*/ prop) { byte propHeader = (byte)0x8; if (!prop.IsStatic) propHeader |= (byte)0x20; //bizarre redundant way to indicate that property accessors are instance methods target.Write(propHeader); ParameterList pars = prop.Parameters; int n = pars == null ? 0 : pars.Count; Ir2md.WriteCompressedInt(target, n); if (prop.Type != null) this.WriteTypeSignature(target, prop.Type); for (int i = 0; i < n; i++) { //^ assert pars != null; Parameter par = pars[i]; if (par == null || par.Type == null) continue; this.WriteTypeSignature(target, par.Type); } } void WriteSerializedTypeName(BinaryWriter target, TypeNode type) { if (target == null || type == null) return; target.Write(this.GetSerializedTypeName(type), false); } string GetSerializedTypeName(TypeNode/*!*/ type) { bool isAssemblyQualified = true; return this.GetSerializedTypeName(type, ref isAssemblyQualified); } string GetSerializedTypeName(TypeNode/*!*/ type, ref bool isAssemblyQualified) { if (type == null) return null; this.VisitReferencedType(type); StringBuilder sb = new StringBuilder(); TypeModifier tMod = type as TypeModifier; if (tMod != null) { sb.Append(this.GetTypeDefOrRefOrSpecEncoded(type)); sb.Append('!'); return sb.ToString(); } ArrayType arrType = type as ArrayType; if (arrType != null) { type = arrType.ElementType; bool isAssemQual = false; this.AppendSerializedTypeName(sb, arrType.ElementType, ref isAssemQual); if (arrType.IsSzArray()) sb.Append("[]"); else { sb.Append('['); if (arrType.Rank == 1) sb.Append('*'); for (int i = 1; i < arrType.Rank; i++) sb.Append(','); sb.Append(']'); } goto done; } Pointer pointer = type as Pointer; if (pointer != null) { type = pointer.ElementType; bool isAssemQual = false; this.AppendSerializedTypeName(sb, pointer.ElementType, ref isAssemQual); sb.Append('*'); goto done; } Reference reference = type as Reference; if (reference != null) { type = reference.ElementType; bool isAssemQual = false; this.AppendSerializedTypeName(sb, reference.ElementType, ref isAssemQual); sb.Append('&'); goto done; } if (type.Template == null) sb.Append(type.FullName); else { sb.Append(type.Template.FullName); sb.Append('['); for (int i = 0, n = type.TemplateArguments == null ? 0 : type.TemplateArguments.Count; i < n; i++) { //^ assert type.TemplateArguments != null; bool isAssemQual = true; this.AppendSerializedTypeName(sb, type.TemplateArguments[i], ref isAssemQual); if (i < n - 1) sb.Append(','); } sb.Append(']'); } done: if (isAssemblyQualified) this.AppendAssemblyQualifierIfNecessary(sb, type, out isAssemblyQualified); return sb.ToString(); } void AppendAssemblyQualifierIfNecessary(StringBuilder/*!*/ sb, TypeNode type, out bool isAssemQualified) { isAssemQualified = false; if (type == null) return; AssemblyNode referencedAssembly = type.DeclaringModule as AssemblyNode; if (referencedAssembly != null && referencedAssembly != this.module /*&& referencedAssembly != CoreSystemTypes.SystemAssembly*/) { sb.Append(", "); sb.Append(referencedAssembly.StrongName); isAssemQualified = true; } } void AppendSerializedTypeName(StringBuilder/*!*/ sb, TypeNode type, ref bool isAssemQualified) { if (type == null) return; string argTypeName = this.GetSerializedTypeName(type, ref isAssemQualified); if (isAssemQualified) sb.Append('['); sb.Append(argTypeName); if (isAssemQualified) sb.Append(']'); } void WriteTypeDefOrRefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { if (!type.IsGeneric && this.IsStructural(type) && !(type is ITypeParameter)) this.WriteTypeSpecEncoded(target, type); else if (type.DeclaringModule == this.module) this.WriteTypeDefEncoded(target, type); else if (type.DeclaringModule != null) this.WriteTypeRefEncoded(target, type); else Debug.Assert(false); } void WriteTypeDefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { int tok = this.GetTypeDefIndex(type); Ir2md.WriteCompressedInt(target, (tok << 2)); } void WriteTypeRefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { int tok = this.GetTypeRefIndex(type); Ir2md.WriteCompressedInt(target, (tok << 2) | 1); } void WriteTypeSpecEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { int tok = this.GetTypeSpecIndex(type); Ir2md.WriteCompressedInt(target, (tok << 2) | 2); } void WriteTypeSignature(BinaryWriter/*!*/ target, TypeNode/*!*/ type) { this.WriteTypeSignature(target, type, false); } void WriteTypeSignature(BinaryWriter/*!*/ target, TypeNode/*!*/ type, bool instantiateGenericTypes) { if (type == null) return; TypeNode t = this.WriteCustomModifiers(target, type); if (this.UseGenerics) { if (t.Template != null && t.Template.IsGeneric && t.TemplateParameters == null) { target.Write((byte)0x15); TypeNode template = t.Template; while (template.Template != null) template = template.Template; this.WriteTypeSignature(target, template); TypeNodeList templArgs = t.ConsolidatedTemplateArguments; int n = templArgs == null ? 0 : templArgs.Count; Ir2md.WriteCompressedInt(target, n); for (int i = 0; i < n; i++) { //^ assume templArgs != null; TypeNode targ = templArgs[i]; if (targ == null) continue; this.WriteTypeSignature(target, targ); } return; } else if (t.IsGeneric && instantiateGenericTypes) { while (t.Template != null) t = t.Template; target.Write((byte)0x15); this.WriteTypeSignature(target, t); TypeNodeList templPars = t.ConsolidatedTemplateParameters; int n = templPars == null ? 0 : templPars.Count; Ir2md.WriteCompressedInt(target, n); for (int i = 0; i < n; i++) { //^ assume templPars != null; TypeNode tp = templPars[i]; if (tp == null) continue; this.WriteTypeSignature(target, tp); } return; } if (t is ITypeParameter) { object num = this.typeParameterNumber[t.UniqueKey]; if (num is int) { int number = (int)num; if (number < 0) { target.Write((byte)0x1e); number = -number; } else target.Write((byte)0x13); Ir2md.WriteCompressedInt(target, number - 1); return; } } } target.Write((byte)t.typeCode); switch (t.typeCode) { case ElementType.Pointer: this.WriteTypeSignature(target, ((Pointer)t).ElementType); break; case ElementType.Reference: this.WriteTypeSignature(target, ((Reference)t).ElementType); break; case ElementType.ValueType: case ElementType.Class: this.WriteTypeDefOrRefEncoded(target, t); break; case ElementType.Array: this.WriteTypeSignature(target, ((ArrayType)t).ElementType); Ir2md.WriteArrayShape(target, (ArrayType)t); break; case ElementType.FunctionPointer: this.WriteMethodSignature(target, (FunctionPointer)t); break; case ElementType.SzArray: this.WriteTypeSignature(target, ((ArrayType)t).ElementType); break; } } #if !ROTOR void IMetaDataEmit.SetModuleProps(string szName) { throw new NotImplementedException(); } void IMetaDataEmit.Save(string szFile, uint dwSaveFlags) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SaveToStream(void* pIStream, uint dwSaveFlags) { throw new NotImplementedException(); } uint IMetaDataEmit.GetSaveSize(uint fSave) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineTypeDef(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineNestedType(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements, uint tdEncloser) { throw new NotImplementedException(); } void IMetaDataEmit.SetHandler([MarshalAs(UnmanagedType.IUnknown), In]object pUnk) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineMethod(uint td, char* zName, uint dwMethodFlags, byte* pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags) { throw new NotImplementedException(); } void IMetaDataEmit.DefineMethodImpl(uint td, uint tkBody, uint tkDecl) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineTypeRefByName(uint tkResolutionScope, char* szName) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineImportType(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint tdImport, IntPtr pAssemEmit) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineMemberRef(uint tkImport, string szName, byte* pvSigBlob, uint cbSigBlob) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineImportMember(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineEvent(uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetClassLayout(uint td, uint dwPackSize, COR_FIELD_OFFSET* rFieldOffsets, uint ulClassSize) { throw new NotImplementedException(); } void IMetaDataEmit.DeleteClassLayout(uint td) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetFieldMarshal(uint tk, byte* pvNativeType, uint cbNativeType) { throw new NotImplementedException(); } void IMetaDataEmit.DeleteFieldMarshal(uint tk) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefinePermissionSet(uint tk, uint dwAction, void* pvPermission, uint cbPermission) { throw new NotImplementedException(); } void IMetaDataEmit.SetRVA(uint md, uint ulRVA) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.GetTokenFromSig(byte* pvSig, uint cbSig) { BinaryWriter sig = new BinaryWriter(new MemoryStream()); for (int i = 0; i < cbSig; i++) sig.Write(*(pvSig + i)); return (uint)(0x11000000 | this.GetStandAloneSignatureIndex(sig)); } uint IMetaDataEmit.DefineModuleRef(string szName) { throw new NotImplementedException(); } void IMetaDataEmit.SetParent(uint mr, uint tk) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.GetTokenFromTypeSpec(byte* pvSig, uint cbSig) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SaveToMemory(void* pbData, uint cbData) { throw new NotImplementedException(); } uint IMetaDataEmit.DefineUserString(string szString, uint cchString) { throw new NotImplementedException(); } void IMetaDataEmit.DeleteToken(uint tkObj) { throw new NotImplementedException(); } void IMetaDataEmit.SetMethodProps(uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetTypeDefProps(uint td, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetEventProps(uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.SetPermissionSetProps(uint tk, uint dwAction, void* pvPermission, uint cbPermission) { throw new NotImplementedException(); } void IMetaDataEmit.DefinePinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL) { throw new NotImplementedException(); } void IMetaDataEmit.SetPinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL) { throw new NotImplementedException(); } void IMetaDataEmit.DeletePinvokeMap(uint tk) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineCustomAttribute(uint tkObj, uint tkType, void* pCustomAttribute, uint cbCustomAttribute) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetCustomAttributeValue(uint pcv, void* pCustomAttribute, uint cbCustomAttribute) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineField(uint td, string szName, uint dwFieldFlags, byte* pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, void* pValue, uint cchValue) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineProperty(uint td, string szProperty, uint dwPropFlags, byte* pvSig, uint cbSig, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.DefineParam(uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetFieldProps(uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetPropertyProps(uint pr, uint dwPropFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods) { throw new NotImplementedException(); } unsafe void IMetaDataEmit.SetParamProps(uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue) { throw new NotImplementedException(); } uint IMetaDataEmit.DefineSecurityAttributeSet(uint tkObj, IntPtr rSecAttrs, uint cSecAttrs) { throw new NotImplementedException(); } void IMetaDataEmit.ApplyEditAndContinue([MarshalAs(UnmanagedType.IUnknown)]object pImport) { throw new NotImplementedException(); } unsafe uint IMetaDataEmit.TranslateSigWithScope(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport import, byte* pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, byte* pvTranslatedSig, uint cbTranslatedSigMax) { throw new NotImplementedException(); } void IMetaDataEmit.SetMethodImplFlags(uint md, uint dwImplFlags) { throw new NotImplementedException(); } void IMetaDataEmit.SetFieldRVA(uint fd, uint ulRVA) { throw new NotImplementedException(); } void IMetaDataEmit.Merge(IMetaDataImport pImport, IntPtr pHostMapToken, [MarshalAs(UnmanagedType.IUnknown)]object pHandler) { throw new NotImplementedException(); } void IMetaDataEmit.MergeEnd() { throw new NotImplementedException(); } [PreserveSig] void IMetaDataImport.CloseEnum(uint hEnum) { throw new NotImplementedException(); } uint IMetaDataImport.CountEnum(uint hEnum) { throw new NotImplementedException(); } void IMetaDataImport.ResetEnum(uint hEnum, uint ulPos) { throw new NotImplementedException(); } uint IMetaDataImport.EnumTypeDefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeDefs, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumInterfaceImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rImpls, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumTypeRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeRefs, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.FindTypeDefByName(string szTypeDef, uint tkEnclosingClass) { throw new NotImplementedException(); } Guid IMetaDataImport.GetScopeProps(StringBuilder szName, uint cchName, out uint pchName) { throw new NotImplementedException(); } uint IMetaDataImport.GetModuleFromScope() { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetTypeDefProps(uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, IntPtr pdwTypeDefFlags) { pchTypeDef = 0; if (td == 0) return 0; TypeNode t = null; if ((td & 0xFF000000) == 0x1B000000) { t = this.typeSpecEntries[(int)(td & 0xFFFFFF) - 1]; if (t.Template != null) t = t.Template; } else t = this.typeDefEntries[(int)(td & 0xFFFFFF) - 1]; if (t == null || t.Name == null) return 0; string tName = t.Name.ToString(); if (tName == null) return 0; pchTypeDef = (uint)tName.Length; if (pchTypeDef >= cchTypeDef) pchTypeDef = cchTypeDef - 1; char* pTypeDef = (char*)szTypeDef.ToPointer(); for (int i = 0; i < pchTypeDef; i++) *(pTypeDef + i) = tName[i]; *(pTypeDef + pchTypeDef) = (char)0; uint* pFlags = (uint*)pdwTypeDefFlags.ToPointer(); *(pFlags) = (uint)t.Flags; TypeNode bt = t.BaseType; if (bt == null) return 0; return (uint)this.GetTypeToken(bt); } uint IMetaDataImport.GetInterfaceImplProps(uint iiImpl, out uint pClass) { throw new NotImplementedException(); } uint IMetaDataImport.GetTypeRefProps(uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName) { throw new NotImplementedException(); } uint IMetaDataImport.ResolveTypeRef(uint tr, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIScope) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMembers(ref uint phEnum, uint cl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMembers, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMembersWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMembers, uint cMax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.EnumMethods(ref uint phEnum, uint cl, uint* rMethods, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMethodsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethods, uint cMax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.EnumFields(ref uint phEnum, uint cl, uint* rFields, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumFieldsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rFields, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumParams(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rParams, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMemberRefs(ref uint phEnum, uint tkParent, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMemberRefs, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMethodImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodBody, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodDecl, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumPermissionSets(ref uint phEnum, uint tk, uint dwActions, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rPermission, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.FindMember(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob) { throw new NotImplementedException(); } uint IMetaDataImport.FindMethod(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob) { throw new NotImplementedException(); } uint IMetaDataImport.FindField(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob) { throw new NotImplementedException(); } uint IMetaDataImport.FindMemberRef(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetMethodProps(uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA) { Method m = null; if ((mb & 0xFF000000) == 0x0A000000) m = this.memberRefEntries[(int)(mb & 0xFFFFFF) - 1] as Method; else m = this.methodEntries[(int)(mb & 0xFFFFFF) - 1]; pchMethod = 0; pClass = 0; if (m == null || m.DeclaringType == null) return 0; pClass = (uint)this.GetTypeDefToken(m.DeclaringType); string methName = m.Name == null ? null : m.Name.ToString(); if (methName == null) return 0; pchMethod = (uint)methName.Length; char* pMethName = (char*)szMethod.ToPointer(); for (int i = 0; i < pchMethod; i++) *(pMethName + i) = methName[i]; *(pMethName + pchMethod) = (char)0; return 0; } unsafe uint IMetaDataImport.GetMemberRefProps(uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out byte* ppvSigBlob) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.EnumProperties(ref uint phEnum, uint td, uint* rProperties, uint cMax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.EnumEvents(ref uint phEnum, uint td, uint* rEvents, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.GetEventProps(uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 11)] uint[] rmdOtherMethod, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumMethodSemantics(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rEventProp, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.GetMethodSemantics(uint mb, uint tkEventProp) { throw new NotImplementedException(); } uint IMetaDataImport.GetClassLayout(uint td, out uint pdwPackSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] COR_FIELD_OFFSET[] rFieldOffset, uint cMax, out uint pcFieldOffset) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetFieldMarshal(uint tk, out byte* ppvNativeType) { throw new NotImplementedException(); } uint IMetaDataImport.GetRVA(uint tk, out uint pulCodeRVA) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetPermissionSetProps(uint pm, out uint pdwAction, out void* ppvPermission) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetSigFromToken(uint mdSig, out byte* ppvSig) { throw new NotImplementedException(); } uint IMetaDataImport.GetModuleRefProps(uint mur, StringBuilder szName, uint cchName) { throw new NotImplementedException(); } uint IMetaDataImport.EnumModuleRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rModuleRefs, uint cmax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetTypeSpecFromToken(uint typespec, out byte* ppvSig) { throw new NotImplementedException(); } uint IMetaDataImport.GetNameFromToken(uint tk) { throw new NotImplementedException(); } uint IMetaDataImport.EnumUnresolvedMethods(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rMethods, uint cMax) { throw new NotImplementedException(); } uint IMetaDataImport.GetUserString(uint stk, StringBuilder szString, uint cchString) { throw new NotImplementedException(); } uint IMetaDataImport.GetPinvokeMap(uint tk, out uint pdwMappingFlags, StringBuilder szImportName, uint cchImportName, out uint pchImportName) { throw new NotImplementedException(); } uint IMetaDataImport.EnumSignatures(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rSignatures, uint cmax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumTypeSpecs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeSpecs, uint cmax) { throw new NotImplementedException(); } uint IMetaDataImport.EnumUserStrings(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rStrings, uint cmax) { throw new NotImplementedException(); } [PreserveSig] int IMetaDataImport.GetParamForMethodIndex(uint md, uint ulParamSeq, out uint pParam) { throw new NotImplementedException(); } uint IMetaDataImport.EnumCustomAttributes(ref uint phEnum, uint tk, uint tkType, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rCustomAttributes, uint cMax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetCustomAttributeProps(uint cv, out uint ptkObj, out uint ptkType, out void* ppBlob) { throw new NotImplementedException(); } uint IMetaDataImport.FindTypeRef(uint tkResolutionScope, string szName) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetMemberProps(uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, out byte* ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out void* ppValue) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetFieldProps(uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, out byte* ppvSigBlob, out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out void* ppValue) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetPropertyProps(uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, out byte* ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out void* ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, out uint pmdGetter, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 14)] uint[] rmdOtherMethod, uint cMax) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetParamProps(uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, out uint pdwAttr, out uint pdwCPlusTypeFlag, out void* ppValue) { throw new NotImplementedException(); } unsafe uint IMetaDataImport.GetCustomAttributeByName(uint tkObj, string szName, out void* ppData) { throw new NotImplementedException(); } [PreserveSig] [return: MarshalAs(UnmanagedType.Bool)] bool IMetaDataImport.IsValidToken(uint tk) { throw new NotImplementedException(); } uint IMetaDataImport.GetNestedClassProps(uint tdNestedClass) { TypeNode t = null; if ((tdNestedClass & 0xFF000000) == 0x1B000000) t = this.typeSpecEntries[(int)(tdNestedClass & 0xFFFFFF) - 1]; else t = this.typeDefEntries[(int)(tdNestedClass & 0xFFFFFF) - 1]; if (t == null || t.DeclaringType == null) return 0; return (uint)this.GetTypeToken(t.DeclaringType); } unsafe uint IMetaDataImport.GetNativeCallConvFromSig(void* pvSig, uint cbSig) { throw new NotImplementedException(); } int IMetaDataImport.IsGlobal(uint pd) { throw new NotImplementedException(); } #endif } #if WHIDBEYwithGenericsAndIEqualityComparer public class ByteArrayKeyComparer : IEqualityComparer, IComparer { int IComparer.Compare(object x, object y) { if (x == null || y == null) throw new ArgumentNullException(); byte[] xa = (byte[])x; byte[] ya = (byte[])y; int n = xa.Length; int result = n - ya.Length; if (result != 0) return result; for (int i = 0; i < n; i++) { result = xa[i] - ya[i]; if (result != 0) return result; } return 0; } bool IEqualityComparer.Equals(object x, object y) { if (x == null || y == null) return x == y; return ((IComparer)this).Compare(x, y) == 0; } int IEqualityComparer.GetHashCode(object/*!*/ x) { Debug.Assert(x != null); byte[] xa = (byte[])x; int hcode = 1; for (int i = 0, n = xa.Length; i < n; i++) hcode = hcode * 17 + xa[i]; return hcode; } } #elif WHIDBEYwithGenerics public class ByteArrayKeyComparer : IKeyComparer{ int IComparer.Compare(object x, object y) { if (x == null || y == null) throw new ArgumentNullException(); byte[] xa = (byte[])x; byte[] ya = (byte[])y; int n = xa.Length; int result = n - ya.Length; if (result != 0) return result; for (int i = 0; i < n; i++){ result = xa[i] - ya[i]; if (result != 0) return result; } return 0; } bool IKeyComparer.Equals(object x, object y){ return ((IKeyComparer)this).Compare(x, y) == 0; } int IHashCodeProvider.GetHashCode(object x) { Debug.Assert(x != null); byte[] xa = (byte[])x; int hcode = 1; for (int i = 0, n = xa.Length; i < n; i++) hcode = hcode * 17 + xa[i]; return hcode; } } #else public class ByteArrayComparer : IComparer{ int IComparer.Compare(object x, object y){ if (x == null || y == null) throw new ArgumentNullException(); byte[] xa = (byte[])x; byte[] ya = (byte[])y; int n = xa.Length; int result = n - ya.Length; if (result != 0) return result; for (int i = 0; i < n; i++){ result = xa[i] - ya[i]; if (result != 0) return result; } return 0; } } public class ByteArrayHasher : IHashCodeProvider{ int IHashCodeProvider.GetHashCode(object x){ Debug.Assert(x != null); byte[] xa = (byte[])x; int hcode = 1; for (int i = 0, n = xa.Length; i < n; i++) hcode = hcode*17 + xa[i]; return hcode; } } #endif internal class Fixup { internal int fixupLocation; internal int addressOfNextInstruction; internal bool shortOffset; internal Fixup nextFixUp; } internal class MethodInfo { internal TrivialHashtable/*!*/ fixupIndex = new TrivialHashtable(); internal int localVarSigTok; internal BinaryWriter/*!*/ localVarSignature; internal TrivialHashtable/*!*/ localVarIndex; #if !ROTOR internal NodeList/*!*/ statementNodes; internal LocalList/*!*/ debugLocals; internal Int32List/*!*/ signatureLengths; internal Int32List/*!*/ signatureOffsets; internal Int32List/*!*/ statementOffsets; #endif public MethodInfo() { //^ base(); } } public class KeyFileNotFoundException : System.ArgumentException { } public class AssemblyCouldNotBeSignedException : System.ApplicationException { } public class DebugSymbolsCouldNotBeWrittenException : System.ApplicationException { } internal class Writer { private Writer() { } internal static void WritePE(System.CodeDom.Compiler.CompilerParameters/*!*/ compilerParameters, Module/*!*/ module) //^ requires module.Location != null; { if (compilerParameters == null) { Debug.Assert(false); return; } CompilerOptions options = compilerParameters as CompilerOptions; if (options == null) Writer.WritePE(module.Location, compilerParameters.IncludeDebugInformation, module, false, null, null); else { if (options.FileAlignment > 512) module.FileAlignment = options.FileAlignment; Writer.WritePE(module.Location, options.IncludeDebugInformation, module, options.DelaySign, options.AssemblyKeyFile, options.AssemblyKeyName); } } internal static void WritePE(string/*!*/ location, bool writeDebugSymbols, Module/*!*/ module) { Writer.WritePE(location, writeDebugSymbols, module, false, null, null); } private static void WritePE(string/*!*/ location, bool writeDebugSymbols, Module/*!*/ module, bool delaySign, string keyFileName, string keyName) { AssemblyNode assem = module as AssemblyNode; location = Path.GetFullPath(location); module.Directory = Path.GetDirectoryName(location); bool keyFileNameDoesNotExist = false; if (assem != null) { assem.KeyContainerName = keyName; if (keyFileName != null && keyFileName.Length > 0) { if (!File.Exists(keyFileName)) keyFileName = Path.Combine(module.Directory, keyFileName); if (File.Exists(keyFileName)) { using (FileStream keyFile = File.OpenRead(keyFileName)) { long size = keyFile.Length; if (size > int.MaxValue) throw new System.IO.FileLoadException(); int n = (int)size; byte[] key = new byte[n]; keyFile.Read(key, 0, n); assem.KeyBlob = key; } } else keyFileNameDoesNotExist = true; } assem.PublicKeyOrToken = Writer.GetPublicKey(assem); } using (FileStream exeFstream = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.None)) { string debugSymbolsLocation = writeDebugSymbols ? Path.ChangeExtension(location, "pdb") : null; if (debugSymbolsLocation != null && File.Exists(debugSymbolsLocation)) File.Delete(debugSymbolsLocation); MemoryStream exeMstream = new MemoryStream(); Ir2md.WritePE(module, debugSymbolsLocation, new BinaryWriter(exeMstream)); exeMstream.WriteTo(exeFstream); } if (keyFileNameDoesNotExist) throw new KeyFileNotFoundException(); if (delaySign || assem == null) return; if (assem.KeyBlob != null || (assem.KeyContainerName != null && assem.KeyContainerName.Length > 0)) { try { if (!Writer.StrongNameSignatureGeneration(location, keyName, assem.KeyBlob, assem.KeyBlob == null ? 0 : assem.KeyBlob.Length, IntPtr.Zero, IntPtr.Zero)) throw new AssemblyCouldNotBeSignedException(); } catch { if (!Writer.MscorsnStrongNameSignatureGeneration(location, keyName, assem.KeyBlob, assem.KeyBlob == null ? 0 : assem.KeyBlob.Length, IntPtr.Zero, IntPtr.Zero)) throw new AssemblyCouldNotBeSignedException(); } } } [DllImport("mscoree.dll", EntryPoint = "StrongNameSignatureGeneration", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private static extern bool StrongNameSignatureGeneration( string wszFilePath, // [in] valid path to the PE file for the assembly string wszKeyContainer, // [in] desired key container name [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pbKeyBlob, // [in] public/private key blob (optional) int cbKeyBlob, IntPtr ppbSignatureBlob, // [out] signature blob IntPtr pcbSignatureBlob); [DllImport("mscorsn.dll", EntryPoint = "StrongNameSignatureGeneration", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private static extern bool MscorsnStrongNameSignatureGeneration( string wszFilePath, // [in] valid path to the PE file for the assembly string wszKeyContainer, // [in] desired key container name [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pbKeyBlob, // [in] public/private key blob (optional) int cbKeyBlob, IntPtr ppbSignatureBlob, // [out] signature blob IntPtr pcbSignatureBlob); private unsafe static byte[] GetPublicKey(AssemblyNode/*!*/ assem) { Debug.Assert(assem != null); IntPtr publicKey = IntPtr.Zero; int size; try { if (assem.KeyBlob != null) { Writer.StrongNameGetPublicKey(null, assem.KeyBlob, assem.KeyBlob.Length, out publicKey, out size); if (publicKey == IntPtr.Zero) return assem.KeyBlob; } else if (assem.KeyContainerName != null) { Writer.StrongNameGetPublicKey(assem.KeyContainerName, null, 0, out publicKey, out size); if (publicKey == IntPtr.Zero) return null; } else return assem.PublicKeyOrToken; byte[] result = new byte[size]; byte* ptr = (byte*)publicKey; for (int i = 0; i < size; i++) result[i] = *ptr++; return result; } catch { } { if (assem.KeyBlob != null) { Writer.MscorsnStrongNameGetPublicKeyUsing(null, assem.KeyBlob, assem.KeyBlob.Length, out publicKey, out size); if (publicKey == IntPtr.Zero) return assem.KeyBlob; } else if (assem.KeyContainerName != null) { Writer.MscorsnStrongNameGetPublicKeyUsing(assem.KeyContainerName, null, 0, out publicKey, out size); if (publicKey == IntPtr.Zero) return null; } else return assem.PublicKeyOrToken; byte[] result = new byte[size]; byte* ptr = (byte*)publicKey; for (int i = 0; i < size; i++) result[i] = *ptr++; return result; } } [DllImport("mscoree.dll", EntryPoint = "StrongNameGetPublicKey", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private static extern bool StrongNameGetPublicKey( string wszKeyContainer, // [in] desired key container name [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pbKeyBlob, // [in] public/private key blob (optional) int cbKeyBlob, [Out] out IntPtr ppbPublicKeyBlob, // [out] public key blob [Out] out int pcbPublicKeyBlob); [DllImport("mscorsn.dll", EntryPoint = "StrongNameGetPublicKey", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private static extern bool MscorsnStrongNameGetPublicKeyUsing( string wszKeyContainer, // [in] desired key container name [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pbKeyBlob, // [in] public/private key blob (optional) int cbKeyBlob, [Out] out IntPtr ppbPublicKeyBlob, // [out] public key blob [Out] out int pcbPublicKeyBlob); internal static void WritePE(Stream/*!*/ executable, Stream debugSymbols, Module/*!*/ module) { MemoryStream mstream = new MemoryStream(); Ir2md.WritePE(module, null, new BinaryWriter(mstream)); //TODO: need to write the PDB symbols to the stream mstream.WriteTo(executable); } internal static void WritePE(out byte[] executable, Module/*!*/ module) { MemoryStream mstream = new MemoryStream(); Ir2md.WritePE(module, null, new BinaryWriter(mstream)); executable = mstream.ToArray(); } internal static void WritePE(out byte[] executable, out byte[] debugSymbols, Module/*!*/ module) { MemoryStream mstream = new MemoryStream(); Ir2md.WritePE(module, null, new BinaryWriter(mstream)); executable = mstream.ToArray(); debugSymbols = null; } internal unsafe static void AddWin32Icon(Module/*!*/ module, string win32IconFilePath) { if (module == null || win32IconFilePath == null) { Debug.Assert(false); return; } using (System.IO.FileStream resStream = File.OpenRead(win32IconFilePath)) { Writer.AddWin32Icon(module, resStream); } } internal unsafe static void AddWin32Icon(Module/*!*/ module, Stream win32IconStream) { if (module == null || win32IconStream == null) { Debug.Assert(false); return; } long size = win32IconStream.Length; if (size > int.MaxValue) throw new System.IO.FileLoadException(); int n = (int)size; byte[] buffer = new byte[n]; win32IconStream.Read(buffer, 0, n); byte* pb = (byte*)Marshal.AllocHGlobal(n); for (int i = 0; i < n; i++) pb[i] = buffer[i]; MemoryCursor cursor = new MemoryCursor(pb, n/*, module*/); if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList(); int reserved = cursor.ReadUInt16(); if (reserved != 0) throw new NullReferenceException(); int resourceType = cursor.ReadUInt16(); if (resourceType != 1) throw new NullReferenceException(); int imageCount = cursor.ReadUInt16(); BinaryWriter indexHeap = new BinaryWriter(new MemoryStream()); indexHeap.Write((ushort)0); //Reserved indexHeap.Write((ushort)1); //idType indexHeap.Write((ushort)imageCount); Win32Resource resource = new Win32Resource(); for (int i = 0; i < imageCount; i++) { resource = new Win32Resource(); resource.CodePage = 0; resource.Id = module.Win32Resources.Count + 2; resource.LanguageId = 0; resource.Name = null; resource.TypeId = 3; resource.TypeName = null; indexHeap.Write(cursor.ReadByte()); //width indexHeap.Write(cursor.ReadByte()); //height indexHeap.Write(cursor.ReadByte()); //color count indexHeap.Write(cursor.ReadByte()); //reserved indexHeap.Write(cursor.ReadUInt16()); //planes indexHeap.Write(cursor.ReadUInt16()); //bit count int len = cursor.ReadInt32(); int offset = cursor.ReadInt32(); indexHeap.Write((int)len); indexHeap.Write((int)module.Win32Resources.Count + 2); MemoryCursor c = new MemoryCursor(cursor); c.Position = offset; resource.Data = c.ReadBytes(len); module.Win32Resources.Add(resource); } resource.CodePage = 0; resource.Data = indexHeap.BaseStream.ToArray(); resource.Id = 0x7f00; resource.LanguageId = 0; resource.Name = null; resource.TypeId = 0xe; resource.TypeName = null; module.Win32Resources.Add(resource); } internal unsafe static void AddWin32ResourceFileToModule(Module/*!*/ module, string/*!*/ win32ResourceFilePath) { if (module == null || win32ResourceFilePath == null) { Debug.Assert(false); return; } using (System.IO.FileStream resStream = File.OpenRead(win32ResourceFilePath)) { Writer.AddWin32ResourceFileToModule(module, resStream); } } internal unsafe static void AddWin32ResourceFileToModule(Module/*!*/ module, Stream/*!*/ win32ResourceStream) { if (module == null || win32ResourceStream == null) { Debug.Assert(false); return; } long size = win32ResourceStream.Length; if (size > int.MaxValue) throw new System.IO.FileLoadException(); int n = (int)size; byte[] buffer = new byte[n]; win32ResourceStream.Read(buffer, 0, n); byte* pb = (byte*)Marshal.AllocHGlobal(n); for (int i = 0; i < n; i++) pb[i] = buffer[i]; MemoryCursor cursor = new MemoryCursor(pb, n/*, module*/); if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList(); while (cursor.Position < n) { Win32Resource resource = new Win32Resource(); resource.CodePage = 0; //Review: Should this be settable? int dataSize = cursor.ReadInt32(); cursor.ReadUInt32(); //headerSize if (cursor.Int16(0) == -1) { cursor.ReadInt16(); resource.TypeId = cursor.ReadUInt16(); resource.TypeName = null; } else { resource.TypeId = 0; resource.TypeName = cursor.ReadUTF16(); } if (cursor.Int16(0) == -1) { cursor.ReadInt16(); resource.Id = cursor.ReadUInt16(); resource.Name = null; } else { resource.Id = 0; resource.Name = cursor.ReadUTF16(); } cursor.ReadUInt32(); //dataVersion cursor.ReadUInt16(); //memoryFlags resource.LanguageId = cursor.ReadUInt16(); cursor.ReadUInt32(); //version cursor.ReadUInt32(); //characteristics resource.Data = cursor.ReadBytes(dataSize); if (resource.Data != null) module.Win32Resources.Add(resource); } } internal static void AddWin32VersionInfo(Module/*!*/ module, CompilerOptions/*!*/ options) { if (module == null || options == null) { Debug.Assert(false); return; } Win32Resource resource = new Win32Resource(); resource.CodePage = 0; resource.Id = 1; resource.LanguageId = 0; resource.Name = null; resource.TypeId = 0x10; resource.TypeName = null; resource.Data = Writer.FillInVsVersionStructure(module, options); if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList(); module.Win32Resources.Add(resource); } private static byte[] FillInVsVersionStructure(Module/*!*/ module, CompilerOptions/*!*/ options) { AssemblyNode assembly = module as AssemblyNode; BinaryWriter data = new BinaryWriter(new MemoryStream(), Encoding.Unicode); data.Write((ushort)0); //Space for length data.Write((ushort)0x34); //VS_FIXEDFILEINFO length data.Write((ushort)0); //Type of data in version resource data.Write("VS_VERSION_INFO", true); data.Write((ushort)0); //Padding to 4 byte boundary // VS_FIXEDFILEINFO starts here data.Write((uint)0xFEEF04BD); //Signature data.Write((uint)0x00010000); //Version of VS_FIXEDFILEINFO Version fileVersion = Writer.ParseVersion(options.TargetInformation.Version, true); if (fileVersion == null && assembly != null) fileVersion = assembly.Version; if (fileVersion == null) fileVersion = new Version(); data.Write((ushort)fileVersion.Minor); data.Write((ushort)fileVersion.Major); data.Write((ushort)fileVersion.Revision); data.Write((ushort)fileVersion.Build); Version productVersion = Writer.ParseVersion(options.TargetInformation.ProductVersion, true); if (productVersion == null) productVersion = fileVersion; data.Write((ushort)productVersion.Minor); data.Write((ushort)productVersion.Major); data.Write((ushort)productVersion.Revision); data.Write((ushort)productVersion.Build); data.Write((uint)0x3f); //FileFlagsMask data.Write((uint)0x0); //FileFlags data.Write((uint)0x4); //OS: Win32 (After all, this is a Win32 resource.) if (options.GenerateExecutable) data.Write((uint)1); //App else data.Write((uint)2); //Dll data.Write((uint)0); //File subtype data.Write((ulong)0); //File Date // VarFileInfo data.Write((ushort)0x44); //Length of VarFileInfo data.Write((ushort)0x0); //Length of value data.Write((ushort)0x1); //type (text) data.Write("VarFileInfo", true); data.Write((ushort)0); //padding to 4 byte boundary // Var data.Write((ushort)0x24); //Length of Var data.Write((ushort)0x04); //length of Value data.Write((ushort)0); //Type (binary) data.Write("Translation", true); data.Write((uint)0); //Padding data.Write((ushort)0x4b0); //Code Page for Unicode // StringFileInfo int positionOfInfoLength = data.BaseStream.Position; data.Write((ushort)0); //length of rest of resource data.Write((ushort)0); //Value length, always 0 data.Write((ushort)1); //Type (text) data.Write("StringFileInfo", true); // StringInfo int stringInfoLengthPos = data.BaseStream.Position; data.Write((ushort)0); //Space for length data.Write((ushort)0); //Value length, always 0 data.Write((ushort)1); //Type (text) data.Write("000004b0", true); //Code page for Unicode Writer.WriteVersionString(data, options.TargetInformation.Description, "Comments"); Writer.WriteVersionString(data, options.TargetInformation.Company, "CompanyName"); Writer.WriteVersionString(data, options.TargetInformation.Title, "FileDescription"); Writer.WriteVersionString(data, Writer.ConvertToString(fileVersion), "FileVersion"); string fileName = module.Name + (options.GenerateExecutable ? ".exe" : ".dll"); Writer.WriteVersionString(data, fileName, "InternalName"); Writer.WriteVersionString(data, options.TargetInformation.Copyright, "LegalCopyright"); Writer.WriteVersionString(data, options.TargetInformation.Trademark, "LegalTrademarks"); Writer.WriteVersionString(data, fileName, "OriginalFilename"); Writer.WriteVersionString(data, options.TargetInformation.Product, "ProductName"); Writer.WriteVersionString(data, Writer.ConvertToString(productVersion), "ProductVersion"); if (assembly != null) Writer.WriteVersionString(data, assembly.Version == null ? "" : assembly.Version.ToString(), "Assembly Version"); int len = data.BaseStream.Position; data.BaseStream.Position = stringInfoLengthPos; data.Write((ushort)(len - stringInfoLengthPos)); data.BaseStream.Position = 0; data.Write((ushort)len); data.BaseStream.Position = positionOfInfoLength; data.Write((ushort)len - positionOfInfoLength); return data.BaseStream.ToArray(); } private static void WriteVersionString(BinaryWriter/*!*/ data, string value, string/*!*/ key) { if (value == null) return; int totalLength = 6; totalLength += key.Length * 2; totalLength += 4 - (totalLength % 4); totalLength += value.Length * 2; totalLength += 4 - (totalLength % 4); data.Write((ushort)totalLength); data.Write((ushort)(value.Length + 1)); data.Write((ushort)1); //Type (text) data.Write(key, true); if (data.BaseStream.Position % 4 != 0) data.Write((char)0); data.Write(value, true); if (data.BaseStream.Position % 4 != 0) data.Write((char)0); } private static string/*!*/ ConvertToString(Version/*!*/ version) { StringBuilder sb = new StringBuilder(); sb.Append(version.Major.ToString()); if (version.Minor != 0 || version.Build != 0 || version.Revision != 0) { sb.Append('.'); sb.Append(version.Minor.ToString()); } if (version.Build != 0 || version.Revision != 0) { sb.Append('.'); sb.Append(version.Build.ToString()); } if (version.Revision != 0) { sb.Append('.'); sb.Append(version.Revision.ToString()); } return sb.ToString(); } private static Version ParseVersion(string vString, bool allowWildcards) { if (vString == null) return null; ushort major = 1; ushort minor = 0; ushort build = 0; ushort revision = 0; try { int n = vString.Length; int i = vString.IndexOf('.', 0); if (i < 0) throw new FormatException(); major = UInt16.Parse(vString.Substring(0, i), CultureInfo.InvariantCulture); int j = vString.IndexOf('.', i + 1); if (j < i + 1) minor = UInt16.Parse(vString.Substring(i + 1, n - i - 1), CultureInfo.InvariantCulture); else { minor = UInt16.Parse(vString.Substring(i + 1, j - i - 1), CultureInfo.InvariantCulture); if (vString[j + 1] == '*' && allowWildcards) { if (j + 1 < n - 1) return null; build = Writer.DaysSince2000(); revision = Writer.SecondsSinceMidnight(); } else { int k = vString.IndexOf('.', j + 1); if (k < j + 1) build = UInt16.Parse(vString.Substring(j + 1, n - j - 1), CultureInfo.InvariantCulture); else { build = UInt16.Parse(vString.Substring(j + 1, k - j - 1), CultureInfo.InvariantCulture); if (vString[k + 1] == '*' && allowWildcards) { if (j + 1 < n - 1) return null; revision = Writer.SecondsSinceMidnight(); } else revision = UInt16.Parse(vString.Substring(k + 1, n - k - 1), CultureInfo.InvariantCulture); } } } } catch (FormatException) { major = minor = build = revision = UInt16.MaxValue; } catch (OverflowException) { major = minor = build = revision = UInt16.MaxValue; } if (major == UInt16.MaxValue && minor == UInt16.MaxValue && build == UInt16.MaxValue && revision == UInt16.MaxValue) { return null; } return new Version(major, minor, build, revision); } private static ushort DaysSince2000() { return (ushort)(DateTime.Now - new DateTime(2000, 1, 1)).Days; } private static ushort SecondsSinceMidnight() { TimeSpan sinceMidnight = DateTime.Now - DateTime.Today; return (ushort)((sinceMidnight.Hours * 60 * 60 + sinceMidnight.Minutes * 60 + sinceMidnight.Seconds) / 2); } } } #endif