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 }); }
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 })); }
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; if (ConstructedEETypeNode.CreationAllowed(type)) { node = factory.ConstructedTypeSymbol(type); } else { node = factory.NecessaryTypeSymbol(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 })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >(); // Build a map from inlinee to the list of inliners // We are only interested in the generic definitions of these. foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods(_module, CompiledMethodCategory.All)) { MethodDesc[] inlinees = methodNode.InlinedMethods; MethodDesc inliner = methodNode.Method; EcmaMethod inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition(); if (inlinerDefinition.IsNonVersionable()) { // Non-versionable methods don't need to be reported continue; } // Only encode inlining info for inliners within the active module, or if cross module inline format is in use Debug.Assert(AllowCrossModuleInlines || (inlinerDefinition.Module == _module)); bool inlinerReportAllVersionsWithInlinee = !AllowCrossModuleInlines || factory.CompilationModuleGroup.CrossModuleCompileable(inlinerDefinition); foreach (MethodDesc inlinee in inlinees) { MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition(); if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition)) { // We don't record non-ECMA methods because they don't have tokens that // diagnostic tools could reason about anyway. continue; } if (inlinee.IsNonVersionable()) { // Non-versionable methods don't need to be reported continue; } if (ReportAllInlinesInSearch) { // We'll definitely track this inline } else if (factory.CompilationModuleGroup.VersionsWithMethodBody(inlineeDefinition)) { if (!inlinerReportAllVersionsWithInlinee) { // We'll won't report this method continue; } } else { Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(inlineeDefinition)); if (_inlineInfoType != InfoType.CrossModuleInliningForCrossModuleDataOnly) { // We'll won't report this method continue; } } if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners)) { inliners = new HashSet <EcmaMethod>(); inlineeToInliners.Add(ecmaInlineeDefinition, inliners); } inliners.Add((EcmaMethod)inlinerDefinition); } } // Serialize the map as a hash table NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable hashtable = new VertexHashtable(); section.Place(hashtable); foreach (var inlineeWithInliners in inlineeToInliners) { EcmaMethod inlinee = inlineeWithInliners.Key; int inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle); int hashCode; if (AllowCrossModuleInlines) { // CrossModuleInlineInfo format hashCode = ReadyToRunHashCode.MethodHashCode(inlinee); } else { // InliningInfo2 format hashCode = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module); hashCode ^= inlineeRid; } var sig = new VertexSequence(); if (!AllowCrossModuleInlines) { // Format of the sequence: // FOR InliningInfo2 table format // Inlinee RID with flag in the lowest bit // - if flag is set, followed by module ID // Followed by inliner RIDs deltas with flag in the lowest bit // - if flag is set, followed by module ID Debug.Assert(_module != null); bool isForeignInlinee = inlinee.Module != _module; sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0)))); if (isForeignInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value); sortedInliners.MergeSort((a, b) => { if (a == b) { return(0); } int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } int result = a.Module.CompareTo(b.Module); Debug.Assert(result != 0); return(result); }); int baseRid = 0; foreach (EcmaMethod inliner in sortedInliners) { int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle); int ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; Debug.Assert(ridDelta >= 0); bool isForeignInliner = inliner.Module != _module; sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0)))); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } } else { // Format of the sequence: // FOR CrossModuleInlineInfo format // Index with 2 flags field in lowest 2 bits to define the inlinee // - If flags & 1 == 0 then index is a MethodDef RID, and if the module is a composite image, a module index of the method follows // - If flags & 1 == 1, then index is an index into the ILBody import section // - If flags & 2 == 0 then what follows is: // - Inliner RID deltas - See definition below // - if flags & 2 == 2 then what follows is: // - count of delta encoded indices into the ILBody import section // - the sequence of delta encoded indices into the ILBody import section // - Inliner RID deltas - See definition below // // Inliner RID deltas (for multi-module version bubble images (specified by the module having the READYTORUN_FLAG_MULTIMODULE_VERSION_BUBBLE flag set) // - a sequence of inliner RID deltas with flag in the lowest bit // - if flag is set, the inliner RID is followed by a module ID // - otherwise the module is the same as the module of the inlinee method // // Inliner RID deltas (for single module version bubble images) // - a sequence of inliner RID deltas bool crossModuleMultiModuleFormat = (factory.CompilationModuleGroup.GetReadyToRunFlags() & ReadyToRunFlags.READYTORUN_FLAG_MultiModuleVersionBubble) != 0; Debug.Assert(_module == null); bool isCrossModuleInlinee = !factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee); Debug.Assert(!isCrossModuleInlinee || factory.CompilationModuleGroup.CrossModuleInlineable(inlinee)); EcmaMethod[] sortedInliners = new EcmaMethod[inlineeWithInliners.Value.Count]; inlineeWithInliners.Value.CopyTo(sortedInliners); sortedInliners.MergeSort((a, b) => { if (a == b) { return(0); } bool isCrossModuleInlinerA = !factory.CompilationModuleGroup.VersionsWithMethodBody(a); bool isCrossModuleInlinerB = !factory.CompilationModuleGroup.VersionsWithMethodBody(b); if (isCrossModuleInlinerA != isCrossModuleInlinerB) { if (isCrossModuleInlinerA) { return(-1); } else { return(1); } } int result; if (isCrossModuleInlinerA) { int indexA = _symbolNodeFactory.CheckILBodyFixupSignature(a).IndexFromBeginningOfArray; int indexB = _symbolNodeFactory.CheckILBodyFixupSignature(b).IndexFromBeginningOfArray; Debug.Assert(indexA != indexB); result = indexA.CompareTo(indexB); } else { int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } result = a.Module.CompareTo(b.Module); } Debug.Assert(result != 0); return(result); }); uint crossModuleInlinerCount = 0; foreach (var method in sortedInliners) { if (factory.CompilationModuleGroup.VersionsWithMethodBody(method)) { break; } Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(method)); crossModuleInlinerCount++; } uint encodedInlinee; checked { uint indexOfInlinee; if (isCrossModuleInlinee) { indexOfInlinee = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inlinee).IndexFromBeginningOfArray; } else { indexOfInlinee = (uint)MetadataTokens.GetRowNumber(inlinee.Handle); } encodedInlinee = indexOfInlinee << (int)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinerIndexShift; if (isCrossModuleInlinee) { encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinee; } if (crossModuleInlinerCount > 0) { encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.HasCrossModuleInliners; } sig.Append(new UnsignedConstant(encodedInlinee)); if (crossModuleMultiModuleFormat && !isCrossModuleInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } int inlinerIndex = 0; if (crossModuleInlinerCount > 0) { sig.Append(new UnsignedConstant(crossModuleInlinerCount)); uint baseIndex = 0; for (; inlinerIndex < crossModuleInlinerCount; inlinerIndex++) { var inliner = sortedInliners[inlinerIndex]; uint ilBodyIndex = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inliner).IndexFromBeginningOfArray; uint ridDelta = ilBodyIndex - baseIndex; sig.Append(new UnsignedConstant(ridDelta)); } } uint baseRid = 0; for (; inlinerIndex < sortedInliners.Length; inlinerIndex++) { var inliner = sortedInliners[inlinerIndex]; uint inlinerRid = (uint)MetadataTokens.GetRowNumber(inliner.Handle); uint ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; bool isForeignInliner = inliner.Module != inlinee.Module; Debug.Assert(!isForeignInliner || crossModuleMultiModuleFormat); if (crossModuleMultiModuleFormat) { uint encodedRid = ridDelta << (int)ReadyToRunCrossModuleInlineFlags.InlinerRidShift; if (isForeignInliner) { encodedRid |= (uint)ReadyToRunCrossModuleInlineFlags.InlinerRidHasModule; } sig.Append(new UnsignedConstant(encodedRid)); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } else { sig.Append(new UnsignedConstant(ridDelta)); } } } } hashtable.Append((uint)hashCode, section.Place(sig)); } MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
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 })); }
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) { 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); uniqueSignatures.Add(signature, signatureBlob); } byte[] fixup = method.GetFixupBlob(factory); BlobVertex fixupBlob = null; if (fixup != null && !uniqueFixups.TryGetValue(fixup, out fixupBlob)) { fixupBlob = new BlobVertex(fixup); 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 })); }
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 })); } // 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 NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) { continue; } // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataManager.MetadataOffsetMask))); } else { var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition())); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset)); } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { 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) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>())); } ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory; 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 r2rFactory.EnumerateCompiledMethods()) { if (method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation) { int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(method); ModuleToken moduleToken = method.SignatureContext.GetModuleTokenForMethod(method.Method.GetTypicalMethodDefinition()); if (moduleToken.Module != r2rFactory.InputModuleContext.GlobalContext) { // TODO: encoding of instance methods relative to other modules within the version bubble continue; } ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder(); signatureBuilder.EmitMethodSignature( new MethodWithToken(method.Method, moduleToken, constrainedType: null), enforceDefEncoding: true, method.SignatureContext, isUnboxingStub: false, 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 })); }
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; } // 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 })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >(); // Build a map from inlinee to the list of inliners // We are only interested in the generic definitions of these. foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods()) { MethodDesc[] inlinees = methodNode.InlinedMethods; MethodDesc inliner = methodNode.Method; EcmaMethod inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition(); if (inlinerDefinition.Module != _module) { // Only encode inlining info for inliners within the active module continue; } foreach (MethodDesc inlinee in inlinees) { MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition(); if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition)) { // We don't record non-ECMA methods because they don't have tokens that // diagnostic tools could reason about anyway. continue; } if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners)) { inliners = new HashSet <EcmaMethod>(); inlineeToInliners.Add(ecmaInlineeDefinition, inliners); } inliners.Add((EcmaMethod)inlinerDefinition); } } // Serialize the map as a hash table NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable hashtable = new VertexHashtable(); section.Place(hashtable); foreach (var inlineeWithInliners in inlineeToInliners) { EcmaMethod inlinee = inlineeWithInliners.Key; int inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle); int hashCode = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module); hashCode ^= inlineeRid; // Format of the sequence: // Inlinee RID with flag in the lowest bit // - if flag is set, followed by module ID // Followed by inliner RIDs deltas with flag in the lowest bit // - if flag is set, followed by module ID var sig = new VertexSequence(); bool isForeignInlinee = inlinee.Module != _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.Sort((a, b) => { if (a == b) { return(0); } int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } int result = a.Module.CompareTo(b.Module); Debug.Assert(result != 0); return(result); }); int baseRid = 0; foreach (EcmaMethod inliner in sortedInliners) { int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle); int ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; Debug.Assert(ridDelta >= 0); bool isForeignInliner = inliner.Module != _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 })); }
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 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()) { 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 })); } NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable typesHashtable = new VertexHashtable(); section.Place(typesHashtable); ReadyToRunTableManager r2rManager = (ReadyToRunTableManager)factory.MetadataManager; foreach (TypeInfo <TypeDefinitionHandle> defTypeInfo in r2rManager.GetDefinedTypes(_module)) { TypeDefinitionHandle defTypeHandle = defTypeInfo.Handle; int hashCode = 0; for (; ;) { TypeDefinition defType = defTypeInfo.MetadataReader.GetTypeDefinition(defTypeHandle); string namespaceName = defTypeInfo.MetadataReader.GetString(defType.Namespace); string typeName = defTypeInfo.MetadataReader.GetString(defType.Name); hashCode ^= ReadyToRunHashCode.NameHashCode(namespaceName, typeName); if (!defType.Attributes.IsNested()) { break; } defTypeHandle = defType.GetDeclaringType(); } typesHashtable.Append(unchecked ((uint)hashCode), section.Place(new UnsignedConstant(((uint)MetadataTokens.GetRowNumber(defTypeInfo.Handle) << 1) | 0))); } foreach (TypeInfo <ExportedTypeHandle> expTypeInfo in r2rManager.GetExportedTypes(_module)) { ExportedTypeHandle expTypeHandle = expTypeInfo.Handle; int hashCode = 0; for (; ;) { ExportedType expType = expTypeInfo.MetadataReader.GetExportedType(expTypeHandle); string namespaceName = expTypeInfo.MetadataReader.GetString(expType.Namespace); string typeName = expTypeInfo.MetadataReader.GetString(expType.Name); hashCode ^= ReadyToRunHashCode.NameHashCode(namespaceName, typeName); if (expType.Implementation.Kind != HandleKind.ExportedType) { // Not a nested class break; } expTypeHandle = (ExportedTypeHandle)expType.Implementation; } typesHashtable.Append(unchecked ((uint)hashCode), section.Place(new UnsignedConstant(((uint)MetadataTokens.GetRowNumber(expTypeInfo.Handle) << 1) | 1))); } MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.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 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: // 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 structType = structEntry.StructType; var nativeType = structEntry.NativeStructType; Vertex marshallingData = null; if (MarshalHelpers.IsStructMarshallingRequired(structType)) { 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; 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 })); }
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); if (slot == -1) { // This method doesn't have a slot. (At this time, this is only done for the Object.Finalize method) Debug.Assert(declaringMethodForSlot.Name == "Finalize"); continue; } 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 })); }
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 & MetadataGeneration.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 })); } 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)); } 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 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 })); }