예제 #1
0
        public static MethodIL EmitIL(MethodDesc target)
        {
            Debug.Assert(target.Name == "EETypePtrOf");
            Debug.Assert(target.Signature.Length == 0 &&
                         target.Signature.ReturnType == target.OwningType);
            Debug.Assert(target.Instantiation.Length == 1);

            ILEmitter emitter    = new ILEmitter();
            var       codeStream = emitter.NewCodeStream();

            TypeSystemContext context = target.Context;
            TypeDesc          runtimeTypeHandleType  = context.GetWellKnownType(WellKnownType.RuntimeTypeHandle);
            MethodDesc        getValueInternalMethod = runtimeTypeHandleType.GetKnownMethod("GetValueInternal", null);
            MethodDesc        eetypePtrCtorMethod    = context.SystemModule
                                                       .GetKnownType("System", "EETypePtr")
                                                       .GetKnownMethod(".ctor", new MethodSignature(0, 0, context.GetWellKnownType(WellKnownType.Void),
                                                                                                    new TypeDesc[] { context.GetWellKnownType(WellKnownType.IntPtr) }));

            // The sequence of these instructions is important. JIT is able to optimize out
            // the LDTOKEN+GetValueInternal call into "load EEType pointer onto the evaluation stack".
            codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(context.GetSignatureVariable(0, true)));
            codeStream.Emit(ILOpcode.call, emitter.NewToken(getValueInternalMethod));
            codeStream.Emit(ILOpcode.newobj, emitter.NewToken(eetypePtrCtorMethod));
            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link());
        }
            public override MethodIL EmitIL()
            {
                if (_owningType.BoxedValue == null)
                {
                    // If this is the fake unboxing thunk for ByRef-like types, just make a method that throws.
                    return(new ILStubMethodIL(this,
                                              new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ },
                                              Array.Empty <LocalVariableDefinition>(),
                                              Array.Empty <object>()));
                }

                // Generate the unboxing stub. This loosely corresponds to following C#:
                // return BoxedValue.InstanceMethod([rest of parameters])

                ILEmitter    emit       = new ILEmitter();
                ILCodeStream codeStream = emit.NewCodeStream();

                FieldDesc boxedValueField = _owningType.BoxedValue.InstantiateAsOpen();

                // unbox to get a pointer to the value type
                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldflda, emit.NewToken(boxedValueField));

                // Load rest of the arguments
                for (int i = 0; i < _targetMethod.Signature.Length; i++)
                {
                    codeStream.EmitLdArg(i + 1);
                }

                TypeDesc   owner = _targetMethod.OwningType;
                MethodDesc methodToInstantiate = _targetMethod;

                if (owner.HasInstantiation)
                {
                    MetadataType instantiatedOwner = (MetadataType)owner.InstantiateAsOpen();
                    methodToInstantiate = _targetMethod.Context.GetMethodForInstantiatedType(_targetMethod, (InstantiatedType)instantiatedOwner);
                }
                if (methodToInstantiate.HasInstantiation)
                {
                    TypeSystemContext context = methodToInstantiate.Context;

                    var inst = new TypeDesc[methodToInstantiate.Instantiation.Length];
                    for (int i = 0; i < inst.Length; i++)
                    {
                        inst[i] = context.GetSignatureVariable(i, true);
                    }

                    methodToInstantiate = context.GetInstantiatedMethod(methodToInstantiate, new Instantiation(inst));
                }

                codeStream.Emit(ILOpcode.call, emit.NewToken(methodToInstantiate));
                codeStream.Emit(ILOpcode.ret);

                return(emit.Link(this));
            }
        private static MethodIL EmitSizeOf(MethodDesc method)
        {
            Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0);

            TypeSystemContext context = method.Context;

            ILEmitter    emit       = new ILEmitter();
            ILCodeStream codeStream = emit.NewCodeStream();

            codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true)));
            codeStream.Emit(ILOpcode.ret);
            return(emit.Link(method));
        }
예제 #4
0
        private static MethodIL EmitCopy(MethodDesc method)
        {
            Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 2);

            TypeSystemContext context = method.Context;

            ILEmitter    emit       = new ILEmitter();
            ILCodeStream codeStream = emit.NewCodeStream();
            ILToken      token      = emit.NewToken(context.GetSignatureVariable(0, method: true));

            codeStream.EmitLdArg(0);
            codeStream.EmitLdArg(1);
            codeStream.Emit(ILOpcode.ldobj, token);
            codeStream.Emit(ILOpcode.stobj, token);
            codeStream.Emit(ILOpcode.ret);

            return(emit.Link(method));
        }
예제 #5
0
        private static MethodIL EmitReadWrite(MethodDesc method, bool write, bool unaligned = false)
        {
            Debug.Assert(method.Signature.IsStatic && method.Signature.Length == (write ? 2 : 1));

            TypeSystemContext context = method.Context;

            ILEmitter    emit       = new ILEmitter();
            ILCodeStream codeStream = emit.NewCodeStream();

            codeStream.EmitLdArg(0);
            if (write)
            {
                codeStream.EmitLdArg(1);
            }
            if (unaligned)
            {
                codeStream.EmitUnaligned();
            }
            codeStream.Emit(write ? ILOpcode.stobj : ILOpcode.ldobj,
                            emit.NewToken(context.GetSignatureVariable(0, method: true)));
            codeStream.Emit(ILOpcode.ret);
            return(emit.Link(method));
        }
예제 #6
0
        public override MethodIL GetMethodIL(MethodDesc method)
        {
            RemoveAction action = GetAction(method);

            switch (action)
            {
            case RemoveAction.Nothing:
                return(_baseILProvider.GetMethodIL(method));

            case RemoveAction.ConvertToStub:
                if (method.Signature.ReturnType.IsVoid)
                {
                    return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null));
                }
                else if (method.Signature.ReturnType.Category == TypeFlags.Boolean)
                {
                    return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null));
                }
                else
                {
                    goto default;
                }

            case RemoveAction.ConvertToTrueStub:
                return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldc_i4_1, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null));

            case RemoveAction.ConvertToGetResourceStringStub:
                return(new ILStubMethodIL(method, new byte[] {
                    (byte)ILOpcode.ldarg_0,
                    (byte)ILOpcode.ret
                },
                                          Array.Empty <LocalVariableDefinition>(), null));

            case RemoveAction.ConvertToThrow:
                return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ }, Array.Empty <LocalVariableDefinition>(), null));

            case RemoveAction.ConvertToGetKnownObjectComparer:
            case RemoveAction.ConvertToGetKnownObjectEqualityComparer:
            {
                TypeSystemContext context      = method.Context;
                MetadataType      comparerType =
                    action == RemoveAction.ConvertToGetKnownObjectComparer ?
                    context.SystemModule.GetType("System.Collections.Generic", "ObjectComparer`1") :
                    context.SystemModule.GetType("System.Collections.Generic", "ObjectEqualityComparer`1");

                MethodDesc methodDef = method.GetTypicalMethodDefinition();

                ILEmitter    emitter    = new ILEmitter();
                ILCodeStream codeStream = emitter.NewCodeStream();

                FieldDesc defaultField = methodDef.OwningType.InstantiateAsOpen().GetField("s_default");

                TypeDesc   objectType            = context.GetWellKnownType(WellKnownType.Object);
                MethodDesc compareExchangeObject = context.SystemModule.
                                                   GetType("System.Threading", "Interlocked").
                                                   GetMethod("CompareExchange",
                                                             new MethodSignature(
                                                                 MethodSignatureFlags.Static,
                                                                 genericParameterCount: 0,
                                                                 returnType: objectType,
                                                                 parameters: new TypeDesc[] { objectType.MakeByRefType(), objectType, objectType }));

                codeStream.Emit(ILOpcode.ldsflda, emitter.NewToken(defaultField));
                codeStream.Emit(ILOpcode.newobj, emitter.NewToken(comparerType.MakeInstantiatedType(context.GetSignatureVariable(0, method: false)).GetDefaultConstructor()));
                codeStream.Emit(ILOpcode.ldnull);
                codeStream.Emit(ILOpcode.call, emitter.NewToken(compareExchangeObject));
                codeStream.Emit(ILOpcode.pop);
                codeStream.Emit(ILOpcode.ldsfld, emitter.NewToken(defaultField));
                codeStream.Emit(ILOpcode.ret);

                return(new InstantiatedMethodIL(method, emitter.Link(methodDef)));
            }

            default:
                throw new NotImplementedException();
            }
        }
예제 #7
0
        private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode)
        {
            // Switch on the type.
            switch (typeCode)
            {
            case SignatureTypeCode.Void:
                return(GetWellKnownType(WellKnownType.Void));

            case SignatureTypeCode.Boolean:
                return(GetWellKnownType(WellKnownType.Boolean));

            case SignatureTypeCode.SByte:
                return(GetWellKnownType(WellKnownType.SByte));

            case SignatureTypeCode.Byte:
                return(GetWellKnownType(WellKnownType.Byte));

            case SignatureTypeCode.Int16:
                return(GetWellKnownType(WellKnownType.Int16));

            case SignatureTypeCode.UInt16:
                return(GetWellKnownType(WellKnownType.UInt16));

            case SignatureTypeCode.Int32:
                return(GetWellKnownType(WellKnownType.Int32));

            case SignatureTypeCode.UInt32:
                return(GetWellKnownType(WellKnownType.UInt32));

            case SignatureTypeCode.Int64:
                return(GetWellKnownType(WellKnownType.Int64));

            case SignatureTypeCode.UInt64:
                return(GetWellKnownType(WellKnownType.UInt64));

            case SignatureTypeCode.Single:
                return(GetWellKnownType(WellKnownType.Single));

            case SignatureTypeCode.Double:
                return(GetWellKnownType(WellKnownType.Double));

            case SignatureTypeCode.Char:
                return(GetWellKnownType(WellKnownType.Char));

            case SignatureTypeCode.String:
                return(GetWellKnownType(WellKnownType.String));

            case SignatureTypeCode.IntPtr:
                return(GetWellKnownType(WellKnownType.IntPtr));

            case SignatureTypeCode.UIntPtr:
                return(GetWellKnownType(WellKnownType.UIntPtr));

            case SignatureTypeCode.Object:
                return(GetWellKnownType(WellKnownType.Object));

            case SignatureTypeCode.TypeHandle:
                return(ResolveHandle(_reader.ReadTypeHandle()));

            case SignatureTypeCode.SZArray:
            {
                var elementType = ParseType();
                if (elementType == null)
                {
                    return(null);
                }
                return(_tsc.GetArrayType(elementType));
            }

            case SignatureTypeCode.Array:
            {
                var elementType = ParseType();
                var rank        = _reader.ReadCompressedInteger();

                if (_embeddedSignatureDataList != null)
                {
                    var    boundsCount = _reader.ReadCompressedInteger();
                    int [] bounds      = boundsCount > 0 ? new int[boundsCount] : Array.Empty <int>();
                    for (int i = 0; i < boundsCount; i++)
                    {
                        bounds[i] = _reader.ReadCompressedInteger();
                    }

                    var    lowerBoundsCount   = _reader.ReadCompressedInteger();
                    int [] lowerBounds        = lowerBoundsCount > 0 ? new int[lowerBoundsCount] : Array.Empty <int>();
                    bool   nonZeroLowerBounds = false;
                    for (int j = 0; j < lowerBoundsCount; j++)
                    {
                        int loBound = _reader.ReadCompressedSignedInteger();
                        if (loBound != 0)
                        {
                            nonZeroLowerBounds = true;
                        }
                        lowerBounds[j] = loBound;
                    }

                    if (boundsCount != 0 || lowerBoundsCount != rank || nonZeroLowerBounds)
                    {
                        StringBuilder arrayShapeString = new StringBuilder();
                        arrayShapeString.Append(string.Join(",", bounds));
                        arrayShapeString.Append('|');
                        arrayShapeString.Append(string.Join(",", lowerBounds));
                        _embeddedSignatureDataList.Add(new EmbeddedSignatureData {
                                index = string.Join(".", _indexStack) + "|" + arrayShapeString.ToString(), kind = EmbeddedSignatureDataKind.ArrayShape, type = null
                            });
                    }
                }
                else
                {
                    var boundsCount = _reader.ReadCompressedInteger();
                    for (int i = 0; i < boundsCount; i++)
                    {
                        _reader.ReadCompressedInteger();
                    }
                    var lowerBoundsCount = _reader.ReadCompressedInteger();
                    for (int j = 0; j < lowerBoundsCount; j++)
                    {
                        _reader.ReadCompressedSignedInteger();
                    }
                }

                if (elementType != null)
                {
                    return(_tsc.GetArrayType(elementType, rank));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.ByReference:
            {
                TypeDesc byRefedType = ParseType();
                if (byRefedType != null)
                {
                    return(byRefedType.MakeByRefType());
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.Pointer:
            {
                TypeDesc pointedAtType = ParseType();
                if (pointedAtType != null)
                {
                    return(_tsc.GetPointerType(pointedAtType));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.GenericTypeParameter:
                return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), false));

            case SignatureTypeCode.GenericMethodParameter:
                return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), true));

            case SignatureTypeCode.GenericTypeInstance:
            {
                TypeDesc     typeDef         = ParseType();
                MetadataType metadataTypeDef = null;

                if (typeDef != null)
                {
                    metadataTypeDef = typeDef as MetadataType;
                    if (metadataTypeDef == null)
                    {
                        throw new BadImageFormatException();
                    }
                }

                TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()];
                for (int i = 0; i < instance.Length; i++)
                {
                    instance[i] = ParseType();
                    if (instance[i] == null)
                    {
                        metadataTypeDef = null;
                    }
                }

                if (metadataTypeDef != null)
                {
                    return(_tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance)));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.TypedReference:
                return(GetWellKnownType(WellKnownType.TypedReference));

            case SignatureTypeCode.FunctionPointer:
                MethodSignature sig = ParseMethodSignatureInternal(skipEmbeddedSignatureData: true);
                if (sig != null)
                {
                    return(_tsc.GetFunctionPointerType(sig));
                }
                else
                {
                    return(null);
                }

            default:
                throw new BadImageFormatException();
            }
        }
예제 #8
0
        /// <summary>
        /// Provides method bodies for intrinsics recognized by the compiler that
        /// are specialized per instantiation. It can return null if the intrinsic
        /// is not recognized.
        /// </summary>
        private MethodIL TryGetPerInstantiationIntrinsicMethodIL(MethodDesc method)
        {
            Debug.Assert(method.IsIntrinsic);

            MetadataType owningType = method.OwningType.GetTypeDefinition() as MetadataType;

            if (owningType == null)
            {
                return(null);
            }

            string methodName = method.Name;

            switch (owningType.Name)
            {
            case "Activator":
            {
                TypeSystemContext context = owningType.Context;
                if (methodName == "CreateInstance" && method.Signature.Length == 0 && method.HasInstantiation &&
                    method.Instantiation[0] is TypeDesc activatedType &&
                    activatedType != context.UniversalCanonType &&
                    activatedType.IsValueType &&
                    activatedType.GetParameterlessConstructor() == null)
                {
                    ILEmitter    emit       = new ILEmitter();
                    ILCodeStream codeStream = emit.NewCodeStream();

                    var t = emit.NewLocal(context.GetSignatureVariable(0, method: true));
                    codeStream.EmitLdLoca(t);
                    codeStream.Emit(ILOpcode.initobj, emit.NewToken(context.GetSignatureVariable(0, method: true)));
                    codeStream.EmitLdLoc(t);
                    codeStream.Emit(ILOpcode.ret);

                    return(new InstantiatedMethodIL(method, emit.Link(method.GetMethodDefinition())));
                }
            }
            break;

            case "RuntimeHelpers":
            {
                if (owningType.Namespace == "System.Runtime.CompilerServices")
                {
                    return(RuntimeHelpersIntrinsics.EmitIL(method));
                }
            }
            break;

            case "Comparer`1":
            {
                if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic")
                {
                    return(ComparerIntrinsics.EmitComparerCreate(method));
                }
            }
            break;

            case "EqualityComparer`1":
            {
                if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic")
                {
                    return(ComparerIntrinsics.EmitEqualityComparerCreate(method));
                }
            }
            break;

            case "ComparerHelpers":
            {
                if (owningType.Namespace != "Internal.IntrinsicSupport")
                {
                    return(null);
                }

                if (methodName == "EnumOnlyCompare")
                {
                    //calls CompareTo for underlyingType to avoid boxing

                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsEnum)
                    {
                        return(null);
                    }

                    TypeDesc   underlyingType            = elementType.UnderlyingType;
                    TypeDesc   returnType                = method.Context.GetWellKnownType(WellKnownType.Int32);
                    MethodDesc underlyingCompareToMethod = underlyingType.GetKnownMethod("CompareTo",
                                                                                         new MethodSignature(
                                                                                             MethodSignatureFlags.None,
                                                                                             genericParameterCount: 0,
                                                                                             returnType: returnType,
                                                                                             parameters: new TypeDesc[] { underlyingType }));

                    ILEmitter emitter    = new ILEmitter();
                    var       codeStream = emitter.NewCodeStream();

                    codeStream.EmitLdArga(0);
                    codeStream.EmitLdArg(1);
                    codeStream.Emit(ILOpcode.call, emitter.NewToken(underlyingCompareToMethod));
                    codeStream.Emit(ILOpcode.ret);

                    return(emitter.Link(method));
                }
            }
            break;

            case "EqualityComparerHelpers":
            {
                if (owningType.Namespace != "Internal.IntrinsicSupport")
                {
                    return(null);
                }

                if (methodName == "EnumOnlyEquals")
                {
                    // EnumOnlyEquals would basically like to do this:
                    // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x == y;
                    // This is not legal though.
                    // We don't want to do this:
                    // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x.Equals(y);
                    // Because it would box y.
                    // So we resort to some per-instantiation magic.

                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsEnum)
                    {
                        return(null);
                    }

                    ILOpcode convInstruction;
                    if (((DefType)elementType).InstanceFieldSize.AsInt <= 4)
                    {
                        convInstruction = ILOpcode.conv_i4;
                    }
                    else
                    {
                        Debug.Assert(((DefType)elementType).InstanceFieldSize.AsInt == 8);
                        convInstruction = ILOpcode.conv_i8;
                    }

                    return(new ILStubMethodIL(method, new byte[] {
                            (byte)ILOpcode.ldarg_0,
                            (byte)convInstruction,
                            (byte)ILOpcode.ldarg_1,
                            (byte)convInstruction,
                            (byte)ILOpcode.prefix1, unchecked ((byte)ILOpcode.ceq),
                            (byte)ILOpcode.ret,
                        },
                                              Array.Empty <LocalVariableDefinition>(), null));
                }
                else if (methodName == "GetComparerForReferenceTypesOnly")
                {
                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsRuntimeDeterminedSubtype &&
                        !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !elementType.IsGCPointer)
                    {
                        return(new ILStubMethodIL(method, new byte[] {
                                (byte)ILOpcode.ldnull,
                                (byte)ILOpcode.ret
                            },
                                                  Array.Empty <LocalVariableDefinition>(), null));
                    }
                }
                else if (methodName == "StructOnlyEquals")
                {
                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsRuntimeDeterminedSubtype &&
                        !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !elementType.IsGCPointer)
                    {
                        Debug.Assert(elementType.IsValueType);

                        TypeSystemContext context    = elementType.Context;
                        MetadataType      helperType = context.SystemModule.GetKnownType("Internal.IntrinsicSupport", "EqualityComparerHelpers");

                        MethodDesc methodToCall;
                        if (elementType.IsEnum)
                        {
                            methodToCall = helperType.GetKnownMethod("EnumOnlyEquals", null).MakeInstantiatedMethod(elementType);
                        }
                        else if (elementType.IsNullable && ComparerIntrinsics.ImplementsIEquatable(elementType.Instantiation[0]))
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyEqualsNullable", null).MakeInstantiatedMethod(elementType.Instantiation[0]);
                        }
                        else if (ComparerIntrinsics.ImplementsIEquatable(elementType))
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyEqualsIEquatable", null).MakeInstantiatedMethod(elementType);
                        }
                        else
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyNormalEquals", null).MakeInstantiatedMethod(elementType);
                        }

                        return(new ILStubMethodIL(method, new byte[]
                            {
                                (byte)ILOpcode.ldarg_0,
                                (byte)ILOpcode.ldarg_1,
                                (byte)ILOpcode.call, 1, 0, 0, 0,
                                (byte)ILOpcode.ret
                            },
                                                  Array.Empty <LocalVariableDefinition>(), new object[] { methodToCall }));
                    }
                }
            }
            break;
            }

            return(null);
        }
예제 #9
0
        private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode)
        {
            // Switch on the type.
            switch (typeCode)
            {
            case SignatureTypeCode.Void:
                return(GetWellKnownType(WellKnownType.Void));

            case SignatureTypeCode.Boolean:
                return(GetWellKnownType(WellKnownType.Boolean));

            case SignatureTypeCode.SByte:
                return(GetWellKnownType(WellKnownType.SByte));

            case SignatureTypeCode.Byte:
                return(GetWellKnownType(WellKnownType.Byte));

            case SignatureTypeCode.Int16:
                return(GetWellKnownType(WellKnownType.Int16));

            case SignatureTypeCode.UInt16:
                return(GetWellKnownType(WellKnownType.UInt16));

            case SignatureTypeCode.Int32:
                return(GetWellKnownType(WellKnownType.Int32));

            case SignatureTypeCode.UInt32:
                return(GetWellKnownType(WellKnownType.UInt32));

            case SignatureTypeCode.Int64:
                return(GetWellKnownType(WellKnownType.Int64));

            case SignatureTypeCode.UInt64:
                return(GetWellKnownType(WellKnownType.UInt64));

            case SignatureTypeCode.Single:
                return(GetWellKnownType(WellKnownType.Single));

            case SignatureTypeCode.Double:
                return(GetWellKnownType(WellKnownType.Double));

            case SignatureTypeCode.Char:
                return(GetWellKnownType(WellKnownType.Char));

            case SignatureTypeCode.String:
                return(GetWellKnownType(WellKnownType.String));

            case SignatureTypeCode.IntPtr:
                return(GetWellKnownType(WellKnownType.IntPtr));

            case SignatureTypeCode.UIntPtr:
                return(GetWellKnownType(WellKnownType.UIntPtr));

            case SignatureTypeCode.Object:
                return(GetWellKnownType(WellKnownType.Object));

            case SignatureTypeCode.TypeHandle:
                return(ResolveHandle(_reader.ReadTypeHandle()));

            case SignatureTypeCode.SZArray:
            {
                var elementType = ParseType();
                if (elementType == null)
                {
                    return(null);
                }
                return(_tsc.GetArrayType(elementType));
            }

            case SignatureTypeCode.Array:
            {
                var elementType = ParseType();
                var rank        = _reader.ReadCompressedInteger();

                // TODO: Bounds for multi-dimmensional arrays
                var boundsCount = _reader.ReadCompressedInteger();
                for (int i = 0; i < boundsCount; i++)
                {
                    _reader.ReadCompressedInteger();
                }
                var lowerBoundsCount = _reader.ReadCompressedInteger();
                for (int j = 0; j < lowerBoundsCount; j++)
                {
                    _reader.ReadCompressedInteger();
                }

                if (elementType != null)
                {
                    return(_tsc.GetArrayType(elementType, rank));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.ByReference:
            {
                TypeDesc byRefedType = ParseType();
                if (byRefedType != null)
                {
                    return(byRefedType.MakeByRefType());
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.Pointer:
            {
                TypeDesc pointedAtType = ParseType();
                if (pointedAtType != null)
                {
                    return(_tsc.GetPointerType(pointedAtType));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.GenericTypeParameter:
                return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), false));

            case SignatureTypeCode.GenericMethodParameter:
                return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), true));

            case SignatureTypeCode.GenericTypeInstance:
            {
                TypeDesc     typeDef         = ParseType();
                MetadataType metadataTypeDef = null;

                if (typeDef != null)
                {
                    metadataTypeDef = typeDef as MetadataType;
                    if (metadataTypeDef == null)
                    {
                        throw new BadImageFormatException();
                    }
                }

                TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()];
                for (int i = 0; i < instance.Length; i++)
                {
                    instance[i] = ParseType();
                    if (instance[i] == null)
                    {
                        metadataTypeDef = null;
                    }
                }

                if (metadataTypeDef != null)
                {
                    return(_tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance)));
                }
                else
                {
                    return(null);
                }
            }

            case SignatureTypeCode.TypedReference:
                return(GetWellKnownType(WellKnownType.TypedReference));

            case SignatureTypeCode.FunctionPointer:
                MethodSignature sig = ParseMethodSignatureInternal(skipEmbeddedSignatureData: true);
                if (sig != null)
                {
                    return(_tsc.GetFunctionPointerType(sig));
                }
                else
                {
                    return(null);
                }

            default:
                throw new BadImageFormatException();
            }
        }
예제 #10
0
        public override IEnumerable <CombinedDependencyListEntry> SearchDynamicDependencies(List <DependencyNodeCore <NodeFactory> > markedNodes, int firstNode, NodeFactory factory)
        {
            List <CombinedDependencyListEntry> dynamicDependencies = new List <CombinedDependencyListEntry>();

            TypeDesc methodOwningType = _method.OwningType;
            bool     methodIsShared   = _method.IsSharedByGenericInstantiations;

            TypeSystemContext context = _method.Context;

            for (int i = firstNode; i < markedNodes.Count; i++)
            {
                DependencyNodeCore <NodeFactory> entry = markedNodes[i];
                EETypeNode entryAsEETypeNode           = entry as EETypeNode;

                if (entryAsEETypeNode == null)
                {
                    continue;
                }

                TypeDesc potentialOverrideType = entryAsEETypeNode.Type;
                if (!potentialOverrideType.IsDefType || potentialOverrideType.IsInterface)
                {
                    continue;
                }

                // If method is canonical, don't allow using it with non-canonical types - we can wait until
                // we see the __Canon instantiation. If there isn't one, the canonical method wouldn't be useful anyway.
                if (methodIsShared &&
                    potentialOverrideType.ConvertToCanonForm(CanonicalFormKind.Specific) != potentialOverrideType)
                {
                    continue;
                }

                // Similarly, if the type is canonical but this method instantiation isn't, don't mix them.
                if (!methodIsShared &&
                    potentialOverrideType.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    continue;
                }

                // If this is an interface gvm, look for types that implement the interface
                // and other instantantiations that have the same canonical form.
                // This ensure the various slot numbers remain equivalent across all types where there is an equivalence
                // relationship in the vtable.
                if (methodOwningType.IsInterface)
                {
                    // We go over definitions because a single canonical interface method could actually be implemented
                    // by multiple methods - consider:
                    //
                    // class Foo<T, U> : IFoo<T>, IFoo<U>, IFoo<string> { }
                    //
                    // If we ask what implements IFoo<__Canon>.Method, the answer could be "three methods"
                    // and that's expected. We therefore resolve IFoo<__Canon>.Method for each IFoo<!0>.Method,
                    // IFoo<!1>.Method, and IFoo<string>.Method, adding GVMDependencies for each.
                    TypeDesc  potentialOverrideDefinition   = potentialOverrideType.GetTypeDefinition();
                    DefType[] potentialInterfaces           = potentialOverrideType.RuntimeInterfaces;
                    DefType[] potentialDefinitionInterfaces = potentialOverrideDefinition.RuntimeInterfaces;
                    for (int interfaceIndex = 0; interfaceIndex < potentialInterfaces.Length; interfaceIndex++)
                    {
                        if (potentialInterfaces[interfaceIndex].ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType)
                        {
                            MethodDesc interfaceMethod = _method.GetMethodDefinition();
                            if (methodOwningType.HasInstantiation)
                            {
                                interfaceMethod = context.GetMethodForInstantiatedType(
                                    _method.GetTypicalMethodDefinition(), (InstantiatedType)potentialDefinitionInterfaces[interfaceIndex]);
                            }

                            MethodDesc slotDecl = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodTarget(interfaceMethod);
                            if (slotDecl == null)
                            {
                                // The method might be implemented through a default interface method
                                var result = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, out slotDecl);
                                if (result != DefaultInterfaceMethodResolution.DefaultImplementation)
                                {
                                    slotDecl = null;
                                }
                            }

                            if (slotDecl != null)
                            {
                                TypeDesc[] openInstantiation = new TypeDesc[_method.Instantiation.Length];
                                for (int instArg = 0; instArg < openInstantiation.Length; instArg++)
                                {
                                    openInstantiation[instArg] = context.GetSignatureVariable(instArg, method: true);
                                }
                                MethodDesc implementingMethodInstantiation = slotDecl.MakeInstantiatedMethod(openInstantiation).InstantiateSignature(potentialOverrideType.Instantiation, _method.Instantiation);
                                dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation"));
                            }
                        }
                    }
                }
                else
                {
                    // This is not an interface GVM. Check whether the current type overrides the virtual method.
                    // We might need to change what virtual method we ask about - consider:
                    //
                    // class Base<T> { virtual Method(); }
                    // class Derived : Base<string> { override Method(); }
                    //
                    // We need to resolve Base<__Canon>.Method on Derived, but if we were to ask the virtual
                    // method resolution algorithm, the answer would be "does not override" because Base<__Canon>
                    // is not even in the inheritance hierarchy.
                    //
                    // So we need to modify the question to resolve Base<string>.Method instead and then
                    // canonicalize the result.

                    TypeDesc overrideTypeCur = potentialOverrideType;
                    do
                    {
                        if (overrideTypeCur.ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType)
                        {
                            break;
                        }

                        overrideTypeCur = overrideTypeCur.BaseType;
                    }while (overrideTypeCur != null);

                    if (overrideTypeCur == null)
                    {
                        continue;
                    }

                    MethodDesc methodToResolve;
                    if (methodOwningType == overrideTypeCur)
                    {
                        methodToResolve = _method;
                    }
                    else
                    {
                        methodToResolve = context
                                          .GetMethodForInstantiatedType(_method.GetTypicalMethodDefinition(), (InstantiatedType)overrideTypeCur)
                                          .MakeInstantiatedMethod(_method.Instantiation);
                    }

                    MethodDesc instantiatedTargetMethod = potentialOverrideType.FindVirtualFunctionTargetMethodOnObjectType(methodToResolve)
                                                          .GetCanonMethodTarget(CanonicalFormKind.Specific);
                    if (instantiatedTargetMethod != _method)
                    {
                        dynamicDependencies.Add(new CombinedDependencyListEntry(
                                                    factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation"));
                    }
                }
            }

            return(dynamicDependencies);
        }
 public TypeDesc GetGenericMethodParameter(object genericContext, int index) => _tsc.GetSignatureVariable(index, method: true);
        public static MethodIL EmitIL(MethodDesc method)
        {
            Debug.Assert(method.OwningType.IsDelegate);
            Debug.Assert(method.OwningType.IsTypeDefinition);
            Debug.Assert(method.IsRuntimeImplemented);

            if (method.Name == "BeginInvoke" || method.Name == "EndInvoke")
            {
                // BeginInvoke and EndInvoke are not supported on .NET Core
                ILEmitter    emit       = new ILEmitter();
                ILCodeStream codeStream = emit.NewCodeStream();
                MethodDesc   notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException");
                codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper);
                return(emit.Link(method));
            }

            if (method.Name == ".ctor")
            {
                // We only support delegate creation if the IL follows the delegate creation verifiability requirements
                // described in ECMA-335 III.4.21 (newobj - create a new object). The codegen is expected to
                // intrinsically expand the pattern.
                // If the delegate creation doesn't follow the pattern, we generate code that throws at runtime.
                // We could potentially implement this (unreliably) through the use of reflection metadata,
                // but it remains to be proven that this is an actual customer scenario.
                ILEmitter    emit       = new ILEmitter();
                ILCodeStream codeStream = emit.NewCodeStream();
                MethodDesc   notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException");
                codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper);
                return(emit.Link(method));
            }

            if (method.Name == "Invoke")
            {
                TypeSystemContext context = method.Context;

                ILEmitter    emit                 = new ILEmitter();
                TypeDesc     delegateType         = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;
                FieldDesc    firstParameterField  = delegateType.GetKnownField("m_firstParameter");
                FieldDesc    functionPointerField = delegateType.GetKnownField("m_functionPointer");
                ILCodeStream codeStream           = emit.NewCodeStream();

                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldfld, emit.NewToken(firstParameterField.InstantiateAsOpen()));
                for (int i = 0; i < method.Signature.Length; i++)
                {
                    codeStream.EmitLdArg(i + 1);
                }
                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldfld, emit.NewToken(functionPointerField.InstantiateAsOpen()));

                MethodSignature signature = method.Signature;
                if (method.OwningType.HasInstantiation)
                {
                    // If the owning type is generic, the signature will contain T's and U's.
                    // We need !0's and !1's.
                    TypeDesc[] typesToReplace   = new TypeDesc[method.OwningType.Instantiation.Length];
                    TypeDesc[] replacementTypes = new TypeDesc[typesToReplace.Length];
                    for (int i = 0; i < typesToReplace.Length; i++)
                    {
                        typesToReplace[i]   = method.OwningType.Instantiation[i];
                        replacementTypes[i] = context.GetSignatureVariable(i, method: false);
                    }
                    TypeDesc[] parameters = new TypeDesc[method.Signature.Length];
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        parameters[i] = method.Signature[i].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
                    }
                    TypeDesc returnType = method.Signature.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
                    signature = new MethodSignature(signature.Flags, signature.GenericParameterCount, returnType, parameters);
                }

                codeStream.Emit(ILOpcode.calli, emit.NewToken(signature));

                codeStream.Emit(ILOpcode.ret);

                return(emit.Link(method));
            }

            return(null);
        }
예제 #13
0
        public static MethodIL EmitIL(MethodDesc method)
        {
            Debug.Assert(method.OwningType.IsDelegate);
            Debug.Assert(method.OwningType.IsTypeDefinition);
            Debug.Assert(method.IsRuntimeImplemented);

            if (method.Name == "BeginInvoke" || method.Name == "EndInvoke")
            {
                // BeginInvoke and EndInvoke are not supported on .NET Core
                ILEmitter    emit       = new ILEmitter();
                ILCodeStream codeStream = emit.NewCodeStream();
                MethodDesc   notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException");
                codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper);
                return(emit.Link(method));
            }

            if (method.Name == ".ctor")
            {
                // TODO: this should be an assert that codegen never asks for this.
                // This is just a workaround for https://github.com/dotnet/corert/issues/2102
                // The code below is making a wild guess that we're creating a closed
                // instance delegate. Without shared generics, this should only happen
                // for virtual method (so we're fine there). With shared generics, this can
                // happen for anything and might be pretty wrong.
                TypeSystemContext context = method.Context;

                ILEmitter    emit             = new ILEmitter();
                TypeDesc     delegateType     = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;
                MethodDesc   initializeMethod = delegateType.GetKnownMethod("InitializeClosedInstanceSlow", null);
                ILCodeStream codeStream       = emit.NewCodeStream();

                codeStream.EmitLdArg(0);
                codeStream.EmitLdArg(1);
                codeStream.EmitLdArg(2);
                codeStream.Emit(ILOpcode.call, emit.NewToken(initializeMethod));
                codeStream.Emit(ILOpcode.ret);

                return(emit.Link(method));
            }

            if (method.Name == "Invoke")
            {
                TypeSystemContext context = method.Context;

                ILEmitter    emit                 = new ILEmitter();
                TypeDesc     delegateType         = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;
                FieldDesc    firstParameterField  = delegateType.GetKnownField("m_firstParameter");
                FieldDesc    functionPointerField = delegateType.GetKnownField("m_functionPointer");
                ILCodeStream codeStream           = emit.NewCodeStream();

                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldfld, emit.NewToken(firstParameterField.InstantiateAsOpen()));
                for (int i = 0; i < method.Signature.Length; i++)
                {
                    codeStream.EmitLdArg(i + 1);
                }
                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldfld, emit.NewToken(functionPointerField.InstantiateAsOpen()));

                MethodSignature signature = method.Signature;
                if (method.OwningType.HasInstantiation)
                {
                    // If the owning type is generic, the signature will contain T's and U's.
                    // We need !0's and !1's.
                    TypeDesc[] typesToReplace   = new TypeDesc[method.OwningType.Instantiation.Length];
                    TypeDesc[] replacementTypes = new TypeDesc[typesToReplace.Length];
                    for (int i = 0; i < typesToReplace.Length; i++)
                    {
                        typesToReplace[i]   = method.OwningType.Instantiation[i];
                        replacementTypes[i] = context.GetSignatureVariable(i, method: false);
                    }
                    TypeDesc[] parameters = new TypeDesc[method.Signature.Length];
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        parameters[i] = method.Signature[i].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
                    }
                    TypeDesc returnType = method.Signature.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
                    signature = new MethodSignature(signature.Flags, signature.GenericParameterCount, returnType, parameters);
                }

                codeStream.Emit(ILOpcode.calli, emit.NewToken(signature));

                codeStream.Emit(ILOpcode.ret);

                return(emit.Link(method));
            }

            return(null);
        }