Пример #1
0
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
#if !READYTORUN
                                                                 InteropStateManager interopStateManager,
#endif
                                                                 MarshalAsDescriptor marshalAs,
                                                                 bool isArrayElement = false)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Default;

            if (marshalAs != null)
            {
                nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
            }

            switch (kind)
            {
            case MarshallerKind.BlittableValue:
            {
                switch (nativeType)
                {
                case NativeTypeKind.I1:
                    return(context.GetWellKnownType(WellKnownType.SByte));

                case NativeTypeKind.U1:
                    return(context.GetWellKnownType(WellKnownType.Byte));

                case NativeTypeKind.I2:
                    return(context.GetWellKnownType(WellKnownType.Int16));

                case NativeTypeKind.U2:
                    return(context.GetWellKnownType(WellKnownType.UInt16));

                case NativeTypeKind.I4:
                    return(context.GetWellKnownType(WellKnownType.Int32));

                case NativeTypeKind.U4:
                    return(context.GetWellKnownType(WellKnownType.UInt32));

                case NativeTypeKind.I8:
                    return(context.GetWellKnownType(WellKnownType.Int64));

                case NativeTypeKind.U8:
                    return(context.GetWellKnownType(WellKnownType.UInt64));

                case NativeTypeKind.R4:
                    return(context.GetWellKnownType(WellKnownType.Single));

                case NativeTypeKind.R8:
                    return(context.GetWellKnownType(WellKnownType.Double));

                default:
                    return(type.UnderlyingType);
                }
            }

            case MarshallerKind.Bool:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case MarshallerKind.CBool:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.Enum:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.Decimal:
            case MarshallerKind.VoidReturn:
                return(type);

#if !READYTORUN
            case MarshallerKind.Struct:
            case MarshallerKind.LayoutClass:
                return(interopStateManager.GetStructMarshallingNativeType((MetadataType)type));
#endif

            case MarshallerKind.BlittableStructPtr:
                return(type.MakePointerType());

            case MarshallerKind.HandleRef:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeChar:
                if (nativeType == NativeTypeKind.U2)
                {
                    return(context.GetWellKnownType(WellKnownType.UInt16));
                }
                else
                {
                    return(context.GetWellKnownType(WellKnownType.Int16));
                }

            case MarshallerKind.OleDateTime:
                return(context.GetWellKnownType(WellKnownType.Double));

            case MarshallerKind.SafeHandle:
            case MarshallerKind.CriticalHandle:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.BSTRString:
            case MarshallerKind.UnicodeString:
            case MarshallerKind.UnicodeStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Char).MakePointerType());

            case MarshallerKind.AnsiBSTRString:
            case MarshallerKind.AnsiString:
            case MarshallerKind.AnsiStringBuilder:
            case MarshallerKind.UTF8String:
                return(context.GetWellKnownType(WellKnownType.Byte).MakePointerType());

            case MarshallerKind.BlittableArray:
            case MarshallerKind.Array:
            case MarshallerKind.AnsiCharArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                //
                // We need to construct the unsafe array from the right unsafe array element type
                //
                TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind(
                    arrayType.ElementType,
                    elementMarshallerKind,
                    MarshallerKind.Unknown,
#if !READYTORUN
                    interopStateManager,
#endif
                    marshalAs,
                    isArrayElement: true);

                return(elementNativeType.MakePointerType());
            }

            case MarshallerKind.AnsiChar:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.FunctionPointer:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

#if !READYTORUN
            case MarshallerKind.ByValUnicodeString:
            case MarshallerKind.ByValAnsiString:
            {
                var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs);
                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.ByValArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs);

                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }
#endif

            case MarshallerKind.LayoutClassPtr:
            case MarshallerKind.AsAnyA:
            case MarshallerKind.AsAnyW:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.ComInterface:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
Пример #2
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();
            }
        }
Пример #3
0
        public static TypeDesc GetPrimitiveType(TypeSystemContext context, PrimitiveTypeCode typeCode)
        {
            WellKnownType wkt;

            switch (typeCode)
            {
            case PrimitiveTypeCode.Boolean:
                wkt = WellKnownType.Boolean;
                break;

            case PrimitiveTypeCode.Byte:
                wkt = WellKnownType.Byte;
                break;

            case PrimitiveTypeCode.Char:
                wkt = WellKnownType.Char;
                break;

            case PrimitiveTypeCode.Double:
                wkt = WellKnownType.Double;
                break;

            case PrimitiveTypeCode.Int16:
                wkt = WellKnownType.Int16;
                break;

            case PrimitiveTypeCode.Int32:
                wkt = WellKnownType.Int32;
                break;

            case PrimitiveTypeCode.Int64:
                wkt = WellKnownType.Int64;
                break;

            case PrimitiveTypeCode.IntPtr:
                wkt = WellKnownType.IntPtr;
                break;

            case PrimitiveTypeCode.Object:
                wkt = WellKnownType.Object;
                break;

            case PrimitiveTypeCode.SByte:
                wkt = WellKnownType.SByte;
                break;

            case PrimitiveTypeCode.Single:
                wkt = WellKnownType.Single;
                break;

            case PrimitiveTypeCode.String:
                wkt = WellKnownType.String;
                break;

            case PrimitiveTypeCode.UInt16:
                wkt = WellKnownType.UInt16;
                break;

            case PrimitiveTypeCode.UInt32:
                wkt = WellKnownType.UInt32;
                break;

            case PrimitiveTypeCode.UInt64:
                wkt = WellKnownType.UInt64;
                break;

            case PrimitiveTypeCode.UIntPtr:
                wkt = WellKnownType.UIntPtr;
                break;

            case PrimitiveTypeCode.Void:
                wkt = WellKnownType.Void;
                break;

            case PrimitiveTypeCode.TypedReference:
                wkt = WellKnownType.TypedReference;
                break;

            default:
                throw new BadImageFormatException();
            }

            return(context.GetWellKnownType(wkt));
        }
