private BlobHandle GetFieldSignatureBlobHandle(FieldDesc field)
        {
            var fieldDef        = field.GetTypicalFieldDefinition();
            var embeddedSigData = field.GetEmbeddedSignatureData();
            EmbeddedSignatureDataEmitter signatureDataEmitter;

            if (embeddedSigData != null && embeddedSigData.Length != 0)
            {
                signatureDataEmitter = new EmbeddedSignatureDataEmitter(embeddedSigData, this);
            }
            else
            {
                signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton;
            }

            BlobBuilder memberRefSig = new BlobBuilder();

            EncodeFieldSignature(memberRefSig, field.FieldType, signatureDataEmitter);

            if (!signatureDataEmitter.Complete)
            {
                throw new ArgumentException();
            }

            var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig);

            return(sigBlob);
        }
        private BlobHandle GetMethodSignatureBlobHandle(MethodSignature sig)
        {
            EmbeddedSignatureDataEmitter signatureDataEmitter;

            if (sig.HasEmbeddedSignatureData)
            {
                signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this);
            }
            else
            {
                signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton;
            }

            BlobBuilder memberRefSig = new BlobBuilder();

            EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter);

            if (!signatureDataEmitter.Complete)
            {
                throw new ArgumentException();
            }

            var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig);

            return(sigBlob);
        }
        void EncodeFieldSignature(BlobBuilder signatureBuilder, TypeDesc fieldType, EmbeddedSignatureDataEmitter signatureDataEmitter)
        {
            signatureDataEmitter.Push();
            BlobEncoder signatureEncoder = new BlobEncoder(signatureBuilder);

            signatureEncoder.FieldSignature();
            EncodeType(signatureBuilder, fieldType, signatureDataEmitter);
            signatureDataEmitter.Pop();
        }
        public EntityHandle GetMethodRef(MethodDesc method)
        {
            if (_methodRefs.TryGetValue(method, out var handle))
            {
                return(handle);
            }

            EntityHandle methodHandle;

            if (method.HasInstantiation && (method.GetMethodDefinition() != method))
            {
                EntityHandle uninstantiatedHandle = GetMethodRef(method.GetMethodDefinition());
                BlobBuilder  methodSpecSig        = new BlobBuilder();
                BlobEncoder  methodSpecEncoder    = new BlobEncoder(methodSpecSig);
                methodSpecEncoder.MethodSpecificationSignature(method.Instantiation.Length);
                foreach (var type in method.Instantiation)
                {
                    EncodeType(methodSpecSig, type, EmbeddedSignatureDataEmitter.EmptySingleton);
                }

                var methodSpecSigHandle = _metadataBuilder.GetOrAddBlob(methodSpecSig);
                methodHandle = _metadataBuilder.AddMethodSpecification(uninstantiatedHandle, methodSpecSigHandle);
            }
            else
            {
                EntityHandle typeHandle = GetTypeRef((MetadataType)method.OwningType);
                StringHandle methodName = _metadataBuilder.GetOrAddString(method.Name);
                var          sig        = method.GetTypicalMethodDefinition().Signature;

                EmbeddedSignatureDataEmitter signatureDataEmitter;
                if (sig.HasEmbeddedSignatureData)
                {
                    signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this);
                }
                else
                {
                    signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton;
                }

                BlobBuilder memberRefSig = new BlobBuilder();
                EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter);

                if (!signatureDataEmitter.Complete)
                {
                    throw new ArgumentException();
                }

                var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig);
                methodHandle = _metadataBuilder.AddMemberReference(typeHandle, methodName, sigBlob);
            }

            _methodRefs.Add(method, methodHandle);
            return(methodHandle);
        }
        void EncodeMethodSignature(BlobBuilder signatureBuilder, MethodSignature sig, EmbeddedSignatureDataEmitter signatureDataEmitter)
        {
            signatureDataEmitter.Push();
            BlobEncoder signatureEncoder      = new BlobEncoder(signatureBuilder);
            int         genericParameterCount = sig.GenericParameterCount;
            bool        isInstanceMethod      = !sig.IsStatic;
            SignatureCallingConvention sigCallingConvention = SignatureCallingConvention.Default;

            switch (sig.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask)
            {
            case MethodSignatureFlags.CallingConventionVarargs:
                sigCallingConvention = SignatureCallingConvention.VarArgs;
                break;

            case MethodSignatureFlags.UnmanagedCallingConventionCdecl:
                sigCallingConvention = SignatureCallingConvention.CDecl;
                break;

            case MethodSignatureFlags.UnmanagedCallingConventionStdCall:
                sigCallingConvention = SignatureCallingConvention.StdCall;
                break;

            case MethodSignatureFlags.UnmanagedCallingConventionThisCall:
                sigCallingConvention = SignatureCallingConvention.ThisCall;
                break;

            case MethodSignatureFlags.UnmanagedCallingConvention:
                // [TODO] sigCallingConvention = SignatureCallingConvention.Unmanaged;
                sigCallingConvention = (SignatureCallingConvention)9;
                break;
            }

            signatureEncoder.MethodSignature(sigCallingConvention, genericParameterCount, isInstanceMethod);
            signatureBuilder.WriteCompressedInteger(sig.Length);
            // TODO Process custom modifiers in some way
            EncodeType(signatureBuilder, sig.ReturnType, signatureDataEmitter);
            for (int i = 0; i < sig.Length; i++)
            {
                EncodeType(signatureBuilder, sig[i], signatureDataEmitter);
            }

            signatureDataEmitter.Pop();
        }
        private void EncodeType(BlobBuilder blobBuilder, TypeDesc type, EmbeddedSignatureDataEmitter signatureDataEmitter)
        {
            signatureDataEmitter.Push();
            signatureDataEmitter.Push();
            signatureDataEmitter.EmitAtCurrentIndexStack(blobBuilder);
            signatureDataEmitter.Pop();

            signatureDataEmitter.Push();
            if (type.IsPrimitive)
            {
                SignatureTypeCode primitiveCode;
                switch (type.Category)
                {
                case TypeFlags.Void:
                    primitiveCode = SignatureTypeCode.Void;
                    break;

                case TypeFlags.Boolean:
                    primitiveCode = SignatureTypeCode.Boolean;
                    break;

                case TypeFlags.Char:
                    primitiveCode = SignatureTypeCode.Char;
                    break;

                case TypeFlags.SByte:
                    primitiveCode = SignatureTypeCode.SByte;
                    break;

                case TypeFlags.Byte:
                    primitiveCode = SignatureTypeCode.Byte;
                    break;

                case TypeFlags.Int16:
                    primitiveCode = SignatureTypeCode.Int16;
                    break;

                case TypeFlags.UInt16:
                    primitiveCode = SignatureTypeCode.UInt16;
                    break;

                case TypeFlags.Int32:
                    primitiveCode = SignatureTypeCode.Int32;
                    break;

                case TypeFlags.UInt32:
                    primitiveCode = SignatureTypeCode.UInt32;
                    break;

                case TypeFlags.Int64:
                    primitiveCode = SignatureTypeCode.Int64;
                    break;

                case TypeFlags.UInt64:
                    primitiveCode = SignatureTypeCode.UInt64;
                    break;

                case TypeFlags.IntPtr:
                    primitiveCode = SignatureTypeCode.IntPtr;
                    break;

                case TypeFlags.UIntPtr:
                    primitiveCode = SignatureTypeCode.UIntPtr;
                    break;

                case TypeFlags.Single:
                    primitiveCode = SignatureTypeCode.Single;
                    break;

                case TypeFlags.Double:
                    primitiveCode = SignatureTypeCode.Double;
                    break;

                default:
                    throw new Exception("Unknown primitive type");
                }

                blobBuilder.WriteByte((byte)primitiveCode);
            }
            else if (type.IsSzArray)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.SZArray);
                EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter);
            }
            else if (type.IsArray)
            {
                var arrayType = (ArrayType)type;
                blobBuilder.WriteByte((byte)SignatureTypeCode.Array);
                EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter);
                var shapeEncoder = new ArrayShapeEncoder(blobBuilder);
                // TODO Add support for non-standard array shapes
                shapeEncoder.Shape(arrayType.Rank, default(ImmutableArray <int>), default(ImmutableArray <int>));
            }
            else if (type.IsPointer)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.Pointer);
                EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter);
            }
            else if (type.IsFunctionPointer)
            {
                FunctionPointerType fnptrType = (FunctionPointerType)type;
                EncodeMethodSignature(blobBuilder, fnptrType.Signature, signatureDataEmitter);
            }
            else if (type.IsByRef)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.ByReference);
                EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter);
            }
            else if (type.IsObject)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.Object);
            }
            else if (type.IsString)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.String);
            }
            else if (type.IsWellKnownType(WellKnownType.TypedReference))
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.TypedReference);
            }
            else if (type.IsWellKnownType(WellKnownType.Void))
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.Void);
            }
            else if (type is SignatureVariable)
            {
                SignatureVariable sigVar = (SignatureVariable)type;
                SignatureTypeCode code   = sigVar.IsMethodSignatureVariable ? SignatureTypeCode.GenericMethodParameter : SignatureTypeCode.GenericTypeParameter;
                blobBuilder.WriteByte((byte)code);
                blobBuilder.WriteCompressedInteger(sigVar.Index);
            }
            else if (type is InstantiatedType)
            {
                blobBuilder.WriteByte((byte)SignatureTypeCode.GenericTypeInstance);
                EncodeType(blobBuilder, type.GetTypeDefinition(), signatureDataEmitter);
                blobBuilder.WriteCompressedInteger(type.Instantiation.Length);
                foreach (var instantiationArg in type.Instantiation)
                {
                    EncodeType(blobBuilder, instantiationArg, signatureDataEmitter);
                }
            }
            else if (type is MetadataType)
            {
                var metadataType = (MetadataType)type;
                // Must be class or valuetype
                blobBuilder.WriteByte(type.IsValueType ? (byte)SignatureTypeKind.ValueType : (byte)SignatureTypeKind.Class);
                int codedIndex = CodedIndex.TypeDefOrRef(GetTypeRef(metadataType));
                blobBuilder.WriteCompressedInteger(codedIndex);
            }
            else
            {
                throw new Exception("Unexpected type");
            }
            signatureDataEmitter.Pop();
            signatureDataEmitter.Pop();
        }