public static DependencyList GetExactMethodInstantiationDependenciesForMethod(NodeFactory factory, MethodDesc method) { if (!IsMethodEligibleForTracking(method)) { return(null); } DependencyList dependencies = new DependencyList(); // Method entry point dependency bool getUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; IMethodNode methodEntryPointNode = factory.MethodEntrypoint(method, getUnboxingStub); dependencies.Add(new DependencyListEntry(methodEntryPointNode, "Exact method instantiation entry")); // Get native layout dependencies for the declaring type dependencies.Add(new DependencyListEntry(factory.NecessaryTypeSymbol(method.OwningType), "Exact method instantiation entry")); // Get native layout dependencies for the method instantiation args foreach (var arg in method.Instantiation) { dependencies.Add(new DependencyListEntry(factory.NecessaryTypeSymbol(arg), "Exact method instantiation entry")); } // Get native layout dependencies for the method signature. NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); dependencies.Add(new DependencyListEntry(factory.NativeLayout.PlacedSignatureVertex(nameAndSig), "Exact method instantiation entry")); return(dependencies); }
public static void GetVirtualInvokeMapDependencies(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { if (!factory.MetadataManager.SupportsReflection) { return; } if (NeedsVirtualInvokeInfo(method)) { dependencies = dependencies ?? new DependencyList(); dependencies.Add( factory.NecessaryTypeSymbol(method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific)), "Reflection virtual invoke owning type"); NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); dependencies.Add(placedNameAndSig, "Reflection virtual invoke method signature"); if (!method.HasInstantiation) { MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); if (!factory.VTable(slotDefiningMethod.OwningType).HasFixedSlots) { dependencies.Add(factory.VirtualMethodUse(slotDefiningMethod), "Reflection virtual invoke method"); } } } }
public static IEnumerable <DependencyListEntry> GetVirtualInvokeMapDependencies(NodeFactory factory, MethodDesc method) { if (NeedsVirtualInvokeInfo(method)) { if (factory.Target.Abi == TargetAbi.ProjectN) { yield return(new DependencyListEntry( factory.NecessaryTypeSymbol(method.OwningType.GetTypeDefinition()), "Reflection virtual invoke owning type")); } else { yield return(new DependencyListEntry( factory.NecessaryTypeSymbol(method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific)), "Reflection virtual invoke owning type")); } NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); yield return(new DependencyListEntry(placedNameAndSig, "Reflection virtual invoke method signature")); } }
public static void GetVirtualInvokeMapDependencies(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { if (NeedsVirtualInvokeInfo(method)) { dependencies = dependencies ?? new DependencyList(); if (factory.Target.Abi == TargetAbi.ProjectN) { dependencies.Add( factory.NecessaryTypeSymbol(method.OwningType.GetTypeDefinition()), "Reflection virtual invoke owning type"); } else { dependencies.Add( factory.NecessaryTypeSymbol(method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific)), "Reflection virtual invoke owning type"); } NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); dependencies.Add(placedNameAndSig, "Reflection virtual invoke method signature"); } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout blob has been saved factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); Dictionary <int, HashSet <TypeDesc> > methodsEmitted = new Dictionary <int, HashSet <TypeDesc> >(); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory)) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.IsReflectionInvokable(method)) { continue; } // Only virtual methods are interesting if (!NeedsVirtualInvokeInfo(method)) { continue; } // // When working with the ProjectN ABI, the entries in the map are based on the definition types. All // instantiations of these definition types will have the same vtable method entries. // On CoreRT, the vtable entries for each instantiated type might not necessarily exist. // Example 1: // If there's a call to Foo<string>.Method1 and a call to Foo<int>.Method2, Foo<string> will // not have Method2 in its vtable and Foo<int> will not have Method1. // Example 2: // If there's a call to Foo<string>.Method1 and a call to Foo<object>.Method2, given that both // of these instantiations share the same canonical form, Foo<__Canon> will have both method // entries, and therefore Foo<string> and Foo<object> will have both entries too. // For this reason, the entries that we write to the map in CoreRT will be based on the canonical form // of the method's containing type instead of the open type definition. // // Similarly, given that we use the open type definition for ProjectN, the slot numbers ignore dictionary // entries in the vtable, and computing the correct slot number in the presence of dictionary entries is // done at runtime. When working with the CoreRT ABI, the correct slot numbers will be written to the map, // and no adjustments will be performed at runtime. // TypeDesc containingTypeKey; if (factory.Target.Abi == TargetAbi.ProjectN) { containingTypeKey = method.OwningType.GetTypeDefinition(); } else { containingTypeKey = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific); } HashSet <TypeDesc> cache; if (!methodsEmitted.TryGetValue(mappingEntry.MetadataHandle, out cache)) { methodsEmitted[mappingEntry.MetadataHandle] = cache = new HashSet <TypeDesc>(); } // Only one record is needed for any instantiation. if (!cache.Add(containingTypeKey)) { continue; } // Grammar of an entry in the hash table: // Virtual Method uses a normal slot // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1) + slot // OR // Generic Virtual Method // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1 + 1) int parentHierarchyDistance; MethodDesc declaringMethodForSlot = GetDeclaringVirtualMethodAndHierarchyDistance(method, out parentHierarchyDistance); Vertex vertex = null; ISymbolNode containingTypeKeyNode = factory.NecessaryTypeSymbol(containingTypeKey); NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); if (method.HasInstantiation) { vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)), writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset), writer.GetUnsignedConstant(((uint)parentHierarchyDistance << 1) + VirtualInvokeTableEntry.GenericVirtualMethod)); } else { // Get the declaring method for slot on the instantiated declaring type int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, declaringMethodForSlot, factory.Target.Abi != TargetAbi.ProjectN); Debug.Assert(slot != -1); vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)), writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)parentHierarchyDistance << 1), writer.GetUnsignedConstant((uint)slot)); } int hashCode = containingTypeKey.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
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 })); }