Пример #4
0
        public UTCNameMangler(bool hasImport, bool hasExport, ImportExportOrdinals ordinals, TypeSystemContext context, List <EcmaModule> inputModules, bool buildingClassLib) : base(new UtcNodeMangler())
        {
            // Do not support both imports and exports for one module
            Debug.Assert(!hasImport || !hasExport);
            HasImport        = hasImport;
            HasExport        = hasExport;
            BuildingClassLib = buildingClassLib;

            if (hasImport)
            {
                _importOrdinals = ordinals;
            }
            else if (hasExport)
            {
                _exportOrdinals = ordinals;
            }

            _inputModuleIndices = new Dictionary <EcmaModule, int>();
            for (int i = 0; i < inputModules.Count; i++)
            {
                _inputModuleIndices[inputModules[i]] = i;
            }

            // Use SHA256 hash here to provide a high degree of uniqueness to symbol names without requiring them to be long
            // This hash function provides an exceedingly high likelihood that no two strings will be given equal symbol names
            // This is not considered used for security purpose; however collisions would be highly unfortunate as they will cause compilation
            // failure.
            _sha256 = SHA256.Create();

            // Special case primitive types and use shortened names. This reduces string sizes in symbol names, and reduces the overall native memory
            // usage of the compiler
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Void), "void");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Boolean), "bool");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Char), "char");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.SByte), "sbyte");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Byte), "byte");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Int16), "short");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.UInt16), "ushort");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Int32), "int");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.UInt32), "uint");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Int64), "long");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.UInt64), "ulong");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Single), "float");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Double), "double");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.Object), "object");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.String), "string");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.IntPtr), "IntPtr");
            _mangledTypeNames = _mangledTypeNames.Add(context.GetWellKnownType(WellKnownType.UIntPtr), "UIntPtr");
        }
Пример #5
0
        /// <summary>
        /// Constructs a new instance of <see cref="DelegateCreationInfo"/> set up to construct a delegate of type
        /// '<paramref name="delegateType"/>' pointing to '<paramref name="targetMethod"/>'.
        /// </summary>
        public static DelegateCreationInfo Create(TypeDesc delegateType, MethodDesc targetMethod, NodeFactory factory)
        {
            TypeSystemContext context        = delegateType.Context;
            DefType           systemDelegate = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;

            int paramCountTargetMethod = targetMethod.Signature.Length;

            if (!targetMethod.Signature.IsStatic)
            {
                paramCountTargetMethod++;
            }

            DelegateInfo delegateInfo             = context.GetDelegateInfo(delegateType.GetTypeDefinition());
            int          paramCountDelegateClosed = delegateInfo.Signature.Length + 1;
            bool         closed = false;

            if (paramCountDelegateClosed == paramCountTargetMethod)
            {
                closed = true;
            }
            else
            {
                Debug.Assert(paramCountDelegateClosed == paramCountTargetMethod + 1);
            }

            if (targetMethod.Signature.IsStatic)
            {
                MethodDesc invokeThunk;
                MethodDesc initMethod;

                if (!closed)
                {
                    // Open delegate to a static method
                    if (targetMethod.IsNativeCallable)
                    {
                        // If target method is native callable, create a reverse PInvoke delegate
                        initMethod  = systemDelegate.GetKnownMethod("InitializeReversePInvokeThunk", null);
                        invokeThunk = delegateInfo.Thunks[DelegateThunkKind.ReversePinvokeThunk];

                        // You might hit this when the delegate is generic: you need to make the delegate non-generic.
                        // If the code works on Project N, it's because the delegate is used in connection with
                        // AddrOf intrinsic (please validate that). We don't have the necessary AddrOf expansion in
                        // the codegen to make this work without actually constructing the delegate. You can't construct
                        // the delegate if it's generic, even on Project N.
                        // TODO: Make this throw something like "TypeSystemException.InvalidProgramException"?
                        Debug.Assert(invokeThunk != null, "Delegate with a non-native signature for a NativeCallable method");
                    }
                    else
                    {
                        initMethod  = systemDelegate.GetKnownMethod("InitializeOpenStaticThunk", null);
                        invokeThunk = delegateInfo.Thunks[DelegateThunkKind.OpenStaticThunk];
                    }
                }
                else
                {
                    // Closed delegate to a static method (i.e. delegate to an extension method that locks the first parameter)
                    invokeThunk = delegateInfo.Thunks[DelegateThunkKind.ClosedStaticThunk];
                    initMethod  = systemDelegate.GetKnownMethod("InitializeClosedStaticThunk", null);
                }

                var instantiatedDelegateType = delegateType as InstantiatedType;
                if (instantiatedDelegateType != null)
                {
                    invokeThunk = context.GetMethodForInstantiatedType(invokeThunk, instantiatedDelegateType);
                }

                return(new DelegateCreationInfo(
                           factory.MethodEntrypoint(initMethod),
                           factory.MethodEntrypoint(targetMethod),
                           factory.MethodEntrypoint(invokeThunk)));
            }
            else
            {
                if (!closed)
                {
                    throw new NotImplementedException("Open instance delegates");
                }

                bool useUnboxingStub = targetMethod.OwningType.IsValueType;

                IMethodNode targetMethodNode;
                string      initializeMethodName = "InitializeClosedInstance";
                MethodDesc  targetCanonMethod    = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                if (targetMethod.HasInstantiation)
                {
                    Debug.Assert(!targetMethod.IsVirtual, "TODO: delegate to generic virtual method");

                    if (targetMethod != targetCanonMethod)
                    {
                        // Closed delegates to generic instance methods need to be constructed through a slow helper that
                        // checks for the fat function pointer case (function pointer + instantiation argument in a single
                        // pointer) and injects an invocation thunk to unwrap the fat function pointer as part of
                        // the invocation if necessary.
                        initializeMethodName = "InitializeClosedInstanceSlow";
                        targetMethodNode     = factory.FatFunctionPointer(targetMethod, useUnboxingStub);
                    }
                    else
                    {
                        targetMethodNode = factory.MethodEntrypoint(targetMethod, useUnboxingStub);
                    }
                }
                else
                {
                    // If the method can be canonicalized, point to the canon method body, but track the dependencies.
                    if (targetMethod != targetCanonMethod)
                    {
                        targetMethodNode = factory.ShadowConcreteMethod(targetMethod, useUnboxingStub);
                    }
                    else
                    {
                        targetMethodNode = factory.MethodEntrypoint(targetMethod, useUnboxingStub);
                    }
                }

                return(new DelegateCreationInfo(
                           factory.MethodEntrypoint(systemDelegate.GetKnownMethod(initializeMethodName, null)),
                           targetMethodNode));
            }
        }
