} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(ElementType == null || ElementType.HandleType == HandleType.TypeDefinition || ElementType.HandleType == HandleType.TypeReference || ElementType.HandleType == HandleType.TypeSpecification); writer.Write(ElementType); writer.Write(Rank); writer.Write(Sizes); writer.Write(LowerBounds); } // Save
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); foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping()) { if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity)) continue; // We are looking for any EEType - constructed or not, it has to be in the mapping // table so that we can map it to metadata. EETypeNode node = null; if (!mappingEntry.Entity.IsGenericDefinition) { node = factory.ConstructedTypeSymbol(mappingEntry.Entity) as EETypeNode; } if (node == null || !node.Marked) { // This might have been a typeof() expression. node = factory.NecessaryTypeSymbol(mappingEntry.Entity) as EETypeNode; } if (node.Marked) { Vertex vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(node)), writer.GetUnsignedConstant((uint)mappingEntry.MetadataHandle) ); int hashCode = node.Type.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 }); }
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); foreach (var node in factory.MetadataManager.GetCctorContextMapping()) { MetadataType type = node.Type; Debug.Assert(factory.TypeSystemContext.HasLazyStaticConstructor(type)); // If this type doesn't generate an EEType in the current compilation, don't report it in the table. // If nobody can get to the EEType, they can't ask to run the cctor. We don't need to force generate it. if (!factory.MetadataManager.TypeGeneratesEEType(type)) continue; // Hash table is hashed by the hashcode of the owning type. // Each entry has: the EEType of the type, followed by the non-GC static base. // The non-GC static base is prefixed by the class constructor context. // Unfortunately we need to adjust for the cctor context just so that we can subtract it again at runtime... int delta = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.TypeSystemContext.Target, type); Vertex vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(type))), writer.GetUnsignedConstant(_externalReferences.GetIndex(node, delta)) ); int hashCode = type.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 }); }
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); foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping()) { if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity)) continue; // Types that don't have EETypes don't need mapping table entries because there's no risk of them // not unifying to the same System.Type at runtime. if (!factory.MetadataManager.TypeGeneratesEEType(mappingEntry.Entity)) continue; // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode typeSymbol = factory.NecessaryTypeSymbol(mappingEntry.Entity); Vertex vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(typeSymbol)), writer.GetUnsignedConstant((uint)mappingEntry.MetadataHandle) ); int hashCode = typeSymbol.Type.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 }); }
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); foreach (var arrayType in factory.MetadataManager.GetArrayTypeMapping()) { if (!arrayType.IsSzArray) continue; if (!factory.MetadataManager.TypeGeneratesEEType(arrayType)) continue; // TODO: This should only be emitted for arrays of value types. The type loader builds everything else. // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode arrayTypeSymbol = factory.NecessaryTypeSymbol(arrayType); Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol)); int hashCode = arrayType.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 }); }
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(MethodBody == null || MethodBody.HandleType == HandleType.QualifiedMethod || MethodBody.HandleType == HandleType.MemberReference); writer.Write(MethodBody); Debug.Assert(MethodDeclaration == null || MethodDeclaration.HandleType == HandleType.QualifiedMethod || MethodDeclaration.HandleType == HandleType.MemberReference); writer.Write(MethodDeclaration); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(Parent == null || Parent.HandleType == HandleType.TypeDefinition || Parent.HandleType == HandleType.TypeReference || Parent.HandleType == HandleType.TypeSpecification); writer.Write(Parent); writer.Write(Name); Debug.Assert(Signature == null || Signature.HandleType == HandleType.MethodSignature || Signature.HandleType == HandleType.FieldSignature); writer.Write(Signature); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); Debug.Assert(Type == null || Type.HandleType == HandleType.TypeDefinition || Type.HandleType == HandleType.TypeReference || Type.HandleType == HandleType.TypeSpecification); writer.Write(Type); Debug.Assert(Value == null || Value.HandleType == HandleType.TypeDefinition || Value.HandleType == HandleType.TypeReference || Value.HandleType == HandleType.TypeSpecification || Value.HandleType == HandleType.ConstantBooleanArray || Value.HandleType == HandleType.ConstantBooleanValue || Value.HandleType == HandleType.ConstantByteArray || Value.HandleType == HandleType.ConstantByteValue || Value.HandleType == HandleType.ConstantCharArray || Value.HandleType == HandleType.ConstantCharValue || Value.HandleType == HandleType.ConstantDoubleArray || Value.HandleType == HandleType.ConstantDoubleValue || Value.HandleType == HandleType.ConstantHandleArray || Value.HandleType == HandleType.ConstantInt16Array || Value.HandleType == HandleType.ConstantInt16Value || Value.HandleType == HandleType.ConstantInt32Array || Value.HandleType == HandleType.ConstantInt32Value || Value.HandleType == HandleType.ConstantInt64Array || Value.HandleType == HandleType.ConstantInt64Value || Value.HandleType == HandleType.ConstantReferenceValue || Value.HandleType == HandleType.ConstantSByteArray || Value.HandleType == HandleType.ConstantSByteValue || Value.HandleType == HandleType.ConstantSingleArray || Value.HandleType == HandleType.ConstantSingleValue || Value.HandleType == HandleType.ConstantStringArray || Value.HandleType == HandleType.ConstantStringValue || Value.HandleType == HandleType.ConstantUInt16Array || Value.HandleType == HandleType.ConstantUInt16Value || Value.HandleType == HandleType.ConstantUInt32Array || Value.HandleType == HandleType.ConstantUInt32Value || Value.HandleType == HandleType.ConstantUInt64Array || Value.HandleType == HandleType.ConstantUInt64Value); writer.Write(Value); } // Save
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(); Section section = writer.NewSection(); VertexArray vertexArray = new VertexArray(section); section.Place(vertexArray); Dictionary <byte[], BlobVertex> blobCache = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods()) { MemoryStream methodDebugBlob = new MemoryStream(); byte[] bounds = method.DebugLocInfos; byte[] vars = method.DebugVarInfos; NibbleWriter nibbleWriter = new NibbleWriter(); nibbleWriter.WriteUInt((uint)(bounds?.Length ?? 0)); nibbleWriter.WriteUInt((uint)(vars?.Length ?? 0)); byte[] header = nibbleWriter.ToArray(); methodDebugBlob.Write(header, 0, header.Length); if (bounds?.Length > 0) { methodDebugBlob.Write(bounds, 0, bounds.Length); } if (vars?.Length > 0) { methodDebugBlob.Write(vars, 0, vars.Length); } byte[] debugBlobArrayKey = methodDebugBlob.ToArray(); if (!blobCache.TryGetValue(debugBlobArrayKey, out BlobVertex debugBlob)) { debugBlob = new BlobVertex(methodDebugBlob.ToArray()); blobCache.Add(debugBlobArrayKey, debugBlob); } vertexArray.Set(factory.RuntimeFunctionsTable.GetIndex(method), new DebugInfoVertex(debugBlob)); } vertexArray.ExpandLayout(); MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Scope); writer.Write(Name); writer.Write(NestedTypes); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(ElementType == null || ElementType.HandleType == HandleType.TypeDefinition || ElementType.HandleType == HandleType.TypeReference || ElementType.HandleType == HandleType.TypeSpecification || ElementType.HandleType == HandleType.ModifiedType); writer.Write(ElementType); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(ParentScopeOrNamespace == null || ParentScopeOrNamespace.HandleType == HandleType.NamespaceReference || ParentScopeOrNamespace.HandleType == HandleType.ScopeReference); writer.Write(ParentScopeOrNamespace); writer.Write(Name); } // Save
public static void Write(this NativeWriter writer, double value) { writer.WriteDouble(value); }
public static void Write(this NativeWriter writer, float value) { writer.WriteFloat(value); }
public static void Write(this NativeWriter writer, char value) { writer.WriteUnsigned((uint)value); }
public static void Write(this NativeWriter writer, string value) { Debug.Assert(value != null); writer.WriteString(value); }
public static void Write(this NativeWriter writer, long value) { writer.WriteSignedLong(value); }
public static void Write(this NativeWriter writer, uint value) { writer.WriteUnsigned(value); }
public static void Write(this NativeWriter writer, short value) { writer.WriteSigned(value); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Attributes); writer.Write(Method); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(ParentScopeOrNamespace == null || ParentScopeOrNamespace.HandleType == HandleType.NamespaceDefinition || ParentScopeOrNamespace.HandleType == HandleType.ScopeDefinition); writer.Write(ParentScopeOrNamespace); writer.Write(Name); writer.Write(TypeDefinitions); writer.Write(TypeForwarders); writer.Write(NamespaceDefinitions); } // Save
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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(CallingConvention); Debug.Assert(Type == null || Type.HandleType == HandleType.TypeDefinition || Type.HandleType == HandleType.TypeReference || Type.HandleType == HandleType.TypeSpecification || Type.HandleType == HandleType.ModifiedType); writer.Write(Type); Debug.Assert(Parameters.TrueForAll(handle => handle == null || handle.HandleType == HandleType.TypeDefinition || handle.HandleType == HandleType.TypeReference || handle.HandleType == HandleType.TypeSpecification || handle.HandleType == HandleType.ModifiedType)); writer.Write(Parameters); } // Save
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(); // Only encode inlining info for inliners within the active module Debug.Assert(inlinerDefinition.Module == _module); 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 (!factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee)) { // We cannot record inlining info across version bubble as cross-bubble assemblies // are not guaranteed to preserve token values. Only non-versionable methods may be // inlined across the version bubble. Debug.Assert(inlinee.IsNonVersionable()); 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 != _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))); } } 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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); writer.Write(Name); writer.Write(MajorVersion); writer.Write(MinorVersion); writer.Write(BuildNumber); writer.Write(RevisionNumber); writer.Write(PublicKeyOrToken); writer.Write(Culture); writer.Write(CustomAttributes); } // Save
internal override void Save(NativeWriter writer) { writer.WriteUInt32(Signature); writer.Write(ScopeDefinitions); }
public static void Write(this NativeWriter writer, sbyte value) { writer.WriteUInt8((byte)value); }
public void Write(Stream stream) { _visitor = new RecordVisitor(); _visitor.Run(ScopeDefinitions.AsEnumerable()); _visitor.Run(UnreachableTypeReferences.AsEnumerable()); IEnumerable <MetadataRecord> records = _visitor.Graph.Vertices.Where(v => v != _visitor.MetaSourceVertex); var writer = new NativeWriter(); var section = writer.NewSection(); _metadataHeader.ScopeDefinitions = ScopeDefinitions; section.Place(_metadataHeader); foreach (var rec in records) { section.Place(rec); } writer.Save(stream); if (LogWriter != null) { // Create a CSV file, one line per meta-data record. LogWriter.WriteLine("Handle, Kind, Name, Children"); // needed to enumerate children of a meta-data record var childVisitor = new WriteChildrenVisitor(LogWriter); foreach (var rec in records) { // First the metadata handle LogWriter.Write(rec.Handle._value.ToString("x8")); LogWriter.Write(", "); // Next the handle type LogWriter.Write(rec.HandleType.ToString()); LogWriter.Write(", "); // 3rd, the name, Quote the string if not already quoted string asString = rec.ToString(false); bool alreadyQuoted = asString.StartsWith("\"") && asString.EndsWith("\""); if (!alreadyQuoted) { LogWriter.Write("\""); asString = asString.Replace("\\", "\\\\").Replace("\"", "\\\""); // Quote " and \ } // TODO we assume that a quoted string is escaped properly LogWriter.Write(asString); if (!alreadyQuoted) { LogWriter.Write("\""); } LogWriter.Write(", "); // Finally write out the handle IDs for my children LogWriter.Write("\""); childVisitor.Reset(); rec.Visit(childVisitor); LogWriter.Write("\""); LogWriter.WriteLine(); } LogWriter.Flush(); } }
internal override void Save(NativeWriter writer) { throw new NotImplementedException(); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>())); } NativeWriter hashtableWriter = new NativeWriter(); Section hashtableSection = hashtableWriter.NewSection(); VertexHashtable vertexHashtable = new VertexHashtable(); hashtableSection.Place(vertexHashtable); Dictionary <byte[], BlobVertex> uniqueFixups = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); Dictionary <byte[], BlobVertex> uniqueSignatures = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods(null, CompiledMethodCategory.Instantiated)) { Debug.Assert(method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation); int methodIndex = factory.RuntimeFunctionsTable.GetIndex(method); // In composite R2R format, always enforce owning type to let us share generic instantiations among modules EcmaMethod typicalMethod = (EcmaMethod)method.Method.GetTypicalMethodDefinition(); ModuleToken moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle); ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder(); signatureBuilder.EmitMethodSignature( new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false, context: null), enforceDefEncoding: true, enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module), factory.SignatureContext, isInstantiatingStub: false); byte[] signature = signatureBuilder.ToArray(); BlobVertex signatureBlob; if (!uniqueSignatures.TryGetValue(signature, out signatureBlob)) { signatureBlob = new BlobVertex(signature); hashtableSection.Place(signatureBlob); uniqueSignatures.Add(signature, signatureBlob); } byte[] fixup = method.GetFixupBlob(factory); BlobVertex fixupBlob = null; if (fixup != null && !uniqueFixups.TryGetValue(fixup, out fixupBlob)) { fixupBlob = new BlobVertex(fixup); hashtableSection.Place(fixupBlob); uniqueFixups.Add(fixup, fixupBlob); } EntryPointVertex entryPointVertex = new EntryPointWithBlobVertex((uint)methodIndex, fixupBlob, signatureBlob); hashtableSection.Place(entryPointVertex); vertexHashtable.Append(unchecked ((uint)ReadyToRunHashCode.MethodHashCode(method.Method)), entryPointVertex); } MemoryStream hashtableContent = new MemoryStream(); hashtableWriter.Save(hashtableContent); return(new ObjectData( data: hashtableContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Number); writer.Write(Flags); writer.Write(Kind); writer.Write(Name); Debug.Assert(Constraints.TrueForAll(handle => handle == null || handle.HandleType == HandleType.TypeDefinition || handle.HandleType == HandleType.TypeReference || handle.HandleType == HandleType.TypeSpecification)); writer.Write(Constraints); writer.Write(CustomAttributes); } // Save
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) { // If the type does not have fully constructed type, don't emit it. // TODO: Remove the workaround once we stop using the STS dependency analysis. if (!factory.ConstructedTypeSymbol(type).Marked) { continue; } } // Type's native layout info DefType defType = GetActualTemplateTypeForType(factory, type); NativeLayoutTemplateTypeLayoutVertexNode templateNode = factory.NativeLayout.TemplateTypeLayout(defType); // 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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); writer.Write(ImplFlags); writer.Write(Name); writer.Write(Signature); writer.Write(Parameters); writer.Write(GenericParameters); writer.Write(CustomAttributes); } // Save
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 (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { bool goesThroughInstantiatingUnboxingThunk = method.OwningType.IsValueType && !method.Signature.IsStatic && !method.HasInstantiation; if (!goesThroughInstantiatingUnboxingThunk) { 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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(Method == null || Method.HandleType == HandleType.QualifiedMethod || Method.HandleType == HandleType.MemberReference); writer.Write(Method); Debug.Assert(GenericTypeArguments.TrueForAll(handle => handle == null || handle.HandleType == HandleType.TypeDefinition || handle.HandleType == HandleType.TypeReference || handle.HandleType == HandleType.TypeSpecification)); writer.Write(GenericTypeArguments); writer.Write(CustomAttributes); } // Save
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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(IsOptional); Debug.Assert(ModifierType == null || ModifierType.HandleType == HandleType.TypeDefinition || ModifierType.HandleType == HandleType.TypeReference || ModifierType.HandleType == HandleType.TypeSpecification); writer.Write(ModifierType); Debug.Assert(Type == null || Type.HandleType == HandleType.TypeDefinition || Type.HandleType == HandleType.TypeReference || Type.HandleType == HandleType.TypeSpecification || Type.HandleType == HandleType.ModifiedType); writer.Write(Type); } // Save
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 })); } // 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; MemoryStream stream = new MemoryStream(); nativeFormatWriter.Save(stream); byte[] streamBytes = stream.ToArray(); _endSymbol.SetSymbolOffset(streamBytes.Length); return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(Value == null || Value.HandleType == HandleType.ConstantByteValue || Value.HandleType == HandleType.ConstantSByteValue || Value.HandleType == HandleType.ConstantInt16Value || Value.HandleType == HandleType.ConstantUInt16Value || Value.HandleType == HandleType.ConstantInt32Value || Value.HandleType == HandleType.ConstantUInt32Value || Value.HandleType == HandleType.ConstantInt64Value || Value.HandleType == HandleType.ConstantUInt64Value); writer.Write(Value); Debug.Assert(Type == null || Type.HandleType == HandleType.TypeDefinition || Type.HandleType == HandleType.TypeReference); writer.Write(Type); } // Save
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 })); } 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)); } MemoryStream stream = new MemoryStream(); nativeWriter.Save(stream); byte[] streamBytes = stream.ToArray(); _endSymbol.SetSymbolOffset(streamBytes.Length); return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); writer.Write(Name); writer.Write(Signature); writer.Write(MethodSemantics); Debug.Assert(DefaultValue == null || DefaultValue.HandleType == HandleType.TypeDefinition || DefaultValue.HandleType == HandleType.TypeReference || DefaultValue.HandleType == HandleType.TypeSpecification || DefaultValue.HandleType == HandleType.ConstantBooleanArray || DefaultValue.HandleType == HandleType.ConstantBooleanValue || DefaultValue.HandleType == HandleType.ConstantByteArray || DefaultValue.HandleType == HandleType.ConstantByteValue || DefaultValue.HandleType == HandleType.ConstantCharArray || DefaultValue.HandleType == HandleType.ConstantCharValue || DefaultValue.HandleType == HandleType.ConstantDoubleArray || DefaultValue.HandleType == HandleType.ConstantDoubleValue || DefaultValue.HandleType == HandleType.ConstantHandleArray || DefaultValue.HandleType == HandleType.ConstantInt16Array || DefaultValue.HandleType == HandleType.ConstantInt16Value || DefaultValue.HandleType == HandleType.ConstantInt32Array || DefaultValue.HandleType == HandleType.ConstantInt32Value || DefaultValue.HandleType == HandleType.ConstantInt64Array || DefaultValue.HandleType == HandleType.ConstantInt64Value || DefaultValue.HandleType == HandleType.ConstantReferenceValue || DefaultValue.HandleType == HandleType.ConstantSByteArray || DefaultValue.HandleType == HandleType.ConstantSByteValue || DefaultValue.HandleType == HandleType.ConstantSingleArray || DefaultValue.HandleType == HandleType.ConstantSingleValue || DefaultValue.HandleType == HandleType.ConstantStringArray || DefaultValue.HandleType == HandleType.ConstantStringValue || DefaultValue.HandleType == HandleType.ConstantUInt16Array || DefaultValue.HandleType == HandleType.ConstantUInt16Value || DefaultValue.HandleType == HandleType.ConstantUInt32Array || DefaultValue.HandleType == HandleType.ConstantUInt32Value || DefaultValue.HandleType == HandleType.ConstantUInt64Array || DefaultValue.HandleType == HandleType.ConstantUInt64Value); writer.Write(DefaultValue); writer.Write(CustomAttributes); } // Save
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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Method); writer.Write(EnclosingType); } // Save
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; } // CppCodegen: implement thread statics if (factory.Target.Abi == TargetAbi.CppCodegen && field.IsThreadStatic) { continue; } FieldTableFlags flags; if (field.IsStatic) { if (field.IsThreadStatic) { flags = FieldTableFlags.ThreadStatic; } else if (field.HasGCStaticBase) { flags = FieldTableFlags.GCStatic; } else { flags = FieldTableFlags.NonGCStatic; } 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.Any)) { flags |= FieldTableFlags.IsAnyCanonicalEntry; } if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { flags |= FieldTableFlags.IsUniversalCanonicalEntry; } if (field.IsInitOnly) { flags |= FieldTableFlags.IsInitOnly; } // 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) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(checked ((uint)field.GetFieldOrdinal()))); } else { switch (flags & FieldTableFlags.StorageClass) { case FieldTableFlags.ThreadStatic: case FieldTableFlags.GCStatic: case FieldTableFlags.NonGCStatic: { if (field.OwningType.HasInstantiation) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); } else { MetadataType metadataType = (MetadataType)field.OwningType; ISymbolNode staticsNode; if (field.IsThreadStatic) { staticsNode = factory.TypeThreadStaticIndex(metadataType); } else if (field.HasGCStaticBase) { staticsNode = factory.TypeGCStaticsSymbol(metadataType); } else { staticsNode = factory.TypeNonGCStaticsSymbol(metadataType); } if (!field.IsThreadStatic && !field.HasGCStaticBase) { uint index = _externalReferences.GetIndex(staticsNode, field.Offset.AsInt); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index)); } else { 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 })); }
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); writer.Write(Name); writer.Write(HashAlgorithm); writer.Write(MajorVersion); writer.Write(MinorVersion); writer.Write(BuildNumber); writer.Write(RevisionNumber); writer.Write(PublicKey); writer.Write(Culture); writer.Write(RootNamespaceDefinition); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(ParentNamespaceOrType == null || ParentNamespaceOrType.HandleType == HandleType.NamespaceReference || ParentNamespaceOrType.HandleType == HandleType.TypeReference); writer.Write(ParentNamespaceOrType); writer.Write(TypeName); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Flags); Debug.Assert(BaseType == null || BaseType.HandleType == HandleType.TypeDefinition || BaseType.HandleType == HandleType.TypeReference || BaseType.HandleType == HandleType.TypeSpecification); writer.Write(BaseType); writer.Write(NamespaceDefinition); writer.Write(Name); writer.Write(Size); writer.Write(PackingSize); writer.Write(EnclosingType); writer.Write(NestedTypes); writer.Write(Methods); writer.Write(Fields); writer.Write(Properties); writer.Write(Events); writer.Write(GenericParameters); Debug.Assert(Interfaces.TrueForAll(handle => handle == null || handle.HandleType == HandleType.TypeDefinition || handle.HandleType == HandleType.TypeReference || handle.HandleType == HandleType.TypeSpecification)); writer.Write(Interfaces); writer.Write(MethodImpls); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Number); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(GenericType == null || GenericType.HandleType == HandleType.TypeDefinition || GenericType.HandleType == HandleType.TypeReference || GenericType.HandleType == HandleType.TypeSpecification); writer.Write(GenericType); Debug.Assert(GenericTypeArguments.TrueForAll(handle => handle == null || handle.HandleType == HandleType.TypeDefinition || handle.HandleType == HandleType.TypeReference || handle.HandleType == HandleType.TypeSpecification)); writer.Write(GenericTypeArguments); } // Save
public static void Write(this NativeWriter writer, bool value) { writer.WriteUInt8((byte)(value ? 1 : 0)); }
} // GetHashCode internal override void Save(NativeWriter writer) { Debug.Assert(Signature == null || Signature.HandleType == HandleType.TypeDefinition || Signature.HandleType == HandleType.TypeReference || Signature.HandleType == HandleType.TypeInstantiationSignature || Signature.HandleType == HandleType.SZArraySignature || Signature.HandleType == HandleType.ArraySignature || Signature.HandleType == HandleType.PointerSignature || Signature.HandleType == HandleType.ByReferenceSignature || Signature.HandleType == HandleType.TypeVariableSignature || Signature.HandleType == HandleType.MethodTypeVariableSignature); writer.Write(Signature); writer.Write(CustomAttributes); } // Save
} // GetHashCode internal override void Save(NativeWriter writer) { writer.Write(Value); } // Save
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>())); } ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory; List <EntryPoint> ridToEntryPoint = new List <EntryPoint>(); foreach (MethodWithGCInfo method in r2rFactory.EnumerateCompiledMethods()) { if (method.Method is EcmaMethod ecmaMethod) { // Strip away the token type bits, keep just the low 24 bits RID uint rid = SignatureBuilder.RidFromToken((mdToken)MetadataTokens.GetToken(ecmaMethod.Handle)); Debug.Assert(rid != 0); rid--; while (ridToEntryPoint.Count <= rid) { ridToEntryPoint.Add(EntryPoint.Null); } int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(method); ridToEntryPoint[(int)rid] = new EntryPoint(methodIndex, method); } } NativeWriter writer = new NativeWriter(); Section arraySection = writer.NewSection(); VertexArray vertexArray = new VertexArray(arraySection); arraySection.Place(vertexArray); Section fixupSection = writer.NewSection(); Dictionary <byte[], BlobVertex> uniqueFixups = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); for (int rid = 0; rid < ridToEntryPoint.Count; rid++) { EntryPoint entryPoint = ridToEntryPoint[rid]; if (!entryPoint.IsNull) { byte[] fixups = entryPoint.Method.GetFixupBlob(factory); BlobVertex fixupBlobVertex = null; if (fixups != null && !uniqueFixups.TryGetValue(fixups, out fixupBlobVertex)) { fixupBlobVertex = new BlobVertex(fixups); fixupSection.Place(fixupBlobVertex); uniqueFixups.Add(fixups, fixupBlobVertex); } EntryPointVertex entryPointVertex = new EntryPointVertex((uint)entryPoint.MethodIndex, fixupBlobVertex); vertexArray.Set(rid, entryPointVertex); } } vertexArray.ExpandLayout(); MemoryStream arrayContent = new MemoryStream(); writer.Save(arrayContent); return(new ObjectData( data: arrayContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
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 })); } 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) { int cctorOffset = 0; if (factory.TypeSystemContext.HasLazyStaticConstructor(type)) { cctorOffset += NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.TypeSystemContext.Target, metadataType); } ISymbolNode nonGCStaticIndirection = factory.Indirection(factory.TypeNonGCStaticsSymbol(metadataType), cctorOffset); bag.AppendUnsigned(BagElementKind.NonGcStaticData, _nativeStaticsReferences.GetIndex(nonGCStaticIndirection)); } // TODO: TLS 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 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 }); 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 }); }
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.InstanceFieldSize.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 })); }