// 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. using System; using System.Collections; #if FxCop using System.Collections.Generic; using AssemblyReferenceList = Microsoft.Cci.AssemblyReferenceCollection; using AttributeList = Microsoft.Cci.AttributeNodeCollection; using BlockList = Microsoft.Cci.BlockCollection; using ExpressionList = Microsoft.Cci.ExpressionCollection; using InstructionList = Microsoft.Cci.InstructionCollection; using Int32List = System.Collections.Generic.List; using InterfaceList = Microsoft.Cci.InterfaceCollection; using LocalList = Microsoft.Cci.LocalCollection; using MemberList = Microsoft.Cci.MemberCollection; using MethodList = Microsoft.Cci.MethodCollection; using ModuleReferenceList = Microsoft.Cci.ModuleReferenceCollection; using NamespaceList = Microsoft.Cci.NamespaceCollection; using ParameterList = Microsoft.Cci.ParameterCollection; using ResourceList = Microsoft.Cci.ResourceCollection; using SecurityAttributeList = Microsoft.Cci.SecurityAttributeCollection; using StatementList = Microsoft.Cci.StatementCollection; using TypeNodeList = Microsoft.Cci.TypeNodeCollection; using Win32ResourceList = Microsoft.Cci.Win32ResourceCollection; using Property = Microsoft.Cci.PropertyNode; using Module = Microsoft.Cci.ModuleNode; using Class = Microsoft.Cci.ClassNode; using Interface = Microsoft.Cci.InterfaceNode; using Event = Microsoft.Cci.EventNode; using Return = Microsoft.Cci.ReturnNode; using Throw = Microsoft.Cci.ThrowNode; #endif #if UseSingularityPDB using Microsoft.Singularity.PdbInfo; using Microsoft.Singularity.PdbInfo.Features; #endif #if CCINamespace using Microsoft.Cci; #else using System.Compiler; #endif using System.Diagnostics; using System.Globalization; using Marshal = System.Runtime.InteropServices.Marshal; using System.Runtime.InteropServices; using System.IO; #if CCINamespace namespace Microsoft.Cci.Metadata{ #else namespace System.Compiler.Metadata { #endif #if !ROTOR && !UseSingularityPDB enum CorOpenFlags : uint { ofRead = 0x00000000, // Open scope for read ofWrite = 0x00000001, // Open scope for write. ofCopyMemory = 0x00000002, // Open scope with memory. Ask metadata to maintain its own copy of memory. ofCacheImage = 0x00000004, // EE maps but does not do relocations or verify image ofNoTypeLib = 0x00000080, // Don't OpenScope on a typelib. } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("809c652e-7396-11d2-9771-00A0C9B4D50C")] interface IMetaDataDispenser { void DefineScope(ref Guid clsid, uint createFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval); [PreserveSig] int OpenScope(string scope, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object import); void OpenScopeOnMemory(IntPtr data, uint dataSize, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("AA544D42-28CB-11d3-BD22-0000F80849BD")] interface ISymUnmanagedBinder { [PreserveSig] int GetReaderForFile([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, out ISymUnmanagedReader reader); ISymUnmanagedReader GetReaderForStream([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.IUnknown)] object stream); } [ComImport, Guid("ACCEE350-89AF-4ccb-8B40-1C2C4C6F9434"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(false)] interface ISymUnmanagedBinder2 : ISymUnmanagedBinder { void GetReaderForFile(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String filename, [MarshalAs(UnmanagedType.LPWStr)] String SearchPath, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal); void GetReaderFromStream(IntPtr importer, IntPtr stream, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal); [PreserveSig] int GetReaderForFile2([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal); // void GetReaderForFile3(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, IntPtr callback, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal); } [ComImport, Guid("AA544D41-28CB-11d3-BD22-0000F80849BD")] class CorSymBinder { } [ComImport, Guid("0A29FF9E-7F9C-4437-8B11-F424491E3931")] class CorSymBinder2 { } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5")] interface ISymUnmanagedReader { ISymUnmanagedDocument GetDocument(string url, ref Guid language, ref Guid languageVendor, ref Guid documentType); void GetDocuments(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ISymUnmanagedDocument[] docs); uint GetUserEntryPoint(); [PreserveSig] int GetMethod(uint token, ref ISymUnmanagedMethod method); ISymUnmanagedMethod GetMethodByVersion(uint token, int version); void GetVariables(uint parent, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ISymUnmanagedVariable[] vars); void GetGlobalVariables(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ISymUnmanagedVariable[] vars); ISymUnmanagedMethod GetMethodFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column); void GetSymAttribute(uint parent, string name, ulong size, ref uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] buffer); void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] namespaces); void Initialize([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, [MarshalAs(UnmanagedType.IUnknown)] object stream); void UpdateSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream); void ReplaceSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream); void GetSymbolStoreFileName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] char[] name); void GetMethodsFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] ISymUnmanagedMethod[] retval); void GetDocumentVersion(ISymUnmanagedDocument doc, out int version, out bool isLatest); void GetMethodVersion(ISymUnmanagedMethod method, out int version); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B62B923C-B500-3158-A543-24F307A8B7E1")] interface ISymUnmanagedMethod { uint GetToken(); uint GetSequencePointCount(); ISymUnmanagedScope GetRootScope(); ISymUnmanagedScope GetScopeFromOffset(uint offset); uint Getoffset(ISymUnmanagedDocument document, uint line, uint column); void GetRanges(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] ranges); void GetParameters(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ISymUnmanagedVariable[] parms); IntPtr GetNamespace(); bool GetSourceStartEnd([MarshalAs(UnmanagedType.LPArray, SizeConst = 2)] ISymUnmanagedDocument[] docs, [MarshalAs(UnmanagedType.LPArray)] uint[] lines, [MarshalAs(UnmanagedType.LPArray)] uint[] columns); void GetSequencePoints(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] offsets, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, SizeParamIndex = 0)] IntPtr[] documents, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] lines, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] columns, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] endLines, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] endColumns); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")] interface ISymUnmanagedDocument { void GetURL(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] char[] url); void GetDocumentType(out Guid retval); void GetLanguage(out Guid retval); void GetLanguageVendor(out Guid retval); void GetCheckSumAlgorithmId(out Guid retval); void GetCheckSum(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] data); uint FindClosestLine(uint line); bool HasEmbeddedSource(); uint GetSourceLength(); void GetSourceRange(uint startLine, uint startColumn, uint endLine, uint endColumn, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] source); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("9F60EEBE-2D9A-3F7C-BF58-80BC991C60BB")] interface ISymUnmanagedVariable { void GetName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] char[] name); uint GetAttributes(); void GetSignature(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] name); uint GetAddressKind(); uint GetAddressField1(); uint GetAddressField2(); uint GetAddressField3(); uint GetStartOffset(); uint GetEndOffset(); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("68005D0F-B8E0-3B01-84D5-A11A94154942")] interface ISymUnmanagedScope { ISymUnmanagedMethod GetMethod(); ISymUnmanagedScope GetParent(); void GetChildren(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] children); uint GetStartOffset(); uint GetEndOffset(); uint GetLocalCount(); void GetLocals(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] locals); void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] namespaces); } #endif internal sealed class UnmanagedBuffer : IDisposable { internal IntPtr Pointer; internal UnmanagedBuffer(int length) { this.Pointer = Marshal.AllocHGlobal(length); } public void Dispose() { if (this.Pointer != IntPtr.Zero) Marshal.FreeHGlobal(this.Pointer); this.Pointer = IntPtr.Zero; GC.SuppressFinalize(this); } ~UnmanagedBuffer() { this.Dispose(); } } internal unsafe class Reader : IDisposable { private string directory; private string fileName; private bool doNotLockFile; private Module/*!*/ module = new Module(); internal TypeNode currentType; private long sortedTablesMask; internal MetadataReader/*!*/ tables; private UnmanagedBuffer unmanagedBuffer; private int bufferLength; private IDictionary/*!*/ localAssemblyCache; //use for simple names internal readonly static IDictionary/*!*/ StaticAssemblyCache = new SynchronizedWeakDictionary(); //use for strong names private bool useStaticCache; //^ [Microsoft.Contracts.SpecInternal] private TrivialHashtable namespaceTable; internal NamespaceList namespaceList; #if UseSingularityPDB internal PdbFunction[] pdbFunctions; #elif !ROTOR internal ISymUnmanagedReader debugReader; #endif #if FxCop internal static bool probeGAC = true; #endif internal bool getDebugSymbols; private bool getDebugSymbolsFailed; private TypeNodeList currentTypeParameters; private TypeNodeList currentMethodTypeParameters; internal bool preserveShortBranches; #if !MinimalReader internal unsafe Reader(byte[]/*!*/ buffer, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches) { Debug.Assert(buffer != null); if (localAssemblyCache == null) localAssemblyCache = new Hashtable(); this.localAssemblyCache = localAssemblyCache; this.getDebugSymbols = getDebugInfo; this.doNotLockFile = false; this.useStaticCache = useStaticCache; this.preserveShortBranches = preserveShortBranches; int n = this.bufferLength = buffer.Length; this.unmanagedBuffer = new UnmanagedBuffer(n); //^ base(); byte* pb = (byte*)this.unmanagedBuffer.Pointer; for (int i = 0; i < n; i++) *pb++ = buffer[i]; } #endif internal Reader(string/*!*/ fileName, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches) { if (localAssemblyCache == null) localAssemblyCache = new Hashtable(); this.localAssemblyCache = localAssemblyCache; fileName = System.IO.Path.GetFullPath(fileName); this.fileName = fileName; this.directory = System.IO.Path.GetDirectoryName(fileName); this.getDebugSymbols = getDebugInfo; this.doNotLockFile = doNotLockFile; this.useStaticCache = useStaticCache; this.preserveShortBranches = preserveShortBranches; //^ base(); } internal Reader(IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches) { if (localAssemblyCache == null) localAssemblyCache = new Hashtable(); this.localAssemblyCache = localAssemblyCache; this.directory = System.IO.Directory.GetCurrentDirectory(); this.getDebugSymbols = getDebugInfo; this.doNotLockFile = doNotLockFile; this.useStaticCache = useStaticCache; this.preserveShortBranches = preserveShortBranches; //^ base(); } public void Dispose() { if (this.unmanagedBuffer != null) this.unmanagedBuffer.Dispose(); this.unmanagedBuffer = null; if (this.tables != null) this.tables.Dispose(); //this.tables = null; #if !ROTOR && !UseSingularityPDB if (this.debugReader != null) Marshal.ReleaseComObject(this.debugReader); this.debugReader = null; #endif } private unsafe void SetupReader() { Debug.Assert(this.localAssemblyCache != null); #if !ROTOR if (this.doNotLockFile) { #endif using (System.IO.FileStream inputStream = new System.IO.FileStream(this.fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) { this.ReadFileIntoUnmanagedBuffer(inputStream); } #if !ROTOR } if (this.unmanagedBuffer == null) this.tables = new MetadataReader(this.fileName); //Uses a memory map that locks the file else #endif this.tables = new MetadataReader((byte*)this.unmanagedBuffer.Pointer, this.bufferLength); //^ assume this.tables.tablesHeader != null; this.sortedTablesMask = this.tables.tablesHeader.maskSorted; } #if !ROTOR [DllImport("kernel32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern unsafe bool ReadFile(IntPtr FileHandle, byte* Buffer, int NumberOfBytesToRead, int* NumberOfBytesRead, IntPtr Overlapped); #endif private unsafe void ReadFileIntoUnmanagedBuffer(System.IO.FileStream/*!*/ inputStream) { long size = inputStream.Seek(0, System.IO.SeekOrigin.End); if (size > int.MaxValue) throw new System.IO.FileLoadException(); inputStream.Seek(0, System.IO.SeekOrigin.Begin); int n = (int)size; this.bufferLength = n; this.unmanagedBuffer = new UnmanagedBuffer(n); byte* pb = (byte*)this.unmanagedBuffer.Pointer; #if !ROTOR #if WHIDBEY && !OldWhidbey if (!Reader.ReadFile(inputStream.SafeFileHandle.DangerousGetHandle(), pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException(); #else if (!Reader.ReadFile(inputStream.Handle, pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException(); #endif #else //Read a fixed length block at a time, so that the GC does not come under pressure from lots of large byte arrays. int bufferLen = 8096; byte[] buffer = new byte[bufferLen]; while (n > 0){ if (n < bufferLen) bufferLen = n; inputStream.Read(buffer, 0, bufferLen); for (int i = 0; i < bufferLen; i++) *pb++ = buffer[i]; n -= bufferLen; } #endif } internal void SetupDebugReader(string filename, string pdbSearchPath) { #if UseSingularityPDB string pdbFileName = BetterPath.ChangeExtension(filename, "pdb"); this.getDebugSymbolsFailed = true; //TODO: use search path if (System.IO.File.Exists(pdbFileName)) { using (System.IO.FileStream inputStream = new System.IO.FileStream(pdbFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) { this.pdbFunctions = PdbFile.LoadFunctions(inputStream, true); this.getDebugSymbolsFailed = false; } } #elif !ROTOR if (filename == null) return; CorSymBinder binderObj1 = null; CorSymBinder2 binderObj2 = null; getDebugSymbolsFailed = false; object importer = null; try { int hresult = 0; try { binderObj2 = new CorSymBinder2(); ISymUnmanagedBinder2 binder2 = (ISymUnmanagedBinder2)binderObj2; #if !NoWriter importer = new Ir2md(new Module()); #else importer = new EmptyImporter(); #endif hresult = binder2.GetReaderForFile(importer, filename, pdbSearchPath, out this.debugReader); } catch (COMException e) { // could not instantiate ISymUnmanagedBinder2, fall back to ISymUnmanagedBinder if ((uint)e.ErrorCode == 0x80040111) { binderObj1 = new CorSymBinder(); ISymUnmanagedBinder binder = (ISymUnmanagedBinder)binderObj1; hresult = binder.GetReaderForFile(importer, filename, null, out this.debugReader); } else { throw; } } switch ((uint)hresult) { case 0x0: break; case 0x806d0005: // EC_NOT_FOUND case 0x806d0014: // EC_INVALID_EXE_TIMESTAMP #if FxCop this.getDebugSymbols = false; this.getDebugSymbolsFailed = true; #else // Sometimes GetReaderForFile erroneously reports missing pdb files as being "out of date", // so we check if the file actually exists before reporting the error. // The mere absence of a pdb file is not an error. If not present, do not report. if (System.IO.File.Exists(System.IO.Path.ChangeExtension(filename, ".pdb"))) throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.PdbAssociatedWithFileIsOutOfDate, filename)); #endif break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.GetReaderForFileReturnedUnexpectedHResult, hresult.ToString("X"))); } #if !FxCop } catch (Exception e) { this.getDebugSymbols = false; this.getDebugSymbolsFailed = true; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); #endif } finally { if (binderObj1 != null) Marshal.ReleaseComObject(binderObj1); if (binderObj2 != null) Marshal.ReleaseComObject(binderObj2); } #endif // !ROTOR } private AssemblyNode ReadAssembly() { try { AssemblyNode assembly = new AssemblyNode(new Module.TypeNodeProvider(this.GetTypeFromName), new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor), new Module.ResourceProvider(this.GetResources), this.directory); assembly.reader = this; this.ReadModuleProperties(assembly); this.ReadAssemblyProperties(assembly); //Hashvalue, Name, etc. this.module = assembly; this.ReadAssemblyReferences(assembly); this.ReadModuleReferences(assembly); AssemblyNode cachedAssembly = this.GetCachedAssembly(assembly); if (cachedAssembly != null) return cachedAssembly; if (this.getDebugSymbols) assembly.SetupDebugReader(null); #if !MinimalReader assembly.AfterAssemblyLoadProcessing(); #endif return assembly; #if !FxCop } catch (Exception e) { if (this.module == null) return null; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); return this.module as AssemblyNode; } #else }finally{} #endif } private AssemblyNode GetCachedAssembly(AssemblyNode/*!*/ assembly) { //Always return the one true mscorlib. Things get too weird if more than one mscorlib is being read at the same time. //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name && CoreSystemTypes.SystemAssembly.reader != null) { // if (CoreSystemTypes.SystemAssembly.reader != this) { // if (this.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbolsFailed) // CoreSystemTypes.SystemAssembly.SetupDebugReader(null); // this.Dispose(); // } // return CoreSystemTypes.SystemAssembly; //} if (assembly.PublicKeyOrToken == null || assembly.PublicKeyOrToken.Length == 0) { AssemblyNode cachedAssembly = null; if (assembly.Location != null) cachedAssembly = this.localAssemblyCache[assembly.Location] as AssemblyNode; if (cachedAssembly == null && assembly.Name != null) { cachedAssembly = this.localAssemblyCache[assembly.Name] as AssemblyNode; if (cachedAssembly != null && assembly.Location != null) this.localAssemblyCache[assembly.Location] = cachedAssembly; } if (cachedAssembly != null) { if (cachedAssembly.reader != this && cachedAssembly.reader != null) { if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed) cachedAssembly.SetupDebugReader(null); this.Dispose(); } return cachedAssembly; } lock (Reader.StaticAssemblyCache) { if (assembly.Name != null) this.localAssemblyCache[assembly.Name] = assembly; if (this.fileName != null) this.localAssemblyCache[this.fileName] = assembly; } } else { string assemblyStrongName = assembly.StrongName; AssemblyNode cachedAssembly = null; if (this.useStaticCache) { //See if assembly is a platform assembly (and apply unification) AssemblyReference assemblyReference = new AssemblyReference(assembly); AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey]; if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)) { AssemblyNode platformAssembly = aRef.assembly; if (platformAssembly == null) { Debug.Assert(aRef.Location != null); if (Path.GetFullPath(aRef.Location) == assembly.Location) { if (aRef.Version != assemblyReference.Version) { HandleError(assembly, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.BadTargetPlatformLocation, assembly.Name, TargetPlatform.PlatformAssembliesLocation, assembly.Version, aRef.Version)); } lock (Reader.StaticAssemblyCache) { Reader.StaticAssemblyCache[assemblyStrongName] = assembly; if (aRef.Location != null) Reader.StaticAssemblyCache[aRef.Location] = assembly; } return null; //Prevents infinite recursion } platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); } if (platformAssembly != null) { lock (Reader.StaticAssemblyCache) { if (aRef.Location != null) Reader.StaticAssemblyCache[aRef.Location] = platformAssembly; Reader.StaticAssemblyCache[assemblyStrongName] = platformAssembly; } return aRef.assembly = platformAssembly; } } cachedAssembly = Reader.StaticAssemblyCache[assemblyStrongName] as AssemblyNode; if (cachedAssembly != null) { if (aRef == null && assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc && assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) { lock (Reader.StaticAssemblyCache) { Reader.StaticAssemblyCache[assemblyStrongName] = assembly; } return null; } if (cachedAssembly.reader != this && cachedAssembly.reader != null) { if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed) cachedAssembly.SetupDebugReader(null); this.Dispose(); } return cachedAssembly; } lock (Reader.StaticAssemblyCache) { Reader.StaticAssemblyCache[assemblyStrongName] = assembly; if (this.fileName != null) { Reader.StaticAssemblyCache[this.fileName] = assembly; } } } else { cachedAssembly = this.localAssemblyCache[assemblyStrongName] as AssemblyNode; if (cachedAssembly != null) { if (assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc && assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) { this.localAssemblyCache[assemblyStrongName] = assembly; return null; } if (cachedAssembly.reader != this && cachedAssembly.reader != null) { #if UseSingularityPDB if (this.getDebugSymbols && cachedAssembly.reader.pdbFunctions == null && !cachedAssembly.reader.getDebugSymbolsFailed) cachedAssembly.SetupDebugReader(null); #elif !ROTOR if (this.getDebugSymbols && cachedAssembly.reader.debugReader == null && !cachedAssembly.reader.getDebugSymbolsFailed) cachedAssembly.SetupDebugReader(null); #endif this.Dispose(); } return cachedAssembly; } this.localAssemblyCache[assemblyStrongName] = assembly; if (this.fileName != null) this.localAssemblyCache[this.fileName] = assembly; } } return null; } internal Module ReadModule() { try { if (this.fileName != null) { if (!System.IO.File.Exists(this.fileName)) return null; AssemblyNode cachedAssembly; if (this.useStaticCache) { cachedAssembly = Reader.StaticAssemblyCache[this.fileName] as AssemblyNode; if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) { this.Dispose(); return cachedAssembly; } } cachedAssembly = this.localAssemblyCache[this.fileName] as AssemblyNode; if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) { this.Dispose(); return cachedAssembly; } } this.SetupReader(); if (this.tables.AssemblyTable.Length > 0) return this.ReadAssembly(); Module module = this.module = new Module(new Module.TypeNodeProvider(this.GetTypeFromName), new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor), new Module.ResourceProvider(this.GetResources)); module.reader = this; this.ReadModuleProperties(module); this.module = module; this.ReadAssemblyReferences(module); this.ReadModuleReferences(module); if (this.getDebugSymbols) this.SetupDebugReader(this.fileName, null); return module; #if !FxCop } catch (Exception e) { if (this.module == null) return null; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); return module; } #else }finally{} #endif } private void ReadModuleProperties(Module/*!*/ module) { ModuleRow[] mods = this.tables.ModuleTable; if (mods.Length != 1) throw new InvalidMetadataException(ExceptionStrings.InvalidModuleTable); ModuleRow mrow = mods[0]; module.reader = this; module.FileAlignment = this.tables.fileAlignment; module.HashValue = this.tables.HashValue; module.Kind = this.tables.moduleKind; module.Location = this.fileName; module.TargetRuntimeVersion = this.tables.targetRuntimeVersion; module.LinkerMajorVersion = this.tables.linkerMajorVersion; module.LinkerMinorVersion = this.tables.linkerMinorVersion; module.MetadataFormatMajorVersion = this.tables.metadataFormatMajorVersion; module.MetadataFormatMinorVersion = this.tables.metadataFormatMinorVersion; module.Name = this.tables.GetString(mrow.Name); module.Mvid = this.tables.GetGuid(mrow.Mvid); module.PEKind = this.tables.peKind; module.TrackDebugData = this.tables.TrackDebugData; } private void ReadAssemblyProperties(AssemblyNode/*!*/ assembly) { AssemblyRow assemblyRow = this.tables.AssemblyTable[0]; assembly.HashAlgorithm = (AssemblyHashAlgorithm)assemblyRow.HashAlgId; assembly.Version = new System.Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber); assembly.Flags = (AssemblyFlags)assemblyRow.Flags; assembly.PublicKeyOrToken = this.tables.GetBlob(assemblyRow.PublicKey); assembly.ModuleName = assembly.Name; assembly.Name = this.tables.GetString(assemblyRow.Name); assembly.Culture = this.tables.GetString(assemblyRow.Culture); if (this.fileName != null) { assembly.FileLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(this.fileName); } assembly.ContainingAssembly = assembly; } private void ReadAssemblyReferences(Module/*!*/ module) { AssemblyRefRow[] assems = this.tables.AssemblyRefTable; int n = assems.Length; AssemblyReferenceList assemblies = module.AssemblyReferences = new AssemblyReferenceList(n); for (int i = 0; i < n; i++) { AssemblyRefRow arr = assems[i]; AssemblyReference assemRef = new AssemblyReference(); assemRef.Version = new System.Version(arr.MajorVersion, arr.MinorVersion, arr.BuildNumber, arr.RevisionNumber); assemRef.Flags = (AssemblyFlags)arr.Flags; assemRef.PublicKeyOrToken = this.tables.GetBlob(arr.PublicKeyOrToken); assemRef.Name = this.tables.GetString(arr.Name); //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemRef.Name && // assemRef.Version > CoreSystemTypes.SystemAssembly.Version){ // HandleError(module, ExceptionStrings.ModuleOrAssemblyDependsOnMoreRecentVersionOfCoreLibrary); //} assemRef.Culture = this.tables.GetString(arr.Culture); if (assemRef.Culture != null && assemRef.Culture.Length == 0) assemRef.Culture = null; assemRef.HashValue = this.tables.GetBlob(arr.HashValue); assemRef.Reader = this; assems[i].AssemblyReference = assemRef; assemblies.Add(assemRef); } } private void ReadModuleReferences(Module/*!*/ module) { FileRow[] files = this.tables.FileTable; ModuleRefRow[] modRefs = this.tables.ModuleRefTable; int n = modRefs.Length; ModuleReferenceList modules = module.ModuleReferences = new ModuleReferenceList(n); for (int i = 0; i < n; i++) { Module mod; int nameIndex = modRefs[i].Name; string name = this.tables.GetString(nameIndex); string dir = BetterPath.GetDirectoryName(this.module.Location); string location = BetterPath.Combine(dir, name); for (int j = 0, m = files == null ? 0 : files.Length; j < m; j++) { if (files[j].Name != nameIndex) continue; if ((files[j].Flags & (int)FileFlags.ContainsNoMetaData) == 0) mod = Module.GetModule(location, this.doNotLockFile, this.getDebugSymbols, false); else mod = null; if (mod == null) { mod = new Module(); mod.Name = name; mod.Location = location; mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary; } mod.HashValue = this.tables.GetBlob(files[j].HashValue); mod.ContainingAssembly = module.ContainingAssembly; modRefs[i].Module = mod; modules.Add(new ModuleReference(name, mod)); goto nextModRef; } mod = new Module(); mod.Name = name; mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary; if (System.IO.File.Exists(location)) mod.Location = location; mod.ContainingAssembly = module.ContainingAssembly; modRefs[i].Module = mod; modules.Add(new ModuleReference(name, mod)); nextModRef: ; } } private static string ReadSerString(MemoryCursor/*!*/ sigReader) { int n = sigReader.ReadCompressedInt(); if (n < 0) return null; return sigReader.ReadUTF8(n); } private void AddFieldsToType(TypeNode/*!*/ type, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) { for (int i = start; i < end; i++) { int ii = i; if (fieldPtrs.Length > 0) ii = fieldPtrs[i - 1].Field; Field field = this.GetFieldFromDef(ii, type); if (field != null) type.Members.Add(field); } } private void GetUnderlyingTypeOfEnumNode(EnumNode /*!*/enumNode, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) { TypeNode underlyingType = null; for (int i = start; i < end; i++) { int ii = i; if (fieldPtrs.Length > 0) ii = fieldPtrs[i - 1].Field; FieldRow fld = fieldDefs[ii - 1]; if (fld.Field != null && !fld.Field.IsStatic) { underlyingType = fld.Field.Type; break; } FieldFlags fieldFlags = (FieldFlags)fld.Flags; if ((fieldFlags & FieldFlags.Static) == 0) { this.tables.GetSignatureLength(fld.Signature); MemoryCursor sigReader = this.tables.GetNewCursor(); GetAndCheckSignatureToken(6, sigReader); underlyingType = this.ParseTypeSignature(sigReader); break; } } enumNode.underlyingType = underlyingType; } private void AddMethodsToType(TypeNode/*!*/ type, MethodPtrRow[]/*!*/ methodPtrs, int start, int end) //^ requires type.members != null; { for (int i = start; i < end; i++) { int ii = i; if (methodPtrs.Length > 0) ii = methodPtrs[i - 1].Method; Method method = this.GetMethodFromDef(ii, type); if (method != null && ((method.Flags & MethodFlags.RTSpecialName) == 0 || method.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey)) type.members.Add(method); } } private void AddMoreStuffToParameters(Method method, ParameterList parameters, int start, int end) { ParamRow[] pars = this.tables.ParamTable; int n = parameters == null ? 0 : parameters.Count; for (int i = start; i < end; i++) { ParamRow pr = pars[i - 1]; if (pr.Sequence == 0 && method != null) { //The parameter entry with sequence 0 is used as a target for custom attributes that apply to the return value method.ReturnAttributes = this.GetCustomAttributesFor((i << 5) | 4); if ((pr.Flags & (int)ParameterFlags.HasFieldMarshal) != 0) method.ReturnTypeMarshallingInformation = this.GetMarshallingInformation((i << 1) | 1); this.AddMoreStuffToParameters(null, parameters, start + 1, end); return; } int j = pr.Sequence; if (j < 1 || j > n) continue; //Bad metadata, ignore if (parameters == null) continue; Parameter par = parameters[j - 1]; par.Attributes = this.GetCustomAttributesFor((i << 5) | 4); par.Flags = (ParameterFlags)pr.Flags; if ((par.Flags & ParameterFlags.HasDefault) != 0) par.DefaultValue = this.GetLiteral((i << 2) | 1, par.Type); if ((par.Flags & ParameterFlags.HasFieldMarshal) != 0) par.MarshallingInformation = this.GetMarshallingInformation((i << 1) | 1); par.Name = tables.GetIdentifier(pr.Name); #if ExtendedRuntime for (int k = 0, al = par.Attributes == null ? 0 : par.Attributes.Count; k < al; k++) { if (par.Attributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) { Reference r = par.Type as Reference; if (r != null){ // need to make it a reference to a non-null type and not a non-null wrapper around the reference // also *must* make it a new Reference. OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, r.ElementType); par.Type = om.GetReferenceType(); }else{ par.Type = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, par.Type); } // Someone putting an attribute directly on the "real" method is still a // kind of out-of-band contract. // This marking is the way to signal that any override or implementing method being compiled // should not have its non-null annotations persisted as optional modifiers. par.DeclaringMethod.HasOutOfBandContract = true; break; } } #endif } } private void AddPropertiesToType(TypeNode/*!*/ type, PropertyRow[]/*!*/ propertyDefs, PropertyPtrRow[]/*!*/ propertyPtrs, int start, int end) //requires type.members != null; { MetadataReader tables = this.tables; for (int i = start; i < end; i++) { int ii = i; if (propertyPtrs.Length > 0) ii = propertyPtrs[i - 1].Property; PropertyRow prop = propertyDefs[ii - 1]; Property property = new Property(); property.Attributes = this.GetCustomAttributesFor((ii << 5) | 9); property.DeclaringType = type; property.Flags = (PropertyFlags)prop.Flags; property.Name = tables.GetIdentifier(prop.Name); if ((property.Flags & PropertyFlags.RTSpecialName) == 0 || property.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey) { this.AddMethodsToProperty(ii, property); type.members.Add(property); } //REVIEW: the signature seems to be redundant. Is there any point in retrieving it? } } private void AddMethodsToProperty(int propIndex, Property/*!*/ property) { int codedPropIndex = (propIndex << 1) | 1; MetadataReader tables = this.tables; MethodRow[] methods = tables.MethodTable; MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable; int i = 0, n = methodSemantics.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (methodSemantics[k].Association < codedPropIndex) i = k + 1; else j = k; } while (i > 0 && methodSemantics[i - 1].Association == codedPropIndex) i--; } for (; i < n; i++) { MethodSemanticsRow meth = methodSemantics[i]; Method propertyMethod = methods[meth.Method - 1].Method; if (propertyMethod == null) continue; if (meth.Association == codedPropIndex) { propertyMethod.DeclaringMember = property; switch (meth.Semantics) { case 0x0001: property.Setter = propertyMethod; break; case 0x0002: property.Getter = propertyMethod; break; default: if (property.OtherMethods == null) property.OtherMethods = new MethodList(); property.OtherMethods.Add(propertyMethod); break; } } else if (sorted) break; } } private void AddEventsToType(TypeNode/*!*/ type, EventRow[]/*!*/ eventDefs, EventPtrRow[]/*!*/ eventPtrs, int start, int end) { MetadataReader tables = this.tables; for (int i = start; i < end; i++) { int ii = i; if (eventPtrs.Length > 0) ii = eventPtrs[i].Event; EventRow ev = eventDefs[ii - 1]; Event evnt = new Event(); evnt.Attributes = this.GetCustomAttributesFor((ii << 5) | 10); evnt.DeclaringType = type; evnt.Flags = (EventFlags)ev.Flags; evnt.HandlerType = this.DecodeAndGetTypeDefOrRefOrSpec(ev.EventType); evnt.Name = tables.GetIdentifier(ev.Name); if ((evnt.Flags & EventFlags.RTSpecialName) == 0 || evnt.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey) { this.AddMethodsToEvent(ii, evnt); type.Members.Add(evnt); } } } private void AddMethodsToEvent(int eventIndex, Event/*!*/ evnt) { int codedEventIndex = eventIndex << 1; MetadataReader tables = this.tables; MethodRow[] methods = tables.MethodTable; MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable; int i = 0, n = methodSemantics.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (methodSemantics[k].Association < codedEventIndex) i = k + 1; else j = k; } while (i > 0 && methodSemantics[i - 1].Association == codedEventIndex) i--; } MethodFlags handlerFlags = (MethodFlags)0; for (; i < n; i++) { MethodSemanticsRow meth = methodSemantics[i]; Method eventMethod = methods[meth.Method - 1].Method; if (eventMethod == null) continue; if (meth.Association == codedEventIndex) { eventMethod.DeclaringMember = evnt; switch (meth.Semantics) { case 0x0008: evnt.HandlerAdder = eventMethod; handlerFlags = eventMethod.Flags; break; case 0x0010: evnt.HandlerRemover = eventMethod; handlerFlags = eventMethod.Flags; break; case 0x0020: evnt.HandlerCaller = eventMethod; break; default: if (evnt.OtherMethods == null) evnt.OtherMethods = new MethodList(); evnt.OtherMethods.Add(eventMethod); break; } } else if (sorted) break; } evnt.HandlerFlags = handlerFlags; } private bool TypeDefOrRefOrSpecIsClass(int codedIndex) { if (codedIndex == 0) return false; switch (codedIndex & 0x3) { case 0x00: return this.TypeDefIsClass(codedIndex >> 2); case 0x01: TypeNode t = this.GetTypeFromRef(codedIndex >> 2); return t is Class; case 0x02: return this.TypeSpecIsClass(codedIndex >> 2); } throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef); } private bool TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(int codedIndex) { if (codedIndex == 0) return false; switch (codedIndex & 0x3) { case 0x00: return this.TypeDefIsClassButNotValueTypeBaseClass(codedIndex >> 2); case 0x01: TypeNode t = this.GetTypeFromRef(codedIndex >> 2); return t != CoreSystemTypes.ValueType && t != CoreSystemTypes.Enum && t is Class; case 0x02: return this.TypeSpecIsClass(codedIndex >> 2); } throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef); } private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex) { if (codedIndex == 0) return null; switch (codedIndex & 0x3) { case 0x00: return this.GetTypeFromDef(codedIndex >> 2); case 0x01: return this.GetTypeFromRef(codedIndex >> 2); case 0x02: return this.GetTypeFromSpec(codedIndex >> 2); } throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef); } private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex, bool expectStruct) { if (codedIndex == 0) return null; switch (codedIndex & 0x3) { case 0x00: return this.GetTypeFromDef(codedIndex >> 2); case 0x01: return this.GetTypeFromRef(codedIndex >> 2, expectStruct); case 0x02: return this.GetTypeFromSpec(codedIndex >> 2); } throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef); } #if ExtendedRuntime private Interface GetInterfaceIfNotGenericInstance(int codedIndex){ if (codedIndex == 0) return null; switch(codedIndex & 0x3){ case 0x00 : return this.GetTypeFromDef(codedIndex >> 2) as Interface; case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, false) as Interface; } return null; } #endif private TypeNode GetTypeIfNotGenericInstance(int codedIndex) { if (codedIndex == 0) return null; switch (codedIndex & 0x3) { case 0x00: return this.GetTypeFromDef(codedIndex >> 2); case 0x01: return this.GetTypeFromRef(codedIndex >> 2, false); } return null; } internal AssemblyNode/*!*/ GetAssemblyFromReference(AssemblyReference/*!*/ assemblyReference) { lock (this) { if (SystemAssemblyLocation.ParsedAssembly != null && (assemblyReference.Name == "mscorlib" || assemblyReference.Name == "basetypes" || assemblyReference.Name == "ioconfig" || assemblyReference.Name == "singularity.v1")) return SystemAssemblyLocation.ParsedAssembly; if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemblyReference.Name) return CoreSystemTypes.SystemAssembly; string strongName = null; object cachedValue = null; if (assemblyReference.PublicKeyOrToken == null || assemblyReference.PublicKeyOrToken.Length == 0) { if (assemblyReference.Location != null) cachedValue = this.localAssemblyCache[assemblyReference.Location]; if (cachedValue == null) { cachedValue = this.localAssemblyCache[assemblyReference.Name]; if (cachedValue != null && assemblyReference.Location != null) this.localAssemblyCache[assemblyReference.Location] = cachedValue; } } else { strongName = assemblyReference.StrongName; if (this.useStaticCache) { //See if reference is to an assembly that lives in the GAC. if (assemblyReference.Location != null) cachedValue = Reader.StaticAssemblyCache[assemblyReference.Location]; if (cachedValue == null) cachedValue = Reader.StaticAssemblyCache[strongName]; } if (cachedValue == null) cachedValue = this.localAssemblyCache[strongName]; } if (cachedValue == null) { //See if assembly is a platform assembly (and apply unification) AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey]; if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)) { AssemblyNode platformAssembly = aRef.assembly; if (platformAssembly == null) { Debug.Assert(aRef.Location != null); platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); } if (platformAssembly != null) { if (strongName == null) strongName = assemblyReference.Name; lock (Reader.StaticAssemblyCache) { if (aRef.Location != null) Reader.StaticAssemblyCache[aRef.Location] = platformAssembly; Reader.StaticAssemblyCache[strongName] = platformAssembly; } return aRef.assembly = platformAssembly; } } } AssemblyNode assembly = cachedValue as AssemblyNode; if (assembly != null) goto done; //No cached assembly and no cached reader for this assembly. Look for a resolver. if (this.module != null) { assembly = this.module.Resolve(assemblyReference); if (assembly != null) { if (strongName == null) { this.localAssemblyCache[assembly.Name] = assembly; if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly; } else { if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name) return CoreSystemTypes.SystemAssembly; lock (Reader.StaticAssemblyCache) { if (this.useStaticCache) { if (assembly.Location != null) Reader.StaticAssemblyCache[assembly.Location] = assembly; Reader.StaticAssemblyCache[strongName] = assembly; } else { this.localAssemblyCache[strongName] = assembly; if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly; } } } goto done; } } //Look for an assembly with the given name in the same directory as the referencing module if (this.directory != null) { string fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name + ".dll"); if (System.IO.File.Exists(fileName)) { assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { if (strongName == null) goto cacheIt; //found something //return assembly only if it matches the strong name of the reference if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt; } } fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name + ".exe"); if (System.IO.File.Exists(fileName)) { assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { if (strongName == null) goto cacheIt; //found something //return assembly only if it matches the strong name of the reference if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt; } } fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name + ".ill"); if (System.IO.File.Exists(fileName)) { assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { if (strongName == null) goto cacheIt; //found something //return assembly only if it matches the strong name of the reference if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt; } } } //Look for an assembly in the same directory as the application using Reader. { string fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name + ".dll"); if (System.IO.File.Exists(fileName)) { assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { if (strongName == null) goto cacheIt; //found something //return assembly only if it matches the strong name of the reference if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt; } } fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name + ".exe"); if (System.IO.File.Exists(fileName)) { assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { if (strongName == null) goto cacheIt; //found something //return assembly only if it matches the strong name of the reference if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt; } } } assembly = null; //Probe the GAC #if FxCop if(probeGAC){ #endif string gacLocation = null; if (strongName != null) { #if !ROTOR //Look for the assembly in the system's Global Assembly Cache gacLocation = GlobalAssemblyCache.GetLocation(assemblyReference); if (gacLocation != null && gacLocation.Length == 0) gacLocation = null; #else //TODO: look in the ROTOR GAC #endif if (gacLocation != null) { assembly = AssemblyNode.GetAssembly(gacLocation, this.useStaticCache ? Reader.StaticAssemblyCache : this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache); if (assembly != null) { lock (Reader.StaticAssemblyCache) { if (this.useStaticCache) { Reader.StaticAssemblyCache[gacLocation] = assembly; Reader.StaticAssemblyCache[strongName] = assembly; } else { this.localAssemblyCache[gacLocation] = assembly; this.localAssemblyCache[strongName] = assembly; } } } } } #if FxCop } #endif goto done; cacheIt: if (strongName == null) { this.localAssemblyCache[assembly.Name] = assembly; if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly; } else { this.localAssemblyCache[strongName] = assembly; if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly; } done: if (assembly != null) assembly.InitializeAssemblyReferenceResolution(this.module); if (assembly == null) { if (this.module != null) { assembly = this.module.ResolveAfterProbingFailed(assemblyReference); if (assembly != null) goto cacheIt; HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.AssemblyReferenceNotResolved, assemblyReference.StrongName)); } assembly = new AssemblyNode(); assembly.Culture = assemblyReference.Culture; assembly.Name = assemblyReference.Name; assembly.PublicKeyOrToken = assemblyReference.PublicKeyOrToken; assembly.Version = assemblyReference.Version; assembly.Location = "unknown:location"; goto cacheIt; } return assembly; } } private static void GetAndCheckSignatureToken(int expectedToken, MemoryCursor/*!*/ sigReader) { int tok = sigReader.ReadCompressedInt(); if (tok != expectedToken) throw new InvalidMetadataException(ExceptionStrings.MalformedSignature); } private Method GetConstructorDefOrRef(int codedIndex, out TypeNodeList varArgTypes) { varArgTypes = null; switch (codedIndex & 0x7) { case 0x02: return this.GetMethodFromDef(codedIndex >> 3); case 0x03: return (Method)this.GetMemberFromRef(codedIndex >> 3, out varArgTypes); } throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken); } private void GetResources(Module/*!*/ module) { ManifestResourceRow[] manifestResourceTable = this.tables.ManifestResourceTable; int n = manifestResourceTable.Length; ResourceList resources = new ResourceList(n); for (int i = 0; i < n; i++) { ManifestResourceRow mrr = manifestResourceTable[i]; Resource r = new Resource(); r.Name = this.tables.GetString(mrr.Name); r.IsPublic = (mrr.Flags & 7) == 1; int impl = mrr.Implementation; if (impl != 0) { switch (impl & 0x3) { case 0x0: string modName = this.tables.GetString(this.tables.FileTable[(impl >> 2) - 1].Name); if ((this.tables.FileTable[(impl >> 2) - 1].Flags & (int)FileFlags.ContainsNoMetaData) != 0) { r.DefiningModule = new Module(); r.DefiningModule.Directory = module.Directory; r.DefiningModule.Location = Path.Combine(module.Directory, modName); r.DefiningModule.Name = modName; r.DefiningModule.Kind = ModuleKindFlags.ManifestResourceFile; r.DefiningModule.ContainingAssembly = module.ContainingAssembly; r.DefiningModule.HashValue = this.tables.GetBlob(this.tables.FileTable[(impl >> 2) - 1].HashValue); } else { string modLocation = modName; r.DefiningModule = GetNestedModule(module, modName, ref modLocation); } break; case 0x1: r.DefiningModule = this.tables.AssemblyRefTable[(impl >> 2) - 1].AssemblyReference.Assembly; break; } } else { r.DefiningModule = module; r.Data = this.tables.GetResourceData(mrr.Offset); } resources.Add(r); } module.Resources = resources; module.Win32Resources = this.tables.ReadWin32Resources(); } private SecurityAttribute GetSecurityAttribute(int i) { DeclSecurityRow dsr = this.tables.DeclSecurityTable[i]; SecurityAttribute attr = new SecurityAttribute(); attr.Action = (System.Security.Permissions.SecurityAction)dsr.Action; if (this.module.MetadataFormatMajorVersion > 1 || this.module.MetadataFormatMinorVersion > 0) { attr.PermissionAttributes = this.GetPermissionAttributes(dsr.PermissionSet, attr.Action); if (attr.PermissionAttributes != null) return attr; } attr.SerializedPermissions = (string)this.tables.GetBlobString(dsr.PermissionSet); return attr; } private AttributeList GetPermissionAttributes(int blobIndex, System.Security.Permissions.SecurityAction action) { AttributeList result = new AttributeList(); int blobLength; MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength); if (blobLength == 0) return null; byte header = sigReader.ReadByte(); if (header != (byte)'*') { if (header == (byte)'<') return null; if (header == (byte)'.') return this.GetPermissionAttributes2(blobIndex, action); HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob); return null; } sigReader.ReadInt32(); //Skip over the token for the attribute target sigReader.ReadInt32(); //Skip over the security action int numAttrs = sigReader.ReadInt32(); for (int i = 0; i < numAttrs; i++) result.Add(this.GetPermissionAttribute(sigReader)); return result; } private AttributeNode GetPermissionAttribute(MemoryCursor/*!*/ sigReader) { sigReader.ReadInt32(); //Skip over index int typeNameLength = sigReader.ReadInt32(); sigReader.ReadUTF8(typeNameLength); //Skip over type name int constructorToken = sigReader.ReadInt32(); sigReader.ReadInt32(); //Skip over attribute type token sigReader.ReadInt32(); //Skip over assembly ref token int caBlobLength = sigReader.ReadInt32(); sigReader.ReadInt32(); //Skip over the number of parameters in the CA blob TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes Method cons = this.GetConstructorDefOrRef(constructorToken, out varArgTypes); if (cons == null) cons = new Method(); return this.GetCustomAttribute(cons, sigReader, caBlobLength); } private AttributeList GetPermissionAttributes2(int blobIndex, System.Security.Permissions.SecurityAction action) { AttributeList result = new AttributeList(); int blobLength; MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength); if (blobLength == 0) return null; byte header = sigReader.ReadByte(); if (header != (byte)'.') { HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob); return null; } int numAttrs = sigReader.ReadCompressedInt(); for (int i = 0; i < numAttrs; i++) result.Add(this.GetPermissionAttribute2(sigReader, action)); return result; } private AttributeNode GetPermissionAttribute2(MemoryCursor/*!*/ sigReader, System.Security.Permissions.SecurityAction action) { int typeNameLength = sigReader.ReadCompressedInt(); string serializedTypeName = sigReader.ReadUTF8(typeNameLength); TypeNode attrType = null; try { attrType = this.GetTypeFromSerializedName(serializedTypeName); } catch (InvalidMetadataException) { } if (attrType == null) { HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveType, serializedTypeName)); return null; } InstanceInitializer cons = attrType.GetConstructor(CoreSystemTypes.SecurityAction); if (cons == null) { HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.SecurityAttributeTypeDoesNotHaveADefaultConstructor, serializedTypeName)); return null; } sigReader.ReadCompressedInt(); //caBlobLength int numProps = sigReader.ReadCompressedInt(); //Skip over the number of properties in the CA blob ExpressionList arguments = new ExpressionList(numProps + 1); arguments.Add(new Literal(action, CoreSystemTypes.SecurityAction)); this.GetCustomAttributeNamedArguments(arguments, (ushort)numProps, sigReader); return new AttributeNode(new MemberBinding(null, cons), arguments); } private static void HandleError(Module mod, string errorMessage) { #if !FxCop if (mod != null) { if (mod.MetadataImportErrors == null) mod.MetadataImportErrors = new ArrayList(); mod.MetadataImportErrors.Add(new InvalidMetadataException(errorMessage)); } #else throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.ModuleError, mod.Name, errorMessage)); #endif } private AttributeNode GetCustomAttribute(int i) { CustomAttributeRow ca = this.tables.CustomAttributeTable[i]; TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes Method cons = this.GetConstructorDefOrRef(ca.Constructor, out varArgTypes); if (cons == null) cons = new Method(); int blobLength; MemoryCursor sigReader = this.tables.GetBlobCursor(ca.Value, out blobLength); return this.GetCustomAttribute(cons, sigReader, blobLength); } private AttributeNode GetCustomAttribute(Method/*!*/ cons, MemoryCursor/*!*/ sigReader, int blobLength) { AttributeNode attr = new AttributeNode(); attr.Constructor = new MemberBinding(null, cons); int n = cons.Parameters == null ? 0 : cons.Parameters.Count; ExpressionList arguments = attr.Expressions = new ExpressionList(n); int posAtBlobStart = sigReader.Position; sigReader.ReadUInt16(); //Prolog for (int j = 0; j < n; j++) { TypeNode t = TypeNode.StripModifiers(cons.Parameters[j].Type); if (t == null) continue; TypeNode/*!*/ pt = t; object val = null; try { val = this.GetCustomAttributeLiteralValue(sigReader, ref pt); #if !FxCop } catch (Exception e) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } #else }finally{} #endif Literal lit = val as Literal; if (lit == null) lit = new Literal(val, pt); arguments.Add(lit); } if (sigReader.Position + 1 < posAtBlobStart + blobLength) { ushort numNamed = sigReader.ReadUInt16(); this.GetCustomAttributeNamedArguments(arguments, numNamed, sigReader); } return attr; } private void GetCustomAttributeNamedArguments(ExpressionList/*!*/ arguments, ushort numNamed, MemoryCursor/*!*/ sigReader) { for (int j = 0; j < numNamed; j++) { int nameTag = sigReader.ReadByte(); bool mustBox = sigReader.Byte(0) == (byte)ElementType.BoxedEnum; TypeNode/*!*/ vType = this.ParseTypeSignature(sigReader); Identifier id = sigReader.ReadIdentifierFromSerString(); object val = this.GetCustomAttributeLiteralValue(sigReader, ref vType); Literal lit = val as Literal; if (lit == null) lit = new Literal(val, vType); NamedArgument narg = new NamedArgument(id, lit); narg.Type = vType; narg.IsCustomAttributeProperty = nameTag == 0x54; narg.ValueIsBoxed = mustBox; arguments.Add(narg); } } private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, TypeNode/*!*/ type) { TypeNode/*!*/ t = type; object result = this.GetCustomAttributeLiteralValue(sigReader, ref t); EnumNode enumType = t as EnumNode; if (enumType != null && type == CoreSystemTypes.Object) result = new Literal(result, enumType); return result; } private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, ref TypeNode/*!*/ type) { if (type == null) return sigReader.ReadInt32(); switch (type.typeCode) { case ElementType.Boolean: return sigReader.ReadBoolean(); case ElementType.Char: return sigReader.ReadChar(); case ElementType.Double: return sigReader.ReadDouble(); case ElementType.Single: return sigReader.ReadSingle(); case ElementType.Int16: return sigReader.ReadInt16(); case ElementType.Int32: return sigReader.ReadInt32(); case ElementType.Int64: return sigReader.ReadInt64(); case ElementType.Int8: return sigReader.ReadSByte(); case ElementType.UInt16: return sigReader.ReadUInt16(); case ElementType.UInt32: return sigReader.ReadUInt32(); case ElementType.UInt64: return sigReader.ReadUInt64(); case ElementType.UInt8: return sigReader.ReadByte(); case ElementType.String: return ReadSerString(sigReader); case ElementType.ValueType: EnumNode etype = GetCustomAttributeEnumNode(ref type); return this.GetCustomAttributeLiteralValue(sigReader, etype.UnderlyingType); case ElementType.Class: return this.GetTypeFromSerializedName(ReadSerString(sigReader)); case ElementType.SzArray: int numElems = sigReader.ReadInt32(); TypeNode elemType = ((ArrayType)type).ElementType; return this.GetCustomAttributeLiteralArray(sigReader, numElems, elemType); case ElementType.Object: { type = this.ParseTypeSignature(sigReader); return this.GetCustomAttributeLiteralValue(sigReader, ref type); } } throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute); } private static EnumNode/*!*/ GetCustomAttributeEnumNode(ref TypeNode/*!*/ type) { EnumNode etype = ((TypeNode)type) as EnumNode; if (etype == null || etype.UnderlyingType == null) { //Happens when type is declared in a assembly that has not been resolved. In that case only the type name //and the fact that it is a value type is known. There is no completely safe recovery from it, but at this point we //can fake up an enum with Int32 as underlying type. This works in most situations. etype = new EnumNode(); etype.Name = type.Name; etype.Namespace = type.Namespace; etype.DeclaringModule = type.DeclaringModule; etype.UnderlyingType = CoreSystemTypes.Int32; type = etype; } return etype; } private Array GetCustomAttributeLiteralArray(MemoryCursor/*!*/ sigReader, int numElems, TypeNode/*!*/ elemType) { Array array = this.ConstructCustomAttributeLiteralArray(numElems, elemType); for (int i = 0; i < numElems; i++) { object elem = this.GetCustomAttributeLiteralValue(sigReader, elemType); array.SetValue(elem, i); } return array; } private Array ConstructCustomAttributeLiteralArray(int numElems, TypeNode/*!*/ elemType) { if (numElems == -1) return null; if (numElems < 0) throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute); switch (elemType.typeCode) { case ElementType.Boolean: return new Boolean[numElems]; case ElementType.Char: return new Char[numElems]; case ElementType.Double: return new Double[numElems]; case ElementType.Single: return new Single[numElems]; case ElementType.Int16: return new Int16[numElems]; case ElementType.Int32: return new Int32[numElems]; case ElementType.Int64: return new Int64[numElems]; case ElementType.Int8: return new SByte[numElems]; case ElementType.UInt16: return new UInt16[numElems]; case ElementType.UInt32: return new UInt32[numElems]; case ElementType.UInt64: return new UInt64[numElems]; case ElementType.UInt8: return new Byte[numElems]; case ElementType.String: return new String[numElems]; // Only enum value types are legal in attribute instances as stated in section 17.1.3 of the C# 1.0 spec case ElementType.ValueType: TypeNode/*!*/ elType = elemType; EnumNode eType = GetCustomAttributeEnumNode(ref elType); return this.ConstructCustomAttributeLiteralArray(numElems, eType.UnderlyingType); // This needs to be a TypeNode since GetCustomAttributeLiteralValue will return a Struct if the Type is a value type case ElementType.Class: return new TypeNode[numElems]; // REVIEW: Is this the right exception? Is this the right exception string? // Multi-dimensional arrays are not legal in attribute instances according section 17.1.3 of the C# 1.0 spec case ElementType.SzArray: throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken); case ElementType.Object: return new Object[numElems]; } throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute); } //TODO: rewrite this entire mess using a proper grammar based parser private TypeNode/*!*/ GetTypeFromSerializedName(string serializedName) { if (serializedName == null) return null; string assemblyName = null; string typeName = serializedName; int firstComma = FindFirstCommaOutsideBrackets(serializedName); if (firstComma > 0) { int i = 1; while (firstComma + i < serializedName.Length && serializedName[firstComma + i] == ' ') i++; assemblyName = serializedName.Substring(firstComma + i); typeName = serializedName.Substring(0, firstComma); } return this.GetTypeFromSerializedName(typeName, assemblyName); } private static int FindFirstCommaOutsideBrackets(string/*!*/ serializedName) { int numBrackets = 0; int numAngles = 0; for (int i = 0, n = serializedName == null ? 0 : serializedName.Length; i < n; i++) { char ch = serializedName[i]; if (ch == '[') numBrackets++; else if (ch == ']') { if (--numBrackets < 0) return -1; } else if (ch == '<') numAngles++; else if (ch == '>') { if (--numAngles < 0) return -1; } else if (ch == ',' && numBrackets == 0 && numAngles == 0) return i; } return -1; } private TypeNode/*!*/ GetTypeFromSerializedName(string/*!*/ typeName, string assemblyName) { string/*!*/ nspace, name; int i; ParseTypeName(typeName, out nspace, out name, out i); Module tMod = null; TypeNode t = this.LookupType(nspace, name, assemblyName, out tMod); if (t == null) { if (i < typeName.Length && typeName[i] == '!') { int codedIndex = 0; if (PlatformHelpers.TryParseInt32(typeName.Substring(0, i), out codedIndex)) { t = this.DecodeAndGetTypeDefOrRefOrSpec(codedIndex); if (t != null) return t; } } t = this.GetDummyTypeNode(Identifier.For(nspace), Identifier.For(name), tMod, null, false); } if (i >= typeName.Length) return t; char ch = typeName[i]; if (ch == '+') return this.GetTypeFromSerializedName(typeName.Substring(i + 1), t); if (ch == '&') return t.GetReferenceType(); if (ch == '*') return t.GetPointerType(); if (ch == '[') return this.ParseArrayOrGenericType(typeName.Substring(i + 1, typeName.Length - 1 - i), t); throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); } private TypeNode/*!*/ GetTypeFromSerializedName(string/*!*/ typeName, TypeNode/*!*/ nestingType) { string/*!*/ name; int i = 0; ParseSimpleTypeName(typeName, out name, ref i); TypeNode t = nestingType.GetNestedType(Identifier.For(name)); if (t == null) t = this.GetDummyTypeNode(Identifier.Empty, Identifier.For(name), nestingType.DeclaringModule, nestingType, false); if (i >= typeName.Length) return t; char ch = typeName[i]; if (ch == '+') return this.GetTypeFromSerializedName(typeName.Substring(i + 1), t); if (ch == '&') return t.GetReferenceType(); if (ch == '*') return t.GetPointerType(); if (ch == '[') return this.ParseArrayOrGenericType(typeName.Substring(i + 1, typeName.Length - 1 - i), t); throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); } private TypeNode/*!*/ ParseArrayOrGenericType(string typeName, TypeNode/*!*/ rootType) { if (typeName == null || rootType == null) { Debug.Assert(false); return rootType; } //Get here after "rootType[" has been parsed. What follows is either an array type specifier or some generic type arguments. if (typeName.Length == 0) throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); //Something ought to follow the [ if (typeName[0] == ']') { //Single dimensional array with zero lower bound if (typeName.Length == 1) return rootType.GetArrayType(1); if (typeName[1] == '[' && typeName.Length > 2) return this.ParseArrayOrGenericType(typeName.Substring(2), rootType.GetArrayType(1)); throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); } if (typeName[0] == '*') { //Single dimensional array with unknown lower bound if (typeName.Length > 1 && typeName[1] == ']') { if (typeName.Length == 2) return rootType.GetArrayType(1, true); if (typeName[2] == '[' && typeName.Length > 3) return this.ParseArrayOrGenericType(typeName.Substring(3), rootType.GetArrayType(1, true)); } throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); } if (typeName[0] == ',') { //Muti dimensional array int rank = 1; while (rank < typeName.Length && typeName[rank] == ',') rank++; if (rank < typeName.Length && typeName[rank] == ']') { if (typeName.Length == rank + 1) return rootType.GetArrayType(rank + 1); if (typeName[rank + 1] == '[' && typeName.Length > rank + 2) return this.ParseArrayOrGenericType(typeName.Substring(rank + 2), rootType.GetArrayType(rank)); } throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); } //Generic type instance int offset = 0; if (typeName[0] == '[') offset = 1; //Assembly qualified type name forming part of a generic parameter list TypeNodeList arguments = new TypeNodeList(); int commaPos = FindFirstCommaOutsideBrackets(typeName); while (commaPos > 1) { arguments.Add(this.GetTypeFromSerializedName(typeName.Substring(offset, commaPos - offset))); typeName = typeName.Substring(commaPos + 1); offset = typeName[0] == '[' ? 1 : 0; commaPos = FindFirstCommaOutsideBrackets(typeName); } //Find the position of the first unbalanced ]. int lastCharPos = offset; for (int leftBracketCount = 0; lastCharPos < typeName.Length; lastCharPos++) { char ch = typeName[lastCharPos]; if (ch == '[') leftBracketCount++; else if (ch == ']') { leftBracketCount--; if (leftBracketCount < 0) break; } } arguments.Add(this.GetTypeFromSerializedName(typeName.Substring(offset, lastCharPos - offset))); TypeNode retVal = rootType.GetGenericTemplateInstance(this.module, arguments); if (lastCharPos + 1 < typeName.Length && typeName[lastCharPos + 1] == ']') lastCharPos++; if (lastCharPos + 1 < typeName.Length) { //The generic type is complete, but there is yet more to the type char ch = typeName[lastCharPos + 1]; if (ch == '+') retVal = this.GetTypeFromSerializedName(typeName.Substring(lastCharPos + 2), retVal); if (ch == '&') retVal = retVal.GetReferenceType(); if (ch == '*') retVal = retVal.GetPointerType(); if (ch == '[') retVal = this.ParseArrayOrGenericType(typeName.Substring(lastCharPos + 2, typeName.Length - 1 - lastCharPos - 1), retVal); } return retVal; } private static void ParseSimpleTypeName(string/*!*/ source, out string/*!*/ name, ref int i) { int n = source.Length; int start = i; for (; i < n; i++) { char ch = source[i]; if (ch == '\\') { i++; continue; } if (ch == '.' || ch == '+' || ch == '&' || ch == '*' || ch == '[' || ch == '!') break; if (ch == '<') { int unmatched = 1; while (unmatched > 0 && ++i < n) { ch = source[i]; if (ch == '\\') i++; else if (ch == '<') unmatched++; else if (ch == '>') unmatched--; } } } if (i < n) name = source.Substring(start, i - start); else name = source.Substring(start); } private static void ParseTypeName(string/*!*/ source, out string/*!*/ nspace, out string/*!*/ name, out int i) { i = 0; int n = source.Length; nspace = string.Empty; while (true) { int start = i; ParseSimpleTypeName(source, out name, ref i); if (i < n && source[i] == '.') { i++; continue; } if (start != 0) nspace = source.Substring(0, start - 1); return; } } private TypeNode LookupType(string/*!*/ nameSpace, string/*!*/ name, string assemblyName, out Module module) { Identifier namespaceId = Identifier.For(nameSpace); Identifier nameId = Identifier.For(name); module = this.module; //^ assume module != null; if (assemblyName == null) { TypeNode t = module.GetType(namespaceId, nameId); if (t != null) return t; module = CoreSystemTypes.SystemAssembly; return CoreSystemTypes.SystemAssembly.GetType(namespaceId, nameId); } //See if the type is in one of the assemblies explcitly referenced by the current module AssemblyReferenceList arefs = module.AssemblyReferences; for (int i = 0, n = arefs == null ? 0 : arefs.Count; i < n; i++) { AssemblyReference aref = arefs[i]; if (aref != null && aref.StrongName == assemblyName && aref.Assembly != null) { module = aref.Assembly; return aref.Assembly.GetType(namespaceId, nameId); } } //Construct an assembly reference and probe for it AssemblyReference aRef = new AssemblyReference(assemblyName); AssemblyNode referringAssembly = this.module as AssemblyNode; if (referringAssembly != null && (referringAssembly.Flags & AssemblyFlags.Retargetable) != 0) aRef.Flags |= AssemblyFlags.Retargetable; AssemblyNode aNode = this.GetAssemblyFromReference(aRef); if (aNode != null) { module = aNode; TypeNode result = aNode.GetType(namespaceId, nameId); return result; } return null; } private void GetCustomAttributesFor(Module/*!*/ module) { try { if (this.tables.entryPointToken != 0) module.EntryPoint = (Method)this.GetMemberFromToken(this.tables.entryPointToken); else module.EntryPoint = Module.NoSuchMethod; if (module.NodeType == NodeType.Module) { module.Attributes = this.GetCustomAttributesFor((1 << 5) | 7); return; } AssemblyNode assembly = (AssemblyNode)module; assembly.SecurityAttributes = this.GetSecurityAttributesFor((1 << 2) | 2); assembly.Attributes = this.GetCustomAttributesFor((1 << 5) | 14); assembly.ModuleAttributes = this.GetCustomAttributesFor((1 << 5) | 7); #if !FxCop } catch (Exception e) { if (this.module == null) return; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); module.Attributes = new AttributeList(0); } #else }finally{} #endif } private AttributeList/*!*/ GetCustomAttributesFor(int parentIndex) { CustomAttributeRow[] customAttributes = this.tables.CustomAttributeTable; AttributeList attributes = new AttributeList(); try { int i = 0, n = customAttributes.Length, j = n - 1; if (n == 0) return attributes; bool sorted = (this.sortedTablesMask >> (int)TableIndices.CustomAttribute) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (customAttributes[k].Parent < parentIndex) i = k + 1; else j = k; } while (i > 0 && customAttributes[i - 1].Parent == parentIndex) i--; } for (; i < n; i++) if (customAttributes[i].Parent == parentIndex) attributes.Add(this.GetCustomAttribute(i)); else if (sorted) break; #if !FxCop } catch (Exception e) { if (this.module == null) return attributes; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } #else }finally{} #endif return attributes; } private SecurityAttributeList GetSecurityAttributesFor(int parentIndex) { DeclSecurityRow[] securityAttributes = this.tables.DeclSecurityTable; SecurityAttributeList attributes = new SecurityAttributeList(); try { int i = 0, n = securityAttributes.Length, j = n - 1; if (n == 0) return attributes; bool sorted = (this.sortedTablesMask >> (int)TableIndices.DeclSecurity) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (securityAttributes[k].Parent < parentIndex) i = k + 1; else j = k; } while (i > 0 && securityAttributes[i - 1].Parent == parentIndex) i--; } for (; i < n; i++) if (securityAttributes[i].Parent == parentIndex) attributes.Add(this.GetSecurityAttribute(i)); else if (sorted) break; #if !FxCop } catch (Exception e) { if (this.module == null) return attributes; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } #else }finally{} #endif return attributes; } private void GetTypeParameterConstraints(int parentIndex, TypeNodeList parameters) { if (parameters == null) return; GenericParamRow[] genericParameters = this.tables.GenericParamTable; int i = 0, n = genericParameters.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (genericParameters[k].Owner < parentIndex) i = k + 1; else j = k; } while (i > 0 && genericParameters[i - 1].Owner == parentIndex) i--; } for (int k = 0; i < n && k < parameters.Count; i++, k++) if (genericParameters[i].Owner == parentIndex) { TypeNode gp = parameters[k]; this.GetGenericParameterConstraints(i, ref gp); parameters[k] = gp; } else if (sorted) break; } private TypeNodeList GetTypeParametersFor(int parentIndex, Member parent) { GenericParamRow[] genericParameters = this.tables.GenericParamTable; TypeNodeList types = new TypeNodeList(); int i = 0, n = genericParameters.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (genericParameters[k].Owner < parentIndex) i = k + 1; else j = k; } while (i > 0 && genericParameters[i - 1].Owner == parentIndex) i--; } for (int index = 0; i < n; i++, index++) if (genericParameters[i].Owner == parentIndex) types.Add(this.GetGenericParameter(i, index, parent)); else if (sorted) break; if (types.Count == 0) return null; return types; } private TypeNode GetGenericParameter(int index, int parameterListIndex, Member parent) { GenericParamRow[] genericParameters = this.tables.GenericParamTable; GenericParamRow gpr = genericParameters[index++]; string name = this.tables.GetString(gpr.Name); GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable; bool isClass = false; int i = 0, n = genericParameterConstraints.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (genericParameterConstraints[k].Param < index) i = k + 1; else j = k; } while (i > 0 && genericParameterConstraints[i - 1].Param == index) i--; } for (; i < n && !isClass; i++) { if (genericParameterConstraints[i].Param == index) { isClass = this.TypeDefOrRefOrSpecIsClass(genericParameterConstraints[i].Constraint); } else if (sorted) break; } if (isClass) { ClassParameter cp = parent is Method ? new MethodClassParameter() : new ClassParameter(); cp.DeclaringMember = parent; cp.ParameterListIndex = parameterListIndex; cp.Name = Identifier.For(name); cp.DeclaringModule = this.module; cp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags; return cp; } TypeParameter tp = parent is Method ? new MethodTypeParameter() : new TypeParameter(); tp.DeclaringMember = parent; tp.ParameterListIndex = parameterListIndex; tp.Name = Identifier.For(name); tp.DeclaringModule = this.module; tp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags; return tp; } private void GetGenericParameterConstraints(int index, ref TypeNode/*!*/ parameter) { Debug.Assert(parameter != null); index++; GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable; TypeNodeList constraints = new TypeNodeList(); Class baseClass = null; InterfaceList interfaces = new InterfaceList(); int i = 0, n = genericParameterConstraints.Length, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (genericParameterConstraints[k].Param < index) i = k + 1; else j = k; } while (i > 0 && genericParameterConstraints[i - 1].Param == index) i--; } for (; i < n; i++) { if (genericParameterConstraints[i].Param == index) { TypeNode t = this.DecodeAndGetTypeDefOrRefOrSpec(genericParameterConstraints[i].Constraint); Class c = t as Class; if (c != null) baseClass = c; else if (t is Interface) interfaces.Add((Interface)t); constraints.Add(t); } else if (sorted) break; } ClassParameter cp = parameter as ClassParameter; if (cp == null && baseClass != null) { cp = ((ITypeParameter)parameter).DeclaringMember is Method ? new MethodClassParameter() : new ClassParameter(); cp.Name = parameter.Name; cp.DeclaringMember = ((ITypeParameter)parameter).DeclaringMember; cp.ParameterListIndex = ((ITypeParameter)parameter).ParameterListIndex; cp.DeclaringModule = this.module; cp.TypeParameterFlags = ((ITypeParameter)parameter).TypeParameterFlags; parameter = cp; } if (cp != null) cp.structuralElementTypes = constraints; else ((TypeParameter)parameter).structuralElementTypes = constraints; if (baseClass != null && cp != null) cp.BaseClass = baseClass; parameter.Interfaces = interfaces; } internal static Block/*!*/ GetOrCreateBlock(TrivialHashtable/*!*/ blockMap, int address) { Block block = (Block)blockMap[address + 1]; if (block == null) { blockMap[address + 1] = block = new Block(new StatementList()); #if !FxCop block.SourceContext.StartPos = address; #else block.ILOffset = address; #endif } return block; } internal Field GetFieldFromDef(int i) { return this.GetFieldFromDef(i, null); } internal Field GetFieldFromDef(int i, TypeNode declaringType) { FieldRow[] fieldDefs = this.tables.FieldTable; FieldRow fld = fieldDefs[i - 1]; if (fld.Field != null) return fld.Field; Field field = new Field(); fieldDefs[i - 1].Field = field; field.Attributes = this.GetCustomAttributesFor((i << 5) | 1); field.Flags = (FieldFlags)fld.Flags; field.Name = tables.GetIdentifier(fld.Name); if ((field.Flags & FieldFlags.RTSpecialName) != 0 && field.Name.UniqueIdKey == StandardIds._Deleted.UniqueIdKey) return null; tables.GetSignatureLength(fld.Signature); //sigLength MemoryCursor sigReader = this.tables.GetNewCursor(); GetAndCheckSignatureToken(6, sigReader); field.Type = this.ParseTypeSignature(sigReader); RequiredModifier reqMod = field.Type as RequiredModifier; if (reqMod != null && reqMod.Modifier == CoreSystemTypes.IsVolatile) { field.IsVolatile = true; field.Type = reqMod.ModifiedType; } if ((field.Flags & FieldFlags.HasDefault) != 0) field.DefaultValue = this.GetLiteral(i << 2, field.Type); if ((field.Flags & FieldFlags.HasFieldMarshal) != 0) field.MarshallingInformation = this.GetMarshallingInformation((i << 1) | 0); if ((field.Flags & FieldFlags.HasFieldRVA) != 0) field.InitialData = this.GetInitialData(i, field.Type, out field.section); if (declaringType == null) { TypeDefRow[] typeDefs = this.tables.TypeDefTable; int indx = i; FieldPtrRow[] fieldPtrs = this.tables.FieldPtrTable; int n = fieldPtrs.Length; for (int j = 0; j < n; j++) { if (fieldPtrs[j].Field == i) { indx = j + 1; break; } } n = typeDefs.Length; for (int j = n - 1; j >= 0; j--) { //TODO: binary search TypeDefRow tdr = typeDefs[j]; if (tdr.FieldList <= indx) { declaringType = this.GetTypeFromDef(j + 1); break; } } } field.DeclaringType = declaringType; if (declaringType != null && (declaringType.Flags & TypeFlags.ExplicitLayout) != 0) { FieldLayoutRow[] fieldLayouts = this.tables.FieldLayoutTable; int n = fieldLayouts.Length; for (int j = n - 1; j >= 0; j--) { //TODO: binary search FieldLayoutRow flr = fieldLayouts[j]; if (flr.Field == i) { field.Offset = flr.Offset; break; } } } return field; } private byte[] GetInitialData(int fieldIndex, TypeNode fieldType, out PESection targetSection) { targetSection = PESection.Text; FieldRvaRow[] fieldRvaTable = this.tables.FieldRvaTable; bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldRva) % 2 == 1; int i = 0, n = fieldRvaTable.Length, j = n - 1; if (n == 0) return null; if (sorted) { while (i < j) { int k = (i + j) / 2; if (fieldRvaTable[k].Field < fieldIndex) i = k + 1; else j = k; } } else for (; i < j; i++) if (fieldRvaTable[i].Field == fieldIndex) break; FieldRvaRow frr = fieldRvaTable[i]; if (frr.Field != fieldIndex) return null; Field fld = this.tables.FieldTable[fieldIndex - 1].Field; if (fld != null) fld.Offset = frr.RVA; fieldType = TypeNode.StripModifiers(fieldType); EnumNode enumType = fieldType as EnumNode; if (enumType != null) fieldType = TypeNode.StripModifiers(enumType.UnderlyingType); if (fieldType == null) { Debug.Fail(""); return null; } int size = fieldType.ClassSize; if (size <= 0) { switch (fieldType.typeCode) { case ElementType.Boolean: size = 1; break; case ElementType.Char: size = 2; break; case ElementType.Double: size = 8; break; case ElementType.Int16: size = 2; break; case ElementType.Int32: size = 4; break; case ElementType.Int64: size = 8; break; case ElementType.Int8: size = 1; break; case ElementType.Single: size = 4; break; case ElementType.UInt16: size = 2; break; case ElementType.UInt32: size = 4; break; case ElementType.UInt64: size = 8; break; case ElementType.UInt8: size = 1; break; default: if (fieldType is Pointer || fieldType is FunctionPointer) { size = 4; break; } //TODO: this seems wrong if (i < n - 1) size = fieldRvaTable[i + 1].RVA - frr.RVA; else if (targetSection != PESection.Text) size = this.tables.GetOffsetToEndOfSection(frr.RVA); break; } } if (size <= 0) return null; if (this.tables.NoOffsetFor(frr.RVA) || this.tables.NoOffsetFor(frr.RVA + size - 1)) return null; MemoryCursor c = this.tables.GetNewCursor(frr.RVA, out targetSection); byte[] result = new byte[size]; for (i = 0; i < size; i++) result[i] = c.ReadByte(); return result; } private Literal GetLiteral(int parentCodedIndex, TypeNode/*!*/ type) { ConstantRow[] constants = this.tables.ConstantTable; //TODO: do a binary search for (int i = 0, n = constants.Length; i < n; i++) { if (constants[i].Parent != parentCodedIndex) continue; object value = this.tables.GetValueFromBlob(constants[i].Type, constants[i].Value); TypeCode valTypeCode = System.Convert.GetTypeCode(value); TypeNode underlyingType = type; if (type is EnumNode) underlyingType = ((EnumNode)type).UnderlyingType; if (underlyingType.TypeCode != valTypeCode) type = CoreSystemTypes.Object; if (type == CoreSystemTypes.Object && value != null) { switch (valTypeCode) { case TypeCode.Boolean: type = CoreSystemTypes.Boolean; break; case TypeCode.Byte: type = CoreSystemTypes.UInt8; break; case TypeCode.Char: type = CoreSystemTypes.Char; break; case TypeCode.Double: type = CoreSystemTypes.Double; break; case TypeCode.Int16: type = CoreSystemTypes.Int16; break; case TypeCode.Int32: type = CoreSystemTypes.Int32; break; case TypeCode.Int64: type = CoreSystemTypes.Int64; break; case TypeCode.SByte: type = CoreSystemTypes.Int8; break; case TypeCode.Single: type = CoreSystemTypes.Single; break; case TypeCode.String: type = CoreSystemTypes.String; break; case TypeCode.UInt16: type = CoreSystemTypes.UInt16; break; case TypeCode.UInt32: type = CoreSystemTypes.UInt32; break; case TypeCode.UInt64: type = CoreSystemTypes.UInt64; break; case TypeCode.Empty: case TypeCode.Object: type = CoreSystemTypes.Type; break; } } return new Literal(value, type); } throw new InvalidMetadataException(ExceptionStrings.BadConstantParentIndex); } internal FunctionPointer GetCalliSignature(int ssigToken) { #if !FxCop StandAloneSigRow ssr = this.tables.StandAloneSigTable[(ssigToken & 0xFFFFFF) - 1]; #else int index = (ssigToken & 0xFFFFFF) - 1; if (index < 0 || index >= this.tables.StandAloneSigTable.Length) return null; StandAloneSigRow ssr = this.tables.StandAloneSigTable[index]; #endif MemoryCursor sigReader = this.tables.GetBlobCursor(ssr.Signature); return this.ParseFunctionPointer(sigReader); } internal void GetLocals(int localIndex, LocalList/*!*/ locals, Hashtable/*!*/ localSourceNames) { if (localIndex == 0) return; StandAloneSigRow ssr = this.tables.StandAloneSigTable[(localIndex & 0xFFFFFF) - 1]; this.tables.GetSignatureLength(ssr.Signature); MemoryCursor sigReader = this.tables.GetNewCursor(); if (sigReader.ReadByte() != 0x7) throw new InvalidMetadataException(ExceptionStrings.InvalidLocalSignature); int count = sigReader.ReadCompressedInt(); for (int i = 0; i < count; i++) { string lookupName = (string)localSourceNames[i]; #if !FxCop string name = lookupName == null ? "local" + i : lookupName; #else string name = lookupName == null ? "local$"+i : lookupName; #endif bool pinned = false; TypeNode locType = this.ParseTypeSignature(sigReader, ref pinned); Local loc = new Local(Identifier.For(name), locType); loc.Pinned = pinned; locals.Add(loc); } } #if !ROTOR && !UseSingularityPDB internal void GetLocalSourceNames(ISymUnmanagedScope/*!*/ scope, Hashtable/*!*/ localSourceNames) { uint numLocals = scope.GetLocalCount(); IntPtr[] localPtrs = new IntPtr[numLocals]; scope.GetLocals((uint)localPtrs.Length, out numLocals, localPtrs); char[] nameBuffer = new char[100]; uint nameLen; for (int i = 0; i < numLocals; i++) { ISymUnmanagedVariable local = (ISymUnmanagedVariable)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(localPtrs[i], typeof(ISymUnmanagedVariable)); if (local != null) { local.GetName((uint)nameBuffer.Length, out nameLen, nameBuffer); int localIndex = (int)local.GetAddressField1(); localSourceNames[localIndex] = new String(nameBuffer, 0, (int)nameLen - 1); System.Runtime.InteropServices.Marshal.ReleaseComObject(local); } System.Runtime.InteropServices.Marshal.Release(localPtrs[i]); } IntPtr[] subscopes = new IntPtr[100]; uint numScopes; scope.GetChildren((uint)subscopes.Length, out numScopes, subscopes); for (int i = 0; i < numScopes; i++) { ISymUnmanagedScope subscope = (ISymUnmanagedScope)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(subscopes[i], typeof(ISymUnmanagedScope)); if (subscope != null) { this.GetLocalSourceNames(subscope, localSourceNames); System.Runtime.InteropServices.Marshal.ReleaseComObject(subscope); } System.Runtime.InteropServices.Marshal.Release(subscopes[i]); //TODO: need to figure out how map these scope to blocks and set HasLocals on those blocks } } #endif private MarshallingInformation GetMarshallingInformation(int parentCodedIndex) { FieldMarshalRow[] mtypes = this.tables.FieldMarshalTable; bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldMarshal) % 2 == 1; int i = 0, n = mtypes.Length, j = n - 1; if (n == 0) return null; if (sorted) { while (i < j) { int k = (i + j) / 2; if (mtypes[k].Parent < parentCodedIndex) i = k + 1; else j = k; } while (i > 0 && mtypes[i - 1].Parent == parentCodedIndex) i--; } else for (; i < j; i++) if (mtypes[i].Parent == parentCodedIndex) break; FieldMarshalRow fmr = mtypes[i]; if (fmr.Parent != parentCodedIndex) return null; MarshallingInformation result = new MarshallingInformation(); int blobSize = 0; MemoryCursor c = this.tables.GetBlobCursor(fmr.NativeType, out blobSize); int initialPosition = c.Position; result.NativeType = (NativeType)c.ReadByte(); if (result.NativeType == NativeType.CustomMarshaler) { c.ReadUInt16(); //Skip over 0 result.Class = ReadSerString(c); result.Cookie = ReadSerString(c); } else if (blobSize > 1) { if (result.NativeType == NativeType.LPArray) { result.ElementType = (NativeType)c.ReadByte(); result.ParamIndex = -1; int bytesRead = 2; if (bytesRead < blobSize) { int pos = c.Position; result.ParamIndex = c.ReadCompressedInt(); bytesRead += c.Position - pos; if (bytesRead < blobSize) { pos = c.Position; result.ElementSize = c.ReadCompressedInt(); bytesRead += c.Position - pos; if (bytesRead < blobSize) result.NumberOfElements = c.ReadCompressedInt(); } } } else if (result.NativeType == NativeType.SafeArray) { result.ElementType = (NativeType)c.ReadByte(); //Actually a variant type. TODO: what about VT_VECTOR VT_ARRAY and VT_BYREF? if (c.Position < initialPosition + blobSize - 1) result.Class = ReadSerString(c); } else { result.Size = c.ReadCompressedInt(); if (result.NativeType == NativeType.ByValArray) { if (blobSize > 2) result.ElementType = (NativeType)c.ReadByte(); else result.ElementType = NativeType.NotSpecified; } } } return result; } private void GetMethodBody(Method/*!*/ method, object/*!*/ i, bool asInstructionList) { if (asInstructionList) { this.GetMethodInstructions(method, i); return; } TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters; this.currentMethodTypeParameters = method.templateParameters; TypeNode savedCurrentType = this.currentType; this.currentType = method.DeclaringType; try { MethodRow meth = this.tables.MethodTable[((int)i) - 1]; StatementList statements; if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed) { if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000 | (uint)(int)i); statements = this.ParseMethodBody(method, (int)i, meth.RVA); } else statements = new StatementList(0); method.Body = new Block(statements); #if FxCop if (statements.Count > 0) { SourceContext context = statements[0].SourceContext; method.SourceContext = context; method.Body.SourceContext = context; } #endif #if !MinimalReader method.Body.HasLocals = true; #endif #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } method.Body = new Block(new StatementList(0)); #endif } finally { this.currentMethodTypeParameters = savedCurrentMethodTypeParameters; this.currentType = savedCurrentType; } } private void GetMethodDebugSymbols(Method/*!*/ method, uint methodToken) //^ requires this.debugReader != null; { #if UseSingularityPDB PdbFunction pdbFunc = this.GetPdbFunction(methodToken); if (pdbFunc != null) method.RecordSequencePoints(pdbFunc); #elif !ROTOR ISymUnmanagedMethod methodInfo = null; try { try { this.debugReader.GetMethod(methodToken, ref methodInfo); method.RecordSequencePoints(methodInfo); } catch (COMException) { } catch (InvalidCastException) { } catch (System.Runtime.InteropServices.InvalidComObjectException) { } } finally { if (methodInfo != null) Marshal.ReleaseComObject(methodInfo); } #endif } #if UseSingularityPDB internal PdbFunction GetPdbFunction(uint methodToken) { PdbFunction[] pdbFunctions = this.pdbFunctions; int i = 0, n = pdbFunctions == null ? 0 : pdbFunctions.Length, j = n-1; while (i < j) { int k = (i+j) / 2; if (pdbFunctions[k].token < methodToken) i = k+1; else j = k; } while (i > 0 && pdbFunctions[i-1].token == methodToken) i--; if (0 <= i && i < n && pdbFunctions[i].token == methodToken) return pdbFunctions[i]; return null; } #endif private void GetMethodInstructions(Method/*!*/ method, object/*!*/ i) { TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters; this.currentMethodTypeParameters = method.templateParameters; TypeNode savedCurrentType = this.currentType; this.currentType = method.DeclaringType; try { MethodRow meth = this.tables.MethodTable[((int)i) - 1]; if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed) { if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000 | (uint)(int)i); method.Instructions = this.ParseMethodInstructions(method, (int)i, meth.RVA); } else method.Instructions = new InstructionList(0); #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } method.Instructions = new InstructionList(0); #endif } finally { this.currentMethodTypeParameters = savedCurrentMethodTypeParameters; this.currentType = savedCurrentType; } } private Method GetMethodDefOrRef(int codedIndex) { switch (codedIndex & 0x1) { case 0x00: return this.GetMethodFromDef(codedIndex >> 1); case 0x01: TypeNodeList varArgTypes; return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes); } throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken); } private Method GetMethodDefOrRef(int codedIndex, int numberOfGenericArguments) { switch (codedIndex & 0x1) { case 0x00: return this.GetMethodFromDef(codedIndex >> 1); case 0x01: TypeNodeList varArgTypes; return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes, numberOfGenericArguments); } throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken); } internal Method/*!*/ GetMethodFromDef(int index) { return this.GetMethodFromDef(index, null); } internal Method/*!*/ GetMethodFromDef(int index, TypeNode declaringType) { TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters; TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; MethodRow[] methodDefs = this.tables.MethodTable; MethodRow meth = methodDefs[index - 1]; if (meth.Method != null) return meth.Method; if (declaringType == null) { int indx = index; MethodPtrRow[] methodPtrs = this.tables.MethodPtrTable; int n = methodPtrs.Length, i = 0, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodPtr) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (methodPtrs[k].Method < index) i = k + 1; else j = k; } while (i > 0 && methodPtrs[i - 1].Method == index) i--; } for (; i < n; i++) { if (methodPtrs[i].Method == index) { indx = i + 1; break; } } TypeDefRow[] typeDefs = this.tables.TypeDefTable; n = typeDefs.Length; i = 0; j = n - 1; sorted = (this.sortedTablesMask >> (int)TableIndices.TypeDef) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if (typeDefs[k].MethodList < indx) i = k + 1; else j = k; } j = i; while (j < n - 1 && typeDefs[j + 1].MethodList == indx) j++; } for (; j >= 0; j--) { if (typeDefs[j].MethodList <= indx) { declaringType = this.GetTypeFromDef(j + 1); break; } } } Method.MethodBodyProvider provider = new Method.MethodBodyProvider(this.GetMethodBody); Identifier name = tables.GetIdentifier(meth.Name); Method method; if ((((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0 && (((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0) { if (name.Name == ".ctor") method = methodDefs[index - 1].Method = new InstanceInitializer(provider, index); else if (name.Name == ".cctor") method = methodDefs[index - 1].Method = new StaticInitializer(provider, index); else method = methodDefs[index - 1].Method = new Method(provider, index); } else method = methodDefs[index - 1].Method = new Method(provider, index); method.ProvideMethodAttributes = new Method.MethodAttributeProvider(this.GetMethodAttributes); //method.Attributes = this.GetCustomAttributesFor((index << 5)|0); //TODO: get attributes lazily method.Flags = (MethodFlags)meth.Flags; method.ImplFlags = (MethodImplFlags)meth.ImplFlags; method.Name = name; if (declaringType != null && declaringType.IsGeneric) { if (declaringType.Template != null) this.currentTypeParameters = declaringType.ConsolidatedTemplateArguments; else this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters; } tables.GetSignatureLength(meth.Signature); MemoryCursor sigReader = this.tables.GetNewCursor(); method.CallingConvention = (CallingConventionFlags)sigReader.ReadByte(); if (method.IsGeneric = (method.CallingConvention & CallingConventionFlags.Generic) != 0) { int numTemplateParameters = sigReader.ReadCompressedInt(); this.currentMethodTypeParameters = new TypeNodeList(numTemplateParameters); this.currentMethodTypeParameters = method.TemplateParameters = this.GetTypeParametersFor((index << 1) | 1, method); this.GetTypeParameterConstraints((index << 1) | 1, method.TemplateParameters); } int numParams = sigReader.ReadCompressedInt(); method.ReturnType = this.ParseTypeSignature(sigReader); if (declaringType != null && declaringType.IsValueType) method.ThisParameter = new This(declaringType.GetReferenceType()); else method.ThisParameter = new This(declaringType); ParameterList paramList = method.Parameters = new ParameterList(numParams); if (numParams > 0) { int offset = method.IsStatic ? 0 : 1; for (int i = 0; i < numParams; i++) { Parameter param = new Parameter(); param.ParameterListIndex = i; param.ArgumentListIndex = i + offset; param.Type = this.ParseTypeSignature(sigReader); param.DeclaringMethod = method; paramList.Add(param); } int end = this.tables.ParamTable.Length + 1; if (index < methodDefs.Length) end = methodDefs[index].ParamList; this.AddMoreStuffToParameters(method, paramList, meth.ParamList, end); for (int i = 0; i < numParams; i++) { Parameter param = paramList[i]; if (param.Name == null) param.Name = Identifier.For("param" + (i)); } } else if (method.ReturnType != CoreSystemTypes.Void) { //check for custom attributes and marshalling information on return value int i = meth.ParamList; ParamPtrRow[] parPtrs = this.tables.ParamPtrTable; //TODO: why use ParamPtrTable in the branch and not the one above? Factor this out. ParamRow[] pars = this.tables.ParamTable; int n = methodDefs.Length; int m = pars.Length; if (index < n) m = methodDefs[index].ParamList - 1; if (parPtrs.Length > 0) { if (pars != null && 0 < i && i <= m) { int j = parPtrs[i - 1].Param; ParamRow pr = pars[j - 1]; if (pr.Sequence == 0) this.AddMoreStuffToParameters(method, null, j, j + 1); } } else { if (pars != null && 0 < i && i <= m) { ParamRow pr = pars[i - 1]; if (pr.Sequence == 0) this.AddMoreStuffToParameters(method, null, i, i + 1); } } } #if ExtendedRuntime for (int k = 0, al = method.ReturnAttributes == null ? 0 : method.ReturnAttributes.Count; k < al; k++) { if (method.ReturnAttributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) { method.ReturnType = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, method.ReturnType); // Someone putting an attribute directly on the "real" method is still a // kind of out-of-band contract. // This marking is the way to signal that any override or implementing method being compiled // should not have its non-null annotations persisted as optional modifiers. method.HasOutOfBandContract = true; break; } } #endif //if ((method.Flags & MethodFlags.HasSecurity) != 0) // method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2)|1); if ((method.Flags & MethodFlags.PInvokeImpl) != 0) { ImplMapRow[] implMaps = this.tables.ImplMapTable; int n = implMaps.Length, i = 0, j = n - 1; bool sorted = (this.sortedTablesMask >> (int)TableIndices.ImplMap) % 2 == 1; if (sorted) { while (i < j) { int k = (i + j) / 2; if ((implMaps[k].MemberForwarded >> 1) < index) i = k + 1; else j = k; } while (i > 0 && (implMaps[i - 1].MemberForwarded >> 1) == index) i--; } for (; i < n; i++) { ImplMapRow imr = implMaps[i]; if (imr.MemberForwarded >> 1 == index) { method.PInvokeFlags = (PInvokeFlags)imr.MappingFlags; method.PInvokeImportName = tables.GetString(imr.ImportName); method.PInvokeModule = this.module.ModuleReferences[imr.ImportScope - 1].Module; break; } } } method.DeclaringType = declaringType; this.currentMethodTypeParameters = savedCurrentMethodTypeParameters; this.currentTypeParameters = savedCurrentTypeParameters; return method; } private void GetMethodAttributes(Method/*!*/ method, object/*!*/ handle) { TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters; try { MetadataReader tables = this.tables; int index = (int)handle; MethodRow[] methodDefs = tables.MethodTable; int n = methodDefs.Length; if (index < 1 || index > n) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); MethodRow md = methodDefs[index - 1]; if (method != md.Method) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); //Get custom attributes method.Attributes = this.GetCustomAttributesFor((index << 5) | 0); this.currentTypeParameters = savedCurrentTypeParameters; this.currentMethodTypeParameters = savedCurrentMethodTypeParameters; //Get security attributes if ((method.Flags & MethodFlags.HasSecurity) != 0) method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2) | 1); #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } method.Attributes = new AttributeList(0); this.currentTypeParameters = savedCurrentTypeParameters; this.currentMethodTypeParameters = savedCurrentMethodTypeParameters; } #else }finally{} #endif } private Method/*!*/ GetMethodFromSpec(int i) { MethodSpecRow[] methodSpecs = this.tables.MethodSpecTable; MethodSpecRow msr = methodSpecs[i - 1]; if (msr.InstantiatedMethod != null) return msr.InstantiatedMethod; MemoryCursor sigReader = this.tables.GetBlobCursor(msr.Instantiation); byte header = sigReader.ReadByte(); //skip over redundant header byte Debug.Assert(header == 0x0a); TypeNodeList templateArguments = this.ParseTypeList(sigReader); Method template = this.GetMethodDefOrRef(msr.Method, templateArguments.Count); if (template == null) return new Method(); if (template.TemplateParameters == null) return template; //Likely a dummy method return template.GetTemplateInstance(this.currentType, templateArguments); } internal Member/*!*/ GetMemberFromToken(int tok) { TypeNodeList varArgTypes; return this.GetMemberFromToken(tok, out varArgTypes); } internal Member/*!*/ GetMemberFromToken(int tok, out TypeNodeList varArgTypes) { varArgTypes = null; Member member = null; switch ((TableIndices)(tok >> 24)) { case TableIndices.Field: member = this.GetFieldFromDef(tok & 0xFFFFFF); break; case TableIndices.Method: member = this.GetMethodFromDef(tok & 0xFFFFFF); break; case TableIndices.MemberRef: member = this.GetMemberFromRef(tok & 0xFFFFFF, out varArgTypes); break; case TableIndices.TypeDef: member = this.GetTypeFromDef(tok & 0xFFFFFF); break; case TableIndices.TypeRef: member = this.GetTypeFromRef(tok & 0xFFFFFF); break; case TableIndices.TypeSpec: member = this.GetTypeFromSpec(tok & 0xFFFFFF); break; case TableIndices.MethodSpec: member = this.GetMethodFromSpec(tok & 0xFFFFFF); break; default: throw new InvalidMetadataException(ExceptionStrings.BadMemberToken); } if (member == null) throw new InvalidMetadataException(ExceptionStrings.BadMemberToken); return member; } internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes) { return this.GetMemberFromRef(i, out varArgTypes, 0); } internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes, int numGenericArgs) { MemberRefRow mref = this.tables.MemberRefTable[i - 1]; if (mref.Member != null) { varArgTypes = mref.VarargTypes; return mref.Member; } varArgTypes = null; Member result = null; int codedIndex = mref.Class; if (codedIndex == 0) return null; TypeNode parent = null; TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; switch (codedIndex & 0x7) { case 0x00: parent = this.GetTypeFromDef(codedIndex >> 3); break; case 0x01: parent = this.GetTypeFromRef(codedIndex >> 3); break; case 0x02: parent = this.GetTypeGlobalMemberContainerTypeFromModule(codedIndex >> 3); break; case 0x03: result = this.GetMethodFromDef(codedIndex >> 3); if ((((Method)result).CallingConvention & CallingConventionFlags.VarArg) != 0) { MemoryCursor sRdr = this.tables.GetBlobCursor(mref.Signature); sRdr.ReadByte(); //hdr int pCount = sRdr.ReadCompressedInt(); this.ParseTypeSignature(sRdr); //rType bool genParameterEncountered = false; this.ParseParameterTypes(out varArgTypes, sRdr, pCount, ref genParameterEncountered); } goto done; case 0x04: parent = this.GetTypeFromSpec(codedIndex >> 3); break; default: throw new InvalidMetadataException(""); } if (parent != null && parent.IsGeneric) { if (parent.Template != null) this.currentTypeParameters = parent.ConsolidatedTemplateArguments; else this.currentTypeParameters = parent.ConsolidatedTemplateParameters; } Identifier memberName = this.tables.GetIdentifier(mref.Name); MemoryCursor sigReader = this.tables.GetBlobCursor(mref.Signature); byte header = sigReader.ReadByte(); if (header == 0x6) { TypeNode fieldType = this.ParseTypeSignature(sigReader); TypeNode fType = TypeNode.StripModifiers(fieldType); TypeNode parnt = parent; while (parnt != null) { MemberList members = parnt.GetMembersNamed(memberName); for (int j = 0, n = members.Count; j < n; j++) { Field f = members[j] as Field; if (f == null) continue; if (TypeNode.StripModifiers(f.Type) == fType) { result = f; goto done; } } Class c = parnt as Class; if (c != null) parnt = c.BaseClass; else break; } if (result == null) { result = new Field(memberName); result.DeclaringType = parent; ((Field)result).Type = fieldType; goto error; } goto done; } int typeParamCount = int.MinValue; CallingConventionFlags callingConvention = CallingConventionFlags.Default; if ((header & 0x20) != 0) callingConvention |= CallingConventionFlags.HasThis; if ((header & 0x40) != 0) callingConvention |= CallingConventionFlags.ExplicitThis; switch (header & 7) { case 1: callingConvention |= CallingConventionFlags.C; break; case 2: callingConvention |= CallingConventionFlags.StandardCall; break; case 3: callingConvention |= CallingConventionFlags.ThisCall; break; case 4: callingConvention |= CallingConventionFlags.FastCall; break; case 5: callingConvention |= CallingConventionFlags.VarArg; break; } if ((header & 0x10) != 0) { typeParamCount = sigReader.ReadCompressedInt(); callingConvention |= CallingConventionFlags.Generic; } int paramCount = sigReader.ReadCompressedInt(); TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters; this.currentTypeParameters = parent.ConsolidatedTemplateArguments; TypeNode pnt = parent; if (numGenericArgs > 0) { while (pnt != null) { MemberList members = pnt.GetMembersNamed(memberName); for (int k = 0, n = members.Count; k < n; k++) { Method m = members[k] as Method; if (m == null) continue; if (m.TemplateParameters == null || m.TemplateParameters.Count != numGenericArgs) continue; if (m.Parameters == null || m.Parameters.Count != paramCount) continue; this.currentMethodTypeParameters = m.TemplateParameters; this.currentTypeParameters = pnt.ConsolidatedTemplateArguments; goto parseSignature; } Class c = pnt as Class; if (c != null) pnt = c.BaseClass; else break; } } parseSignature: TypeNode returnType = this.ParseTypeSignature(sigReader); if (returnType == null) returnType = CoreSystemTypes.Object; bool genericParameterEncountered = returnType.IsGeneric; TypeNodeList paramTypes = this.ParseParameterTypes(out varArgTypes, sigReader, paramCount, ref genericParameterEncountered); this.currentMethodTypeParameters = savedMethodTypeParameters; this.currentTypeParameters = savedCurrentTypeParameters; pnt = parent; while (pnt != null) { MemberList members = pnt.GetMembersNamed(memberName); for (int k = 0, n = members.Count; k < n; k++) { Method m = members[k] as Method; if (m == null) continue; if (m.ReturnType == null) continue; TypeNode mrtype = TypeNode.StripModifiers(m.ReturnType); //^ assert mrtype != null; if (!mrtype.IsStructurallyEquivalentTo(TypeNode.StripModifiers(returnType))) continue; if (!m.ParameterTypesMatchStructurally(paramTypes)) continue; if (m.CallingConvention != callingConvention) continue; if (typeParamCount != int.MinValue && (!m.IsGeneric || m.TemplateParameters == null || m.TemplateParameters.Count != typeParamCount)) continue; result = m; goto done; } if (memberName.UniqueIdKey == StandardIds.Ctor.UniqueIdKey) { //Can't run up the base class chain for constructors. members = pnt.GetConstructors(); if (members != null && members.Count == 1 && paramCount == 0) { //Only one constructor. The CLR metadata API's seem to think that this should match the empty signature result = members[0]; goto done; } break; } Class c = pnt as Class; if (c != null) pnt = c.BaseClass; else break; } if (result == null) { ParameterList parameters = new ParameterList(paramCount); for (int j = 0; j < paramCount; j++) { Parameter p = new Parameter(Identifier.Empty, paramTypes[j]); parameters.Add(p); } //TODO: let the caller indicate if it expects a constructor Method meth = new Method(parent, null, memberName, parameters, returnType, null); meth.CallingConvention = callingConvention; if ((callingConvention & CallingConventionFlags.HasThis) == 0) meth.Flags |= MethodFlags.Static; result = meth; } error: if (this.module != null) { HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveMemberReference, parent.FullName + "::" + memberName)); if (parent != null) parent.Members.Add(result); } done: if (Reader.CanCacheMember(result)) { this.tables.MemberRefTable[i - 1].Member = result; this.tables.MemberRefTable[i - 1].VarargTypes = varArgTypes; } this.currentTypeParameters = savedCurrentTypeParameters; return result; } private static bool CanCacheMethodHelper(Method/*!*/ method) { if (method.IsGeneric) { if (method.TemplateArguments == null) return false; for (int i = 0; i < method.TemplateArguments.Count; i++) if (!CanCacheTypeNode(method.TemplateArguments[i])) return false; } return true; } private static bool CanCacheMember(Member/*!*/ member) { return (member.DeclaringType == null || CanCacheTypeNode(member.DeclaringType)) && (member.NodeType != NodeType.Method || CanCacheMethodHelper((Method)member)); } private TypeNodeList/*!*/ ParseParameterTypes(out TypeNodeList varArgTypes, MemoryCursor/*!*/ sigReader, int paramCount, ref bool genericParameterEncountered) { varArgTypes = null; TypeNodeList paramTypes = new TypeNodeList(paramCount); for (int j = 0; j < paramCount; j++) { TypeNode paramType = this.ParseTypeSignature(sigReader); if (paramType == null) { //got a sentinel varArgTypes = new TypeNodeList(paramCount - j); j--; continue; } if (varArgTypes != null) { varArgTypes.Add(paramType); continue; } if (paramType.IsGeneric) genericParameterEncountered = true; paramTypes.Add(paramType); } return paramTypes; } private bool TypeDefIsClass(int i) { if (i == 0) return false; TypeDefRow typeDef = this.tables.TypeDefTable[i - 1]; if (typeDef.Type != null) return typeDef.Type is Class; if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false; return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends); } private bool TypeDefIsClassButNotValueTypeBaseClass(int i) { if (i == 0) return false; TypeDefRow typeDef = this.tables.TypeDefTable[i - 1]; if (typeDef.Type != null) return typeDef.Type != CoreSystemTypes.ValueType && typeDef.Type != CoreSystemTypes.Enum && typeDef.Type is Class; if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false; return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends); } internal TypeNodeList GetInstantiatedTypes() { TypeNodeList result = null; TypeDefRow[] typeDefs = this.tables.TypeDefTable; for (int i = 0, n = typeDefs.Length; i < n; i++) { TypeNode t = typeDefs[i].Type; if (t == null) continue; if (result == null) result = new TypeNodeList(); result.Add(t); } return result; } internal TypeNode/*!*/ GetTypeFromDef(int i) { TypeDefRow typeDef = this.tables.TypeDefTable[i - 1]; if (typeDef.Type != null) return typeDef.Type; // Save current state because the helper might change it but this method must not. TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; TypeNode savedCurrentType = this.currentType; try { return this.GetTypeFromDefHelper(i); #if !FxCop } catch (Exception e) { if (this.module == null) return new Class(); if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); return new Class(); #endif } finally { this.currentTypeParameters = savedCurrentTypeParameters; this.currentType = savedCurrentType; } } internal TypeNode/*!*/ GetTypeFromDefHelper(int i) { // This is added to prevent loops. // Check the code in GetTypeFromDef which checks != null before callig this function this.tables.TypeDefTable[i - 1].Type = Class.Dummy; TypeDefRow typeDef = this.tables.TypeDefTable[i - 1]; Identifier name = this.tables.GetIdentifier(typeDef.Name); Identifier namesp = this.tables.GetIdentifier(typeDef.Namespace); int firstInterfaceIndex; int lastInterfaceIndex; this.GetInterfaceIndices(i, out firstInterfaceIndex, out lastInterfaceIndex); InterfaceList interfaces = new InterfaceList(); TypeNode result = this.ConstructCorrectTypeNodeSubclass(i, namesp, firstInterfaceIndex, lastInterfaceIndex, (TypeFlags)typeDef.Flags, interfaces, typeDef.Extends, name.UniqueIdKey == StandardIds.Enum.UniqueIdKey && namesp.UniqueIdKey == StandardIds.System.UniqueIdKey); result.DeclaringModule = this.module; result.Name = name; result.Namespace = namesp; TypeNodeList typeParameters = this.currentTypeParameters = this.GetTypeParametersFor((i << 1) | 0, result); result.TemplateParameters = typeParameters; result.IsGeneric = typeParameters != null; this.tables.TypeDefTable[i - 1].Type = result; this.currentType = result; this.RemoveTypeParametersBelongToDeclaringType(i, ref typeParameters, result); //Now that the type instance has been allocated, it is safe to get hold of things that could refer to this type. if (result is Class && result.BaseType == null) { TypeNode baseType = this.DecodeAndGetTypeDefOrRefOrSpec(typeDef.Extends); ((Class)result).BaseClass = baseType as Class; if (baseType != null && !(baseType is Class) && this.module != null) { HandleError(this.module, ExceptionStrings.InvalidBaseClass); } } if (result.IsGeneric) this.GetTypeParameterConstraints((i << 1) | 0, typeParameters); if (firstInterfaceIndex >= 0) this.GetInterfaces(i, firstInterfaceIndex, interfaces); if ((result.Flags & (TypeFlags.ExplicitLayout | TypeFlags.SequentialLayout)) != 0) this.GetClassSizeAndPackingSize(i, result); return result; } private void GetInterfaceIndices(int i, out int firstInterfaceIndex, out int lastInterfaceIndex) { firstInterfaceIndex = -1; lastInterfaceIndex = -1; InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable; //TODO: binary search for (int j = 0, n = intfaces.Length; j < n; j++) { if (intfaces[j].Class != i) continue; if (firstInterfaceIndex == -1) firstInterfaceIndex = j; lastInterfaceIndex = j; } } private void GetClassSizeAndPackingSize(int i, TypeNode/*!*/ result) { ClassLayoutRow[] classLayouts = tables.ClassLayoutTable; for (int j = 0, n = classLayouts.Length; j < n; j++) { //TODO: binary search ClassLayoutRow clr = classLayouts[j]; if (clr.Parent == i) { result.ClassSize = clr.ClassSize; result.PackingSize = clr.PackingSize; break; } } } private void GetInterfaces(int i, int firstInterfaceIndex, InterfaceList/*!*/ interfaces) { InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable; for (int j = firstInterfaceIndex, n = intfaces.Length; j < n; j++) { if (intfaces[j].Class != i) continue; //TODO: break if sorted TypeNode ifaceT = this.DecodeAndGetTypeDefOrRefOrSpec(intfaces[j].Interface); Interface iface = ifaceT as Interface; if (iface == null) { iface = new Interface(); if (ifaceT != null) { iface.DeclaringModule = ifaceT.DeclaringModule; iface.Namespace = ifaceT.Namespace; iface.Name = ifaceT.Name; } } interfaces.Add(iface); } } private void RemoveTypeParametersBelongToDeclaringType(int i, ref TypeNodeList typeParameters, TypeNode/*!*/ type) { NestedClassRow[] nestedClasses = tables.NestedClassTable; for (int j = 0, n = nestedClasses.Length; j < n; j++) { //TODO: binary search NestedClassRow ncr = nestedClasses[j]; if (ncr.NestedClass == i) { type.DeclaringType = this.GetTypeFromDef(ncr.EnclosingClass); if (type.DeclaringType != null && type.DeclaringType.IsGeneric) { //remove type parameters that belong to declaring type from nested type's list if (type.templateParameters != null) { int icount = GetInheritedTypeParameterCount(type); int rcount = type.templateParameters.Count; if (icount >= rcount) type.templateParameters = null; else { TypeNodeList tpars = new TypeNodeList(rcount - icount); for (int k = icount; k < rcount; k++) tpars.Add(type.templateParameters[k]); type.templateParameters = tpars; } this.currentTypeParameters = typeParameters = type.ConsolidatedTemplateParameters; } } break; } } } private TypeNode/*!*/ ConstructCorrectTypeNodeSubclass(int i, Identifier/*!*/ namesp, int firstInterfaceIndex, int lastInterfaceIndex, TypeFlags flags, InterfaceList interfaces, int baseTypeCodedIndex, bool isSystemEnum) { TypeNode result; TypeNode.TypeAttributeProvider attributeProvider = new TypeNode.TypeAttributeProvider(this.GetTypeAttributes); TypeNode.NestedTypeProvider nestedTypeProvider = new TypeNode.NestedTypeProvider(this.GetNestedTypes); TypeNode.TypeMemberProvider memberProvider = new TypeNode.TypeMemberProvider(this.GetTypeMembers); bool isTemplateParameter = false; #if ExtendedRuntime InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable; Interface firstInterface = null; Interface lastInterface = null; if (firstInterfaceIndex >= 0){ firstInterface = this.GetInterfaceIfNotGenericInstance(intfaces[firstInterfaceIndex].Interface); if (firstInterface != null){ lastInterface = this.GetInterfaceIfNotGenericInstance(intfaces[lastInterfaceIndex].Interface); isTemplateParameter = CoreSystemTypes.IsInitialized && lastInterface != null && lastInterface == ExtendedRuntimeTypes.ITemplateParameter; } } #endif if ((flags & TypeFlags.Interface) != 0) { if (isTemplateParameter) result = new TypeParameter(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i); else result = new Interface(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i); } else if (isTemplateParameter) { result = new ClassParameter(nestedTypeProvider, attributeProvider, memberProvider, i); } else { result = null; TypeNode baseClass = this.GetTypeIfNotGenericInstance(baseTypeCodedIndex); if (baseClass != null) { if (baseClass == CoreSystemTypes.MulticastDelegate) //TODO: handle single cast delegates result = new DelegateNode(nestedTypeProvider, attributeProvider, memberProvider, i); else if (baseClass == CoreSystemTypes.Enum) result = new EnumNode(nestedTypeProvider, attributeProvider, memberProvider, i); else if (baseClass == CoreSystemTypes.ValueType && !(isSystemEnum && (flags & TypeFlags.Sealed) == 0)) { #if ExtendedRuntime Struct st = null; if (firstInterface != null){ if (namesp.UniqueIdKey == StandardIds.StructuralTypes.UniqueIdKey){ if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TupleType) st = new TupleType(nestedTypeProvider, attributeProvider, memberProvider, i); else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeIntersection) st = new TypeIntersection(nestedTypeProvider, attributeProvider, memberProvider, i); else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeUnion) st = new TypeUnion(nestedTypeProvider, attributeProvider, memberProvider, i); else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.ConstrainedType) st = new ConstrainedType(nestedTypeProvider, attributeProvider, memberProvider, i); else st = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i); } else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeAlias) st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, false); else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeDefinition) st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, true); } if (st == null && lastInterface != null) { result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface); } else { result = st; } if (result == null) #endif result = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i); } } if (result == null) { #if ExtendedRuntime if (lastInterface != null) result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface); if (result == null) #endif result = new Class(nestedTypeProvider, attributeProvider, memberProvider, i); } } result.Flags = flags; result.Interfaces = interfaces; return result; } #if !MinimalReader private TrivialHashtable/**//*!*/ TypeExtensionTable = new TrivialHashtable(); delegate TypeNode TypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle); private static TypeNode DummyTypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle) { return null; } private TypeExtensionProvider/*!*/ dummyTEProvider = new TypeExtensionProvider(DummyTypeExtensionProvider); private TypeNode GetTypeExtensionFromDef(TypeNode.NestedTypeProvider nestedTypeProvider, TypeNode.TypeAttributeProvider attributeProvider, TypeNode.TypeMemberProvider memberProvider, object handle, TypeNode baseType, Interface/*!*/ lastInterface) { if (lastInterface.Namespace.UniqueIdKey == StandardIds.CciTypeExtensions.UniqueIdKey) { TypeExtensionProvider teprovider = (TypeExtensionProvider)TypeExtensionTable[lastInterface.Name.UniqueIdKey]; if (teprovider == null) { string loc = lastInterface.DeclaringModule.Location.ToLower(CultureInfo.InvariantCulture); if (loc.EndsWith(".runtime.dll")) { loc = System.IO.Path.GetFileName(loc); string compilerDllName = loc.Replace(".runtime.dll", ""); System.Reflection.Assembly rassem; try { rassem = System.Reflection.Assembly.Load(compilerDllName); } catch { HandleError(this.module, string.Format(CultureInfo.CurrentCulture, ExceptionStrings.CannotLoadTypeExtension, lastInterface.FullName, compilerDllName)); goto ExtensionNotFound; } if (rassem == null) goto ExtensionNotFound; System.Type tprov = rassem.GetType(StandardIds.CciTypeExtensions.Name + "." + lastInterface.Name.Name + "Provider"); if (tprov == null) goto ExtensionNotFound; System.Reflection.MethodInfo providerMethod = tprov.GetMethod("For"); if (providerMethod == null) goto ExtensionNotFound; teprovider = (TypeExtensionProvider)Delegate.CreateDelegate(typeof(TypeExtensionProvider), providerMethod); ExtensionNotFound: ; if (teprovider == null) { // install a not-found dummy provider teprovider = this.dummyTEProvider; } TypeExtensionTable[lastInterface.Name.UniqueIdKey] = teprovider; } } if (teprovider == null) return null; return teprovider(nestedTypeProvider, attributeProvider, memberProvider, baseType, handle); } return null; } #endif private static int GetInheritedTypeParameterCount(TypeNode type) { if (type == null) return 0; int n = 0; type = type.DeclaringType; while (type != null) { n += type.templateParameters == null ? 0 : type.templateParameters.Count; type = type.DeclaringType; } return n; } private TypeNode/*!*/ GetTypeGlobalMemberContainerTypeFromModule(int i) { ModuleRefRow mr = this.tables.ModuleRefTable[i - 1]; Module mod = mr.Module; TypeNode result = null; if (mod != null && mod.Types != null && mod.Types.Count > 0) result = mod.Types[0]; if (result != null) return result; result = this.GetDummyTypeNode(Identifier.Empty, Identifier.For(""), mod, null, false); if (mod != null) mod.Types = new TypeNodeList(result); return result; } internal void GetNamespaces() //^ ensures this.namespaceTable != null; { TypeDefRow[] typeDefs = this.tables.TypeDefTable; int n = typeDefs.Length; TrivialHashtable nsT = this.namespaceTable = new TrivialHashtable(n * 2); TrivialHashtable nsFor = new TrivialHashtable(); NamespaceList nsL = this.namespaceList = new NamespaceList(n); for (int i = 0; i < n; i++) { TypeDefRow typeDef = typeDefs[i]; TrivialHashtable ns = (TrivialHashtable)nsT[typeDef.NamespaceKey]; Namespace nSpace = (Namespace)nsFor[typeDef.NamespaceKey]; if (ns == null) { nsT[typeDef.NamespaceKey] = ns = new TrivialHashtable(); nsFor[typeDef.NamespaceKey] = nSpace = new Namespace(typeDef.NamespaceId); nsL.Add(nSpace); } Debug.Assert(nSpace != null); if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 0) ns[typeDef.NameKey] = i + 1; else if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 1) { nSpace.isPublic = true; ns[typeDef.NameKey] = i + 1; } } } private TypeNode GetTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) { try { if (this.namespaceTable == null) this.GetNamespaces(); //^ assert this.namespaceTable != null; TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey]; if (nsTable == null) return this.GetForwardedTypeFromName(Namespace, name); object ti = nsTable[name.UniqueIdKey]; if (ti == null) return this.GetForwardedTypeFromName(Namespace, name); TypeNode t = this.GetTypeFromDef((int)ti); return t; #if !FxCop } catch (Exception e) { if (this.module == null) return null; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); return null; } #else }finally{} #endif } private TypeNode GetForwardedTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) { ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable; for (int i = 0, n = exportedTypes == null ? 0 : exportedTypes.Length; i < n; i++) { ExportedTypeRow etr = exportedTypes[i]; if ((etr.Flags & (int)TypeFlags.Forwarder) == 0) continue; if (this.tables.GetString(etr.TypeNamespace) != Namespace.Name || this.tables.GetString(etr.TypeName) != name.Name) continue; int index = etr.Implementation >> 2; AssemblyRefRow arr = this.tables.AssemblyRefTable[index - 1]; return arr.AssemblyReference.Assembly.GetType(Namespace, name); } return null; } internal bool IsValidTypeName(Identifier/*!*/ Namespace, Identifier/*!*/ name) { try { if (this.namespaceTable == null) this.GetNamespaces(); //^ assert this.namespaceTable != null; TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey]; if (nsTable == null) return false; return nsTable[name.UniqueIdKey] != null; #if !FxCop } catch (Exception e) { if (this.module == null) return false; if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); return false; } #else }finally{} #endif } internal TypeNode/*!*/ GetTypeFromRef(int i) { return this.GetTypeFromRef(i, false); } internal TypeNode/*!*/ GetTypeFromRef(int i, bool expectStruct) { TypeRefRow[] trtable = this.tables.TypeRefTable; TypeRefRow trr = trtable[i - 1]; TypeNode result = trr.Type; if (result != null) return result; Identifier name = tables.GetIdentifier(trr.Name); Identifier namesp = tables.GetIdentifier(trr.Namespace); int resolutionScope = trr.ResolutionScope; Module declaringModule = null; TypeNode declaringType = null; int index = resolutionScope >> 2; switch (resolutionScope & 0x3) { case 0: declaringModule = this.module; //^ assume declaringModule != null; result = declaringModule.GetType(namesp, name); //REVIEW: deal with case where ref is in same (multi-module) assembly, but not the current module? index == 0 break; case 1: declaringModule = this.tables.ModuleRefTable[index - 1].Module; if (declaringModule != null) result = declaringModule.GetType(namesp, name); break; case 2: declaringModule = this.tables.AssemblyRefTable[index - 1].AssemblyReference.Assembly; if (declaringModule != null) result = declaringModule.GetType(namesp, name); break; case 3: declaringType = this.GetTypeFromRef(index); declaringModule = declaringType.DeclaringModule; if (namesp == null || namesp.length == 0) result = (TypeNode)declaringType.GetMembersNamed(name)[0]; else result = (TypeNode)declaringType.GetMembersNamed(Identifier.For(namesp.Name + "." + name.Name))[0]; break; default: declaringModule = this.module; break; } if (result == null) result = this.GetDummyTypeNode(namesp, name, declaringModule, declaringType, expectStruct); trtable[i - 1].Type = result; if (!Reader.CanCacheTypeNode(result)) trtable[i - 1].Type = null; return result; } private TypeNode/*!*/ GetDummyTypeNode(Identifier namesp, Identifier name, Module declaringModule, TypeNode declaringType, bool expectStruct) { TypeNode result = null; if (this.module != null) { string modName = declaringModule == null ? "" : declaringModule.Name == null ? "" : declaringModule.Name.ToString(); HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveTypeReference, "[" + modName + "]" + namesp + "." + name)); } result = expectStruct ? (TypeNode)new Struct() : (TypeNode)new Class(); if (name != null && name.ToString().StartsWith("I") && name.ToString().Length > 1 && char.IsUpper(name.ToString()[1])) result = new Interface(); result.Flags |= TypeFlags.Public; result.Name = name; result.Namespace = namesp; if (declaringType != null) { result.DeclaringType = declaringType; result.DeclaringType.DeclaringModule = declaringType.DeclaringModule; declaringType.Members.Add(result); } else { if (declaringModule == null) declaringModule = this.module; //^ assume declaringModule != null; result.DeclaringModule = declaringModule; if (declaringModule.types != null) declaringModule.types.Add(result); } return result; } private bool TypeSpecIsClass(int i) { TypeSpecRow tsr = this.tables.TypeSpecTable[i - 1]; if (tsr.Type != null) return tsr.Type is Class; this.tables.GetSignatureLength(tsr.Signature); return this.TypeSignatureIsClass(this.tables.GetNewCursor()); } internal TypeNode/*!*/ GetTypeFromSpec(int i) { TypeSpecRow tsr = this.tables.TypeSpecTable[i - 1]; if (tsr.Type != null) return tsr.Type; this.tables.GetSignatureLength(tsr.Signature); bool pinned = false; bool isTypeArgument = false; TypeNode result = this.ParseTypeSignature(this.tables.GetNewCursor(), ref pinned, ref isTypeArgument); if (result == null) result = new Class(); //Get custom attributes AttributeList attributes = this.GetCustomAttributesFor((i << 5) | 13); if (attributes.Count > 0) { //Append attributes "inherited" from template to metadata attributes AttributeList templAttributes = result.Attributes; for (int j = 0, n = templAttributes == null ? 0 : templAttributes.Count; j < n; j++) { AttributeNode attr = result.Attributes[j]; if (attr == null) continue; attributes.Add(attr); } result.Attributes = attributes; } #if ExtendedRuntime for (int j = 0, n = attributes.Count; j < n; j++) { if (attributes[j].Type == SystemTypes.NotNullGenericArgumentsAttribute) { Literal l = (Literal)attributes[j].Expressions[0]; string s = (string)l.Value; TypeNodeList ts = new TypeNodeList(s.Length); for (int k = 0, m = s.Length; k < m; k++) { if (s[k] == '!') ts.Add(OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, result.ConsolidatedTemplateArguments[k])); else ts.Add(result.ConsolidatedTemplateArguments[k]); } result = result.Template.GetGenericTemplateInstance(this.module, ts); //^ assume result != null; } } #endif if (!isTypeArgument && Reader.CanCacheTypeNode(result)) this.tables.TypeSpecTable[i - 1].Type = result; return result; } private static bool CanCacheTypeNode(TypeNode/*!*/ type) { #if WHIDBEY return !type.IsGeneric && (type.Template == null || !type.IsNotFullySpecialized) && type.NodeType != NodeType.TypeParameter && type.NodeType != NodeType.ClassParameter && type.NodeType != NodeType.InterfaceExpression; #else return true; #endif } private static Module GetNestedModule(Module module, string modName, ref string modLocation) { if (module == null || modName == null) { Debug.Assert(false); return null; } Module mod = module.GetNestedModule(modName); if (mod == null) { if (module.Location != null) modLocation = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(module.Location), modName); if (modLocation != null && System.IO.File.Exists(modLocation)) { mod = Module.GetModule(modLocation); if (mod != null) { mod.ContainingAssembly = module.ContainingAssembly; module.ModuleReferences.Add(new ModuleReference(modName, mod)); } } } if (mod == null) { HandleError(module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotFindReferencedModule, modLocation)); mod = new Module(); mod.Name = modName; mod.ContainingAssembly = module.ContainingAssembly; mod.Kind = ModuleKindFlags.DynamicallyLinkedLibrary; } return mod; } private void GetTypeList(Module/*!*/ module) { TypeNodeList types = new TypeNodeList(); TypeDefRow[] typeDefs = this.tables.TypeDefTable; for (int i = 0, n = typeDefs.Length; i < n; i++) { TypeNode t = this.GetTypeFromDef(i + 1); if (t != null && t.DeclaringType == null) types.Add(t); } module.Types = types; AssemblyNode assem = module as AssemblyNode; if (assem == null) return; types = new TypeNodeList(); ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable; for (int i = 0, n = exportedTypes.Length; i < n; i++) { ExportedTypeRow etr = exportedTypes[i]; Identifier nameSpace = Identifier.For(this.tables.GetString(etr.TypeNamespace)); Identifier typeName = Identifier.For(this.tables.GetString(etr.TypeName)); TypeNode exportedType = null; switch (etr.Implementation & 0x3) { case 0: string modName = this.tables.GetString(this.tables.FileTable[(etr.Implementation >> 2) - 1].Name); string modLocation = modName; Module mod = GetNestedModule(assem, modName, ref modLocation); if (mod == null) { Debug.Assert(false); break; } exportedType = mod.GetType(nameSpace, typeName); if (exportedType == null) { HandleError(assem, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotFindExportedTypeInModule, nameSpace + "." + typeName, modLocation)); exportedType = new Class(); exportedType.Name = typeName; exportedType.Namespace = nameSpace; exportedType.Flags = TypeFlags.Class | TypeFlags.Public; exportedType.DeclaringModule = mod; } break; case 1: AssemblyReference aref = this.tables.AssemblyRefTable[(etr.Implementation >> 2) - 1].AssemblyReference; if (aref == null) { HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchAssemblyReference); aref = new AssemblyReference("dummy assembly for bad reference"); } AssemblyNode a = aref.Assembly; if (a == null) { Debug.Assert(false); continue; } exportedType = a.GetType(nameSpace, typeName); if (exportedType == null) { HandleError(assem, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotFindExportedTypeInAssembly, nameSpace + "." + typeName, a.StrongName)); exportedType = new Class(); exportedType.Name = typeName; exportedType.Namespace = nameSpace; exportedType.Flags = TypeFlags.Class | TypeFlags.Public; exportedType.DeclaringModule = a; } break; case 2: TypeNode parentType = types[(etr.Implementation >> 2) - 1]; if (parentType == null) { HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchParentType); parentType = new Class(); parentType.DeclaringModule = this.module; parentType.Name = Identifier.For("Missing parent type"); } exportedType = parentType.GetNestedType(typeName); if (exportedType == null) { HandleError(assem, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotFindExportedNestedTypeInType, typeName, parentType.FullName)); exportedType = new Class(); exportedType.Name = typeName; exportedType.Flags = TypeFlags.Class | TypeFlags.NestedPublic; exportedType.DeclaringType = parentType; exportedType.DeclaringModule = parentType.DeclaringModule; } break; } types.Add(exportedType); } assem.ExportedTypes = types; } private void GetNestedTypes(TypeNode/*!*/ type, object/*!*/ handle) { type.nestedTypes = null; TypeNodeList result = new TypeNodeList(); #if !FxCop TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; #endif try { if (type.IsGeneric) { if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0); this.currentTypeParameters = type.ConsolidatedTemplateParameters; } this.currentType = type; TypeNode declaringType = type.DeclaringType; while (this.currentTypeParameters == null && declaringType != null) { if (declaringType.IsGeneric) { if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0); this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters; } declaringType = declaringType.DeclaringType; } MetadataReader tables = this.tables; int typeTableIndex = (int)handle; TypeDefRow[] typeDefs = tables.TypeDefTable; int n = typeDefs.Length; if (typeTableIndex < 1 || typeTableIndex > n) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); NestedClassRow[] nestedClasses = tables.NestedClassTable; n = nestedClasses.Length; for (int i = 0; i < n; i++) { //TODO: binary lookup NestedClassRow ncr = nestedClasses[i]; if (ncr.EnclosingClass != typeTableIndex) continue; TypeNode t = this.GetTypeFromDef(ncr.NestedClass); if (t != null) { if (type.nestedTypes != null) return; //A recursive call to GetNestedTypes has already done the deed t.DeclaringType = type; if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey) result.Add(t); } else { throw new InvalidMetadataException("Invalid nested class row"); } } type.nestedTypes = result; #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } this.currentTypeParameters = savedCurrentTypeParameters; } #else }finally{} #endif } private void GetTypeMembers(TypeNode/*!*/ type, object/*!*/ handle) { TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; try { MetadataReader tables = this.tables; int typeTableIndex = (int)handle; TypeDefRow[] typeDefs = tables.TypeDefTable; FieldRow[] fieldDefs = tables.FieldTable; FieldPtrRow[] fieldPtrs = tables.FieldPtrTable; MethodRow[] methodDefs = tables.MethodTable; MethodPtrRow[] methodPtrs = tables.MethodPtrTable; EventMapRow[] eventMaps = tables.EventMapTable; EventRow[] eventDefs = tables.EventTable; EventPtrRow[] eventPtrs = tables.EventPtrTable; MethodImplRow[] methodImpls = tables.MethodImplTable; PropertyMapRow[] propertyMaps = tables.PropertyMapTable; PropertyPtrRow[] propertyPtrs = tables.PropertyPtrTable; PropertyRow[] propertyDefs = this.tables.PropertyTable; NestedClassRow[] nestedClasses = tables.NestedClassTable; int n = typeDefs.Length; if (typeTableIndex < 1 || typeTableIndex > n) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); TypeDefRow td = typeDefs[typeTableIndex - 1]; if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); //Get type members if (type.IsGeneric) { if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0); this.currentTypeParameters = type.ConsolidatedTemplateParameters; } this.currentType = type; TypeNode declaringType = type.DeclaringType; while (this.currentTypeParameters == null && declaringType != null) { if (declaringType.IsGeneric) { if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0); this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters; } declaringType = declaringType.DeclaringType; } type.members = new MemberList(); n = nestedClasses.Length; for (int i = 0; i < n; i++) { NestedClassRow ncr = nestedClasses[i]; if (ncr.EnclosingClass != typeTableIndex) continue; TypeNode t = this.GetTypeFromDef(ncr.NestedClass); if (t != null) { t.DeclaringType = type; if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey) type.Members.Add(t); } } n = typeDefs.Length; int m = fieldDefs.Length; int start = td.FieldList; int end = m + 1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].FieldList; if (type is EnumNode) this.GetUnderlyingTypeOfEnumNode((EnumNode)type, fieldDefs, fieldPtrs, start, end); this.AddFieldsToType(type, fieldDefs, fieldPtrs, start, end); m = methodDefs.Length; start = td.MethodList; end = m + 1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].MethodList; this.AddMethodsToType(type, methodPtrs, start, end); n = propertyMaps.Length; m = propertyDefs.Length; for (int i = 0; i < n; i++) { //TODO: binary search PropertyMapRow pm = propertyMaps[i]; if (pm.Parent != typeTableIndex) continue; start = pm.PropertyList; end = m + 1; if (i < n - 1) end = propertyMaps[i + 1].PropertyList; this.AddPropertiesToType(type, propertyDefs, propertyPtrs, start, end); } n = eventMaps.Length; m = eventDefs.Length; for (int i = 0; i < n; i++) { //TODO: binary search EventMapRow em = eventMaps[i]; if (em.Parent != typeTableIndex) continue; start = em.EventList; end = m + 1; if (i < n - 1) end = eventMaps[i + 1].EventList; this.AddEventsToType(type, eventDefs, eventPtrs, start, end); } n = methodImpls.Length; for (int i = 0; i < n; i++) { //TODO: binary search MethodImplRow mir = methodImpls[i]; if (mir.Class != typeTableIndex) continue; Method implementer = this.GetMethodDefOrRef(mir.MethodBody); if (implementer == null) continue; MethodList implementedInterfaceMethods = implementer.ImplementedInterfaceMethods; if (implementedInterfaceMethods == null) implementedInterfaceMethods = implementer.ImplementedInterfaceMethods = new MethodList(); TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters; this.currentMethodTypeParameters = implementer.TemplateParameters; implementedInterfaceMethods.Add(this.GetMethodDefOrRef(mir.MethodDeclaration)); this.currentMethodTypeParameters = savedMethodTypeParameters; } this.currentTypeParameters = savedCurrentTypeParameters; #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } type.Members = new MemberList(0); this.currentTypeParameters = savedCurrentTypeParameters; } #else }finally{} #endif } private void GetTypeAttributes(TypeNode/*!*/ type, object/*!*/ handle) { TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; try { MetadataReader tables = this.tables; int typeTableIndex = (int)handle; TypeDefRow[] typeDefs = tables.TypeDefTable; int n = typeDefs.Length; if (typeTableIndex < 1 || typeTableIndex > n) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); TypeDefRow td = typeDefs[typeTableIndex - 1]; if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex); //Get custom attributes type.Attributes = this.GetCustomAttributesFor((typeTableIndex << 5) | 3); this.currentTypeParameters = savedCurrentTypeParameters; //Get security attributes if ((type.Flags & TypeFlags.HasSecurity) != 0) type.SecurityAttributes = this.GetSecurityAttributesFor((typeTableIndex << 2) | 0); #if !FxCop } catch (Exception e) { if (this.module != null) { if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList(); this.module.MetadataImportErrors.Add(e); } type.Attributes = new AttributeList(0); this.currentTypeParameters = savedCurrentTypeParameters; } #else }finally{} #endif } private TypeNodeList/*!*/ ParseTypeList(MemoryCursor/*!*/ sigReader) { int n = sigReader.ReadCompressedInt(); TypeNodeList result = new TypeNodeList(n); for (int i = 0; i < n; i++) { TypeNode t = this.ParseTypeSignature(sigReader); if (t == null || t == Struct.Dummy) { //Can happen when dealing with a primitive type that implements an interface that references the primitive type. //For example, System.String implements IComparable. if (this.currentType != null && !CoreSystemTypes.Initialized) t = this.currentType; else { Debug.Assert(false); t = new TypeParameter(); t.Name = Identifier.For("Bad type parameter in position " + i); t.DeclaringModule = this.module; } } result.Add(t); } return result; } private bool TypeSignatureIsClass(MemoryCursor/*!*/ sigReader) { ElementType tok = (ElementType)sigReader.ReadCompressedInt(); switch (tok) { case ElementType.Pinned: case ElementType.Pointer: case ElementType.Reference: return this.TypeSignatureIsClass(sigReader); case ElementType.OptionalModifier: case ElementType.RequiredModifier: sigReader.ReadCompressedInt(); return this.TypeSignatureIsClass(sigReader); case ElementType.Class: return true; case ElementType.GenericTypeInstance: return this.TypeSignatureIsClass(sigReader); case ElementType.TypeParameter: { int pnum = sigReader.ReadCompressedInt(); if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum) { TypeNode tPar = this.currentTypeParameters[pnum]; return tPar != null && tPar is Class; } return false; } case ElementType.MethodParameter: { int pnum = sigReader.ReadCompressedInt(); if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum) { TypeNode tPar = this.currentMethodTypeParameters[pnum]; return tPar != null && tPar is Class; } return false; } default: return false; } } private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader) { bool junk = false; return this.ParseTypeSignature(sigReader, ref junk, ref junk); } private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned) { bool junk = false; return this.ParseTypeSignature(sigReader, ref pinned, ref junk); } private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned, ref bool isTypeArgument) { TypeNode elementType; ElementType tok = (ElementType)sigReader.ReadCompressedInt(); if (tok == ElementType.Pinned) { pinned = true; tok = (ElementType)sigReader.ReadCompressedInt(); } switch (tok) { case ElementType.Boolean: return CoreSystemTypes.Boolean; case ElementType.Char: return CoreSystemTypes.Char; case ElementType.Double: return CoreSystemTypes.Double; case ElementType.Int16: return CoreSystemTypes.Int16; case ElementType.Int32: return CoreSystemTypes.Int32; case ElementType.Int64: return CoreSystemTypes.Int64; case ElementType.Int8: return CoreSystemTypes.Int8; case ElementType.IntPtr: return CoreSystemTypes.IntPtr; case ElementType.BoxedEnum: case ElementType.Object: return CoreSystemTypes.Object; case ElementType.Single: return CoreSystemTypes.Single; case ElementType.String: return CoreSystemTypes.String; case ElementType.DynamicallyTypedReference: return CoreSystemTypes.DynamicallyTypedReference; case ElementType.UInt16: return CoreSystemTypes.UInt16; case ElementType.UInt32: return CoreSystemTypes.UInt32; case ElementType.UInt64: return CoreSystemTypes.UInt64; case ElementType.UInt8: return CoreSystemTypes.UInt8; case ElementType.UIntPtr: return CoreSystemTypes.UIntPtr; case ElementType.Void: return CoreSystemTypes.Void; case ElementType.Pointer: elementType = this.ParseTypeSignature(sigReader, ref pinned); if (elementType == null) elementType = CoreSystemTypes.Object; if (elementType == null) return null; return elementType.GetPointerType(); case ElementType.Reference: elementType = this.ParseTypeSignature(sigReader, ref pinned); if (elementType == null) elementType = CoreSystemTypes.Object; return elementType.GetReferenceType(); case ElementType.FunctionPointer: return this.ParseFunctionPointer(sigReader); case ElementType.OptionalModifier: case ElementType.RequiredModifier: TypeNode modifier = this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt()); if (modifier == null) modifier = CoreSystemTypes.Object; TypeNode modified = this.ParseTypeSignature(sigReader, ref pinned); if (modified == null) modified = CoreSystemTypes.Object; if (modified == null || modified == null) return null; if (tok == ElementType.RequiredModifier) return RequiredModifier.For(modifier, modified); else return OptionalModifier.For(modifier, modified); case ElementType.Class: return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt()); case ElementType.ValueType: return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt(), true); case ElementType.TypeParameter: TypeNode tPar = null; int pnum = sigReader.ReadCompressedInt(); if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum) tPar = this.currentTypeParameters[pnum]; if (tPar == null) { HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.BadTypeParameterInPositionForType, pnum, this.currentType == null ? "" : this.currentType.FullName)); tPar = new TypeParameter(); tPar.Name = Identifier.For("Bad type parameter in position " + pnum); tPar.DeclaringModule = this.module; } isTypeArgument = true; return tPar; case ElementType.MethodParameter: TypeNode mTPar = null; pnum = sigReader.ReadCompressedInt(); if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum) mTPar = this.currentMethodTypeParameters[pnum]; if (mTPar == null) { HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.BadMethodTypeParameterInPosition, pnum)); mTPar = new MethodTypeParameter(); mTPar.Name = Identifier.For("Bad method type parameter in position " + pnum); } isTypeArgument = true; return mTPar; case ElementType.GenericTypeInstance: TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; TypeNode template = this.ParseTypeSignature(sigReader, ref pinned); this.currentTypeParameters = savedCurrentTypeParameters; if (template == null || template.ConsolidatedTemplateParameters == null) return template; //Likely a dummy type if (CoreSystemTypes.Initialized) { if (this.currentTypeParameters == null || this.currentTypeParameters.Count == 0) this.currentTypeParameters = template.ConsolidatedTemplateParameters; TypeNodeList genArgs = this.ParseTypeList(sigReader); if (this.module == null) return null; TypeNode genInst = template.GetGenericTemplateInstance(this.module, genArgs); this.currentTypeParameters = savedCurrentTypeParameters; return genInst; } InterfaceExpression ifaceExpr = new InterfaceExpression(null); ifaceExpr.Template = template; ifaceExpr.Namespace = template.Namespace; ifaceExpr.Name = template.Name; ifaceExpr.TemplateArguments = this.ParseTypeList(sigReader); this.currentTypeParameters = savedCurrentTypeParameters; return ifaceExpr; case ElementType.SzArray: elementType = this.ParseTypeSignature(sigReader, ref pinned); if (elementType == null) elementType = CoreSystemTypes.Object; if (elementType == null) return null; return elementType.GetArrayType(1); case ElementType.Array: elementType = this.ParseTypeSignature(sigReader, ref pinned); if (elementType == null) elementType = CoreSystemTypes.Object; if (elementType == null) return null; int rank = sigReader.ReadCompressedInt(); int numSizes = sigReader.ReadCompressedInt(); int[] sizes = new int[numSizes]; for (int i = 0; i < numSizes; i++) sizes[i] = sigReader.ReadCompressedInt(); int numLoBounds = sigReader.ReadCompressedInt(); int[] loBounds = new int[numLoBounds]; for (int i = 0; i < numLoBounds; i++) loBounds[i] = sigReader.ReadCompressedInt(); return elementType.GetArrayType(rank, numSizes, numLoBounds, sizes, loBounds); case ElementType.Sentinel: return null; case ElementType.Type: return CoreSystemTypes.Type; case ElementType.Enum: return this.GetTypeFromSerializedName(ReadSerString(sigReader)); } throw new InvalidMetadataException(ExceptionStrings.MalformedSignature); } private FunctionPointer/*!*/ ParseFunctionPointer(MemoryCursor/*!*/ sigReader) { CallingConventionFlags convention = (CallingConventionFlags)sigReader.ReadByte(); int n = sigReader.ReadCompressedInt(); TypeNode returnType = this.ParseTypeSignature(sigReader); if (returnType == null) returnType = CoreSystemTypes.Object; TypeNodeList parameterTypes = new TypeNodeList(n); int m = n; for (int i = 0; i < n; i++) { TypeNode t = this.ParseTypeSignature(sigReader); if (t == null) m = i--; else parameterTypes.Add(t); } FunctionPointer fp = FunctionPointer.For(parameterTypes, returnType); fp.CallingConvention = convention; fp.VarArgStart = m; return fp; } private StatementList ParseMethodBody(Method/*!*/ method, int methodIndex, int RVA) { TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; if (method.DeclaringType.Template != null) this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments; else this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters; BodyParser parser = new BodyParser(this, method, methodIndex, RVA); StatementList result = parser.ParseStatements(); this.currentTypeParameters = savedCurrentTypeParameters; return result; } private InstructionList ParseMethodInstructions(Method/*!*/ method, int methodIndex, int RVA) { TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters; if (method.DeclaringType.Template != null) this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments; else this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters; InstructionParser parser = new InstructionParser(this, method, methodIndex, RVA); InstructionList result = parser.ParseInstructions(); this.currentTypeParameters = savedCurrentTypeParameters; return result; } } internal abstract class ILParser { internal int counter; protected Reader/*!*/ reader; protected MemoryCursor/*!*/ bodyReader; internal int size; protected Method/*!*/ method; protected int methodIndex; protected int RVA; protected LocalList/*!*/ locals = new LocalList(); internal ILParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA) { this.reader = reader; this.bodyReader = reader.tables.GetNewCursor(); this.method = method; #if !FxCop this.method.LocalList = this.locals; #else this.method.Locals = this.locals; #endif this.methodIndex = methodIndex; this.RVA = RVA; //^ base(); } protected Expression Parameters(int i) { if (this.method.IsStatic) return this.method.Parameters[i]; if (i == 0) return this.method.ThisParameter; return this.method.Parameters[i - 1]; } protected void ParseHeader() { byte header = this.reader.tables.GetMethodBodyHeaderByte(this.RVA); if ((header & 0x3) == 2) { this.size = header >> 2; this.bodyReader = this.reader.tables.GetNewCursor(); this.reader.tables.Skip(size); } else { method.InitLocals = (header & 0x10) != 0; byte header2 = this.reader.tables.GetByte(); int fatHeaderSize = header2 >> 4; if (fatHeaderSize == 2) return; if (fatHeaderSize != 3) throw new InvalidMetadataException(ExceptionStrings.InvalidFatMethodHeader); this.reader.tables.Skip(2); //Skip over maxstack. No need to remember it. this.size = this.reader.tables.GetInt32(); int localIndex = this.reader.tables.GetInt32(); this.bodyReader = this.reader.tables.GetNewCursor(); this.reader.tables.Skip(size); this.reader.tables.AlignTo32BitBoundary(); while ((header & 0x8) != 0) { header = this.reader.tables.GetByte(); if ((header & 3) != 1) throw new InvalidMetadataException(ExceptionStrings.BadMethodHeaderSection); if ((header & 0x80) != 0) throw new InvalidMetadataException(ExceptionStrings.TooManyMethodHeaderSections); this.ParseExceptionHandlerEntry((header & 0x40) == 0); } Hashtable localSourceNames = new Hashtable(); #if UseSingularityPDB if (this.reader.getDebugSymbols && this.reader.pdbFunctions != null) { PdbFunction pdbFunc = this.reader.GetPdbFunction(0x6000000|(uint)methodIndex); if (pdbFunc != null) this.GetLocalNames(pdbFunc.scopes, localSourceNames); } #elif !ROTOR if (this.reader.getDebugSymbols && this.reader.debugReader != null) { ISymUnmanagedMethod methodInfo = null; try { try { this.reader.debugReader.GetMethod(0x6000000 | (uint)methodIndex, ref methodInfo); if (methodInfo != null) { ISymUnmanagedScope rootScope = methodInfo.GetRootScope(); try { this.reader.GetLocalSourceNames(rootScope, localSourceNames); } finally { if (rootScope != null) Marshal.ReleaseComObject(rootScope); } } } catch (COMException) { } catch (InvalidCastException) { } catch (System.Runtime.InteropServices.InvalidComObjectException) { } } finally { if (methodInfo != null) Marshal.ReleaseComObject(methodInfo); } } #endif this.reader.GetLocals(localIndex, this.locals, localSourceNames); } } #if UseSingularityPDB private void GetLocalNames(PdbScope[] scopes, Hashtable localSourceNames) { for (int i = 0, n = scopes == null ? 0 : scopes.Length; i < n; i++) { PdbScope scope = scopes[i]; foreach (PdbSlot slot in scope.slots) localSourceNames[(int)slot.slot] = slot.name; this.GetLocalNames(scope.scopes, localSourceNames); } } #endif abstract protected void ParseExceptionHandlerEntry(bool smallSection); protected byte GetByte() { this.counter += 1; return this.bodyReader.ReadByte(); } protected sbyte GetSByte() { this.counter += 1; return this.bodyReader.ReadSByte(); } protected short GetInt16() { this.counter += 2; return this.bodyReader.ReadInt16(); } protected int GetInt32() { this.counter += 4; return this.bodyReader.ReadInt32(); } protected long GetInt64() { this.counter += 8; return this.bodyReader.ReadInt64(); } protected float GetSingle() { this.counter += 4; return this.bodyReader.ReadSingle(); } protected double GetDouble() { this.counter += 8; return this.bodyReader.ReadDouble(); } protected Member/*!*/ GetMemberFromToken() { return this.reader.GetMemberFromToken(this.GetInt32()); } protected Member/*!*/ GetMemberFromToken(out TypeNodeList varArgTypes) { return this.reader.GetMemberFromToken(this.GetInt32(), out varArgTypes); } protected string/*!*/ GetStringFromToken() { int tok = this.GetInt32(); return this.reader.tables.GetUserString(tok & 0xFFFFFF); } protected OpCode GetOpCode() { int result = this.GetByte(); if (result == (int)OpCode.Prefix1) result = result << 8 | this.GetByte(); return (OpCode)result; } } sealed internal class BodyParser : ILParser { private readonly ExpressionStack/*!*/ operandStack = new ExpressionStack(); private readonly TrivialHashtable/*!*/ blockMap = new TrivialHashtable(); private int alignment = -1; private bool isReadOnly; private bool isTailCall; private bool isVolatile; private TypeNode constraint; internal BodyParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA) : base(reader, method, methodIndex, RVA) { //^ base; } #if !FxCop override protected void ParseExceptionHandlerEntry(bool smallSection) { int dataSize = this.reader.tables.GetByte(); int n = (int)(ushort)this.reader.tables.GetInt16(); if (smallSection) n = dataSize / 12; else n = (dataSize + (n << 8)) / 24; if (n < 0) n = 0; this.method.ExceptionHandlers = new ExceptionHandlerList(n); for (int i = 0; i < n; i++) { int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset; if (smallSection) { flags = this.reader.tables.GetInt16(); tryOffset = this.reader.tables.GetUInt16(); tryLength = this.reader.tables.GetByte(); handlerOffset = this.reader.tables.GetUInt16(); handlerLength = this.reader.tables.GetByte(); } else { flags = this.reader.tables.GetInt32(); tryOffset = this.reader.tables.GetInt32(); tryLength = this.reader.tables.GetInt32(); handlerOffset = this.reader.tables.GetInt32(); handlerLength = this.reader.tables.GetInt32(); } tokenOrOffset = this.reader.tables.GetInt32(); ExceptionHandler eh = new ExceptionHandler(); switch (flags) { case 0x00: eh.HandlerType = NodeType.Catch; int pos = this.reader.tables.GetCurrentPosition(); eh.FilterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset); this.reader.tables.SetCurrentPosition(pos); break; case 0x01: eh.HandlerType = NodeType.Filter; eh.FilterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset); break; case 0x02: eh.HandlerType = NodeType.Finally; break; case 0x04: eh.HandlerType = NodeType.FaultHandler; break; default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType); } eh.TryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset); eh.BlockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset + tryLength); eh.HandlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset); eh.BlockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset + handlerLength); this.method.ExceptionHandlers.Add(eh); } } #endif private AssignmentStatement/*!*/ ParseArrayElementAssignment(OpCode opCode) { Expression rhvalue = PopOperand(); ExpressionList indexers = new ExpressionList(1); indexers.Add(PopOperand()); Expression array = PopOperand(); Indexer indexer = new Indexer(array, indexers); TypeNode t = CoreSystemTypes.Object; switch (opCode) { case OpCode.Stelem_I: t = CoreSystemTypes.IntPtr; break; case OpCode.Stelem_I1: t = CoreSystemTypes.Int8; break; case OpCode.Stelem_I2: t = CoreSystemTypes.Int16; break; case OpCode.Stelem_I4: t = CoreSystemTypes.Int32; break; case OpCode.Stelem_I8: t = CoreSystemTypes.Int64; break; case OpCode.Stelem_R4: t = CoreSystemTypes.Single; break; case OpCode.Stelem_R8: t = CoreSystemTypes.Double; break; case OpCode.Stelem: t = (TypeNode)this.GetMemberFromToken(); break; default: ArrayType arrT = array.Type as ArrayType; if (arrT != null) t = arrT.ElementType; break; } indexer.ElementType = indexer.Type = t; return new AssignmentStatement(indexer, rhvalue); } private Indexer/*!*/ ParseArrayElementLoad(OpCode opCode, TypeNode elementType) { ExpressionList indexers = new ExpressionList(1); indexers.Add(PopOperand()); Expression array = PopOperand(); Indexer indexer = new Indexer(array, indexers); TypeNode t = elementType; switch (opCode) { case OpCode.Ldelem_I1: t = CoreSystemTypes.Int8; break; case OpCode.Ldelem_U1: t = CoreSystemTypes.UInt8; break; case OpCode.Ldelem_I2: t = CoreSystemTypes.Int16; break; case OpCode.Ldelem_U2: t = CoreSystemTypes.UInt16; break; case OpCode.Ldelem_I4: t = CoreSystemTypes.Int32; break; case OpCode.Ldelem_U4: t = CoreSystemTypes.UInt32; break; case OpCode.Ldelem_I8: t = CoreSystemTypes.Int64; break; case OpCode.Ldelem_I: t = CoreSystemTypes.IntPtr; break; case OpCode.Ldelem_R4: t = CoreSystemTypes.Single; break; case OpCode.Ldelem_R8: t = CoreSystemTypes.Double; break; case OpCode.Ldelem: t = (TypeNode)this.GetMemberFromToken(); break; default: if (t != null) break; t = CoreSystemTypes.Object; ArrayType arrT = array.Type as ArrayType; if (arrT != null) t = arrT.ElementType; break; } indexer.ElementType = indexer.Type = t; return indexer; } private UnaryExpression/*!*/ ParseArrayElementLoadAddress() { TypeNode elemType = (TypeNode)this.GetMemberFromToken(); return new UnaryExpression(this.ParseArrayElementLoad(0, elemType), this.isReadOnly ? NodeType.ReadOnlyAddressOf : NodeType.AddressOf, elemType.GetReferenceType()); } private static UnaryExpression/*!*/ SetType(UnaryExpression/*!*/ uex) { if (uex == null || uex.Operand == null) return uex; TypeNode elemType = uex.Operand.Type; if (elemType == null) return uex; uex.Type = elemType.GetReferenceType(); return uex; } private BinaryExpression/*!*/ ParseBinaryComparison(NodeType oper) { Expression op2 = PopOperand(); Expression op1 = PopOperand(); BinaryExpression result = new BinaryExpression(op1, op2, oper); result.Type = CoreSystemTypes.Int32; return result; } private BinaryExpression/*!*/ ParseBinaryOperation(NodeType oper) { Expression op2 = PopOperand(); Expression op1 = PopOperand(); BinaryExpression result = new BinaryExpression(op1, op2, oper); result.Type = op1.Type; if (result.Type == null) result.Type = op2.Type; return result; } private UnaryExpression/*!*/ ParseUnaryOperation(NodeType oper) { Expression op = PopOperand(); return new UnaryExpression(op, oper, op.Type); } private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered) { return this.ParseBranch(operatorType, operandCount, shortOffset, unordered, false); } private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered, bool leavesExceptionBlock) { Expression operand2 = operandCount > 1 ? PopOperand() : null; Expression operand1 = operandCount > 0 ? PopOperand() : null; Expression condition = operandCount > 1 ? (Expression)new BinaryExpression(operand1, operand2, operatorType) : (operandCount > 0 ? (operatorType == NodeType.Nop ? operand1 : (Expression)new UnaryExpression(operand1, operatorType)) : null); int targetAddress = shortOffset ? this.GetSByte() : this.GetInt32(); Block targetBlock = (Block)this.blockMap[targetAddress + this.counter + 1]; Debug.Assert(targetBlock != null); if (targetAddress >= 0 && !this.reader.preserveShortBranches) shortOffset = false; return new Branch(condition, targetBlock, shortOffset, unordered, leavesExceptionBlock); } private MethodCall/*!*/ ParseCall(NodeType typeOfCall, out bool isStatement) { TypeNodeList varArgTypes; Method meth = (Method)this.GetMemberFromToken(out varArgTypes); int numVarArgs = varArgTypes == null ? 0 : varArgTypes.Count; isStatement = BodyParser.TypeIsVoid(meth.ReturnType); int n = meth.Parameters == null ? 0 : meth.Parameters.Count; if (typeOfCall == NodeType.Jmp) n = 0; else n += numVarArgs; Expression[] args = new Expression[n]; ExpressionList arguments = new ExpressionList(n); for (int i = n - 1; i >= 0; i--) args[i] = PopOperand(); for (int i = 0; i < n; i++) arguments.Add(args[i]); if (varArgTypes != null) { for (int i = n - 1, j = numVarArgs; j > 0; j--, i--) { Expression e = arguments[i]; TypeNode t = varArgTypes[j - 1]; if (e != null && t != null) e.Type = t; } } Expression thisob = meth.IsStatic ? null : PopOperand(); MemberBinding methBinding = new MemberBinding(thisob, meth); MethodCall result = new MethodCall(methBinding, arguments, typeOfCall); result.Type = meth.ReturnType; result.IsTailCall = this.isTailCall; if (this.constraint != null) { result.Constraint = this.constraint; this.constraint = null; } return result; } private static bool TypeIsVoid(TypeNode t) { if (t == null) return false; for (; ; ) { switch (t.NodeType) { case NodeType.OptionalModifier: case NodeType.RequiredModifier: t = ((TypeModifier)t).ModifiedType; break; default: return t == CoreSystemTypes.Void; } } } private MethodCall/*!*/ ParseCalli(out bool isStatement) { FunctionPointer fp = this.reader.GetCalliSignature(this.GetInt32()); if (fp == null) throw new InvalidMetadataException(ExceptionStrings.BaddCalliSignature); isStatement = BodyParser.TypeIsVoid(fp.ReturnType); int n = fp.ParameterTypes.Count; Expression[] args = new Expression[n + 1]; ExpressionList arguments = new ExpressionList(n + 1); for (int i = n; i >= 0; i--) args[i] = PopOperand(); for (int i = 0; i <= n; i++) arguments.Add(args[i]); Expression thisob = fp.IsStatic ? null : PopOperand(); MemberBinding methBinding = new MemberBinding(thisob, fp); MethodCall result = new MethodCall(methBinding, arguments, NodeType.Calli); result.Type = fp.ReturnType; result.IsTailCall = this.isTailCall; return result; } private static Expression/*!*/ ParseTypeCheck(Expression operand, TypeNode type, NodeType typeOfCheck) { TypeNode etype = type; if (typeOfCheck == NodeType.Unbox) etype = type.GetReferenceType(); Expression expr = new BinaryExpression(operand, new Literal(type, CoreSystemTypes.Type), typeOfCheck, etype); return expr; } private Construct/*!*/ ParseConstruct() { TypeNodeList varArgTypes; Method meth = (Method)this.GetMemberFromToken(out varArgTypes); int n = meth.Parameters.Count; Expression[] args = new Expression[n]; ExpressionList arguments = new ExpressionList(n); for (int i = n - 1; i >= 0; i--) args[i] = PopOperand(); for (int i = 0; i < n; i++) arguments.Add(args[i]); Construct result = new Construct(new MemberBinding(null, meth), arguments); result.Type = meth.DeclaringType; return result; } private AssignmentStatement/*!*/ ParseCopyObject() { TypeNode type = (TypeNode)this.GetMemberFromToken(); Expression rhaddr = PopOperand(); Expression lhaddr = PopOperand(); return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new AddressDereference(rhaddr, type)); } private UnaryExpression /*!*/ ParseLoadRuntimeMetadataToken() { Expression expr = null; TypeNode exprType = null; Member member = this.GetMemberFromToken(); TypeNode t = member as TypeNode; if (t == null) { exprType = (member.NodeType == NodeType.Field) ? CoreSystemTypes.RuntimeFieldHandle : CoreSystemTypes.RuntimeMethodHandle; expr = new MemberBinding(null, member); } else { exprType = CoreSystemTypes.RuntimeTypeHandle; expr = new Literal(t, CoreSystemTypes.Type); } return new UnaryExpression(expr, NodeType.Ldtoken, exprType); } private AssignmentStatement/*!*/ ParseInitObject() { TypeNode type = (TypeNode)this.GetMemberFromToken(); Expression lhaddr = PopOperand(); return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new Literal(null, CoreSystemTypes.Object)); } private ConstructArray/*!*/ ParseNewArray() { TypeNode type = (TypeNode)this.GetMemberFromToken(); ExpressionList sizes = new ExpressionList(1); sizes.Add(PopOperand()); ConstructArray result = new ConstructArray(type, sizes, null); result.Type = type.GetArrayType(1); return result; } #if !FxCop internal StatementList/*!*/ ParseStatements() { this.ParseHeader(); if (this.size == 0) return new StatementList(0); this.CreateBlocksForBranchTargets(); StatementList result = new StatementList(); Block currentBlock = null; while (this.counter < size) { if (currentBlock == null) { currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter); result.Add(currentBlock); } bool endOfBasicBlock = this.ParseStatement(currentBlock); if (endOfBasicBlock) currentBlock = null; } result.Add(Reader.GetOrCreateBlock(this.blockMap, this.counter)); return result; } #endif private bool ParseStatement(Block/*!*/ block) { //parse instructions and put in expression tree until an assignment, void call, branch target, or branch is encountered StatementList statementList = block.Statements; Expression expr = null; Statement statement = null; bool transferStatement = false; int startingAddress = 0; #if !FxCop SourceContext sourceContext = new SourceContext(); sourceContext.StartPos = this.counter; #endif #if !ROTOR if (this.method.contextForOffset != null) { object sctx = this.method.contextForOffset[this.counter + 1]; if (sctx != null) sourceContext = (SourceContext)sctx; } #endif while (true) { bool isStatement = false; startingAddress = this.counter + 1; //Add one so that it is never zero (the latter means no entry to the TrivialHashtable) #if !FxCop OpCode opCode = this.GetOpCode(); #else this.ilOffset = this.counter; if (this.handlerMap.TryGetValue(this.ilOffset, out expr)){ expr.sourceContext = sourceContext; expr.ILOffset = this.ilOffset; this.operandStack.Push(expr); } this.opCode = this.GetOpCode(); #endif switch (opCode) { case OpCode.Nop: statement = new Statement(NodeType.Nop); goto done; case OpCode.Break: statement = new Statement(NodeType.DebugBreak); goto done; case OpCode.Ldarg_0: expr = this.Parameters(0); break; case OpCode.Ldarg_1: expr = this.Parameters(1); break; case OpCode.Ldarg_2: expr = this.Parameters(2); break; case OpCode.Ldarg_3: expr = this.Parameters(3); break; case OpCode.Ldloc_0: expr = this.locals[0]; break; case OpCode.Ldloc_1: expr = this.locals[1]; break; case OpCode.Ldloc_2: expr = this.locals[2]; break; case OpCode.Ldloc_3: expr = this.locals[3]; break; case OpCode.Stloc_0: statement = new AssignmentStatement(this.locals[0], PopOperand()); goto done; case OpCode.Stloc_1: statement = new AssignmentStatement(this.locals[1], PopOperand()); goto done; case OpCode.Stloc_2: statement = new AssignmentStatement(this.locals[2], PopOperand()); goto done; case OpCode.Stloc_3: statement = new AssignmentStatement(this.locals[3], PopOperand()); goto done; case OpCode.Ldarg_S: expr = this.Parameters(this.GetByte()); break; case OpCode.Ldarga_S: expr = SetType(new UnaryExpression(this.Parameters(this.GetByte()), NodeType.AddressOf)); break; case OpCode.Starg_S: statement = new AssignmentStatement(this.Parameters(this.GetByte()), PopOperand()); goto done; case OpCode.Ldloc_S: expr = this.locals[this.GetByte()]; break; case OpCode.Ldloca_S: expr = SetType(new UnaryExpression(this.locals[this.GetByte()], NodeType.AddressOf)); break; case OpCode.Stloc_S: statement = new AssignmentStatement(this.locals[this.GetByte()], PopOperand()); goto done; case OpCode.Ldnull: expr = new Literal(null, CoreSystemTypes.Object); break; case OpCode.Ldc_I4_M1: expr = new Literal(-1, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_0: expr = new Literal(0, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_1: expr = new Literal(1, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_2: expr = new Literal(2, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_3: expr = new Literal(3, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_4: expr = new Literal(4, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_5: expr = new Literal(5, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_6: expr = new Literal(6, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_7: expr = new Literal(7, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_8: expr = new Literal(8, CoreSystemTypes.Int32); break; case OpCode.Ldc_I4_S: expr = new Literal((int)this.GetSByte(), CoreSystemTypes.Int32); break; case OpCode.Ldc_I4: expr = new Literal(this.GetInt32(), CoreSystemTypes.Int32); break; case OpCode.Ldc_I8: expr = new Literal(this.GetInt64(), CoreSystemTypes.Int64); break; case OpCode.Ldc_R4: expr = new Literal(this.GetSingle(), CoreSystemTypes.Single); break; case OpCode.Ldc_R8: expr = new Literal(this.GetDouble(), CoreSystemTypes.Double); break; case OpCode.Dup: statement = new ExpressionStatement(new Expression(NodeType.Dup)); goto done; case OpCode.Pop: statement = new ExpressionStatement(new UnaryExpression(PopOperand(), NodeType.Pop)); goto done; case OpCode.Jmp: expr = this.ParseCall(NodeType.Jmp, out isStatement); if (isStatement) goto done; break; case OpCode.Call: expr = this.ParseCall(NodeType.Call, out isStatement); if (isStatement) goto done; break; case OpCode.Calli: expr = this.ParseCalli(out isStatement); if (isStatement) goto done; break; case OpCode.Ret: Expression retVal = BodyParser.TypeIsVoid(this.method.ReturnType) ? null : PopOperand(); statement = new Return(retVal); transferStatement = true; goto done; case OpCode.Br_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false); transferStatement = true; goto done; case OpCode.Brfalse_S: statement = this.ParseBranch(NodeType.LogicalNot, 1, true, false); transferStatement = true; goto done; case OpCode.Brtrue_S: statement = this.ParseBranch(NodeType.Nop, 1, true, false); transferStatement = true; goto done; case OpCode.Beq_S: statement = this.ParseBranch(NodeType.Eq, 2, true, false); transferStatement = true; goto done; case OpCode.Bge_S: statement = this.ParseBranch(NodeType.Ge, 2, true, false); transferStatement = true; goto done; case OpCode.Bgt_S: statement = this.ParseBranch(NodeType.Gt, 2, true, false); transferStatement = true; goto done; case OpCode.Ble_S: statement = this.ParseBranch(NodeType.Le, 2, true, false); transferStatement = true; goto done; case OpCode.Blt_S: statement = this.ParseBranch(NodeType.Lt, 2, true, false); transferStatement = true; goto done; case OpCode.Bne_Un_S: statement = this.ParseBranch(NodeType.Ne, 2, true, true); transferStatement = true; goto done; case OpCode.Bge_Un_S: statement = this.ParseBranch(NodeType.Ge, 2, true, true); transferStatement = true; goto done; case OpCode.Bgt_Un_S: statement = this.ParseBranch(NodeType.Gt, 2, true, true); transferStatement = true; goto done; case OpCode.Ble_Un_S: statement = this.ParseBranch(NodeType.Le, 2, true, true); transferStatement = true; goto done; case OpCode.Blt_Un_S: statement = this.ParseBranch(NodeType.Lt, 2, true, true); transferStatement = true; goto done; case OpCode.Br: statement = this.ParseBranch(NodeType.Nop, 0, false, false); transferStatement = true; goto done; case OpCode.Brfalse: statement = this.ParseBranch(NodeType.LogicalNot, 1, false, false); transferStatement = true; goto done; case OpCode.Brtrue: statement = this.ParseBranch(NodeType.Nop, 1, false, false); transferStatement = true; goto done; case OpCode.Beq: statement = this.ParseBranch(NodeType.Eq, 2, false, false); transferStatement = true; goto done; case OpCode.Bge: statement = this.ParseBranch(NodeType.Ge, 2, false, false); transferStatement = true; goto done; case OpCode.Bgt: statement = this.ParseBranch(NodeType.Gt, 2, false, false); transferStatement = true; goto done; case OpCode.Ble: statement = this.ParseBranch(NodeType.Le, 2, false, false); transferStatement = true; goto done; case OpCode.Blt: statement = this.ParseBranch(NodeType.Lt, 2, false, false); transferStatement = true; goto done; case OpCode.Bne_Un: statement = this.ParseBranch(NodeType.Ne, 2, false, true); transferStatement = true; goto done; case OpCode.Bge_Un: statement = this.ParseBranch(NodeType.Ge, 2, false, true); transferStatement = true; goto done; case OpCode.Bgt_Un: statement = this.ParseBranch(NodeType.Gt, 2, false, true); transferStatement = true; goto done; case OpCode.Ble_Un: statement = this.ParseBranch(NodeType.Le, 2, false, true); transferStatement = true; goto done; case OpCode.Blt_Un: statement = this.ParseBranch(NodeType.Lt, 2, false, true); transferStatement = true; goto done; case OpCode.Switch: statement = this.ParseSwitchInstruction(); transferStatement = true; goto done; case OpCode.Ldind_I1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int8, this.isVolatile, this.alignment); break; case OpCode.Ldind_U1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt8, this.isVolatile, this.alignment); break; case OpCode.Ldind_I2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int16, this.isVolatile, this.alignment); break; case OpCode.Ldind_U2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt16, this.isVolatile, this.alignment); break; case OpCode.Ldind_I4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int32, this.isVolatile, this.alignment); break; case OpCode.Ldind_U4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt32, this.isVolatile, this.alignment); break; case OpCode.Ldind_I8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int64, this.isVolatile, this.alignment); break; case OpCode.Ldind_I: expr = new AddressDereference(PopOperand(), CoreSystemTypes.IntPtr, this.isVolatile, this.alignment); break; case OpCode.Ldind_R4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Single, this.isVolatile, this.alignment); break; case OpCode.Ldind_R8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Double, this.isVolatile, this.alignment); break; case OpCode.Ldind_Ref: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Object, this.isVolatile, this.alignment); break; case OpCode.Stind_Ref: statement = this.ParseStoreIndirect(CoreSystemTypes.Object); goto done; case OpCode.Stind_I1: statement = this.ParseStoreIndirect(CoreSystemTypes.Int8); goto done; case OpCode.Stind_I2: statement = this.ParseStoreIndirect(CoreSystemTypes.Int16); goto done; case OpCode.Stind_I4: statement = this.ParseStoreIndirect(CoreSystemTypes.Int32); goto done; case OpCode.Stind_I8: statement = this.ParseStoreIndirect(CoreSystemTypes.Int64); goto done; case OpCode.Stind_R4: statement = this.ParseStoreIndirect(CoreSystemTypes.Single); goto done; case OpCode.Stind_R8: statement = this.ParseStoreIndirect(CoreSystemTypes.Double); goto done; case OpCode.Add: expr = this.ParseBinaryOperation(NodeType.Add); break; case OpCode.Sub: expr = this.ParseBinaryOperation(NodeType.Sub); break; case OpCode.Mul: expr = this.ParseBinaryOperation(NodeType.Mul); break; case OpCode.Div: expr = this.ParseBinaryOperation(NodeType.Div); break; case OpCode.Div_Un: expr = this.ParseBinaryOperation(NodeType.Div_Un); break; case OpCode.Rem: expr = this.ParseBinaryOperation(NodeType.Rem); break; case OpCode.Rem_Un: expr = this.ParseBinaryOperation(NodeType.Rem_Un); break; case OpCode.And: expr = this.ParseBinaryOperation(NodeType.And); break; case OpCode.Or: expr = this.ParseBinaryOperation(NodeType.Or); break; case OpCode.Xor: expr = this.ParseBinaryOperation(NodeType.Xor); break; case OpCode.Shl: expr = this.ParseBinaryOperation(NodeType.Shl); break; case OpCode.Shr: expr = this.ParseBinaryOperation(NodeType.Shr); break; case OpCode.Shr_Un: expr = this.ParseBinaryOperation(NodeType.Shr_Un); break; case OpCode.Neg: expr = this.ParseUnaryOperation(NodeType.Neg); break; case OpCode.Not: expr = this.ParseUnaryOperation(NodeType.Not); break; case OpCode.Conv_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I1, CoreSystemTypes.Int8); break; case OpCode.Conv_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I2, CoreSystemTypes.Int16); break; case OpCode.Conv_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I4, CoreSystemTypes.Int32); break; case OpCode.Conv_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I8, CoreSystemTypes.Int64); break; case OpCode.Conv_R4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R4, CoreSystemTypes.Single); break; case OpCode.Conv_R8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R8, CoreSystemTypes.Double); break; case OpCode.Conv_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U4, CoreSystemTypes.UInt32); break; case OpCode.Conv_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U8, CoreSystemTypes.UInt64); break; case OpCode.Callvirt: expr = this.ParseCall(NodeType.Callvirt, out isStatement); if (isStatement) goto done; break; case OpCode.Cpobj: statement = this.ParseCopyObject(); goto done; case OpCode.Ldobj: expr = new AddressDereference(PopOperand(), (TypeNode)this.GetMemberFromToken(), this.isVolatile, this.alignment); break; case OpCode.Ldstr: expr = new Literal(this.GetStringFromToken(), CoreSystemTypes.String); break; case OpCode.Newobj: expr = this.ParseConstruct(); break; case OpCode.Castclass: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Castclass); break; case OpCode.Isinst: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Isinst); break; case OpCode.Conv_R_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R_Un, CoreSystemTypes.Double); break; case OpCode.Unbox: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Unbox); break; case OpCode.Throw: statement = new Throw(PopOperand()); transferStatement = true; goto done; case OpCode.Ldfld: expr = new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment); break; case OpCode.Ldflda: expr = SetType(new UnaryExpression(new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment), NodeType.AddressOf)); break; case OpCode.Stfld: statement = this.ParseStoreField(); goto done; case OpCode.Ldsfld: expr = new MemberBinding(null, this.GetMemberFromToken(), this.isVolatile, this.alignment); break; case OpCode.Ldsflda: expr = SetType(new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken(), this.isVolatile, this.alignment), NodeType.AddressOf)); break; case OpCode.Stsfld: statement = new AssignmentStatement(new MemberBinding(null, this.GetMemberFromToken(), this.isVolatile, this.alignment), PopOperand()); goto done; case OpCode.Stobj: statement = this.ParseStoreIndirect((TypeNode)this.GetMemberFromToken()); goto done; case OpCode.Conv_Ovf_I1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1_Un, CoreSystemTypes.Int8); break; case OpCode.Conv_Ovf_I2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2_Un, CoreSystemTypes.Int16); break; case OpCode.Conv_Ovf_I4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4_Un, CoreSystemTypes.Int32); break; case OpCode.Conv_Ovf_I8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8_Un, CoreSystemTypes.Int64); break; case OpCode.Conv_Ovf_U1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1_Un, CoreSystemTypes.UInt8); break; case OpCode.Conv_Ovf_U2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2_Un, CoreSystemTypes.UInt16); break; case OpCode.Conv_Ovf_U4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4_Un, CoreSystemTypes.UInt32); break; case OpCode.Conv_Ovf_U8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8_Un, CoreSystemTypes.UInt64); break; case OpCode.Conv_Ovf_I_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I_Un, CoreSystemTypes.IntPtr); break; case OpCode.Conv_Ovf_U_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U_Un, CoreSystemTypes.UIntPtr); break; case OpCode.Box: TypeNode t = (TypeNode)this.GetMemberFromToken(); TypeNode bt = t is EnumNode ? CoreSystemTypes.Enum : CoreSystemTypes.ValueType; expr = new BinaryExpression(PopOperand(), new Literal(t, CoreSystemTypes.Type), NodeType.Box, bt); break; case OpCode.Newarr: expr = this.ParseNewArray(); break; case OpCode.Ldlen: expr = new UnaryExpression(PopOperand(), NodeType.Ldlen, CoreSystemTypes.UIntPtr); break; case OpCode.Ldelema: expr = this.ParseArrayElementLoadAddress(); break; case OpCode.Ldelem_I1: case OpCode.Ldelem_U1: case OpCode.Ldelem_I2: case OpCode.Ldelem_U2: case OpCode.Ldelem_I4: case OpCode.Ldelem_U4: case OpCode.Ldelem_I8: case OpCode.Ldelem_I: case OpCode.Ldelem_R4: case OpCode.Ldelem_R8: case OpCode.Ldelem_Ref: expr = this.ParseArrayElementLoad(opCode, null); break; case OpCode.Stelem_I: case OpCode.Stelem_I1: case OpCode.Stelem_I2: case OpCode.Stelem_I4: case OpCode.Stelem_I8: case OpCode.Stelem_R4: case OpCode.Stelem_R8: case OpCode.Stelem_Ref: statement = this.ParseArrayElementAssignment(opCode); goto done; case OpCode.Ldelem: expr = this.ParseArrayElementLoad(opCode, null); break; case OpCode.Stelem: statement = this.ParseArrayElementAssignment(opCode); goto done; case OpCode.Unbox_Any: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.UnboxAny); break; case OpCode.Conv_Ovf_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1, CoreSystemTypes.Int8); break; case OpCode.Conv_Ovf_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1, CoreSystemTypes.UInt8); break; case OpCode.Conv_Ovf_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2, CoreSystemTypes.Int16); break; case OpCode.Conv_Ovf_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2, CoreSystemTypes.UInt16); break; case OpCode.Conv_Ovf_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4, CoreSystemTypes.Int32); break; case OpCode.Conv_Ovf_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4, CoreSystemTypes.UInt32); break; case OpCode.Conv_Ovf_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8, CoreSystemTypes.Int64); break; case OpCode.Conv_Ovf_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8, CoreSystemTypes.UInt64); break; case OpCode.Refanyval: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Refanyval, CoreSystemTypes.IntPtr); break; case OpCode.Ckfinite: expr = this.ParseUnaryOperation(NodeType.Ckfinite); break; case OpCode.Mkrefany: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Mkrefany, CoreSystemTypes.DynamicallyTypedReference); break; case OpCode.Ldtoken: expr = ParseLoadRuntimeMetadataToken(); break; case OpCode.Conv_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U2, CoreSystemTypes.UInt16); break; case OpCode.Conv_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U1, CoreSystemTypes.UInt8); break; case OpCode.Conv_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I, CoreSystemTypes.IntPtr); break; case OpCode.Conv_Ovf_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I, CoreSystemTypes.IntPtr); break; case OpCode.Conv_Ovf_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U, CoreSystemTypes.UIntPtr); break; case OpCode.Add_Ovf: expr = this.ParseBinaryOperation(NodeType.Add_Ovf); break; case OpCode.Add_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Add_Ovf_Un); break; case OpCode.Mul_Ovf: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf); break; case OpCode.Mul_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf_Un); break; case OpCode.Sub_Ovf: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf); break; case OpCode.Sub_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf_Un); break; case OpCode.Endfinally: statement = new EndFinally(); transferStatement = true; goto done; case OpCode.Leave: statement = this.ParseBranch(NodeType.Nop, 0, false, false, true); transferStatement = true; goto done; case OpCode.Leave_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false, true); transferStatement = true; goto done; case OpCode.Stind_I: statement = this.ParseStoreIndirect(CoreSystemTypes.IntPtr); goto done; case OpCode.Conv_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U, CoreSystemTypes.UIntPtr); break; case OpCode.Arglist: expr = new Expression(NodeType.Arglist, CoreSystemTypes.ArgIterator); break; case OpCode.Ceq: expr = this.ParseBinaryComparison(NodeType.Ceq); break; case OpCode.Cgt: expr = this.ParseBinaryComparison(NodeType.Cgt); break; case OpCode.Cgt_Un: expr = this.ParseBinaryComparison(NodeType.Cgt_Un); break; case OpCode.Clt: expr = this.ParseBinaryComparison(NodeType.Clt); break; case OpCode.Clt_Un: expr = this.ParseBinaryComparison(NodeType.Clt_Un); break; case OpCode.Ldftn: expr = new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldftn, CoreSystemTypes.IntPtr); break; case OpCode.Ldvirtftn: expr = new BinaryExpression(PopOperand(), new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldvirtftn, CoreSystemTypes.IntPtr); break; case OpCode.Ldarg: expr = this.Parameters((ushort)this.GetInt16()); break; case OpCode.Ldarga: expr = SetType(new UnaryExpression(this.Parameters((ushort)this.GetInt16()), NodeType.AddressOf)); break; case OpCode.Starg: statement = new AssignmentStatement(this.Parameters((ushort)this.GetInt16()), PopOperand()); goto done; case OpCode.Ldloc: expr = this.locals[(ushort)this.GetInt16()]; break; case OpCode.Ldloca: expr = SetType(new UnaryExpression(this.locals[(ushort)this.GetInt16()], NodeType.AddressOf)); break; case OpCode.Stloc: statement = new AssignmentStatement(this.locals[(ushort)this.GetInt16()], PopOperand()); goto done; case OpCode.Localloc: expr = new UnaryExpression(PopOperand(), NodeType.Localloc, CoreSystemTypes.Void); break; case OpCode.Endfilter: statement = new EndFilter(PopOperand()); transferStatement = true; goto done; case OpCode.Unaligned_: this.alignment = this.GetByte(); continue; case OpCode.Volatile_: this.isVolatile = true; continue; case OpCode.Tail_: this.isTailCall = true; continue; case OpCode.Initobj: statement = this.ParseInitObject(); goto done; case OpCode.Constrained_: this.constraint = this.GetMemberFromToken() as TypeNode; continue; case OpCode.Cpblk: expr = this.ParseTernaryOperation(NodeType.Cpblk); goto done; case OpCode.Initblk: expr = this.ParseTernaryOperation(NodeType.Initblk); goto done; case OpCode.Rethrow: statement = new Throw(null); statement.NodeType = NodeType.Rethrow; transferStatement = true; goto done; case OpCode.Sizeof: expr = new UnaryExpression(new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Sizeof, CoreSystemTypes.Int32); break; case OpCode.Refanytype: expr = new UnaryExpression(PopOperand(), NodeType.Refanytype, CoreSystemTypes.RuntimeTypeHandle); break; case OpCode.Readonly_: this.isReadOnly = true; continue; default: throw new InvalidMetadataException(ExceptionStrings.UnknownOpCode); } if (this.blockMap[this.counter + 1] != null) { transferStatement = true; //Falls through to the next basic block, so implicitly a "transfer" statement goto done; } //^ assume expr != null; #if FxCop expr.sourceContext = sourceContext; expr.ILOffset = this.ilOffset; #endif this.operandStack.Push(expr); this.isReadOnly = false; this.isVolatile = false; this.isTailCall = false; this.alignment = -1; } done: for (int i = 0; i <= this.operandStack.top; i++) { Expression e = this.operandStack.elements[i]; //^ assume e != null; Statement s = new ExpressionStatement(e); #if FxCop s.SourceContext = this.sourceContext; s.ILOffset = this.ilOffset; #endif statementList.Add(s); } this.operandStack.top = -1; if (statement == null) { statement = new ExpressionStatement(expr); #if FxCop expr.SourceContext = this.sourceContext; expr.ILOffset = this.ilOffset; #endif } statement.SourceContext = sourceContext; #if FxCop statement.ILOffset = this.ilOffset; #endif statementList.Add(statement); if (transferStatement) return true; return this.blockMap[this.counter + 1] != null; } private AssignmentStatement ParseStoreField() { Expression rhvalue = PopOperand(); Expression thisob = PopOperand(); AssignmentStatement s = new AssignmentStatement(new MemberBinding(thisob, this.GetMemberFromToken(), this.isVolatile, this.alignment), rhvalue); return s; } private AssignmentStatement ParseStoreIndirect(TypeNode type) { Expression rhvalue = PopOperand(); Expression lhaddr = PopOperand(); return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), rhvalue); } private SwitchInstruction ParseSwitchInstruction() { int numTargets = this.GetInt32(); int offset = this.counter + numTargets * 4; BlockList targetList = new BlockList(numTargets); for (int i = 0; i < numTargets; i++) { int targetAddress = this.GetInt32() + offset; targetList.Add(Reader.GetOrCreateBlock(this.blockMap, targetAddress)); } return new SwitchInstruction(PopOperand(), targetList); } private TernaryExpression ParseTernaryOperation(NodeType oper) { Expression op3 = PopOperand(); Expression op2 = PopOperand(); Expression op1 = PopOperand(); return new TernaryExpression(op1, op2, op3, oper, null); } private void CreateBlocksForBranchTargets() { int savedPosition = bodyReader.Position; while (this.counter < this.size) this.ProcessOneILInstruction(); this.counter = 0; bodyReader.Position = savedPosition; } private void ProcessOneILInstruction() { OpCode opc = this.GetOpCode(); switch (opc) { case OpCode.Ldarg_S: case OpCode.Ldarga_S: case OpCode.Starg_S: case OpCode.Ldloc_S: case OpCode.Ldloca_S: case OpCode.Stloc_S: case OpCode.Ldc_I4_S: this.GetByte(); return; case OpCode.Ldc_I4: case OpCode.Jmp: case OpCode.Call: case OpCode.Calli: case OpCode.Callvirt: case OpCode.Cpobj: case OpCode.Ldobj: case OpCode.Ldstr: case OpCode.Newobj: case OpCode.Castclass: case OpCode.Isinst: case OpCode.Unbox: case OpCode.Ldfld: case OpCode.Ldflda: case OpCode.Stfld: case OpCode.Ldsfld: case OpCode.Ldsflda: case OpCode.Stsfld: case OpCode.Stobj: case OpCode.Box: case OpCode.Newarr: case OpCode.Ldelema: case OpCode.Ldelem: case OpCode.Stelem: case OpCode.Unbox_Any: case OpCode.Refanyval: case OpCode.Mkrefany: case OpCode.Ldtoken: this.GetInt32(); return; case OpCode.Ldc_I8: this.GetInt64(); return; case OpCode.Ldc_R4: this.GetSingle(); return; case OpCode.Ldc_R8: this.GetDouble(); return; case OpCode.Br_S: case OpCode.Brfalse_S: case OpCode.Brtrue_S: case OpCode.Beq_S: case OpCode.Bge_S: case OpCode.Bgt_S: case OpCode.Ble_S: case OpCode.Blt_S: case OpCode.Bne_Un_S: case OpCode.Bge_Un_S: case OpCode.Bgt_Un_S: case OpCode.Ble_Un_S: case OpCode.Blt_Un_S: case OpCode.Leave_S: this.SkipBranch(true); return; case OpCode.Br: case OpCode.Brfalse: case OpCode.Brtrue: case OpCode.Beq: case OpCode.Bge: case OpCode.Bgt: case OpCode.Ble: case OpCode.Blt: case OpCode.Bne_Un: case OpCode.Bge_Un: case OpCode.Bgt_Un: case OpCode.Ble_Un: case OpCode.Blt_Un: case OpCode.Leave: this.SkipBranch(false); return; case OpCode.Switch: this.SkipSwitch(); return; case OpCode.Ldftn: case OpCode.Ldvirtftn: case OpCode.Initobj: case OpCode.Constrained_: case OpCode.Sizeof: this.GetInt32(); return; case OpCode.Ldarg: case OpCode.Ldarga: case OpCode.Ldloc: case OpCode.Ldloca: case OpCode.Starg: case OpCode.Stloc: this.GetInt16(); return; case OpCode.Unaligned_: this.GetByte(); return; default: return; } } private void SkipBranch(bool shortOffset) { int offset = shortOffset ? this.GetSByte() : this.GetInt32(); Reader.GetOrCreateBlock(blockMap, this.counter + offset); } private void SkipSwitch() { int numCases = this.GetInt32(); int offset = this.counter + numCases * 4; for (int i = 0; i < numCases; i++) { int targetAddress = this.GetInt32() + offset; Reader.GetOrCreateBlock(this.blockMap, targetAddress); } } private Expression PopOperand() { return this.operandStack.Pop(); } #if FxCop private OpCode opCode; private Block currentBlock; private SourceContext sourceContext; private int ilOffset; private Dictionary> tryMap; private Dictionary handlerMap; internal StatementList/*!*/ ParseStatements() { this.tryMap = new Dictionary>(); this.handlerMap = new Dictionary(); this.ParseHeader(); this.CreateBlocksForBranchTargets(); currentBlock = null; this.sourceContext = new SourceContext(); while (this.counter < size) { if (currentBlock == null) { currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter); } bool endOfBasicBlock = this.ParseStatement(currentBlock); if (endOfBasicBlock) { currentBlock.SourceContext = currentBlock.Statements[0].SourceContext; currentBlock = null; } } Reader.GetOrCreateBlock(this.blockMap, this.counter); int counter = 0; Block block = new Block(); block.Statements = new StatementList(); ProcessBlock(block, ref counter, this.size, null); return block.Statements; } override protected void ParseExceptionHandlerEntry(bool smallSection) { int dataSize = this.reader.tables.GetByte(); int n = (int)(ushort)this.reader.tables.GetInt16(); if (smallSection) n = dataSize / 12; else n = (dataSize + (n << 8)) / 24; for (int i = 0; i < n; i++) { int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset; if (smallSection) { flags = this.reader.tables.GetInt16(); tryOffset = this.reader.tables.GetUInt16(); tryLength = this.reader.tables.GetByte(); handlerOffset = this.reader.tables.GetUInt16(); handlerLength = this.reader.tables.GetByte(); } else { flags = this.reader.tables.GetInt32(); tryOffset = this.reader.tables.GetInt32(); tryLength = this.reader.tables.GetInt32(); handlerOffset = this.reader.tables.GetInt32(); handlerLength = this.reader.tables.GetInt32(); } tokenOrOffset = this.reader.tables.GetInt32(); Block tryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset); Block blockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset + tryLength); Block handlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset); Block blockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset + handlerLength); List tryList = null; if (!this.tryMap.TryGetValue(tryStartBlock, out tryList)) { this.tryMap[tryStartBlock] = tryList = new List(); } TryNode currentTry = null; int tryEnd = tryOffset + tryLength; foreach (TryNode t in tryList) { if (t.tryEnd == tryEnd) { currentTry = t; break; } } if (currentTry == null) { currentTry = new TryNode(); currentTry.tryEnd = tryEnd; tryList.Add(currentTry); } int handlerEnd = handlerOffset + handlerLength; if (currentTry.handlersEnd < handlerEnd) currentTry.handlersEnd = handlerEnd; Debug.Assert((int)flags != 3); Debug.Assert((int)flags < 5); switch (flags) { case 0x00: // for a catch handler, tokenOrOffset represents // the metadata token of the handler type. handlerOffset // is the literal offset for the catch block int pos = this.reader.tables.GetCurrentPosition(); TypeNode filterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset); this.reader.tables.SetCurrentPosition(pos); string variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture); StackVariable exception = new StackVariable(filterType, variableName); CatchNode c = new CatchNode(handlerStartBlock, exception, filterType); c.handlerEnd = handlerEnd; currentTry.Catchers.Add(c); this.handlerMap[handlerOffset] = exception; break; case 0x01: // for a filter, tokenOrOffset represents the IL offset // of the filter block. handlerOffset represents // the IL offset of the associated catch handler Block filterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset); variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture); exception = new StackVariable(CoreSystemTypes.Object, variableName); Filter filter = new Filter(filterExpression, exception); filter.handlerEnd = handlerOffset; c = new CatchNode(handlerStartBlock, exception, null, filter); c.handlerEnd = handlerEnd; currentTry.Catchers.Add(c); // note that handlerOffset would not be correct here! this.handlerMap[tokenOrOffset] = exception; break; case 0x02: FinallyNode f = new FinallyNode(handlerStartBlock); f.handlerEnd = handlerEnd; currentTry.Finally = f; break; case 0x04: FaultHandler fh = new FaultHandler(handlerStartBlock); fh.handlerEnd = handlerEnd; currentTry.FaultHandler = fh; break; } } } private void ProcessBlock(Block currentBlock, ref int counter, int blockEnd, Node blockNode) { while (true) { int lastCounter = counter; Block block = GetNextBlock(ref counter); if (block == null || block.ILOffset >= blockEnd) { counter = lastCounter; if (blockNode != null) blockNode.SourceContext = currentBlock.Statements[0].SourceContext; return; } if (this.tryMap.ContainsKey(block)) { ProcessTryBlock(currentBlock, block, ref counter); } else { if (currentBlock.Statements.Count == 0) currentBlock.SourceContext = block.SourceContext; currentBlock.Statements.Add(block); } } } private void ProcessTryBlock(Block outerBlock, Block currentBlock, ref int counter) { List tryList = this.tryMap[currentBlock]; TryNode outerTry = tryList[tryList.Count - 1]; outerBlock.Statements.Add(outerTry); tryList.Remove(outerTry); if (tryList.Count > 0) { outerTry.Block = new Block(); outerTry.Block.Statements = new StatementList(); ProcessTryBlock(outerTry.Block, currentBlock, ref counter); } else { outerTry.Block = currentBlock; } this.tryMap.Remove(currentBlock); ProcessBlock(outerTry.Block, ref counter, outerTry.tryEnd, outerTry); while (true) { int lastCounter = counter; Block block = GetNextBlock(ref counter); if (counter >= outerTry.handlersEnd) { counter = lastCounter; return; } int handlerEnd; Node handlerNode; GetHandlerEnd(outerTry, block, out handlerEnd, out handlerNode); ProcessBlock(block, ref counter, handlerEnd, handlerNode); } } private Block GetNextBlock(ref int counter) { while (true) { Block result = this.blockMap[counter + 1] as Block; ++counter; if (result != null || counter >= this.size) return result; } } private void GetHandlerEnd(TryNode t, Block block, out int handlerEnd, out Node handlerNode) { handlerEnd = Int32.MaxValue; handlerNode = null; int startPos = block.ILOffset; if (t.Finally != null && t.Finally.handlerEnd > startPos && t.Finally.handlerEnd < handlerEnd) { handlerEnd = t.Finally.handlerEnd; handlerNode = t.Finally; } foreach (CatchNode c in t.Catchers) { if (c.handlerEnd > startPos && c.handlerEnd < handlerEnd) { handlerEnd = c.handlerEnd; handlerNode = c; } if (c.Filter != null && c.Filter.handlerEnd > startPos && c.Filter.handlerEnd < handlerEnd) { handlerEnd = c.Filter.handlerEnd; handlerNode = c.Filter; } } if (t.FaultHandler != null && t.FaultHandler.handlerEnd > startPos && t.FaultHandler.handlerEnd < handlerEnd) { handlerEnd = t.FaultHandler.handlerEnd; handlerNode = t.FaultHandler; } } #endif } internal class InstructionParser : ILParser { private readonly TrivialHashtable/*!*/ ehMap; internal InstructionParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA) : base(reader, method, methodIndex, RVA) { this.ehMap = new TrivialHashtable(); } override protected void ParseExceptionHandlerEntry(bool smallSection) { TrivialHashtable tryMap = new TrivialHashtable(); int dataSize = this.reader.tables.GetByte(); int n = (int)(ushort)this.reader.tables.GetInt16(); if (smallSection) n = dataSize / 12; else n = (dataSize + (n << 8)) / 24; for (int i = 0; i < n; i++) { Instruction matchingInstruction; int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset; if (smallSection) { flags = this.reader.tables.GetInt16(); tryOffset = this.reader.tables.GetUInt16(); tryLength = this.reader.tables.GetByte(); handlerOffset = this.reader.tables.GetUInt16(); handlerLength = this.reader.tables.GetByte(); } else { flags = this.reader.tables.GetInt32(); tryOffset = this.reader.tables.GetInt32(); tryLength = this.reader.tables.GetInt32(); handlerOffset = this.reader.tables.GetInt32(); handlerLength = this.reader.tables.GetInt32(); } tokenOrOffset = this.reader.tables.GetInt32(); if (tryMap[tryOffset + tryLength] == null) { matchingInstruction = this.AddInstruction(OpCode._Try, tryOffset); this.AddInstruction(OpCode._EndTry, tryOffset + tryLength, matchingInstruction); tryMap[tryOffset + tryLength] = String.Empty; } switch (flags) { case 0x00: int pos = this.reader.tables.GetCurrentPosition(); TypeNode catchType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset); this.reader.tables.SetCurrentPosition(pos); matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset, catchType); this.AddInstruction(OpCode._EndHandler, handlerOffset + handlerLength, matchingInstruction); break; case 0x01: matchingInstruction = this.AddInstruction(OpCode._Filter, tokenOrOffset); this.AddInstruction(OpCode._EndFilter, handlerOffset, matchingInstruction); matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset); this.AddInstruction(OpCode._EndHandler, handlerOffset + handlerLength, matchingInstruction); break; case 0x02: matchingInstruction = this.AddInstruction(OpCode._Finally, handlerOffset); this.AddInstruction(OpCode._EndHandler, handlerOffset + handlerLength, matchingInstruction); break; case 0x04: matchingInstruction = this.AddInstruction(OpCode._Fault, handlerOffset); this.AddInstruction(OpCode._EndHandler, handlerOffset + handlerLength, matchingInstruction); break; default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType); } } } private Instruction AddInstruction(OpCode opCode, int offset) { return this.AddInstruction(opCode, offset, null); } private Instruction AddInstruction(OpCode opCode, int offset, object value) { Instruction instruction = new Instruction(opCode, offset, value); InstructionList instructions = (InstructionList)this.ehMap[offset + 1]; if (instructions == null) this.ehMap[offset + 1] = instructions = new InstructionList(2); instructions.Add(instruction); #if !ROTOR if (this.method.contextForOffset != null) { object sctx = this.method.contextForOffset[offset + 1]; if (sctx != null) instruction.SourceContext = (SourceContext)sctx; } #endif return instruction; } private Int32List ParseSwitchInstruction() { int numTargets = this.GetInt32(); Int32List result = new Int32List(numTargets); int offset = this.counter + numTargets * 4; for (int i = 0; i < numTargets; i++) { int targetAddress = this.GetInt32() + offset; result.Add(targetAddress); } return result; } internal InstructionList ParseInstructions() { this.ParseHeader(); if (this.size == 0) return new InstructionList(0); InstructionList result = new InstructionList(); result.Add(new Instruction(OpCode._Locals, 0, this.locals)); while (this.counter <= size) { InstructionList instructions = (InstructionList)this.ehMap[this.counter + 1]; if (instructions != null) { for (int i = 0; i < instructions.Count; i++) result.Add(instructions[i]); } if (this.counter < size) result.Add(this.ParseInstruction()); else break; } return result; } private SourceContext sourceContext = new SourceContext(); internal Instruction ParseInstruction() { if (this.counter >= this.size) return null; int offset = this.counter; #if !ROTOR if (this.method.contextForOffset != null) { object sctx = this.method.contextForOffset[offset + 1]; if (sctx != null) this.sourceContext = (SourceContext)sctx; } #endif object value = null; OpCode opCode = this.GetOpCode(); switch (opCode) { case OpCode.Nop: case OpCode.Break: break; case OpCode.Ldarg_0: value = this.Parameters(0); break; case OpCode.Ldarg_1: value = this.Parameters(1); break; case OpCode.Ldarg_2: value = this.Parameters(2); break; case OpCode.Ldarg_3: value = this.Parameters(3); break; case OpCode.Ldloc_0: value = this.locals[0]; break; case OpCode.Ldloc_1: value = this.locals[1]; break; case OpCode.Ldloc_2: value = this.locals[2]; break; case OpCode.Ldloc_3: value = this.locals[3]; break; case OpCode.Stloc_0: value = this.locals[0]; break; case OpCode.Stloc_1: value = this.locals[1]; break; case OpCode.Stloc_2: value = this.locals[2]; break; case OpCode.Stloc_3: value = this.locals[3]; break; case OpCode.Ldarg_S: case OpCode.Ldarga_S: case OpCode.Starg_S: value = this.Parameters(this.GetByte()); break; case OpCode.Ldloc_S: case OpCode.Ldloca_S: case OpCode.Stloc_S: value = this.locals[this.GetByte()]; break; case OpCode.Ldnull: break; case OpCode.Ldc_I4_M1: value = (Int32)(-1); break; case OpCode.Ldc_I4_0: value = (Int32)0; break; case OpCode.Ldc_I4_1: value = (Int32)1; break; case OpCode.Ldc_I4_2: value = (Int32)2; break; case OpCode.Ldc_I4_3: value = (Int32)3; break; case OpCode.Ldc_I4_4: value = (Int32)4; break; case OpCode.Ldc_I4_5: value = (Int32)5; break; case OpCode.Ldc_I4_6: value = (Int32)6; break; case OpCode.Ldc_I4_7: value = (Int32)7; break; case OpCode.Ldc_I4_8: value = (Int32)8; break; case OpCode.Ldc_I4_S: value = (Int32)this.GetSByte(); break; case OpCode.Ldc_I4: value = this.GetInt32(); break; case OpCode.Ldc_I8: value = this.GetInt64(); break; case OpCode.Ldc_R4: value = this.GetSingle(); break; case OpCode.Ldc_R8: value = this.GetDouble(); break; case OpCode.Dup: case OpCode.Pop: break; case OpCode.Jmp: case OpCode.Call: value = (Method)this.GetMemberFromToken(); break; case OpCode.Calli: value = (FunctionPointer)this.reader.GetCalliSignature(this.GetInt32()); break; case OpCode.Ret: break; case OpCode.Br_S: case OpCode.Brfalse_S: case OpCode.Brtrue_S: case OpCode.Beq_S: case OpCode.Bge_S: case OpCode.Bgt_S: case OpCode.Ble_S: case OpCode.Blt_S: case OpCode.Bne_Un_S: case OpCode.Bge_Un_S: case OpCode.Bgt_Un_S: case OpCode.Ble_Un_S: case OpCode.Blt_Un_S: value = this.counter + 1 + this.GetSByte(); break; case OpCode.Br: case OpCode.Brfalse: case OpCode.Brtrue: case OpCode.Beq: case OpCode.Bge: case OpCode.Bgt: case OpCode.Ble: case OpCode.Blt: case OpCode.Bne_Un: case OpCode.Bge_Un: case OpCode.Bgt_Un: case OpCode.Ble_Un: case OpCode.Blt_Un: value = this.counter + 4 + this.GetInt32(); break; case OpCode.Switch: value = this.ParseSwitchInstruction(); break; case OpCode.Ldind_I1: case OpCode.Ldind_U1: case OpCode.Ldind_I2: case OpCode.Ldind_U2: case OpCode.Ldind_I4: case OpCode.Ldind_U4: case OpCode.Ldind_I8: case OpCode.Ldind_I: case OpCode.Ldind_R4: case OpCode.Ldind_R8: case OpCode.Ldind_Ref: case OpCode.Stind_Ref: case OpCode.Stind_I1: case OpCode.Stind_I2: case OpCode.Stind_I4: case OpCode.Stind_I8: case OpCode.Stind_R4: case OpCode.Stind_R8: case OpCode.Add: case OpCode.Sub: case OpCode.Mul: case OpCode.Div: case OpCode.Div_Un: case OpCode.Rem: case OpCode.Rem_Un: case OpCode.And: case OpCode.Or: case OpCode.Xor: case OpCode.Shl: case OpCode.Shr: case OpCode.Shr_Un: case OpCode.Neg: case OpCode.Not: case OpCode.Conv_I1: case OpCode.Conv_I2: case OpCode.Conv_I4: case OpCode.Conv_I8: case OpCode.Conv_R4: case OpCode.Conv_R8: case OpCode.Conv_U4: case OpCode.Conv_U8: break; case OpCode.Callvirt: value = (Method)this.GetMemberFromToken(); break; case OpCode.Cpobj: case OpCode.Ldobj: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Ldstr: value = this.GetStringFromToken(); break; case OpCode.Newobj: value = (Method)this.GetMemberFromToken(); break; case OpCode.Castclass: case OpCode.Isinst: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Conv_R_Un: break; case OpCode.Unbox: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Throw: break; case OpCode.Ldfld: case OpCode.Ldflda: case OpCode.Stfld: case OpCode.Ldsfld: case OpCode.Ldsflda: case OpCode.Stsfld: case OpCode.Stobj: value = this.GetMemberFromToken(); break; case OpCode.Conv_Ovf_I1_Un: case OpCode.Conv_Ovf_I2_Un: case OpCode.Conv_Ovf_I4_Un: case OpCode.Conv_Ovf_I8_Un: case OpCode.Conv_Ovf_U1_Un: case OpCode.Conv_Ovf_U2_Un: case OpCode.Conv_Ovf_U4_Un: case OpCode.Conv_Ovf_U8_Un: case OpCode.Conv_Ovf_I_Un: case OpCode.Conv_Ovf_U_Un: break; case OpCode.Box: case OpCode.Newarr: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Ldlen: break; case OpCode.Ldelema: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Ldelem_I1: case OpCode.Ldelem_U1: case OpCode.Ldelem_I2: case OpCode.Ldelem_U2: case OpCode.Ldelem_I4: case OpCode.Ldelem_U4: case OpCode.Ldelem_I8: case OpCode.Ldelem_I: case OpCode.Ldelem_R4: case OpCode.Ldelem_R8: case OpCode.Ldelem_Ref: case OpCode.Stelem_I: case OpCode.Stelem_I1: case OpCode.Stelem_I2: case OpCode.Stelem_I4: case OpCode.Stelem_I8: case OpCode.Stelem_R4: case OpCode.Stelem_R8: case OpCode.Stelem_Ref: break; case OpCode.Ldelem: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Stelem: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Unbox_Any: value = this.GetMemberFromToken(); break; case OpCode.Conv_Ovf_I1: case OpCode.Conv_Ovf_U1: case OpCode.Conv_Ovf_I2: case OpCode.Conv_Ovf_U2: case OpCode.Conv_Ovf_I4: case OpCode.Conv_Ovf_U4: case OpCode.Conv_Ovf_I8: case OpCode.Conv_Ovf_U8: break; case OpCode.Refanyval: value = this.GetMemberFromToken(); break; case OpCode.Ckfinite: break; case OpCode.Mkrefany: value = this.GetMemberFromToken(); break; case OpCode.Ldtoken: value = this.GetMemberFromToken(); break; case OpCode.Conv_U2: case OpCode.Conv_U1: case OpCode.Conv_I: case OpCode.Conv_Ovf_I: case OpCode.Conv_Ovf_U: case OpCode.Add_Ovf: case OpCode.Add_Ovf_Un: case OpCode.Mul_Ovf: case OpCode.Mul_Ovf_Un: case OpCode.Sub_Ovf: case OpCode.Sub_Ovf_Un: case OpCode.Endfinally: break; case OpCode.Leave: value = this.counter + 4 + this.GetInt32(); break; case OpCode.Leave_S: value = this.counter + 1 + this.GetSByte(); break; case OpCode.Stind_I: case OpCode.Conv_U: case OpCode.Prefix7: case OpCode.Prefix6: case OpCode.Prefix5: case OpCode.Prefix4: case OpCode.Prefix3: case OpCode.Prefix2: case OpCode.Prefix1: case OpCode.Arglist: case OpCode.Ceq: case OpCode.Cgt: case OpCode.Cgt_Un: case OpCode.Clt: case OpCode.Clt_Un: break; case OpCode.Ldftn: case OpCode.Ldvirtftn: value = this.GetMemberFromToken(); break; case OpCode.Ldarg: case OpCode.Ldarga: case OpCode.Starg: value = this.Parameters(this.GetInt16()); break; case OpCode.Ldloc: case OpCode.Ldloca: case OpCode.Stloc: value = this.locals[this.GetInt16()]; break; case OpCode.Localloc: case OpCode.Endfilter: break; case OpCode.Unaligned_: value = this.GetByte(); break; case OpCode.Volatile_: case OpCode.Tail_: break; case OpCode.Initobj: value = (TypeNode)this.GetMemberFromToken(); break; case OpCode.Constrained_: value = this.GetMemberFromToken() as TypeNode; break; case OpCode.Cpblk: case OpCode.Initblk: break; case OpCode.Rethrow: break; case OpCode.Sizeof: value = this.GetMemberFromToken(); break; case OpCode.Refanytype: case OpCode.Readonly_: break; default: throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.UnknownOpCodeEncountered, opCode.ToString("x"))); } Instruction instruction = new Instruction(opCode, offset, value); instruction.SourceContext = this.sourceContext; return instruction; } } internal class ExpressionStack { internal Expression[]/*!*/ elements = new Expression[64]; internal int top = -1; internal ExpressionStack() { //^ base(); } private void Grow() { int n = this.elements.Length; Expression[] newElements = new Expression[n + 64]; for (int i = 0; i < n; i++) newElements[i] = this.elements[i]; this.elements = newElements; } internal Expression/*!*/ Pop() { if (this.top < 0) return new Expression(NodeType.Pop); Expression e = this.elements[this.top--]; //^ assume e != null; return e; } internal void Push(Expression/*!*/ e) { if (++this.top >= this.elements.Length) this.Grow(); this.elements[this.top] = e; } } /// /// A thin wrapper for a synchronized System.Collections.Hashtable that inserts and strips WeakReference wrappers for the values stored in the table. /// internal class SynchronizedWeakDictionary : IDictionary { private Hashtable/*!*/ Hashtable = System.Collections.Hashtable.Synchronized(new Hashtable()); internal SynchronizedWeakDictionary() { //^ base(); } public void Add(object/*!*/ key, object value) { this.Hashtable.Add(key, new WeakReference(value)); } public void Clear() { this.Hashtable.Clear(); } public bool Contains(object/*!*/ key) { return this.Hashtable.Contains(key); } public IDictionaryEnumerator/*!*/ GetEnumerator() { return this.Hashtable.GetEnumerator(); } public bool IsFixedSize { get { return false; } } public bool IsReadOnly { get { return false; } } public ICollection/*!*/ Keys { get { return this.Hashtable.Keys; } } public void Remove(object/*!*/ key) { this.Hashtable.Remove(key); } public ICollection/*!*/ Values { get { return new WeakValuesCollection(this.Hashtable.Values); } } public object this[object/*!*/ key] { get { WeakReference wref = (WeakReference)this.Hashtable[key]; if (wref == null) return null; return wref.Target; } set { this.Hashtable[key] = new WeakReference(value); } } public void CopyTo(Array/*!*/ array, int index) { IEnumerator enumerator = this.GetEnumerator(); for (int i = 0; enumerator.MoveNext(); i++) array.SetValue(enumerator.Current, index + i); } public int Count { get { return this.Hashtable.Count; } } public bool IsSynchronized { get { return false; } } public object/*!*/ SyncRoot { get { return this.Hashtable.SyncRoot; } } IEnumerator/*!*/ IEnumerable.GetEnumerator() { return new WeakValuesEnumerator(this.Hashtable.GetEnumerator()); } } internal class WeakValuesCollection : ICollection { private ICollection/*!*/ collection; internal WeakValuesCollection(ICollection/*!*/ collection) { this.collection = collection; //^ base(); } public void CopyTo(Array/*!*/ array, int index) { IEnumerator enumerator = this.GetEnumerator(); for (int i = 0; enumerator.MoveNext(); i++) array.SetValue(enumerator.Current, index + i); } public int Count { get { return this.collection.Count; } } public bool IsSynchronized { get { return this.collection.IsSynchronized; } } public object/*!*/ SyncRoot { get { return this.collection.SyncRoot; } } public IEnumerator/*!*/ GetEnumerator() { return new WeakValuesEnumerator(this.collection.GetEnumerator()); } } internal class WeakValuesEnumerator : IEnumerator { private IEnumerator/*!*/ enumerator; internal WeakValuesEnumerator(IEnumerator/*!*/ enumerator) { this.enumerator = enumerator; //^ base(); } public object Current { get { object curr = this.enumerator.Current; if (curr is DictionaryEntry) { DictionaryEntry dicEntry = (DictionaryEntry)curr; curr = dicEntry.Value; } WeakReference wref = curr as WeakReference; if (wref != null) return wref.Target; return null; } } public bool MoveNext() { return this.enumerator.MoveNext(); } public void Reset() { this.enumerator.Reset(); } } #if !ROTOR && NoWriter [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")] internal interface IMetaDataImport{} internal class EmptyImporter : IMetaDataImport{} #endif #if FxCop class StackVariable : Local { internal StackVariable(TypeNode type, string name) : base(type) { this.NodeType = NodeType.StackVariable; this.Name = Identifier.For(name); } internal StackVariable(TypeNode type, int index) : base(type) { this.NodeType = NodeType.StackVariable; this.Name = Identifier.For("stack$" + index.ToString(CultureInfo.InvariantCulture)); } } #endif }