public StructMarshallingThunk(TypeDesc owningType, MetadataType managedType, StructMarshallingThunkType thunkType, InteropStateManager interopStateManager)
 {
     _owningType          = owningType;
     ManagedType          = managedType;
     _interopStateManager = interopStateManager;
     NativeType           = _interopStateManager.GetStructMarshallingNativeType(managedType);
     ThunkType            = thunkType;
 }
Exemple #2
0
 internal IEnumerable <StructMarshallingThunks> GetStructMarshallingTypes()
 {
     foreach (var structType in _structMarshallingTypes)
     {
         yield return
             (new StructMarshallingThunks()
         {
             StructType = structType,
             NativeStructType = InteropStateManager.GetStructMarshallingNativeType(structType),
             MarshallingThunk = InteropStateManager.GetStructMarshallingManagedToNativeThunk(structType),
             UnmarshallingThunk = InteropStateManager.GetStructMarshallingNativeToManagedThunk(structType),
             CleanupThunk = InteropStateManager.GetStructMarshallingCleanupThunk(structType)
         });
     }
 }
Exemple #3
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);
        }
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
                                                                 InteropStateManager interopStateManager,
                                                                 MarshalAsDescriptor marshalAs,
                                                                 bool isArrayElement = false)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;

            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);

            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.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,
                    marshalAs,
                    isArrayElement: true);

                return(elementNativeType.MakePointerType());
            }

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

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

            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));
            }

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
Exemple #5
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.VariantBool:
                return(context.GetWellKnownType(WellKnownType.Int16));

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

#if !READYTORUN
            case MarshallerKind.Struct:
            case MarshallerKind.LayoutClass:
                Debug.Assert(interopStateManager is not null, "An InteropStateManager is required to look up the native representation of a non-blittable struct or class with layout.");
                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.FailedTypeLoad:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            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));

#if !READYTORUN
            case MarshallerKind.Variant:
                return(InteropTypes.GetVariant(context));

            case MarshallerKind.CustomMarshaler:
                return(context.GetWellKnownType(WellKnownType.IntPtr));
#endif

            case MarshallerKind.OleCurrency:
                return(context.GetWellKnownType(WellKnownType.Int64));

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            foreach (var structType in factory.MetadataManager.GetTypesWithStructMarshalling())
            {
                // the order of data written is as follows:
                //  managed struct type
                //  NumFields<< 2 | (HasInvalidLayout ? (2:0)) | (MarshallingRequired ? (1:0))
                //  If MarshallingRequired:
                //    size
                //    struct marshalling thunk
                //    struct unmarshalling thunk
                //    struct cleanup thunk
                //  For each field field:
                //     name
                //     offset

                var nativeType = _interopStateManager.GetStructMarshallingNativeType(structType);

                Vertex marshallingData = null;
                if (MarshalHelpers.IsStructMarshallingRequired(structType))
                {
                    Vertex thunks = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingManagedToNativeThunk(structType)))),
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingNativeToManagedThunk(structType)))),
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(_interopStateManager.GetStructMarshallingCleanupThunk(structType)))));

                    uint size = (uint)nativeType.InstanceFieldSize.AsInt;
                    marshallingData = writer.GetTuple(writer.GetUnsignedConstant(size), thunks);
                }

                Vertex fieldOffsetData = null;
                for (int i = 0; i < nativeType.Fields.Length; i++)
                {
                    var row = writer.GetTuple(
                        writer.GetStringConstant(nativeType.Fields[i].Name),
                        writer.GetUnsignedConstant((uint)nativeType.Fields[i].Offset.AsInt)
                        );

                    fieldOffsetData = (fieldOffsetData != null) ? writer.GetTuple(fieldOffsetData, row) : row;
                }

                uint mask = (uint)((marshallingData != null) ? InteropDataConstants.HasMarshallers : 0) |
                            (uint)(nativeType.HasInvalidLayout ? InteropDataConstants.HasInvalidLayout : 0) |
                            (uint)(nativeType.Fields.Length << InteropDataConstants.FieldCountShift);

                Vertex data = writer.GetUnsignedConstant(mask);
                if (marshallingData != null)
                {
                    data = writer.GetTuple(data, marshallingData);
                }

                if (fieldOffsetData != null)
                {
                    data = writer.GetTuple(data, fieldOffsetData);
                }

                Vertex vertex = writer.GetTuple(
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(structType))),
                    data
                    );

                int hashCode = structType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }