Example #1
0
        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 (TypeDesc type in factory.MetadataManager.GetTypesWithConstructedEETypes())
            {
                if (!IsEligibleToHaveATemplate(type))
                {
                    continue;
                }

                if ((factory.Target.Abi == TargetAbi.ProjectN) && !ProjectNDependencyBehavior.EnableFullAnalysis)
                {
                    // If the type does not have fully constructed type, don't track its dependencies.
                    // TODO: Remove the workaround once we stop using the STS dependency analysis.
                    IDependencyNode node = factory.MaximallyConstructableType(type);

                    if (!node.Marked)
                    {
                        continue;
                    }
                }

                // Type's native layout info
                NativeLayoutTemplateTypeLayoutVertexNode templateNode = factory.NativeLayout.TemplateTypeLayout(type);

                // If this template isn't considered necessary, don't emit it.
                if (!templateNode.Marked)
                {
                    continue;
                }
                Vertex nativeLayout = templateNode.SavedVertex;

                // Hashtable Entry
                Vertex entry = nativeWriter.GetTuple(
                    nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(type))),
                    nativeWriter.GetUnsignedConstant((uint)nativeLayout.VertexOffset));

                // Add to the hash table, hashed by the containing type's hashcode
                uint hashCode = (uint)type.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 }));
        }
Example #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 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);

            Dictionary <int, HashSet <TypeDesc> > methodsEmitted = new Dictionary <int, HashSet <TypeDesc> >();

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

                // Only virtual methods are interesting
                if (!NeedsVirtualInvokeInfo(method))
                {
                    continue;
                }

                //
                // When working with the ProjectN ABI, the entries in the map are based on the definition types. All
                // instantiations of these definition types will have the same vtable method entries.
                // On CoreRT, the vtable entries for each instantiated type might not necessarily exist.
                // Example 1:
                //      If there's a call to Foo<string>.Method1 and a call to Foo<int>.Method2, Foo<string> will
                //      not have Method2 in its vtable and Foo<int> will not have Method1.
                // Example 2:
                //      If there's a call to Foo<string>.Method1 and a call to Foo<object>.Method2, given that both
                //      of these instantiations share the same canonical form, Foo<__Canon> will have both method
                //      entries, and therefore Foo<string> and Foo<object> will have both entries too.
                // For this reason, the entries that we write to the map in CoreRT will be based on the canonical form
                // of the method's containing type instead of the open type definition.
                //
                // Similarly, given that we use the open type definition for ProjectN, the slot numbers ignore dictionary
                // entries in the vtable, and computing the correct slot number in the presence of dictionary entries is
                // done at runtime. When working with the CoreRT ABI, the correct slot numbers will be written to the map,
                // and no adjustments will be performed at runtime.
                //

                TypeDesc containingTypeKey;

                if (factory.Target.Abi == TargetAbi.ProjectN)
                {
                    containingTypeKey = method.OwningType.GetTypeDefinition();
                }
                else
                {
                    containingTypeKey = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
                }

                HashSet <TypeDesc> cache;
                if (!methodsEmitted.TryGetValue(mappingEntry.MetadataHandle, out cache))
                {
                    methodsEmitted[mappingEntry.MetadataHandle] = cache = new HashSet <TypeDesc>();
                }

                // Only one record is needed for any instantiation.
                if (!cache.Add(containingTypeKey))
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Virtual Method uses a normal slot
                // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1) + slot
                // OR
                // Generic Virtual Method
                // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1 + 1)

                int        parentHierarchyDistance;
                MethodDesc declaringMethodForSlot = GetDeclaringVirtualMethodAndHierarchyDistance(method, out parentHierarchyDistance);

                Vertex vertex = null;

                ISymbolNode containingTypeKeyNode = factory.NecessaryTypeSymbol(containingTypeKey);
                NativeLayoutMethodNameAndSignatureVertexNode nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                NativeLayoutPlacedSignatureVertexNode        placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);

                if (method.HasInstantiation)
                {
                    vertex = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)),
                        writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset),
                        writer.GetUnsignedConstant(((uint)parentHierarchyDistance << 1) + VirtualInvokeTableEntry.GenericVirtualMethod));
                }
                else
                {
                    // Get the declaring method for slot on the instantiated declaring type
                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, declaringMethodForSlot, factory.Target.Abi != TargetAbi.ProjectN);
                    Debug.Assert(slot != -1);

                    vertex = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)),
                        writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset));

                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)parentHierarchyDistance << 1),
                                             writer.GetUnsignedConstant((uint)slot));
                }

                int hashCode = containingTypeKey.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 }));
        }
Example #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 }));
            }

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

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(fieldMapHashTable);

            foreach (var fieldMapping in factory.MetadataManager.GetFieldMapping(factory))
            {
                FieldDesc field = fieldMapping.Entity;

                if (field.IsLiteral || field.HasRva)
                {
                    continue;
                }

                FieldTableFlags flags;
                if (field.IsThreadStatic)
                {
                    flags = FieldTableFlags.ThreadStatic;
                }
                else if (field.IsStatic)
                {
                    flags = FieldTableFlags.Static;

                    if (field.HasGCStaticBase)
                    {
                        flags |= FieldTableFlags.IsGcSection;
                    }

                    if (field.OwningType.HasInstantiation)
                    {
                        flags |= FieldTableFlags.FieldOffsetEncodedDirectly;
                    }
                }
                else
                {
                    flags = FieldTableFlags.Instance | FieldTableFlags.FieldOffsetEncodedDirectly;
                }

                if (fieldMapping.MetadataHandle != 0)
                {
                    flags |= FieldTableFlags.HasMetadataHandle;
                }

                if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal))
                {
                    flags |= FieldTableFlags.IsUniversalCanonicalEntry;
                }

                // Grammar of a hash table entry:
                // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset

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

                uint declaringTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(field.OwningType));
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(declaringTypeId));

                if ((flags & FieldTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(fieldMapping.MetadataHandle & MetadataManager.MetadataOffsetMask)));
                }
                else
                {
                    // No metadata handle means we need to store name
                    vertex = writer.GetTuple(vertex,
                                             writer.GetStringConstant(field.Name));
                }

                if ((flags & FieldTableFlags.IsUniversalCanonicalEntry) != 0)
                {
                    // TODO: USG
                    continue;
                }
                else
                {
                    switch (flags & FieldTableFlags.StorageClass)
                    {
                    case FieldTableFlags.ThreadStatic:
                        // TODO: thread statics
                        continue;

                    case FieldTableFlags.Static:
                    {
                        if (field.OwningType.HasInstantiation)
                        {
                            vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt)));
                        }
                        else
                        {
                            MetadataType metadataType = (MetadataType)field.OwningType;

                            ISymbolNode staticsNode = field.HasGCStaticBase ?
                                                      factory.TypeGCStaticsSymbol(metadataType) :
                                                      factory.TypeNonGCStaticsSymbol(metadataType);

                            if (!field.HasGCStaticBase || factory.Target.Abi == TargetAbi.ProjectN)
                            {
                                uint index = _externalReferences.GetIndex(staticsNode, field.Offset.AsInt);
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index));
                            }
                            else
                            {
                                Debug.Assert(field.HasGCStaticBase && factory.Target.Abi == TargetAbi.CoreRT);

                                uint index = _externalReferences.GetIndex(staticsNode);
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index));
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt)));
                            }
                        }
                    }
                    break;

                    case FieldTableFlags.Instance:
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)field.Offset.AsInt));
                        break;
                    }
                }

                int hashCode = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific).GetHashCode();
                fieldMapHashTable.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)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Build the GVM table entries from the list of interesting GVMTableEntryNodes
            foreach (var interestingEntry in factory.MetadataManager.GetTypeGVMEntries())
            {
                foreach (var typeGVMEntryInfo in interestingEntry.ScanForGenericVirtualMethodEntries())
                {
                    AddGenericVirtualMethodImplementation(factory, typeGVMEntryInfo.CallingMethod, typeGVMEntryInfo.ImplementationMethod);
                }
            }

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

            NativeWriter    nativeFormatWriter = new NativeWriter();
            VertexHashtable gvmHashtable       = new VertexHashtable();

            Section gvmHashtableSection = nativeFormatWriter.NewSection();

            gvmHashtableSection.Place(gvmHashtable);

            // Emit the GVM target information entries
            foreach (var gvmEntry in _gvmImplemenations)
            {
                Debug.Assert(!gvmEntry.Key.OwningType.IsInterface);

                foreach (var implementationEntry in gvmEntry.Value)
                {
                    MethodDesc callingMethod        = gvmEntry.Key;
                    TypeDesc   implementationType   = implementationEntry.Key;
                    MethodDesc implementationMethod = implementationEntry.Value;

                    uint   callingTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(callingMethod.OwningType));
                    Vertex vertex        = nativeFormatWriter.GetUnsignedConstant(callingTypeId);

                    uint targetTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(implementationType));
                    vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant(targetTypeId));

                    var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(callingMethod));
                    vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));

                    nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(implementationMethod));
                    vertex     = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));

                    int hashCode = callingMethod.OwningType.GetHashCode();
                    hashCode = ((hashCode << 13) ^ hashCode) ^ implementationType.GetHashCode();

                    gvmHashtable.Append((uint)hashCode, gvmHashtableSection.Place(vertex));
                }
            }

            // Zero out the dictionary so that we AV if someone tries to insert after we're done.
            _gvmImplemenations = null;

            byte[] streamBytes = nativeFormatWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
        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 }));
            }

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

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            foreach (var structEntry in ((CompilerGeneratedInteropStubManager)factory.InteropStubManager).GetStructMarshallingTypes())
            {
                // the order of data written is as follows:
                //  0. managed struct type
                //  1. struct marshalling thunk
                //  2. struct unmarshalling thunk
                //  3. struct cleanup thunk
                //  4. size
                //  5. NumFields<< 1 | HasInvalidLayout
                //  6  for each field
                //      a. name
                //      b. offset

                var    structType = structEntry.StructType;
                var    nativeType = structEntry.NativeStructType;
                Vertex thunks     = writer.GetTuple(
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.MarshallingThunk))),
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.UnmarshallingThunk))),
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.CleanupThunk))));

                uint size = (uint)nativeType.InstanceByteCount.AsInt;
                uint mask = (uint)(nativeType.Fields.Length << 1) | (uint)(nativeType.HasInvalidLayout ? 1 : 0);

                Vertex data = writer.GetTuple(
                    thunks,
                    writer.GetUnsignedConstant(size),
                    writer.GetUnsignedConstant(mask)
                    );

                for (int i = 0; i < nativeType.Fields.Length; i++)
                {
                    data = writer.GetTuple(
                        data,
                        writer.GetStringConstant(nativeType.Fields[i].Name),
                        writer.GetUnsignedConstant((uint)nativeType.Fields[i].Offset.AsInt)
                        );
                }

                Vertex vertex = writer.GetTuple(
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(structType))),
                    data
                    );

                int hashCode = structType.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)
        {
            // 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(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;
                }

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

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

                // 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
                {
                    // 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)
                {
                    bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic;
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(
                                                                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub))));
                }

                // TODO: data to generate the generic dictionary with the type loader
                if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0)
                {
                    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));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }
        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;

                if (!factory.MetadataManager.ShouldMethodBeInInvokeMap(method))
                {
                    continue;
                }

                bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic;

                InvokeTableFlags flags = 0;

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

                if (MethodRequiresInstArg(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub))
                {
                    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 UnmanagedCallersOnly methods
                if (method.IsRawPInvoke() || method.IsUnmanagedCallersOnly)
                {
                    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)
                {
                    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, factory) << 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 }));
        }
Example #9
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 }));
            }

            // Build the GVM table entries from the list of interesting GVMTableEntryNodes
            foreach (var interestingEntry in factory.MetadataManager.GetTypeGVMEntries())
            {
                foreach (var typeGVMEntryInfo in interestingEntry.ScanForInterfaceGenericVirtualMethodEntries())
                {
                    AddGenericVirtualMethodImplementation(factory, typeGVMEntryInfo.CallingMethod, typeGVMEntryInfo.ImplementationType, typeGVMEntryInfo.ImplementationMethod);
                }
            }

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

            NativeWriter    nativeFormatWriter = new NativeWriter();
            VertexHashtable gvmHashtable       = new VertexHashtable();

            Section gvmHashtableSection = nativeFormatWriter.NewSection();

            gvmHashtableSection.Place(gvmHashtable);

            // Emit the interface slot resolution entries
            foreach (var gvmEntry in _interfaceGvmSlots)
            {
                Debug.Assert(gvmEntry.Key.OwningType.IsInterface);

                MethodDesc callingMethod = gvmEntry.Key;

                // Emit the method signature and containing type of the current interface method
                uint   typeId     = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(callingMethod.OwningType));
                var    nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(callingMethod));
                Vertex vertex     = nativeFormatWriter.GetTuple(
                    nativeFormatWriter.GetUnsignedConstant(typeId),
                    nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));

                // Emit the method name / sig and containing type of each GVM target method for the current interface method entry
                vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)gvmEntry.Value.Count));
                foreach (MethodDesc implementationMethod in gvmEntry.Value)
                {
                    nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(implementationMethod));
                    typeId     = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(implementationMethod.OwningType));
                    vertex     = nativeFormatWriter.GetTuple(
                        vertex,
                        nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset),
                        nativeFormatWriter.GetUnsignedConstant(typeId));

                    // Emit the interface GVM slot details for each type that implements the interface methods
                    {
                        Debug.Assert(_interfaceImpls.ContainsKey(implementationMethod));

                        var ifaceImpls = _interfaceImpls[implementationMethod];

                        // First, emit how many types have method implementations for this interface method entry
                        vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)ifaceImpls.Count));

                        // Emit each type that implements the interface method, and the interface signatures for the interfaces implemented by the type
                        foreach (var currentImpl in ifaceImpls)
                        {
                            TypeDesc implementationType = currentImpl.Key;

                            typeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(implementationType));
                            vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant(typeId));

                            // Emit information on which interfaces the current method entry provides implementations for
                            vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)currentImpl.Value.Count));
                            foreach (var ifaceId in currentImpl.Value)
                            {
                                // Emit the signature of the current interface implemented by the method
                                Debug.Assert(((uint)ifaceId) < implementationType.RuntimeInterfaces.Length);
                                TypeDesc currentInterface = implementationType.RuntimeInterfaces[ifaceId];
                                var      typeSig          = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(currentInterface));
                                vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)typeSig.SavedVertex.VertexOffset));
                            }
                        }
                    }
                }

                int hashCode = callingMethod.OwningType.GetHashCode();
                gvmHashtable.Append((uint)hashCode, gvmHashtableSection.Place(vertex));
            }

            // Zero out the dictionary so that we AV if someone tries to insert after we're done.
            _interfaceGvmSlots = null;

            byte[] streamBytes = nativeFormatWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
