Ejemplo n.º 1
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >();

            // Build a map from inlinee to the list of inliners
            // We are only interested in the generic definitions of these.
            foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods())
            {
                MethodDesc[] inlinees          = methodNode.InlinedMethods;
                MethodDesc   inliner           = methodNode.Method;
                MethodDesc   inlinerDefinition = inliner.GetTypicalMethodDefinition();

                foreach (MethodDesc inlinee in inlinees)
                {
                    MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition();
                    if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition))
                    {
                        // We don't record non-ECMA methods because they don't have tokens that
                        // diagnostic tools could reason about anyway.
                        continue;
                    }

                    if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners))
                    {
                        inliners = new HashSet <EcmaMethod>();
                        inlineeToInliners.Add(ecmaInlineeDefinition, inliners);
                    }
                    inliners.Add((EcmaMethod)inlinerDefinition);
                }
            }

            // Serialize the map as a hash table
            NativeWriter writer  = new NativeWriter();
            Section      section = writer.NewSection();

            VertexHashtable hashtable = new VertexHashtable();

            section.Place(hashtable);

            foreach (var inlineeWithInliners in inlineeToInliners)
            {
                EcmaMethod inlinee    = inlineeWithInliners.Key;
                int        inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle);
                int        hashCode   = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module);
                hashCode ^= inlineeRid;

                // Format of the sequence:
                // Inlinee RID with flag in the lowest bit
                // - if flag is set, followed by module ID
                // Followed by inliner RIDs deltas with flag in the lowest bit
                // - if flag is set, followed by module ID

                var sig = new VertexSequence();

                bool isForeignInlinee = inlinee.Module != _globalContext;
                sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0))));
                if (isForeignInlinee)
                {
                    sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                }

                List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value);
                sortedInliners.Sort((a, b) =>
                {
                    if (a == b)
                    {
                        return(0);
                    }

                    int aRid = MetadataTokens.GetRowNumber(a.Handle);
                    int bRid = MetadataTokens.GetRowNumber(b.Handle);
                    if (aRid < bRid)
                    {
                        return(-1);
                    }
                    else if (aRid > bRid)
                    {
                        return(1);
                    }

                    int result = a.Module.CompareTo(b.Module);
                    Debug.Assert(result != 0);
                    return(result);
                });

                int baseRid = 0;
                foreach (EcmaMethod inliner in sortedInliners)
                {
                    int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle);
                    int ridDelta   = inlinerRid - baseRid;
                    baseRid = inlinerRid;
                    Debug.Assert(ridDelta >= 0);
                    bool isForeignInliner = inliner.Module != _globalContext;
                    sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0))));
                    if (isForeignInliner)
                    {
                        sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                    }
                }

                hashtable.Append((uint)hashCode, section.Place(sig));
            }

            MemoryStream writerContent = new MemoryStream();

            writer.Save(writerContent);

            return(new ObjectData(
                       data: writerContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }
Ejemplo n.º 2
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolNode[] { this });

            var writer = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();
            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping())
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                    continue;

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.HasReflectionInvokeStub(method))
                    continue;

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                    flags |= InvokeTableFlags.IsGenericMethod;

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                    flags |= InvokeTableFlags.RequiresInstArg;

                // TODO: better check for default public(!) constructor
                if (method.IsConstructor && method.Signature.Length == 0)
                    flags |= InvokeTableFlags.IsDefaultConstructor;

                // TODO: HasVirtualInvoke

                if (!method.IsAbstract)
                    flags |= InvokeTableFlags.HasEntrypoint;

                // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set.
                flags |= InvokeTableFlags.HasMetadataHandle;

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                    continue;

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask)));
                }
                else
                {
                    // TODO: no MD handle case
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(
                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))));
                }

                // TODO: data to generate the generic dictionary with the type loader
                MethodDesc invokeStubMethod = factory.MetadataManager.GetReflectionInvokeStub(method);
                MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                if (invokeStubMethod != canonInvokeStubMethod)
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1));
                }
                else
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1));
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            MemoryStream ms = new MemoryStream();
            writer.Save(ms);
            byte[] hashTableBytes = ms.ToArray();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolNode[] { this, _endSymbol });
        }
Ejemplo n.º 3
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Ensure the native layout blob has been saved
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory))
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                {
                    continue;
                }

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.IsReflectionInvokable(method))
                {
                    continue;
                }

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                {
                    flags |= InvokeTableFlags.IsGenericMethod;
                }

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                {
                    flags |= InvokeTableFlags.RequiresInstArg;
                }

                if (method.IsDefaultConstructor)
                {
                    flags |= InvokeTableFlags.IsDefaultConstructor;
                }

                if (ReflectionVirtualInvokeMapNode.NeedsVirtualInvokeInfo(method))
                {
                    flags |= InvokeTableFlags.HasVirtualInvoke;
                }

                if (!method.IsAbstract)
                {
                    flags |= InvokeTableFlags.HasEntrypoint;
                }

                if (mappingEntry.MetadataHandle != 0)
                {
                    flags |= InvokeTableFlags.HasMetadataHandle;
                }

                if (!factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method))
                {
                    flags |= InvokeTableFlags.NeedsParameterInterpretation;
                }

                if (method.IsCanonicalMethod(CanonicalFormKind.Universal))
                {
                    flags |= InvokeTableFlags.IsUniversalCanonicalEntry;
                }

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataManager.MetadataOffsetMask)));
                }
                else
                {
                    var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()));
                    vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic;
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(
                                                                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub))));
                }

                if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0)
                {
                    MethodDesc canonInvokeStubMethod = factory.MetadataManager.GetCanonicalReflectionInvokeStub(method);
                    if (canonInvokeStubMethod.IsSharedByGenericInstantiations)
                    {
                        vertex = writer.GetTuple(vertex,
                                                 writer.GetUnsignedConstant(((uint)factory.MetadataManager.DynamicInvokeTemplateData.GetIdForMethod(canonInvokeStubMethod) << 1) | 1));
                    }
                    else
                    {
                        vertex = writer.GetTuple(vertex,
                                                 writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(canonInvokeStubMethod)) << 1));
                    }
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0)
                    {
                        var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSigGenericMethod.SavedVertex.VertexOffset));
                    }
                    else if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // Dependencies for this node are tracked by the method code nodes
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            NativeWriter    nativeWriter  = new NativeWriter();
            VertexHashtable hashtable     = new VertexHashtable();
            Section         nativeSection = nativeWriter.NewSection();

            nativeSection.Place(hashtable);


            foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods())
            {
                if (!IsMethodEligibleForTracking(method))
                {
                    continue;
                }

                // Get the method pointer vertex

                bool        getUnboxingStub      = method.OwningType.IsValueType && !method.Signature.IsStatic;
                IMethodNode methodEntryPointNode = factory.MethodEntrypoint(method, getUnboxingStub);
                Vertex      methodPointer        = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(methodEntryPointNode));

                // Get native layout vertices for the declaring type

                ISymbolNode declaringTypeNode = factory.NecessaryTypeSymbol(method.OwningType);
                Vertex      declaringType     = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(declaringTypeNode));

                // Get a vertex sequence for the method instantiation args if any

                VertexSequence arguments = new VertexSequence();
                foreach (var arg in method.Instantiation)
                {
                    ISymbolNode argNode = factory.NecessaryTypeSymbol(arg);
                    arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode)));
                }

                // Get the name and sig of the method.
                // Note: the method name and signature are stored in the NativeLayoutInfo blob, not in the hashtable we build here.

                NativeLayoutMethodNameAndSignatureVertexNode nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                NativeLayoutPlacedSignatureVertexNode        placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);
                Debug.Assert(placedNameAndSig.SavedVertex != null);
                Vertex placedNameAndSigOffsetSig = nativeWriter.GetOffsetSignature(placedNameAndSig.SavedVertex);

                // Get the vertex for the completed method signature

                Vertex methodSignature = nativeWriter.GetTuple(declaringType, placedNameAndSigOffsetSig, arguments);

                // Make the generic method entry vertex

                Vertex entry = nativeWriter.GetTuple(methodSignature, methodPointer);

                // Add to the hash table, hashed by the containing type's hashcode
                uint hashCode = (uint)method.OwningType.GetHashCode();
                hashtable.Append(hashCode, nativeSection.Place(entry));
            }

            byte[] streamBytes = nativeWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
