| File: Compiler\DependencyAnalysis\ReflectionInvokeMapNode.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Internal.Text; using Internal.TypeSystem; using Internal.NativeFormat; using Debug = System.Diagnostics.Debug; using InvokeTableFlags = Internal.Runtime.InvokeTableFlags; namespace ILCompiler.DependencyAnalysis { /// <summary> /// Represents a map between reflection metadata and generated method bodies. /// </summary> internal sealed class ReflectionInvokeMapNode : ObjectNode, ISymbolDefinitionNode { private ExternalReferencesTableNode _externalReferences; public ReflectionInvokeMapNode(ExternalReferencesTableNode externalReferences) { _externalReferences = externalReferences; } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix).Append("__method_to_entrypoint_map"u8); } public int Offset => 0; public override bool IsShareable => false; public override ObjectNodeSection GetSection(NodeFactory factory) => _externalReferences.GetSection(factory); public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public static void AddDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { Debug.Assert(factory.MetadataManager.IsReflectionInvokable(method)); Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method); dependencies ??= new DependencyList(); dependencies.Add(factory.MaximallyConstructableType(method.OwningType), "Reflection invoke"); if (factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method)) { MethodDesc invokeStub = factory.MetadataManager.GetReflectionInvokeStub(method); dependencies.Add(factory.MethodEntrypoint(invokeStub), "Reflection invoke"); var signature = method.Signature; AddSignatureDependency(ref dependencies, factory, method, signature.ReturnType, "Reflection invoke", isOut: true); foreach (var parameterType in signature) AddSignatureDependency(ref dependencies, factory, method, parameterType, "Reflection invoke", isOut: false); } if (method.OwningType.IsValueType && !method.Signature.IsStatic) dependencies.Add(factory.MethodEntrypoint(method, unboxingStub: true), "Reflection unboxing stub"); if (!method.IsAbstract) { if (method.IsSharedByGenericInstantiations) { dependencies.Add(factory.ShadowNonConcreteMethod(method), "Shadow generic reflectable method"); } dependencies.Add(factory.AddressTakenMethodEntrypoint(method), "Body of a reflectable method"); } if (method.HasInstantiation) { foreach (var instArg in method.Instantiation) { dependencies.Add(factory.NecessaryTypeSymbol(instArg), "Reflectable generic method inst arg"); } } ReflectionVirtualInvokeMapNode.GetVirtualInvokeMapDependencies(ref dependencies, factory, method); } internal static void AddSignatureDependency(ref DependencyList dependencies, NodeFactory factory, TypeSystemEntity referent, TypeDesc type, string reason, bool isOut) { if (type.IsByRef) { type = ((ParameterizedType)type).ParameterType; isOut = true; } // Pointer runtime type handles can be created at runtime if necessary while (type.IsPointer) type = ((ParameterizedType)type).ParameterType; // Skip tracking dependencies for primitive types. Assume that they are always present. if (type.IsPrimitive || type.IsVoid) return; try { factory.TypeSystemContext.DetectGenericCycles(type, referent); // Reflection might need to create boxed instances of valuetypes as part of reflection invocation. // Non-valuetypes are only needed for the purposes of casting/type checks. // If this is a non-exact type, we need the type loader template to get the type handle. if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) GenericTypesTemplateMap.GetTemplateTypeDependencies(ref dependencies, factory, type.NormalizeInstantiation()); else if (isOut && !type.IsGCPointer) dependencies.Add(factory.MaximallyConstructableType(type.NormalizeInstantiation()), reason); else dependencies.Add(factory.MetadataTypeSymbol(type.NormalizeInstantiation()), reason); } catch (TypeSystemException) { // It's fine to continue compiling if there's a problem getting these. There's going to be a MissingMetadata // exception when actually trying to invoke this and the exception will be different than the one we'd get with // a JIT, but that's fine, we don't need to be bug-for-bug compatible. } } 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; Debug.Assert(method == method.GetCanonMethodTarget(CanonicalFormKind.Specific)); if (!factory.MetadataManager.ShouldMethodBeInInvokeMap(method)) continue; InvokeTableFlags flags = 0; if (method.HasInstantiation) flags |= InvokeTableFlags.IsGenericMethod; if (method.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(factory, method)) flags |= InvokeTableFlags.HasVirtualInvoke; if (!method.IsAbstract) flags |= InvokeTableFlags.HasEntrypoint; if (!factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method)) flags |= InvokeTableFlags.NeedsParameterInterpretation; // 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); // 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))); // 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.AddressTakenMethodEntrypoint(method, unboxingStub: method.OwningType.IsValueType && !method.Signature.IsStatic)))); } if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0) { MethodDesc invokeStub = factory.MetadataManager.GetReflectionInvokeStub(method); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStub)))); } if ((flags & InvokeTableFlags.IsGenericMethod) != 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); } int hashCode = method.OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); } protected internal override int Phase => (int)ObjectNodePhase.Ordered; public override int ClassCode => (int)ObjectNodeOrder.ReflectionInvokeMapNode; } }