From 984c9f9f2230bd41b8ba1e3390b9bf76d85061ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 12 Oct 2021 15:49:26 +0900 Subject: [PATCH] Add TypeSpecification and MethodSpecification (#21) These are pretty boring, but adding them adds more testing opportunities for #4 since these all have a blob that #4 should be able to parse/rewrite. --- .../ILTrim/DependencyAnalysis/NodeFactory.cs | 20 ++++++- .../TokenBased/MethodSpecificationNode.cs | 52 +++++++++++++++++++ .../TokenBased/TypeSpecificationNode.cs | 50 ++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/MethodSpecificationNode.cs create mode 100644 src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/TypeSpecificationNode.cs diff --git a/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/NodeFactory.cs index d6a338a7c8c..9c7dd505e9f 100644 --- a/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/NodeFactory.cs @@ -53,7 +53,7 @@ public TokenBasedNode GetNodeForToken(EcmaModule module, EntityHandle handle) case HandleKind.ModuleReference: throw new NotImplementedException(); case HandleKind.TypeSpecification: - throw new NotImplementedException(); + return TypeSpecification(module, (TypeSpecificationHandle)handle); case HandleKind.AssemblyReference: return AssemblyReference(module, (AssemblyReferenceHandle)handle); case HandleKind.AssemblyFile: @@ -65,7 +65,7 @@ public TokenBasedNode GetNodeForToken(EcmaModule module, EntityHandle handle) case HandleKind.GenericParameter: throw new NotImplementedException(); case HandleKind.MethodSpecification: - throw new NotImplementedException(); + return MethodSpecification(module, (MethodSpecificationHandle)handle); case HandleKind.GenericParameterConstraint: throw new NotImplementedException(); default: @@ -145,6 +145,22 @@ public ModuleDefinitionNode ModuleDefinition(EcmaModule module) return _moduleDefinitions.GetOrAdd(module); } + NodeCache, MethodSpecificationNode> _methodSpecifications + = new NodeCache, MethodSpecificationNode>(key + => new MethodSpecificationNode(key.Module, key.Handle)); + public MethodSpecificationNode MethodSpecification(EcmaModule module, MethodSpecificationHandle handle) + { + return _methodSpecifications.GetOrAdd(new HandleKey(module, handle)); + } + + NodeCache, TypeSpecificationNode> _typeSpecifications + = new NodeCache, TypeSpecificationNode>(key + => new TypeSpecificationNode(key.Module, key.Handle)); + public TypeSpecificationNode TypeSpecification(EcmaModule module, TypeSpecificationHandle handle) + { + return _typeSpecifications.GetOrAdd(new HandleKey(module, handle)); + } + NodeCache _assemblyDefinitions = new NodeCache( key => new AssemblyDefinitionNode(key)); diff --git a/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/MethodSpecificationNode.cs b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/MethodSpecificationNode.cs new file mode 100644 index 00000000000..faa23abce27 --- /dev/null +++ b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/MethodSpecificationNode.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Reflection.Metadata; + +namespace ILTrim.DependencyAnalysis +{ + /// + /// Represents an entry in the MethodSpec metadata table (an instantiated generic method). + /// + public sealed class MethodSpecificationNode : TokenBasedNode + { + public MethodSpecificationNode(EcmaModule module, MethodSpecificationHandle handle) + : base(module, handle) + { + } + + private MethodSpecificationHandle Handle => (MethodSpecificationHandle)_handle; + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + MethodSpecification methodSpec = _module.MetadataReader.GetMethodSpecification(Handle); + + // TODO: report dependencies from the signature + + yield return new(factory.GetNodeForToken(_module, methodSpec.Method), "Instantiated method"); + } + + protected override EntityHandle WriteInternal(ModuleWritingContext writeContext) + { + MetadataReader reader = _module.MetadataReader; + + MethodSpecification methodSpec = reader.GetMethodSpecification(Handle); + + var builder = writeContext.MetadataBuilder; + + // TODO: the signature blob might contain references to tokens we need to rewrite + var signatureBlob = reader.GetBlobBytes(methodSpec.Signature); + + return builder.AddMethodSpecification( + writeContext.TokenMap.MapToken(methodSpec.Method), + builder.GetOrAddBlob(signatureBlob)); + } + + public override string ToString() + { + // TODO: would be nice to have a common formatter we can call into + return "MethodSpecification"; + } + } +} diff --git a/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/TypeSpecificationNode.cs b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/TypeSpecificationNode.cs new file mode 100644 index 00000000000..d228e5d778e --- /dev/null +++ b/src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/TypeSpecificationNode.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Reflection.Metadata; + +namespace ILTrim.DependencyAnalysis +{ + /// + /// Represents an entry in the TypeSpec metadata table (a constructed type). + /// + public sealed class TypeSpecificationNode : TokenBasedNode + { + public TypeSpecificationNode(EcmaModule module, TypeSpecificationHandle handle) + : base(module, handle) + { + } + + private TypeSpecificationHandle Handle => (TypeSpecificationHandle)_handle; + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + TypeSpecification typeSpec = _module.MetadataReader.GetTypeSpecification(Handle); + + // TODO: report dependencies from the signature + yield break; + } + + protected override EntityHandle WriteInternal(ModuleWritingContext writeContext) + { + MetadataReader reader = _module.MetadataReader; + + TypeSpecification typeSpec = reader.GetTypeSpecification(Handle); + + var builder = writeContext.MetadataBuilder; + + // TODO: the signature blob might contain references to tokens we need to rewrite + var signatureBlob = reader.GetBlobBytes(typeSpec.Signature); + + return builder.AddTypeSpecification( + builder.GetOrAddBlob(signatureBlob)); + } + + public override string ToString() + { + // TODO: would be nice to have a common formatter we can call into + return "TypeSpecification"; + } + } +}