Пример #6
0
        /// <summary>
        /// Compute the canonical instantiation of a dynamic invoke thunk needed to invoke a method
        /// This algorithm is shared with the runtime, so if a thunk requires generic instantiation
        /// to be used, it must match this algorithm, and cannot be different with different MetadataManagers
        /// NOTE: This function may return null in cases where an exact instantiation does not exist. (Universal Generics)
        /// </summary>
        protected MethodDesc InstantiateCanonicalDynamicInvokeMethodForMethod(MethodDesc thunk, MethodDesc method)
        {
            if (thunk.Instantiation.Length == 0)
            {
                // nothing to instantiate
                return(thunk);
            }

            MethodSignature   sig     = method.Signature;
            TypeSystemContext context = method.Context;

            //
            // Instantiate the generic thunk over the parameters and the return type of the target method
            //

            ParameterMetadata[] paramMetadata = null;
            TypeDesc[]          instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1];
            Debug.Assert(thunk.Instantiation.Length == instantiation.Length);
            for (int i = 0; i < sig.Length; i++)
            {
                TypeDesc parameterType = sig[i];
                if (parameterType.IsByRef)
                {
                    // strip ByRefType off the parameter (the method already has ByRef in the signature)
                    parameterType = ((ByRefType)parameterType).ParameterType;

                    Debug.Assert(!parameterType.IsPointer); // TODO: support for methods returning pointer types - https://github.com/dotnet/corert/issues/2113
                }
                else if (parameterType.IsPointer)
                {
                    // Strip off all the pointers. Pointers are not valid instantiation arguments and the thunk compensates for that
                    // by being specialized for the specific pointer depth.
                    while (parameterType.IsPointer)
                    {
                        parameterType = ((PointerType)parameterType).ParameterType;
                    }
                }
                else if (parameterType.IsEnum)
                {
                    // If the invoke method takes an enum as an input parameter and there is no default value for
                    // that paramter, we don't need to specialize on the exact enum type (we only need to specialize
                    // on the underlying integral type of the enum.)
                    if (paramMetadata == null)
                    {
                        paramMetadata = method.GetParameterMetadata();
                    }

                    bool hasDefaultValue = false;
                    foreach (var p in paramMetadata)
                    {
                        // Parameter metadata indexes are 1-based (0 is reserved for return "parameter")
                        if (p.Index == (i + 1) && p.HasDefault)
                        {
                            hasDefaultValue = true;
                            break;
                        }
                    }

                    if (!hasDefaultValue)
                    {
                        parameterType = parameterType.UnderlyingType;
                    }
                }

                instantiation[i] = parameterType;
            }

            if (!sig.ReturnType.IsVoid)
            {
                TypeDesc returnType = sig.ReturnType;
                Debug.Assert(!returnType.IsByRef);

                // If the invoke method return an object reference, we don't need to specialize on the
                // exact type of the object reference, as the behavior is not different.
                if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray)
                {
                    returnType = context.GetWellKnownType(WellKnownType.Object);
                }

                // Strip off all the pointers. Pointers are not valid instantiation arguments and the thunk compensates for that
                // by being specialized for the specific pointer depth.
                while (returnType.IsPointer)
                {
                    returnType = ((PointerType)returnType).ParameterType;
                }

                instantiation[sig.Length] = returnType;
            }

            Debug.Assert(thunk.Instantiation.Length == instantiation.Length);

            // Check if at least one of the instantiation arguments is a universal canonical type, and if so, we
            // won't create a dynamic invoker instantiation. The arguments will be interpreted at runtime by the
            // calling convention converter during the dynamic invocation
            foreach (TypeDesc type in instantiation)
            {
                if (type.IsCanonicalSubtype(CanonicalFormKind.Universal))
                {
                    return(null);
                }
            }

            // If the thunk ends up being shared code, return the canonical method body.
            // The concrete dictionary for the thunk will be built at runtime and is not interesting for the compiler.
            Instantiation canonInstantiation = context.ConvertInstantiationToCanonForm(new Instantiation(instantiation), CanonicalFormKind.Specific);

            MethodDesc instantiatedDynamicInvokeMethod = thunk.Context.GetInstantiatedMethod(thunk, canonInstantiation);

            return(instantiatedDynamicInvokeMethod);
        }
Пример #7
0
        private static MarshallerKind GetMarshallerKind(TypeDesc type, MarshalAsDescriptor marshalAs, PInvokeMethodData PInvokeMethodData, bool isReturn)
        {
            if (isReturn)
            {
                if (type.IsVoid)
                {
                    return(MarshallerKind.VoidReturn);
                }

                if (MarshalHelpers.IsBlittableType(type))
                {
                    return(MarshallerKind.BlittableValue);
                }

                if (type.Category == TypeFlags.Boolean)
                {
                    return(MarshallerKind.Bool);
                }

                if (PInvokeMethodData.IsSafeHandle(type))
                {
                    return(MarshallerKind.SafeHandle);
                }
                throw new NotSupportedException();
            }

            if (MarshalHelpers.IsBlittableType(type))
            {
                return(MarshallerKind.BlittableValue);
            }
            TypeSystemContext context = PInvokeMethodData.Context;

            if (type.IsSzArray)
            {
                var arrayType = (ArrayType)type;
                if (MarshalHelpers.IsBlittableType(arrayType.ParameterType))
                {
                    return(MarshallerKind.BlittableArray);
                }

                if (arrayType.ParameterType == context.GetWellKnownType(WellKnownType.Char))
                {
                    if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode)
                    {
                        return(MarshallerKind.BlittableArray);
                    }
                }
            }

            if (type.IsByRef)
            {
                var byRefType = (ByRefType)type;
                if (MarshalHelpers.IsBlittableType(byRefType.ParameterType))
                {
                    return(MarshallerKind.BlittableByRef);
                }

                if (byRefType.ParameterType == context.GetWellKnownType(WellKnownType.Char))
                {
                    if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode)
                    {
                        return(MarshallerKind.BlittableByRef);
                    }
                }
            }

            if (type.IsString)
            {
                return(MarshallerKind.String);
            }

            if (type.Category == TypeFlags.Boolean)
            {
                return(MarshallerKind.Bool);
            }

            if (type is MetadataType)
            {
                var metadataType = (MetadataType)type;

                if (metadataType.Module == context.SystemModule)
                {
                    var nameSpace = metadataType.Namespace;
                    var name      = metadataType.Name;

                    if (name == "StringBuilder" && nameSpace == "System.Text")
                    {
                        return(MarshallerKind.StringBuilder);
                    }
                }
            }

            if (PInvokeMethodData.IsSafeHandle(type))
            {
                return(MarshallerKind.SafeHandle);
            }
            throw new NotSupportedException();
        }
Пример #8
0
        private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PInvokeILCodeStreams ilCodeStreams)
        {
            ILEmitter         emitter                 = ilCodeStreams.Emitter;
            ILCodeStream      fnptrLoadStream         = ilCodeStreams.FunctionPointerLoadStream;
            ILCodeStream      marshallingCodeStream   = ilCodeStreams.MarshallingCodeStream;
            ILCodeStream      callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;
            TypeSystemContext context                 = _targetMethod.Context;

            Debug.Assert(delegateMethod != null);

            if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseOpenStatic)
            {
                //
                // For Open static delegates call
                //     InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer()
                // which returns a function pointer. Just call the function pointer and we are done.
                //
                TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1];
                for (int i = 1; i < _marshallers.Length; i++)
                {
                    parameters[i - 1] = _marshallers[i].ManagedParameterType;
                }

                MethodSignature managedSignature = new MethodSignature(
                    MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters);

                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(
                                         delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod(
                                             "GetCurrentCalleeOpenStaticDelegateFunctionPointer", null)));

                ILLocalVariable vDelegateStub = emitter.NewLocal(
                    delegateMethod.Context.GetWellKnownType(WellKnownType.IntPtr));

                fnptrLoadStream.EmitStLoc(vDelegateStub);
                callsiteSetupCodeStream.EmitLdLoc(vDelegateStub);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature));
            }
            else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseClosed)
            {
                //
                // For closed delegates call
                //     InteropHelpers.GetCurrentCalleeDelegate<Delegate>
                // which returns the delegate. Do a CallVirt on the invoke method.
                //
                MethodDesc instantiatedHelper = delegateMethod.Context.GetInstantiatedMethod(
                    delegateMethod.Context.GetHelperType("InteropHelpers")
                    .GetKnownMethod("GetCurrentCalleeDelegate", null),
                    new Instantiation((delegateMethod.DelegateType)));

                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(instantiatedHelper));

                ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType);
                fnptrLoadStream.EmitStLoc(vDelegateStub);
                marshallingCodeStream.EmitLdLoc(vDelegateStub);
                MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null);
                callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod));
            }
            else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind
                     .ForwardNativeFunctionWrapper)
            {
                // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, clear the error code before doing P/Invoke
                if (_flags.SetLastError)
                {
                    callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                     InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null)));
                }

                //
                // For NativeFunctionWrapper we need to load the native function and call it
                //
                fnptrLoadStream.EmitLdArg(0);
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(InteropTypes
                                                                     .GetNativeFunctionPointerWrapper(context)
                                                                     .GetMethod("get_NativeFunctionPointer", null)));

                var fnPtr = emitter.NewLocal(
                    context.GetWellKnownType(WellKnownType.IntPtr));

                fnptrLoadStream.EmitStLoc(fnPtr);
                callsiteSetupCodeStream.EmitLdLoc(fnPtr);

                TypeDesc   nativeReturnType     = _marshallers[0].NativeParameterType;
                TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

                for (int i = 1; i < _marshallers.Length; i++)
                {
                    nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
                }

                MethodSignature nativeSig = new MethodSignature(
                    MethodSignatureFlags.Static | _flags.UnmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes);

                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));

                // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, call the PInvokeMarshal.
                // SaveLastWin32Error so that last error can be used later by calling
                // PInvokeMarshal.GetLastWin32Error
                if (_flags.SetLastError)
                {
                    callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                     InteropTypes.GetPInvokeMarshal(context)
                                                     .GetKnownMethod("SaveLastWin32Error", null)));
                }
            }
            else
            {
                Debug.Fail("Unexpected DelegateMarshallingMethodThunkKind");
            }
        }
Пример #9
0
        private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
        {
            ILEmitter         emitter                 = ilCodeStreams.Emitter;
            ILCodeStream      fnptrLoadStream         = ilCodeStreams.FunctionPointerLoadStream;
            ILCodeStream      callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;
            TypeSystemContext context                 = _targetMethod.Context;

            TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;

            TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if (_flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null)));
            }

            for (int i = 1; i < _marshallers.Length; i++)
            {
                nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
            }

            if (!_pInvokeILEmitterConfiguration.GenerateDirectCall(_importMetadata.Module, _importMetadata.Name))
            {
                MetadataType lazyHelperType   = context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod);

                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType
                                                                     .GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallConv = _flags.UnmanagedCallingConvention;

                MethodSignature nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType,
                    nativeParameterTypes);

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context
                                                                          .GetWellKnownType(WellKnownType.IntPtr));

                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
            }
            else
            {
                // Eager call
                MethodSignature nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(_targetMethod, nativeSig);

                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.
            // SaveLastWin32Error so that last error can be used later by calling
            // PInvokeMarshal.GetLastWin32Error
            if (_flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context)
                                                 .GetKnownMethod("SaveLastWin32Error", null)));
            }
        }
Пример #10
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);
        }