Ejemplo n.º 5
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this }));
            }

            // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            NativeWriter    nativeWriter  = new NativeWriter();
            VertexHashtable hashtable     = new VertexHashtable();
            Section         nativeSection = nativeWriter.NewSection();

            nativeSection.Place(hashtable);

            foreach (var dictionaryNode in factory.MetadataManager.GetCompiledGenericDictionaries())
            {
                MethodGenericDictionaryNode methodDictionary = dictionaryNode as MethodGenericDictionaryNode;
                if (methodDictionary == null)
                {
                    continue;
                }

                MethodDesc method = methodDictionary.OwningMethod;

                Debug.Assert(method.HasInstantiation && !method.IsCanonicalMethod(CanonicalFormKind.Any));

                Vertex fullMethodSignature;
                {
                    // Method's containing type
                    IEETypeNode containingTypeNode = factory.NecessaryTypeSymbol(method.OwningType);
                    Vertex      containingType     = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeNode));

                    // Method's instantiation arguments
                    VertexSequence arguments = new VertexSequence();
                    for (int i = 0; i < method.Instantiation.Length; i++)
                    {
                        IEETypeNode argNode = factory.NecessaryTypeSymbol(method.Instantiation[i]);
                        arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode)));
                    }

                    // Method name and signature
                    NativeLayoutVertexNode      nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                    NativeLayoutSavedVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);
                    Vertex placedNameAndSigVertexOffset          = nativeWriter.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset);

                    fullMethodSignature = nativeWriter.GetTuple(containingType, placedNameAndSigVertexOffset, arguments);
                }

                // Method's dictionary pointer
                Vertex dictionaryVertex = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(dictionaryNode));

                Vertex entry = nativeWriter.GetTuple(dictionaryVertex, fullMethodSignature);

                hashtable.Append((uint)method.GetHashCode(), nativeSection.Place(entry));
            }

            byte[] streamBytes = nativeWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }
Ejemplo n.º 6
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this }));
            }

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping())
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                {
                    continue;
                }

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.HasReflectionInvokeStub(method))
                {
                    continue;
                }

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                {
                    flags |= InvokeTableFlags.IsGenericMethod;
                }

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                {
                    flags |= InvokeTableFlags.RequiresInstArg;
                }

                // TODO: better check for default public(!) constructor
                if (method.IsConstructor && method.Signature.Length == 0)
                {
                    flags |= InvokeTableFlags.IsDefaultConstructor;
                }

                // TODO: HasVirtualInvoke

                if (!method.IsAbstract)
                {
                    flags |= InvokeTableFlags.HasEntrypoint;
                }

                // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set.
                flags |= InvokeTableFlags.HasMetadataHandle;

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask)));
                }
                else
                {
                    // TODO: no MD handle case
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(
                                                                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))));
                }

                // TODO: data to generate the generic dictionary with the type loader
                MethodDesc invokeStubMethod      = factory.MetadataManager.GetReflectionInvokeStub(method);
                MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                if (invokeStubMethod != canonInvokeStubMethod)
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1));
                }
                else
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1));
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            MemoryStream ms = new MemoryStream();

            writer.Save(ms);
            byte[] hashTableBytes = ms.ToArray();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }
Ejemplo n.º 7
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >();

            // Build a map from inlinee to the list of inliners
            // We are only interested in the generic definitions of these.
            foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods(_module, CompiledMethodCategory.All))
            {
                MethodDesc[] inlinees          = methodNode.InlinedMethods;
                MethodDesc   inliner           = methodNode.Method;
                EcmaMethod   inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition();

                if (inlinerDefinition.IsNonVersionable())
                {
                    // Non-versionable methods don't need to be reported
                    continue;
                }

                // Only encode inlining info for inliners within the active module, or if cross module inline format is in use
                Debug.Assert(AllowCrossModuleInlines || (inlinerDefinition.Module == _module));

                bool inlinerReportAllVersionsWithInlinee = !AllowCrossModuleInlines || factory.CompilationModuleGroup.CrossModuleCompileable(inlinerDefinition);

                foreach (MethodDesc inlinee in inlinees)
                {
                    MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition();
                    if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition))
                    {
                        // We don't record non-ECMA methods because they don't have tokens that
                        // diagnostic tools could reason about anyway.
                        continue;
                    }

                    if (inlinee.IsNonVersionable())
                    {
                        // Non-versionable methods don't need to be reported
                        continue;
                    }

                    if (ReportAllInlinesInSearch)
                    {
                        // We'll definitely track this inline
                    }
                    else if (factory.CompilationModuleGroup.VersionsWithMethodBody(inlineeDefinition))
                    {
                        if (!inlinerReportAllVersionsWithInlinee)
                        {
                            // We'll won't report this method
                            continue;
                        }
                    }
                    else
                    {
                        Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(inlineeDefinition));
                        if (_inlineInfoType != InfoType.CrossModuleInliningForCrossModuleDataOnly)
                        {
                            // We'll won't report this method
                            continue;
                        }
                    }

                    if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners))
                    {
                        inliners = new HashSet <EcmaMethod>();
                        inlineeToInliners.Add(ecmaInlineeDefinition, inliners);
                    }
                    inliners.Add((EcmaMethod)inlinerDefinition);
                }
            }

            // Serialize the map as a hash table
            NativeWriter writer  = new NativeWriter();
            Section      section = writer.NewSection();

            VertexHashtable hashtable = new VertexHashtable();

            section.Place(hashtable);

            foreach (var inlineeWithInliners in inlineeToInliners)
            {
                EcmaMethod inlinee    = inlineeWithInliners.Key;
                int        inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle);
                int        hashCode;

                if (AllowCrossModuleInlines)
                {
                    // CrossModuleInlineInfo format
                    hashCode = ReadyToRunHashCode.MethodHashCode(inlinee);
                }
                else
                {
                    // InliningInfo2 format
                    hashCode  = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module);
                    hashCode ^= inlineeRid;
                }

                var sig = new VertexSequence();

                if (!AllowCrossModuleInlines)
                {
                    // Format of the sequence:
                    // FOR InliningInfo2 table format
                    //    Inlinee RID with flag in the lowest bit
                    //    - if flag is set, followed by module ID
                    //    Followed by inliner RIDs deltas with flag in the lowest bit
                    //    - if flag is set, followed by module ID
                    Debug.Assert(_module != null);
                    bool isForeignInlinee = inlinee.Module != _module;
                    sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0))));
                    if (isForeignInlinee)
                    {
                        sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                    }

                    List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value);
                    sortedInliners.MergeSort((a, b) =>
                    {
                        if (a == b)
                        {
                            return(0);
                        }

                        int aRid = MetadataTokens.GetRowNumber(a.Handle);
                        int bRid = MetadataTokens.GetRowNumber(b.Handle);
                        if (aRid < bRid)
                        {
                            return(-1);
                        }
                        else if (aRid > bRid)
                        {
                            return(1);
                        }

                        int result = a.Module.CompareTo(b.Module);
                        Debug.Assert(result != 0);
                        return(result);
                    });

                    int baseRid = 0;
                    foreach (EcmaMethod inliner in sortedInliners)
                    {
                        int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle);
                        int ridDelta   = inlinerRid - baseRid;
                        baseRid = inlinerRid;
                        Debug.Assert(ridDelta >= 0);
                        bool isForeignInliner = inliner.Module != _module;
                        sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0))));
                        if (isForeignInliner)
                        {
                            sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                        }
                    }
                }
                else
                {
                    // Format of the sequence:
                    // FOR CrossModuleInlineInfo format
                    //    Index with 2 flags field in lowest 2 bits to define the inlinee
                    //      - If flags & 1 == 0 then index is a MethodDef RID, and if the module is a composite image, a module index of the method follows
                    //      - If flags & 1 == 1, then index is an index into the ILBody import section
                    //      - If flags & 2 == 0 then what follows is:
                    //        - Inliner RID deltas - See definition below
                    //      - if flags & 2 == 2 then what follows is:
                    //        - count of delta encoded indices into the ILBody import section
                    //        - the sequence of delta encoded indices into the ILBody import section
                    //        - Inliner RID deltas - See definition below
                    //
                    //      Inliner RID deltas (for multi-module version bubble images (specified by the module having the READYTORUN_FLAG_MULTIMODULE_VERSION_BUBBLE flag set)
                    //        - a sequence of inliner RID deltas with flag in the lowest bit
                    //          - if flag is set, the inliner RID is followed by a module ID
                    //          - otherwise the module is the same as the module of the inlinee method
                    //
                    //      Inliner RID deltas (for single module version bubble images)
                    //        - a sequence of inliner RID deltas

                    bool crossModuleMultiModuleFormat = (factory.CompilationModuleGroup.GetReadyToRunFlags() & ReadyToRunFlags.READYTORUN_FLAG_MultiModuleVersionBubble) != 0;

                    Debug.Assert(_module == null);
                    bool isCrossModuleInlinee = !factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee);
                    Debug.Assert(!isCrossModuleInlinee || factory.CompilationModuleGroup.CrossModuleInlineable(inlinee));

                    EcmaMethod[] sortedInliners = new EcmaMethod[inlineeWithInliners.Value.Count];
                    inlineeWithInliners.Value.CopyTo(sortedInliners);

                    sortedInliners.MergeSort((a, b) =>
                    {
                        if (a == b)
                        {
                            return(0);
                        }

                        bool isCrossModuleInlinerA = !factory.CompilationModuleGroup.VersionsWithMethodBody(a);
                        bool isCrossModuleInlinerB = !factory.CompilationModuleGroup.VersionsWithMethodBody(b);
                        if (isCrossModuleInlinerA != isCrossModuleInlinerB)
                        {
                            if (isCrossModuleInlinerA)
                            {
                                return(-1);
                            }
                            else
                            {
                                return(1);
                            }
                        }

                        int result;
                        if (isCrossModuleInlinerA)
                        {
                            int indexA = _symbolNodeFactory.CheckILBodyFixupSignature(a).IndexFromBeginningOfArray;
                            int indexB = _symbolNodeFactory.CheckILBodyFixupSignature(b).IndexFromBeginningOfArray;
                            Debug.Assert(indexA != indexB);
                            result = indexA.CompareTo(indexB);
                        }
                        else
                        {
                            int aRid = MetadataTokens.GetRowNumber(a.Handle);
                            int bRid = MetadataTokens.GetRowNumber(b.Handle);
                            if (aRid < bRid)
                            {
                                return(-1);
                            }
                            else if (aRid > bRid)
                            {
                                return(1);
                            }

                            result = a.Module.CompareTo(b.Module);
                        }
                        Debug.Assert(result != 0);
                        return(result);
                    });

                    uint crossModuleInlinerCount = 0;
                    foreach (var method in sortedInliners)
                    {
                        if (factory.CompilationModuleGroup.VersionsWithMethodBody(method))
                        {
                            break;
                        }

                        Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(method));
                        crossModuleInlinerCount++;
                    }

                    uint encodedInlinee;
                    checked
                    {
                        uint indexOfInlinee;
                        if (isCrossModuleInlinee)
                        {
                            indexOfInlinee = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inlinee).IndexFromBeginningOfArray;
                        }
                        else
                        {
                            indexOfInlinee = (uint)MetadataTokens.GetRowNumber(inlinee.Handle);
                        }

                        encodedInlinee = indexOfInlinee << (int)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinerIndexShift;

                        if (isCrossModuleInlinee)
                        {
                            encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinee;
                        }

                        if (crossModuleInlinerCount > 0)
                        {
                            encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.HasCrossModuleInliners;
                        }

                        sig.Append(new UnsignedConstant(encodedInlinee));
                        if (crossModuleMultiModuleFormat && !isCrossModuleInlinee)
                        {
                            sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                        }

                        int inlinerIndex = 0;
                        if (crossModuleInlinerCount > 0)
                        {
                            sig.Append(new UnsignedConstant(crossModuleInlinerCount));
                            uint baseIndex = 0;
                            for (; inlinerIndex < crossModuleInlinerCount; inlinerIndex++)
                            {
                                var inliner = sortedInliners[inlinerIndex];

                                uint ilBodyIndex = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inliner).IndexFromBeginningOfArray;
                                uint ridDelta    = ilBodyIndex - baseIndex;
                                sig.Append(new UnsignedConstant(ridDelta));
                            }
                        }

                        uint baseRid = 0;
                        for (; inlinerIndex < sortedInliners.Length; inlinerIndex++)
                        {
                            var  inliner    = sortedInliners[inlinerIndex];
                            uint inlinerRid = (uint)MetadataTokens.GetRowNumber(inliner.Handle);
                            uint ridDelta   = inlinerRid - baseRid;
                            baseRid = inlinerRid;
                            bool isForeignInliner = inliner.Module != inlinee.Module;
                            Debug.Assert(!isForeignInliner || crossModuleMultiModuleFormat);

                            if (crossModuleMultiModuleFormat)
                            {
                                uint encodedRid = ridDelta << (int)ReadyToRunCrossModuleInlineFlags.InlinerRidShift;
                                if (isForeignInliner)
                                {
                                    encodedRid |= (uint)ReadyToRunCrossModuleInlineFlags.InlinerRidHasModule;
                                }

                                sig.Append(new UnsignedConstant(encodedRid));
                                if (isForeignInliner)
                                {
                                    sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                                }
                            }
                            else
                            {
                                sig.Append(new UnsignedConstant(ridDelta));
                            }
                        }
                    }
                }

                hashtable.Append((uint)hashCode, section.Place(sig));
            }

            MemoryStream writerContent = new MemoryStream();

            writer.Save(writerContent);

            return(new ObjectData(
                       data: writerContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }