Пример #1
0
        protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream)
        {
            var safeHandleType = PInvokeMethodData.SafeHandleType;

            var vAddRefed   = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.Boolean));
            var vSafeHandle = emitter.NewLocal(managedType);

            marshallingCodeStream.EmitStLoc(vSafeHandle);

            marshallingCodeStream.EmitLdLoc(vSafeHandle);
            marshallingCodeStream.EmitLdLoca(vAddRefed);
            marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                           safeHandleType.GetKnownMethod("DangerousAddRef", null)));

            marshallingCodeStream.EmitLdLoc(vSafeHandle);
            marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                           safeHandleType.GetKnownMethod("DangerousGetHandle", null)));

            // TODO: This should be inside finally block and only executed it the handle was addrefed
            unmarshallingCodeStream.EmitLdLoc(vSafeHandle);
            unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                             safeHandleType.GetKnownMethod("DangerousRelease", null)));

            return(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr));
        }
Пример #2
0
        protected override void AllocManagedToNative(ILCodeStream codeStream)
        {
            ILEmitter   emitter = _ilCodeStreams.Emitter;
            ILCodeLabel lNull   = emitter.NewCodeLabel();

            codeStream.EmitLdc(0);
            codeStream.Emit(ILOpcode.conv_i);
            StoreNativeValue(codeStream);

            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.brfalse, lNull);

            TypeDesc nativeStructType = InteropStateManager.GetStructMarshallingNativeType(ManagedType);

            ILLocalVariable lNativeType = emitter.NewLocal(nativeStructType);

            codeStream.EmitLdLoca(lNativeType);
            codeStream.Emit(ILOpcode.initobj, emitter.NewToken(nativeStructType));
            codeStream.EmitLdLoca(lNativeType);
            StoreNativeValue(codeStream);

            codeStream.EmitLabel(lNull);
        }
Пример #3
0
        protected override void EmitMarshalArgumentManagedToNative()
        {
            ILEmitter    emitter = _ilCodeStreams.Emitter;
            ILCodeStream marshallingCodeStream   = _ilCodeStreams.MarshallingCodeStream;
            ILCodeStream unmarshallingCodeStream = _ilCodeStreams.UnmarshallingCodestream;

            // we don't support [IN,OUT] together yet, either IN or OUT
            Debug.Assert(!(PInvokeParameterMetadata.Out && PInvokeParameterMetadata.In));

            var safeHandleType = PInvokeMethodData.SafeHandleType;

            if (Out)
            {
                // 1) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We
                //    must allocate this before the native call to avoid a failure point when we already have a native resource
                //    allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native
                //    handles need to be tracked and released by a SafeHandle.
                // 2) Initialize a local IntPtr that will be passed to the native call.
                // 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle
                //    is propagated back to the caller.

                Debug.Assert(ManagedParameterType is ByRefType);
                var vOutArg = emitter.NewLocal(ManagedParameterType);
                marshallingCodeStream.EmitStLoc(vOutArg);

                TypeDesc resolvedType = ((ByRefType)ManagedParameterType).ParameterType;

                var nativeType  = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr).MakeByRefType();
                var vOutValue   = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr));
                var vSafeHandle = emitter.NewLocal(resolvedType);
                marshallingCodeStream.Emit(ILOpcode.newobj, emitter.NewToken(resolvedType.GetDefaultConstructor()));
                marshallingCodeStream.EmitStLoc(vSafeHandle);
                marshallingCodeStream.EmitLdLoca(vOutValue);

                unmarshallingCodeStream.EmitLdLoc(vSafeHandle);
                unmarshallingCodeStream.EmitLdLoc(vOutValue);
                unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 PInvokeMethodData.SafeHandleType.GetKnownMethod("SetHandle", null)));

                unmarshallingCodeStream.EmitLdLoc(vOutArg);
                unmarshallingCodeStream.EmitLdLoc(vSafeHandle);
                unmarshallingCodeStream.Emit(ILOpcode.stind_i);

                NativeParameterType = nativeType;
            }
            else
            {
                var vAddRefed   = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.Boolean));
                var vSafeHandle = emitter.NewLocal(ManagedParameterType);

                marshallingCodeStream.EmitStLoc(vSafeHandle);
                marshallingCodeStream.EmitLdLoc(vSafeHandle);
                marshallingCodeStream.EmitLdLoca(vAddRefed);
                marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                               safeHandleType.GetKnownMethod("DangerousAddRef", null)));

                marshallingCodeStream.EmitLdLoc(vSafeHandle);
                marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                               safeHandleType.GetKnownMethod("DangerousGetHandle", null)));

                // TODO: This should be inside finally block and only executed it the handle was addrefed
                unmarshallingCodeStream.EmitLdLoc(vSafeHandle);
                unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 safeHandleType.GetKnownMethod("DangerousRelease", null)));

                NativeParameterType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr);
            }
        }
Пример #4
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);
        }