Пример #11
0
        /// <summary>
        /// Gets a stub that can be used to reflection-invoke a method with a given signature.
        /// </summary>
        public MethodDesc GetReflectionInvokeStub(MethodDesc method)
        {
            // Methods we see here shouldn't be canonicalized, or we'll end up creating bastardized instantiations
            // (e.g. we instantiate over System.Object below.)
            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any));

            TypeSystemContext context = method.Context;
            var sig = method.Signature;

            // Get a generic method that can be used to invoke method with this shape.
            MethodDesc thunk;
            var        lookupSig = new DynamicInvokeMethodSignature(sig);

            if (!_dynamicInvokeThunks.TryGetValue(lookupSig, out thunk))
            {
                thunk = new DynamicInvokeMethodThunk(_nodeFactory.CompilationModuleGroup.GeneratedAssembly.GetGlobalModuleType(), lookupSig);
                _dynamicInvokeThunks.Add(lookupSig, thunk);
            }

            // If the method has no parameters and returns void, we don't need to specialize
            if (sig.ReturnType.IsVoid && sig.Length == 0)
            {
                Debug.Assert(!thunk.HasInstantiation);
                return(thunk);
            }

            //
            // Instantiate the generic thunk over the parameters and the return type of the target method
            //

            TypeDesc[] instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1];
            Debug.Assert(thunk.Instantiation.Length == instantiation.Length);
            for (int i = 0; i < sig.Length; i++)
            {
                TypeDesc parameterType = sig[i];
                if (parameterType.IsByRef)
                {
                    // strip ByRefType off the parameter (the method already has ByRef in the signature)
                    parameterType = ((ByRefType)parameterType).ParameterType;
                }

                if (parameterType.IsPointer || parameterType.IsFunctionPointer)
                {
                    // For pointer typed parameters, instantiate the method over IntPtr
                    parameterType = context.GetWellKnownType(WellKnownType.IntPtr);
                }
                else if (parameterType.IsDefType)
                {
                    // TODO: optimize enum types with no default value
                    // DefType* paramDefType = parameterType->as<DefType> ();
                    // // If the invoke method takes an enum as an input paramter and there is no default value for
                    // // that paramter, we don't need to specialize on the exact enum type (we only need to specialize
                    // // on the underlying integral type of the enum.)
                    // if (paramDefType && (!IsPdHasDefault(methodToInvoke->Parameters()[index].Attributes())) && paramDefType->IsEnum())
                    // {
                    //     CorElementType underlyingElemType = paramDefType->InternalElementType();
                    //     parameterType = paramDefType->GetLoaderContext()->GetElementType(underlyingElemType);
                    // }
                }

                instantiation[i] = parameterType;
            }

            if (!sig.ReturnType.IsVoid)
            {
                TypeDesc returnType = sig.ReturnType;
                Debug.Assert(!returnType.IsByRef);

                // If the invoke method return an object reference, we don't need to specialize on the
                // exact type of the object reference, as the behavior is not different.
                if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray)
                {
                    returnType = context.GetWellKnownType(WellKnownType.Object);
                }

                instantiation[sig.Length] = returnType;
            }

            return(context.GetInstantiatedMethod(thunk, new Instantiation(instantiation)));
        }
Пример #12
0
 private TypeDesc GetWellKnownType(WellKnownType wellKnownType)
 {
     return(_tsc.GetWellKnownType(wellKnownType));
 }
Пример #13
0
        /// <summary>
        /// Marshals a string. Expects the string reference on the stack. Pushes a pointer
        /// to the stack that is safe to pass out to native code.
        /// </summary>
        /// <returns>The type the string was marshalled into.</returns>
        private TypeDesc EmitStringMarshalling()
        {
            PInvokeAttributes charset = _importMetadata.Attributes & PInvokeAttributes.CharSetMask;

            TypeSystemContext context = _targetMethod.Context;

            if (charset == 0)
            {
                // ECMA-335 II.10.1.5 - Default value is Ansi.
                charset = PInvokeAttributes.CharSetAnsi;
            }

            if (charset == PInvokeAttributes.CharSetAuto)
            {
                charset = PInvokeAttributes.CharSetUnicode;
            }

            TypeDesc stringType = context.GetWellKnownType(WellKnownType.String);

            if (charset == PInvokeAttributes.CharSetUnicode)
            {
                //
                // Unicode marshalling. Pin the string and push a pointer to the first character on the stack.
                //

                ILLocalVariable vPinnedString = _emitter.NewLocal(stringType, true);
                ILCodeLabel     lNullString   = _emitter.NewCodeLabel();

                _marshallingCodeStream.EmitStLoc(vPinnedString);
                _marshallingCodeStream.EmitLdLoc(vPinnedString);

                _marshallingCodeStream.Emit(ILOpcode.conv_i);
                _marshallingCodeStream.Emit(ILOpcode.dup);

                // Marshalling a null string?
                _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString);

                // TODO: find a safe, non-awkward way to get to OffsetToStringData
                _marshallingCodeStream.EmitLdc(context.Target.PointerSize + 4);
                _marshallingCodeStream.Emit(ILOpcode.add);

                _marshallingCodeStream.EmitLabel(lNullString);
            }
            else
            {
                //
                // ANSI marshalling. Allocate a byte array, copy characters, pin first element.
                //

                TypeDesc byteType      = context.GetWellKnownType(WellKnownType.Byte);
                TypeDesc byteArrayType = byteType.MakeArrayType();

                MethodDesc getLengthMethod = stringType.GetMethod("get_Length", null);
                MethodDesc getCharsMethod  = stringType.GetMethod("get_Chars", null);

                ILCodeLabel lStart      = _emitter.NewCodeLabel();
                ILCodeLabel lNext       = _emitter.NewCodeLabel();
                ILCodeLabel lNullString = _emitter.NewCodeLabel();
                ILCodeLabel lDone       = _emitter.NewCodeLabel();

                // Check for the simple case: string is null
                ILLocalVariable vStringToMarshal = _emitter.NewLocal(stringType);
                _marshallingCodeStream.EmitStLoc(vStringToMarshal);
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString);

                // TODO: figure out how to reference a helper from here and call the helper instead...

                // byte[] byteArray = new byte[stringToMarshal.Length + 1];
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getLengthMethod));
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.add);
                _marshallingCodeStream.Emit(ILOpcode.newarr, _emitter.NewToken(byteType));
                ILLocalVariable vByteArray = _emitter.NewLocal(byteArrayType);
                _marshallingCodeStream.EmitStLoc(vByteArray);

                // for (int i = 0; i < byteArray.Length - 1; i++)
                //     byteArray[i] = (byte)stringToMarshal[i];
                ILLocalVariable vIterator = _emitter.NewLocal(context.GetWellKnownType(WellKnownType.Int32));
                _marshallingCodeStream.Emit(ILOpcode.ldc_i4_0);
                _marshallingCodeStream.EmitStLoc(vIterator);
                _marshallingCodeStream.Emit(ILOpcode.br, lStart);
                _marshallingCodeStream.EmitLabel(lNext);
                _marshallingCodeStream.EmitLdLoc(vByteArray);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getCharsMethod));
                _marshallingCodeStream.Emit(ILOpcode.conv_u1);
                _marshallingCodeStream.Emit(ILOpcode.stelem_i1);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.add);
                _marshallingCodeStream.EmitStLoc(vIterator);
                _marshallingCodeStream.EmitLabel(lStart);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdLoc(vByteArray);
                _marshallingCodeStream.Emit(ILOpcode.ldlen);
                _marshallingCodeStream.Emit(ILOpcode.conv_i4);
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.sub);
                _marshallingCodeStream.Emit(ILOpcode.blt, lNext);
                _marshallingCodeStream.EmitLdLoc(vByteArray);

                // Pin first element and load the byref on the stack.
                _marshallingCodeStream.EmitLdc(0);
                _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(byteType));
                ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(byteArrayType.MakeByRefType(), true);
                _marshallingCodeStream.EmitStLoc(vPinnedFirstElement);
                _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement);
                _marshallingCodeStream.Emit(ILOpcode.conv_i);
                _marshallingCodeStream.Emit(ILOpcode.br, lDone);

                _marshallingCodeStream.EmitLabel(lNullString);
                _marshallingCodeStream.Emit(ILOpcode.ldnull);
                _marshallingCodeStream.Emit(ILOpcode.conv_i);

                _marshallingCodeStream.EmitLabel(lDone);
            }

            return(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
        }
