diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2017-12-07 21:55:17 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-07 21:55:17 +0300 |
commit | 7ee9fb354edee4fb0846e2a3d5e64e7ec02c7f71 (patch) | |
tree | da0d856519a734603421b4ae8d900595bae431c4 /src/ILCompiler.MetadataTransform | |
parent | d56a610b3c890567feacf9492743a691ee3306e3 (diff) |
Emit metadata for type forwarders (#5054)
Diffstat (limited to 'src/ILCompiler.MetadataTransform')
3 files changed, 134 insertions, 26 deletions
diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj b/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj index 97f6e3ab3..2ecadbac2 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj @@ -32,6 +32,7 @@ <Compile Include="ILCompiler\Metadata\Transform.Scope.cs" /> <Compile Include="ILCompiler\Metadata\Transform.String.cs" /> <Compile Include="ILCompiler\Metadata\Transform.Type.cs" /> + <Compile Include="ILCompiler\Metadata\Transform.TypeForwarders.cs" /> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" Condition="'$(IsProjectNLibrary)' != 'true'"/> </Project> diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs index a518dcb85..406a61511 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs @@ -13,6 +13,7 @@ using Debug = System.Diagnostics.Debug; using AssemblyFlags = Internal.Metadata.NativeFormat.AssemblyFlags; using AssemblyNameFlags = System.Reflection.AssemblyNameFlags; using AssemblyContentType = System.Reflection.AssemblyContentType; +using AssemblyName = System.Reflection.AssemblyName; namespace ILCompiler.Metadata { @@ -97,6 +98,8 @@ namespace ILCompiler.Metadata { scopeDefinition.ModuleCustomAttributes = HandleCustomAttributes(ecmaAssembly, moduleAttributes); } + + HandleTypeForwarders(ecmaAssembly); } } else @@ -105,45 +108,57 @@ namespace ILCompiler.Metadata } } - private EntityMap<Cts.ModuleDesc, ScopeReference> _scopeRefs - = new EntityMap<Cts.ModuleDesc, ScopeReference>(EqualityComparer<Cts.ModuleDesc>.Default); - private Action<Cts.ModuleDesc, ScopeReference> _initScopeRef; + private EntityMap<AssemblyName, ScopeReference> _scopeRefs + = new EntityMap<AssemblyName, ScopeReference>(new SimpleAssemblyNameComparer()); + private Action<AssemblyName, ScopeReference> _initScopeRef; private ScopeReference HandleScopeReference(Cts.ModuleDesc module) { - return _scopeRefs.GetOrCreate(module, _initScopeRef ?? (_initScopeRef = InitializeScopeReference)); + var assembly = module as Cts.IAssemblyDesc; + if (assembly != null) + return HandleScopeReference(assembly.GetName()); + else + throw new NotSupportedException("Multi-module assemblies"); } - private void InitializeScopeReference(Cts.ModuleDesc module, ScopeReference scopeReference) + private ScopeReference HandleScopeReference(AssemblyName assemblyName) { - var assemblyDesc = module as Cts.IAssemblyDesc; - if (assemblyDesc != null) - { - var assemblyName = assemblyDesc.GetName(); + return _scopeRefs.GetOrCreate(assemblyName, _initScopeRef ?? (_initScopeRef = InitializeScopeReference)); + } - scopeReference.Name = HandleString(assemblyName.Name); - scopeReference.Culture = HandleString(assemblyName.CultureName); - scopeReference.MajorVersion = checked((ushort)assemblyName.Version.Major); - scopeReference.MinorVersion = checked((ushort)assemblyName.Version.Minor); - scopeReference.BuildNumber = checked((ushort)assemblyName.Version.Build); - scopeReference.RevisionNumber = checked((ushort)assemblyName.Version.Revision); + private void InitializeScopeReference(AssemblyName assemblyName, ScopeReference scopeReference) + { + scopeReference.Name = HandleString(assemblyName.Name); + scopeReference.Culture = HandleString(assemblyName.CultureName); + scopeReference.MajorVersion = checked((ushort)assemblyName.Version.Major); + scopeReference.MinorVersion = checked((ushort)assemblyName.Version.Minor); + scopeReference.BuildNumber = checked((ushort)assemblyName.Version.Build); + scopeReference.RevisionNumber = checked((ushort)assemblyName.Version.Revision); - Debug.Assert((int)AssemblyFlags.PublicKey == (int)AssemblyNameFlags.PublicKey); - Debug.Assert((int)AssemblyFlags.Retargetable == (int)AssemblyNameFlags.Retargetable); + Debug.Assert((int)AssemblyFlags.PublicKey == (int)AssemblyNameFlags.PublicKey); + Debug.Assert((int)AssemblyFlags.Retargetable == (int)AssemblyNameFlags.Retargetable); - // References use a public key token instead of full public key. - scopeReference.Flags = (AssemblyFlags)(assemblyName.Flags & ~AssemblyNameFlags.PublicKey); + // References use a public key token instead of full public key. + scopeReference.Flags = (AssemblyFlags)(assemblyName.Flags & ~AssemblyNameFlags.PublicKey); - if (assemblyName.ContentType == AssemblyContentType.WindowsRuntime) - { - scopeReference.Flags |= (AssemblyFlags)((int)AssemblyContentType.WindowsRuntime << 9); - } + if (assemblyName.ContentType == AssemblyContentType.WindowsRuntime) + { + scopeReference.Flags |= (AssemblyFlags)((int)AssemblyContentType.WindowsRuntime << 9); + } + + scopeReference.PublicKeyOrToken = assemblyName.GetPublicKeyToken(); + } - scopeReference.PublicKeyOrToken = assemblyName.GetPublicKeyToken(); + private class SimpleAssemblyNameComparer : IEqualityComparer<AssemblyName> + { + public bool Equals(AssemblyName x, AssemblyName y) + { + return Object.Equals(x.Name, y.Name); } - else + + public int GetHashCode(AssemblyName obj) { - throw new NotSupportedException("Multi-module assemblies"); + return obj.Name?.GetHashCode() ?? 0; } } } diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.TypeForwarders.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.TypeForwarders.cs new file mode 100644 index 000000000..be03c1d73 --- /dev/null +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.TypeForwarders.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +using Internal.Metadata.NativeFormat.Writer; + +using Cts = Internal.TypeSystem; +using Ecma = System.Reflection.Metadata; + +using Debug = System.Diagnostics.Debug; +using AssemblyName = System.Reflection.AssemblyName; +using AssemblyContentType = System.Reflection.AssemblyContentType; +using AssemblyNameFlags = System.Reflection.AssemblyNameFlags; +using AssemblyFlags = System.Reflection.AssemblyFlags; + +namespace ILCompiler.Metadata +{ + partial class Transform<TPolicy> + { + private void HandleTypeForwarders(Cts.Ecma.EcmaModule module) + { + foreach (var exportedTypeHandle in module.MetadataReader.ExportedTypes) + { + Ecma.ExportedType exportedType = module.MetadataReader.GetExportedType(exportedTypeHandle); + if (exportedType.IsForwarder || exportedType.Implementation.Kind == Ecma.HandleKind.ExportedType) + { + HandleTypeForwarder(module, exportedType); + } + else + { + Debug.Assert(false, "Multi-module assemblies"); + } + } + } + + private TypeForwarder HandleTypeForwarder(Cts.Ecma.EcmaModule module, Ecma.ExportedType exportedType) + { + Ecma.MetadataReader reader = module.MetadataReader; + string name = reader.GetString(exportedType.Name); + TypeForwarder result; + + switch (exportedType.Implementation.Kind) + { + case Ecma.HandleKind.AssemblyReference: + { + string ns = reader.GetString(exportedType.Namespace); + NamespaceDefinition namespaceDefinition = HandleNamespaceDefinition(module, ns); + + Ecma.AssemblyReference assemblyRef = reader.GetAssemblyReference((Ecma.AssemblyReferenceHandle)exportedType.Implementation); + AssemblyName refName = new AssemblyName + { + ContentType = (AssemblyContentType)((int)(assemblyRef.Flags & AssemblyFlags.ContentTypeMask) >> 9), + Flags = (AssemblyNameFlags)(assemblyRef.Flags & ~AssemblyFlags.ContentTypeMask), + CultureName = reader.GetString(assemblyRef.Culture), + Name = reader.GetString(assemblyRef.Name), + Version = assemblyRef.Version, + }; + + result = new TypeForwarder + { + Name = HandleString(name), + Scope = HandleScopeReference(refName), + }; + + namespaceDefinition.TypeForwarders.Add(result); + } + break; + + case Ecma.HandleKind.ExportedType: + { + TypeForwarder scope = HandleTypeForwarder(module, reader.GetExportedType((Ecma.ExportedTypeHandle)exportedType.Implementation)); + + result = new TypeForwarder + { + Name = HandleString(name), + Scope = scope.Scope, + }; + + scope.NestedTypes.Add(result); + } + break; + + default: + throw new BadImageFormatException(); + } + + return result; + } + } +} |