Example #10
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 }));
            }

            NativeWriter    writer    = new NativeWriter();
            VertexHashtable hashtable = new VertexHashtable();
            Section         section   = writer.NewSection();

            section.Place(hashtable);

            foreach (var type in factory.MetadataManager.GetTypesWithConstructedEETypes())
            {
                if (!type.HasInstantiation || type.IsCanonicalSubtype(CanonicalFormKind.Any) || type.IsGenericDefinition)
                {
                    continue;
                }

                MetadataType metadataType = type as MetadataType;
                if (metadataType == null)
                {
                    continue;
                }

                VertexBag bag = new VertexBag();

                if (metadataType.GCStaticFieldSize.AsInt > 0)
                {
                    ISymbolNode gcStaticIndirection = factory.Indirection(factory.TypeGCStaticsSymbol(metadataType));
                    bag.AppendUnsigned(BagElementKind.GcStaticData, _nativeStaticsReferences.GetIndex(gcStaticIndirection));
                }
                if (metadataType.NonGCStaticFieldSize.AsInt > 0 || factory.TypeSystemContext.HasLazyStaticConstructor(type))
                {
                    ISymbolNode nonGCStaticIndirection = factory.Indirection(factory.TypeNonGCStaticsSymbol(metadataType));
                    bag.AppendUnsigned(BagElementKind.NonGcStaticData, _nativeStaticsReferences.GetIndex(nonGCStaticIndirection));
                }
                if (metadataType.ThreadStaticFieldSize.AsInt > 0)
                {
                    if (factory.Target.Abi == TargetAbi.ProjectN)
                    {
                        UtcNodeFactory utcFactory = (UtcNodeFactory)factory;

                        ISymbolNode threadStaticIndexIndirection = utcFactory.TypeThreadStaticsIndexSymbol(metadataType);
                        bag.AppendUnsigned(BagElementKind.ThreadStaticIndex, _nativeStaticsReferences.GetIndex(threadStaticIndexIndirection));

                        ISymbolNode threadStaticOffsetIndirection = utcFactory.TypeThreadStaticsOffsetSymbol(metadataType);
                        bag.AppendUnsigned(BagElementKind.ThreadStaticOffset, _nativeStaticsReferences.GetIndex(threadStaticOffsetIndirection));
                    }
                    // TODO: TLS for CoreRT
                }

                if (bag.ElementsCount > 0)
                {
                    uint   typeId      = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(type));
                    Vertex staticsInfo = writer.GetTuple(writer.GetUnsignedConstant(typeId), bag);

                    hashtable.Append((uint)type.GetHashCode(), section.Place(staticsInfo));
                }
            }

            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)
        {
            // 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 fieldMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(fieldMapHashTable);

            foreach (var fieldMapping in factory.MetadataManager.GetFieldMapping())
            {
                FieldDesc field = fieldMapping.Entity;

                if (field.IsLiteral || field.HasRva)
                {
                    continue;
                }

                FieldTableFlags flags;
                if (field.IsThreadStatic)
                {
                    flags = FieldTableFlags.ThreadStatic;
                }
                else if (field.IsStatic)
                {
                    flags = FieldTableFlags.Static;

                    if (field.HasGCStaticBase)
                    {
                        flags |= FieldTableFlags.IsGcSection;
                    }
                }
                else
                {
                    flags = FieldTableFlags.Instance;
                }

                // TODO: support emitting field info without a handle for generics in multifile
                flags |= FieldTableFlags.HasMetadataHandle;

                if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal))
                {
                    flags |= FieldTableFlags.IsUniversalCanonicalEntry;
                }

                // Grammar of a hash table entry:
                // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset

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

                uint declaringTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(field.OwningType));
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(declaringTypeId));

                if ((flags & FieldTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(fieldMapping.MetadataHandle & MetadataManager.MetadataOffsetMask)));
                }
                else
                {
                    throw new NotImplementedException();
                }

                if ((flags & FieldTableFlags.IsUniversalCanonicalEntry) != 0)
                {
                    throw new NotImplementedException();
                }
                else
                {
                    switch (flags & FieldTableFlags.StorageClass)
                    {
                    case FieldTableFlags.ThreadStatic:
                    case FieldTableFlags.Static:
                        // TODO: statics and thread statics
                        continue;

                    case FieldTableFlags.Instance:
                        vertex = writer.GetTuple(vertex,
                                                 writer.GetUnsignedConstant((uint)field.Offset));
                        break;
                    }
                }

                int hashCode = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific).GetHashCode();
                fieldMapHashTable.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 }));
        }
        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 }));
        }
        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 }));
            }

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

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            foreach (var structType in factory.MetadataManager.GetTypesWithStructMarshalling())
            {
                // the order of data written is as follows:
                //  managed struct type
                //  NumFields<< 2 | (HasInvalidLayout ? (2:0)) | (MarshallingRequired ? (1:0))
                //  If MarshallingRequired:
                //    size
                //    struct marshalling thunk
                //    struct unmarshalling thunk
                //    struct cleanup thunk
                //  For each field field:
                //     name
                //     offset

                var nativeType = _interopStateManager.GetStructMarshallingNativeType(structType);

                Vertex marshallingData = null;
                if (MarshalHelpers.IsStructMarshallingRequired(structType))
                {
                    Vertex thunks = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingManagedToNativeThunk(structType)))),
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingNativeToManagedThunk(structType)))),
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingCleanupThunk(structType)))));

                    uint size = (uint)nativeType.InstanceFieldSize.AsInt;
                    marshallingData = writer.GetTuple(writer.GetUnsignedConstant(size), thunks);
                }

                Vertex fieldOffsetData = null;
                for (int i = 0; i < nativeType.Fields.Length; i++)
                {
                    var row = writer.GetTuple(
                        writer.GetStringConstant(nativeType.Fields[i].Name),
                        writer.GetUnsignedConstant((uint)nativeType.Fields[i].Offset.AsInt)
                        );

                    fieldOffsetData = (fieldOffsetData != null) ? writer.GetTuple(fieldOffsetData, row) : row;
                }

                uint mask = (uint)((marshallingData != null) ? InteropDataConstants.HasMarshallers : 0) |
                            (uint)(nativeType.HasInvalidLayout ? InteropDataConstants.HasInvalidLayout : 0) |
                            (uint)(nativeType.Fields.Length << InteropDataConstants.FieldCountShift);

                Vertex data = writer.GetUnsignedConstant(mask);
                if (marshallingData != null)
                {
                    data = writer.GetTuple(data, marshallingData);
                }

                if (fieldOffsetData != null)
                {
                    data = writer.GetTuple(data, fieldOffsetData);
                }

                Vertex vertex = writer.GetTuple(
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(structType))),
                    data
                    );

                int hashCode = structType.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 }));
        }