Пример #14
0
        private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
        {
            ILEmitter         emitter                 = ilCodeStreams.Emitter;
            ILCodeStream      fnptrLoadStream         = ilCodeStreams.FunctionPointerLoadStream;
            ILCodeStream      callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;
            TypeSystemContext context                 = _targetMethod.Context;

            bool     isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid;
            TypeDesc nativeReturnType  = _flags.PreserveSig ? _marshallers[0].NativeParameterType : context.GetWellKnownType(WellKnownType.Int32);

            TypeDesc[] nativeParameterTypes = new TypeDesc[isHRSwappedRetVal ? _marshallers.Length : _marshallers.Length - 1];

            bool runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module);

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if (_flags.SetLastError)
            {
                if (!runtimeMarshallingEnabled)
                {
                    // When runtime marshalling is disabled, we don't support SetLastError
                    throw new NotSupportedException();
                }
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastError", null)));
            }

            for (int i = 1; i < _marshallers.Length; i++)
            {
                nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
            }

            if (isHRSwappedRetVal)
            {
                if (!runtimeMarshallingEnabled)
                {
                    // When runtime marshalling is disabled, we don't support HResult-return-swapping
                    throw new NotSupportedException();
                }
                nativeParameterTypes[_marshallers.Length - 1] = _marshallers[0].NativeParameterType;
            }

            if (!_pInvokeILEmitterConfiguration.GenerateDirectCall(_targetMethod, out _))
            {
                MetadataType lazyHelperType   = context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod);

                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType
                                                                     .GetKnownMethod("ResolvePInvoke", null)));

                MethodSignature nativeSig = new MethodSignature(
                    MethodSignatureFlags.Static | MethodSignatureFlags.UnmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes,
                    _targetMethod.GetPInvokeMethodCallingConventions().EncodeAsEmbeddedSignatureData(context));

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context
                                                                          .GetWellKnownType(WellKnownType.IntPtr));

                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
            }
            else
            {
                // Eager call
                MethodSignature nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(_targetMethod, nativeSig);

                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
            }

            if (!_flags.PreserveSig)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetMarshal(context)
                                                 .GetKnownMethod("ThrowExceptionForHR", null)));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError
            // so that last error can be used later by calling Marshal.GetLastPInvokeError
            if (_flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context)
                                                 .GetKnownMethod("SaveLastError", null)));
            }
        }
