diff options
author | David Wrighton <davidwr@microsoft.com> | 2017-09-28 20:52:29 +0300 |
---|---|---|
committer | David Wrighton <davidwr@microsoft.com> | 2017-09-28 20:52:29 +0300 |
commit | 60422e48ddb2bbee2ad054b6c4fb3aa3ace0b36d (patch) | |
tree | 8c8176f07848e70811afb191db48a1549028624b | |
parent | 5eaf07fe20d985b8535552d5a6464aee04efd4bd (diff) |
Refactor ecma signature encoding logic out of ManagedBinaryEmitter
- Create signature encoder that is useable with multiple sources of valid tokens
[tfs-changeset: 1676780]
3 files changed, 203 insertions, 144 deletions
diff --git a/src/Common/src/TypeSystem/Ecma/EcmaSignatureEncoder.cs b/src/Common/src/TypeSystem/Ecma/EcmaSignatureEncoder.cs new file mode 100644 index 000000000..3a1d2ac67 --- /dev/null +++ b/src/Common/src/TypeSystem/Ecma/EcmaSignatureEncoder.cs @@ -0,0 +1,184 @@ +// 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 System.Collections.Immutable; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.Metadata; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public interface IEntityHandleProvider + { + /// Implement to allow EcmaSignatureEncoder to encode types that need metadata references to be resolved. + /// only used to express non-generic references + EntityHandle GetTypeDefOrRefHandleForTypeDesc(TypeDesc type); + } + + public class EcmaSignatureEncoder<TEntityHandleProvider> where TEntityHandleProvider : IEntityHandleProvider + { + TEntityHandleProvider _entityHandleProvider; + + public EcmaSignatureEncoder(TEntityHandleProvider entityHandleProvider) + { + _entityHandleProvider = entityHandleProvider; + } + + public void EncodeMethodSignature(BlobBuilder methodSignatureBlob, MethodSignature signature) + { + BlobEncoder encoder = new BlobEncoder(methodSignatureBlob); + + MethodSignatureEncoder methodSigEncoder = encoder.MethodSignature( + SignatureCallingConvention.Default, signature.GenericParameterCount, !signature.IsStatic); + + ReturnTypeEncoder returnTypeEncoder; + ParametersEncoder parametersEncoder; + methodSigEncoder.Parameters(signature.Length, out returnTypeEncoder, out parametersEncoder); + + // Return Type Sig + EncodeTypeSignature(returnTypeEncoder.Type(), signature.ReturnType); + + // Parameter Types Sig + for (int i = 0; i < signature.Length; i++) + EncodeTypeSignature(parametersEncoder.AddParameter().Type(), signature[i]); + } + + public void EncodeTypeSignature(SignatureTypeEncoder encoder, TypeDesc type) + { + if (type is RuntimeDeterminedType) + { + EncodeTypeSignature(encoder, ((RuntimeDeterminedType)type).RuntimeDeterminedDetailsType); + return; + } + + switch (type.Category) + { + case TypeFlags.Boolean: + encoder.Boolean(); break; + case TypeFlags.Byte: + encoder.Byte(); break; + case TypeFlags.SByte: + encoder.SByte(); break; + case TypeFlags.Char: + encoder.Char(); break; + case TypeFlags.Int16: + encoder.Int16(); break; + case TypeFlags.UInt16: + encoder.UInt16(); break; + case TypeFlags.Int32: + encoder.Int32(); break; + case TypeFlags.UInt32: + encoder.UInt32(); break; + case TypeFlags.Int64: + encoder.Int64(); break; + case TypeFlags.UInt64: + encoder.UInt64(); break; + case TypeFlags.Single: + encoder.Single(); break; + case TypeFlags.Double: + encoder.Double(); break; + case TypeFlags.IntPtr: + encoder.IntPtr(); break; + case TypeFlags.UIntPtr: + encoder.UIntPtr(); break; + case TypeFlags.Void: + encoder.Builder.WriteByte((byte)PrimitiveTypeCode.Void); + break; + + case TypeFlags.SignatureTypeVariable: + encoder.GenericTypeParameter(((SignatureVariable)type).Index); + break; + + case TypeFlags.SignatureMethodVariable: + encoder.GenericMethodTypeParameter(((SignatureMethodVariable)type).Index); + break; + + case TypeFlags.GenericParameter: + { + var genericTypeDesc = (GenericParameterDesc)type; + if (genericTypeDesc.Kind == GenericParameterKind.Type) + encoder.GenericTypeParameter(genericTypeDesc.Index); + else + encoder.GenericMethodTypeParameter(genericTypeDesc.Index); + } + break; + + case TypeFlags.FunctionPointer: + { + FunctionPointerType fptrType = (FunctionPointerType)type; + encoder.FunctionPointer( + SignatureCallingConvention.Default, + fptrType.Signature.IsStatic ? default(FunctionPointerAttributes) : FunctionPointerAttributes.HasThis, + fptrType.Signature.GenericParameterCount); + + // Return Type Sig + EncodeTypeSignature(encoder, fptrType.Signature.ReturnType); + + // Parameter Types Sig + for (int i = 0; i < fptrType.Signature.Length; i++) + EncodeTypeSignature(encoder, fptrType.Signature[i]); + } + break; + + case TypeFlags.Array: + { + // Skip bounds and lobounds (TODO) + ImmutableArray<int> bounds = ImmutableArray.Create<int>(); + ImmutableArray<int> lowerBounds = ImmutableArray.Create<int>(); + encoder.Array( + elementType => EncodeTypeSignature(elementType, ((ArrayType)type).ElementType), + arrayShape => arrayShape.Shape(((ArrayType)type).Rank, bounds, lowerBounds)); + } + break; + + case TypeFlags.SzArray: + encoder.SZArray(); + EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); + break; + + case TypeFlags.ByRef: + encoder.Builder.WriteByte((byte)SignatureTypeCode.ByReference); + EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); + break; + + case TypeFlags.Pointer: + encoder.Builder.WriteByte((byte)SignatureTypeCode.Pointer); + EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); + break; + + case TypeFlags.Enum: + case TypeFlags.Class: + case TypeFlags.ValueType: + case TypeFlags.Interface: + case TypeFlags.Nullable: + { + if (type == type.Context.GetWellKnownType(WellKnownType.TypedReference)) + encoder.Builder.WriteByte((byte)PrimitiveTypeCode.TypedReference); + else if (type == type.Context.GetWellKnownType(WellKnownType.Object)) + encoder.PrimitiveType(PrimitiveTypeCode.Object); + else if (type == type.Context.GetWellKnownType(WellKnownType.String)) + encoder.PrimitiveType(PrimitiveTypeCode.String); + else if (type.HasInstantiation && !type.IsGenericDefinition) + { + encoder.GenericInstantiation(_entityHandleProvider.GetTypeDefOrRefHandleForTypeDesc(type.GetTypeDefinition()), type.Instantiation.Length, type.IsValueType); + + for (int i = 0; i < type.Instantiation.Length; i++) + EncodeTypeSignature(encoder, type.Instantiation[i]); + } + else + { + encoder.Type(_entityHandleProvider.GetTypeDefOrRefHandleForTypeDesc(type), type.IsValueType); + } + } + break; + + default: + throw new InvalidOperationException("Attempting to encode an invalid type signature."); + } + } + } +} diff --git a/src/ILCompiler.Compiler/src/Compiler/ManagedBinaryEmitter.cs b/src/ILCompiler.Compiler/src/Compiler/ManagedBinaryEmitter.cs index f584cc03b..7e5ecbd81 100644 --- a/src/ILCompiler.Compiler/src/Compiler/ManagedBinaryEmitter.cs +++ b/src/ILCompiler.Compiler/src/Compiler/ManagedBinaryEmitter.cs @@ -94,6 +94,7 @@ namespace ILCompiler fieldList: MetadataTokens.FieldDefinitionHandle(1), methodList: MetadataTokens.MethodDefinitionHandle(1)); + _signatureEmitter = new EcmaSignatureEncoder<EntityProviderForEcmaSignature>(new EntityProviderForEcmaSignature(this)); } public EmittedTypeDefinition EmitTypeDefinition(string typeName, bool isValueType) @@ -128,7 +129,7 @@ namespace ILCompiler public void EncodeSignatureForType(TypeDesc type, BlobBuilder blobBuilder) { SignatureTypeEncoder sigEncoder = new SignatureTypeEncoder(blobBuilder); - EncodeTypeSignature(sigEncoder, type); + _signatureEmitter.EncodeTypeSignature(sigEncoder, type); } public void EmitOutputFile(string outputPath) @@ -192,140 +193,23 @@ namespace ILCompiler private Dictionary<MethodSignature, BlobHandle> _methodSignatureHandles = new Dictionary<MethodSignature, BlobHandle>(); private Dictionary<FieldDesc, BlobHandle> _fieldSignatureHandles = new Dictionary<FieldDesc, BlobHandle>(); - private void EncodeTypeSignature(SignatureTypeEncoder encoder, TypeDesc type) + private struct EntityProviderForEcmaSignature : IEntityHandleProvider { - if (type is RuntimeDeterminedType) + private ManagedBinaryEmitter _emitter; + + public EntityProviderForEcmaSignature(ManagedBinaryEmitter emitter) { - EncodeTypeSignature(encoder, ((RuntimeDeterminedType)type).RuntimeDeterminedDetailsType); - return; + _emitter = emitter; } - switch (type.Category) + public EntityHandle GetTypeDefOrRefHandleForTypeDesc(TypeDesc type) { - case TypeFlags.Boolean: - encoder.Boolean(); break; - case TypeFlags.Byte: - encoder.Byte(); break; - case TypeFlags.SByte: - encoder.SByte(); break; - case TypeFlags.Char: - encoder.Char(); break; - case TypeFlags.Int16: - encoder.Int16(); break; - case TypeFlags.UInt16: - encoder.UInt16(); break; - case TypeFlags.Int32: - encoder.Int32(); break; - case TypeFlags.UInt32: - encoder.UInt32(); break; - case TypeFlags.Int64: - encoder.Int64(); break; - case TypeFlags.UInt64: - encoder.UInt64(); break; - case TypeFlags.Single: - encoder.Single(); break; - case TypeFlags.Double: - encoder.Double(); break; - case TypeFlags.IntPtr: - encoder.IntPtr(); break; - case TypeFlags.UIntPtr: - encoder.UIntPtr(); break; - case TypeFlags.Void: - encoder.Builder.WriteByte((byte)PrimitiveTypeCode.Void); - break; - - case TypeFlags.SignatureTypeVariable: - encoder.GenericTypeParameter(((SignatureVariable)type).Index); - break; - - case TypeFlags.SignatureMethodVariable: - encoder.GenericMethodTypeParameter(((SignatureMethodVariable)type).Index); - break; - - case TypeFlags.GenericParameter: - { - var genericTypeDesc = (GenericParameterDesc)type; - if (genericTypeDesc.Kind == GenericParameterKind.Type) - encoder.GenericTypeParameter(genericTypeDesc.Index); - else - encoder.GenericMethodTypeParameter(genericTypeDesc.Index); - } - break; - - case TypeFlags.FunctionPointer: - { - FunctionPointerType fptrType = (FunctionPointerType)type; - encoder.FunctionPointer( - SignatureCallingConvention.Default, - fptrType.Signature.IsStatic ? default(FunctionPointerAttributes) : FunctionPointerAttributes.HasThis, - fptrType.Signature.GenericParameterCount); - - // Return Type Sig - EncodeTypeSignature(encoder, fptrType.Signature.ReturnType); - - // Parameter Types Sig - for (int i = 0; i < fptrType.Signature.Length; i++) - EncodeTypeSignature(encoder, fptrType.Signature[i]); - } - break; - - case TypeFlags.Array: - { - // Skip bounds and lobounds (TODO) - ImmutableArray<int> bounds = ImmutableArray.Create<int>(); - ImmutableArray<int> lowerBounds = ImmutableArray.Create<int>(); - encoder.Array( - elementType => EncodeTypeSignature(elementType, ((ArrayType)type).ElementType), - arrayShape => arrayShape.Shape(((ArrayType)type).Rank, bounds, lowerBounds)); - } - break; - - case TypeFlags.SzArray: - encoder.SZArray(); - EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); - break; - - case TypeFlags.ByRef: - encoder.Builder.WriteByte((byte)SignatureTypeCode.ByReference); - EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); - break; - - case TypeFlags.Pointer: - encoder.Builder.WriteByte((byte)SignatureTypeCode.Pointer); - EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType); - break; - - case TypeFlags.Enum: - case TypeFlags.Class: - case TypeFlags.ValueType: - case TypeFlags.Interface: - case TypeFlags.Nullable: - { - if (type == _typeSystemContext.GetWellKnownType(WellKnownType.TypedReference)) - encoder.Builder.WriteByte((byte)PrimitiveTypeCode.TypedReference); - else if (type == _typeSystemContext.GetWellKnownType(WellKnownType.Object)) - encoder.PrimitiveType(PrimitiveTypeCode.Object); - else if (type == _typeSystemContext.GetWellKnownType(WellKnownType.String)) - encoder.PrimitiveType(PrimitiveTypeCode.String); - else if (type.HasInstantiation && !type.IsGenericDefinition) - { - encoder.GenericInstantiation(MakeTypeRefOrSpecHandle(type.GetTypeDefinition()), type.Instantiation.Length, type.IsValueType); - - for (int i = 0; i < type.Instantiation.Length; i++) - EncodeTypeSignature(encoder, type.Instantiation[i]); - } - else - { - encoder.Type(MakeTypeRefHandle(type), type.IsValueType); - } - } - break; - - default: - throw new InvalidOperationException("Attempting to encode an invalid type signature."); + return _emitter.MakeTypeRefHandle(type); } } + private EcmaSignatureEncoder<EntityProviderForEcmaSignature> _signatureEmitter; + private BlobHandle MakeSignatureHandle(MethodSignature signature) { BlobHandle handle; @@ -334,19 +218,7 @@ namespace ILCompiler { BlobBuilder metadataSignature = new BlobBuilder(); - MethodSignatureEncoder methodSigEncoder = new BlobEncoder(metadataSignature).MethodSignature( - SignatureCallingConvention.Default, signature.GenericParameterCount, !signature.IsStatic); - - ReturnTypeEncoder returnTypeEncoder; - ParametersEncoder parametersEncoder; - methodSigEncoder.Parameters(signature.Length, out returnTypeEncoder, out parametersEncoder); - - // Return Type Sig - EncodeTypeSignature(returnTypeEncoder.Type(), signature.ReturnType); - - // Parameter Types Sig - for (int i = 0; i < signature.Length; i++) - EncodeTypeSignature(parametersEncoder.AddParameter().Type(), signature[i]); + _signatureEmitter.EncodeMethodSignature(metadataSignature, signature); _methodSignatureHandles[signature] = handle = _metadataBuilder.GetOrAddBlob(metadataSignature); } @@ -370,7 +242,7 @@ namespace ILCompiler BlobBuilder metadataSignature = new BlobBuilder(); SignatureTypeEncoder fieldSigEncoder = new BlobEncoder(metadataSignature).FieldSignature(); - EncodeTypeSignature(fieldSigEncoder, field.FieldType); + _signatureEmitter.EncodeTypeSignature(fieldSigEncoder, field.FieldType); _fieldSignatureHandles[field] = handle = _metadataBuilder.GetOrAddBlob(metadataSignature); } @@ -455,7 +327,7 @@ namespace ILCompiler if(!type.IsDefType || !type.IsTypeDefinition || type is RuntimeDeterminedType) { SignatureTypeEncoder sigEncoder = new SignatureTypeEncoder(new BlobBuilder()); - EncodeTypeSignature(sigEncoder, type); + _signatureEmitter.EncodeTypeSignature(sigEncoder, type); handle = _metadataBuilder.AddTypeSpecification(_metadataBuilder.GetOrAddBlob(sigEncoder.Builder)); } else @@ -497,7 +369,7 @@ namespace ILCompiler for (int i = 0; i < method.Instantiation.Length; i++) { SignatureTypeEncoder argTypeEncoder = argEncoder.AddArgument(); - EncodeTypeSignature(argTypeEncoder, method.Instantiation[i]); + _signatureEmitter.EncodeTypeSignature(argTypeEncoder, method.Instantiation[i]); } handle = _metadataBuilder.AddMethodSpecification(handle, _metadataBuilder.GetOrAddBlob(methodSpecEncoder.Builder)); diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 1e94ddbae..02763096a 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -1,4 +1,4 @@ -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" Condition="'$(IsProjectNLibrary)' != 'true'" /> <PropertyGroup> <OutputType>Library</OutputType> @@ -43,6 +43,9 @@ <Compile Include="..\..\Common\src\Internal\Text\Utf8StringBuilder.cs"> <Link>Common\Utf8StringBuilder.cs</Link> </Compile> + <Compile Include="..\..\Common\src\TypeSystem\Ecma\EcmaSignatureEncoder.cs"> + <Link>Ecma\EcmaSignatureEncoder.cs</Link> + </Compile> <Compile Include="..\..\Common\src\TypeSystem\IL\ILImporter.cs"> <Link>IL\ILImporter.cs</Link> </Compile> |