Пример #15
0
        // Load type from IBC ZapSig. Returns null for cases where the type is legally defined, but is not used in R2R image generation
        private TypeDesc GetSigTypeFromIBCZapSig(IBCModule ibcModule, EcmaModule ecmaModule, BlobReader sig)
        {
            TypeSystemContext context = ibcModule.EcmaModule.Context;

            CorElementType typ = (CorElementType)sig.ReadByte();

            switch (typ)
            {
            case CorElementType.ELEMENT_TYPE_VOID:
                return(context.GetWellKnownType(WellKnownType.Void));

            case CorElementType.ELEMENT_TYPE_BOOLEAN:
                return(context.GetWellKnownType(WellKnownType.Boolean));

            case CorElementType.ELEMENT_TYPE_CHAR:
                return(context.GetWellKnownType(WellKnownType.Char));

            case CorElementType.ELEMENT_TYPE_I1:
                return(context.GetWellKnownType(WellKnownType.SByte));

            case CorElementType.ELEMENT_TYPE_U1:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case CorElementType.ELEMENT_TYPE_I2:
                return(context.GetWellKnownType(WellKnownType.Int16));

            case CorElementType.ELEMENT_TYPE_U2:
                return(context.GetWellKnownType(WellKnownType.UInt16));

            case CorElementType.ELEMENT_TYPE_I4:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case CorElementType.ELEMENT_TYPE_U4:
                return(context.GetWellKnownType(WellKnownType.UInt32));

            case CorElementType.ELEMENT_TYPE_I8:
                return(context.GetWellKnownType(WellKnownType.Int64));

            case CorElementType.ELEMENT_TYPE_U8:
                return(context.GetWellKnownType(WellKnownType.UInt64));

            case CorElementType.ELEMENT_TYPE_R4:
                return(context.GetWellKnownType(WellKnownType.Single));

            case CorElementType.ELEMENT_TYPE_R8:
                return(context.GetWellKnownType(WellKnownType.Double));

            case CorElementType.ELEMENT_TYPE_STRING:
                return(context.GetWellKnownType(WellKnownType.String));

            case CorElementType.ELEMENT_TYPE_OBJECT:
                return(context.GetWellKnownType(WellKnownType.Object));

            case CorElementType.ELEMENT_TYPE_TYPEDBYREF:
                return(context.GetWellKnownType(WellKnownType.TypedReference));

            case CorElementType.ELEMENT_TYPE_CANON_ZAPSIG:
                if (!context.SupportsCanon)
                {
                    return(null);
                }
                return(context.CanonType);

            case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
                // Check version bubble by looking at reference to non-local module
                // If null, then the remote reference is not permitted.
                EcmaModule remoteModule = ibcModule.GetModuleFromIndex(sig.ReadCompressedInteger());
                return(GetSigTypeFromIBCZapSig(ibcModule, remoteModule, sig));

            case CorElementType.ELEMENT_TYPE_VAR:
            case CorElementType.ELEMENT_TYPE_MVAR:
                // VAR/MVAR can never appear in a ZapSig
                throw new Exception("Attempt to parse ELEMENT_TYPE_VAR or ELEMENT_TYPE_MVAR in an IBC ZapSig");

            case CorElementType.ELEMENT_TYPE_GENERICINST:
                CorElementType genericTyp            = (CorElementType)sig.ReadByte();
                MetadataType   genericDefinitionType = LoadTypeFromIBCZapSig(ibcModule, ecmaModule, genericTyp, ref sig);
                if (genericDefinitionType == null)
                {
                    return(null);
                }
                int        numTypeArgs = sig.ReadCompressedInteger();
                TypeDesc[] typeArgs    = new TypeDesc[numTypeArgs];
                for (int i = 0; i < numTypeArgs; i++)
                {
                    TypeDesc nextTypeArg = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                    if (nextTypeArg == null)
                    {
                        return(null);
                    }
                    SkipTypeInIBCZapSig(ref sig);
                    typeArgs[i] = nextTypeArg;
                }
                return(genericDefinitionType.MakeInstantiatedType(new Instantiation(typeArgs)));

            case CorElementType.ELEMENT_TYPE_CLASS:
            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                return(LoadTypeFromIBCZapSig(ibcModule, ecmaModule, typ, ref sig));

            case CorElementType.ELEMENT_TYPE_SZARRAY:
            {
                TypeDesc arrayElementType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (arrayElementType == null)
                {
                    return(null);
                }
                return(arrayElementType.MakeArrayType());
            }

            case CorElementType.ELEMENT_TYPE_ARRAY:
            {
                TypeDesc arrayElementType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (arrayElementType == null)
                {
                    return(null);
                }
                SkipTypeInIBCZapSig(ref sig);
                return(arrayElementType.MakeArrayType(sig.ReadCompressedInteger()));
            }

            case CorElementType.ELEMENT_TYPE_PINNED:
                // Return what follows
                return(GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig));

            case CorElementType.ELEMENT_TYPE_BYREF:
            {
                TypeDesc byRefToType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (byRefToType == null)
                {
                    return(null);
                }
                return(byRefToType.MakeByRefType());
            }

            case CorElementType.ELEMENT_TYPE_PTR:
            {
                TypeDesc pointerToType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (pointerToType == null)
                {
                    return(null);
                }
                return(pointerToType.MakePointerType());
            }

            default:
                throw new Exception($"Invalid element type {typ:x} in IBC ZapSig");
            }
        }
Пример #16
0
        /// <summary>
        /// Marshals an array. Expects the array reference on the stack. Pushes a pinned
        /// managed reference to the first element on the stack or null if the array was
        /// null or empty.
        /// </summary>
        /// <returns>Type the array was marshalled into.</returns>
        private TypeDesc EmitArrayMarshalling(ArrayType arrayType)
        {
            Debug.Assert(arrayType.IsSzArray);

            ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(arrayType.ParameterType.MakeByRefType(), true);
            ILLocalVariable vArray     = _emitter.NewLocal(arrayType);
            ILCodeLabel     lNullArray = _emitter.NewCodeLabel();

            // Check for null array, or 0 element array.
            _marshallingCodeStream.Emit(ILOpcode.dup);
            _marshallingCodeStream.EmitStLoc(vArray);
            _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray);
            _marshallingCodeStream.EmitLdLoc(vArray);
            _marshallingCodeStream.Emit(ILOpcode.ldlen);
            _marshallingCodeStream.Emit(ILOpcode.conv_i4);
            _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray);

            // Array has elements.
            _marshallingCodeStream.EmitLdLoc(vArray);
            _marshallingCodeStream.EmitLdc(0);
            _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(arrayType.ElementType));
            _marshallingCodeStream.EmitStLoc(vPinnedFirstElement);

            // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit.
            _marshallingCodeStream.EmitLabel(lNullArray);
            _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement);
            _marshallingCodeStream.Emit(ILOpcode.conv_i);

            return(_context.GetWellKnownType(WellKnownType.IntPtr));
        }
Пример #17
0
            private void RootWellKnownType(WellKnownType wellKnownType, IRootingServiceProvider rootProvider)
            {
                var type = _context.GetWellKnownType(wellKnownType);

                rootProvider.AddCompilationRoot(type, "Enables CPP codegen");
            }
        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);
        }
Пример #19
0
        /// <summary>
        /// Constructs a new instance of <see cref="DelegateCreationInfo"/> set up to construct a delegate of type
        /// '<paramref name="delegateType"/>' pointing to '<paramref name="targetMethod"/>'.
        /// </summary>
        public static DelegateCreationInfo Create(TypeDesc delegateType, MethodDesc targetMethod, NodeFactory factory, bool followVirtualDispatch)
        {
            TypeSystemContext context        = delegateType.Context;
            DefType           systemDelegate = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;

            int paramCountTargetMethod = targetMethod.Signature.Length;

            if (!targetMethod.Signature.IsStatic)
            {
                paramCountTargetMethod++;
            }

            DelegateInfo delegateInfo             = context.GetDelegateInfo(delegateType.GetTypeDefinition());
            int          paramCountDelegateClosed = delegateInfo.Signature.Length + 1;
            bool         closed = false;

            if (paramCountDelegateClosed == paramCountTargetMethod)
            {
                closed = true;
            }
            else
            {
                Debug.Assert(paramCountDelegateClosed == paramCountTargetMethod + 1);
            }

            if (targetMethod.Signature.IsStatic)
            {
                MethodDesc invokeThunk;
                MethodDesc initMethod;

                if (!closed)
                {
                    initMethod  = systemDelegate.GetKnownMethod("InitializeOpenStaticThunk", null);
                    invokeThunk = delegateInfo.Thunks[DelegateThunkKind.OpenStaticThunk];
                }
                else
                {
                    // Closed delegate to a static method (i.e. delegate to an extension method that locks the first parameter)
                    invokeThunk = delegateInfo.Thunks[DelegateThunkKind.ClosedStaticThunk];
                    initMethod  = systemDelegate.GetKnownMethod("InitializeClosedStaticThunk", null);
                }

                var instantiatedDelegateType = delegateType as InstantiatedType;
                if (instantiatedDelegateType != null)
                {
                    invokeThunk = context.GetMethodForInstantiatedType(invokeThunk, instantiatedDelegateType);
                }

                return(new DelegateCreationInfo(
                           factory.MethodEntrypoint(initMethod),
                           targetMethod,
                           TargetKind.ExactCallableAddress,
                           factory.MethodEntrypoint(invokeThunk)));
            }
            else
            {
                if (!closed)
                {
                    throw new NotImplementedException("Open instance delegates");
                }

                string     initializeMethodName = "InitializeClosedInstance";
                MethodDesc targetCanonMethod    = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                TargetKind kind;
                if (targetMethod.HasInstantiation)
                {
                    if (followVirtualDispatch && targetMethod.IsVirtual)
                    {
                        initializeMethodName = "InitializeClosedInstanceWithGVMResolution";
                        kind = TargetKind.MethodHandle;
                    }
                    else
                    {
                        if (targetMethod != targetCanonMethod)
                        {
                            // Closed delegates to generic instance methods need to be constructed through a slow helper that
                            // checks for the fat function pointer case (function pointer + instantiation argument in a single
                            // pointer) and injects an invocation thunk to unwrap the fat function pointer as part of
                            // the invocation if necessary.
                            initializeMethodName = "InitializeClosedInstanceSlow";
                        }

                        kind = TargetKind.ExactCallableAddress;
                    }
                }
                else
                {
                    if (followVirtualDispatch && targetMethod.IsVirtual)
                    {
                        if (targetMethod.OwningType.IsInterface)
                        {
                            kind = TargetKind.InterfaceDispatch;
                            initializeMethodName = "InitializeClosedInstanceToInterface";
                        }
                        else
                        {
                            kind         = TargetKind.VTableLookup;
                            targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                        }
                    }
                    else
                    {
                        kind         = TargetKind.CanonicalEntrypoint;
                        targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                    }
                }

                return(new DelegateCreationInfo(
                           factory.MethodEntrypoint(systemDelegate.GetKnownMethod(initializeMethodName, null)),
                           targetMethod,
                           kind));
            }
        }
Пример #20
0
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
                                                                 InteropStateManager interopStateManager,
                                                                 MarshalAsDescriptor marshalAs)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;

            if (marshalAs != null)
            {
                nativeType = marshalAs.Type;
            }

            switch (kind)
            {
            case MarshallerKind.BlittableValue:
            {
                switch (nativeType)
                {
                case NativeTypeKind.I1:
                    return(context.GetWellKnownType(WellKnownType.SByte));

                case NativeTypeKind.U1:
                    return(context.GetWellKnownType(WellKnownType.Byte));

                case NativeTypeKind.I2:
                    return(context.GetWellKnownType(WellKnownType.Int16));

                case NativeTypeKind.U2:
                    return(context.GetWellKnownType(WellKnownType.UInt16));

                case NativeTypeKind.I4:
                    return(context.GetWellKnownType(WellKnownType.Int32));

                case NativeTypeKind.U4:
                    return(context.GetWellKnownType(WellKnownType.UInt32));

                case NativeTypeKind.I8:
                    return(context.GetWellKnownType(WellKnownType.Int64));

                case NativeTypeKind.U8:
                    return(context.GetWellKnownType(WellKnownType.UInt64));

                case NativeTypeKind.R4:
                    return(context.GetWellKnownType(WellKnownType.Single));

                case NativeTypeKind.R8:
                    return(context.GetWellKnownType(WellKnownType.Double));

                default:
                    return(type.UnderlyingType);
                }
            }

            case MarshallerKind.Bool:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case MarshallerKind.Enum:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.Decimal:
            case MarshallerKind.VoidReturn:
                return(type);

            case MarshallerKind.Struct:
                return(interopStateManager.GetStructMarshallingNativeType((MetadataType)type));

            case MarshallerKind.BlittableStructPtr:
                return(type.MakePointerType());

            case MarshallerKind.HandleRef:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeChar:
                if (nativeType == NativeTypeKind.U2)
                {
                    return(context.GetWellKnownType(WellKnownType.UInt16));
                }
                else
                {
                    return(context.GetWellKnownType(WellKnownType.Int16));
                }

            case MarshallerKind.OleDateTime:
                return(context.GetWellKnownType(WellKnownType.Double));

            case MarshallerKind.SafeHandle:
            case MarshallerKind.CriticalHandle:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeString:
            case MarshallerKind.UnicodeStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Char).MakePointerType());

            case MarshallerKind.AnsiString:
            case MarshallerKind.AnsiStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Byte).MakePointerType());

            case MarshallerKind.CBool:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.BlittableArray:
            case MarshallerKind.Array:
            case MarshallerKind.AnsiCharArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                //
                // We need to construct the unsafe array from the right unsafe array element type
                //
                TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind(
                    arrayType.ElementType,
                    elementMarshallerKind,
                    MarshallerKind.Unknown,
                    interopStateManager,
                    null);

                return(elementNativeType.MakePointerType());
            }

            case MarshallerKind.AnsiChar:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.FunctionPointer:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.ByValArray:
            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }