Ejemplo n.º 1
0
        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            if (type.IsByRef)
            {
                type = type.GetParameterType();
            }
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;
            bool isField = marshallerType == MarshallerType.Field;

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


            elementMarshallerKind = MarshallerKind.Invalid;

            //
            // Determine MarshalerKind
            //
            // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior
            //
            if (type.IsPrimitive)
            {
                switch (type.Category)
                {
                case TypeFlags.Void:
                    return(MarshallerKind.VoidReturn);

                case TypeFlags.Boolean:
                    switch (nativeType)
                    {
                    case NativeTypeKind.Invalid:
                    case NativeTypeKind.Boolean:
                        return(MarshallerKind.Bool);

                    case NativeTypeKind.U1:
                    case NativeTypeKind.I1:
                        return(MarshallerKind.CBool);

                    default:
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Char:
                    switch (nativeType)
                    {
                    case NativeTypeKind.I1:
                    case NativeTypeKind.U1:
                        return(MarshallerKind.AnsiChar);

                    case NativeTypeKind.I2:
                    case NativeTypeKind.U2:
                        return(MarshallerKind.UnicodeChar);

                    case NativeTypeKind.Invalid:
                        if (isAnsi)
                        {
                            return(MarshallerKind.AnsiChar);
                        }
                        else
                        {
                            return(MarshallerKind.UnicodeChar);
                        }

                    default:
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.SByte:
                case TypeFlags.Byte:
                    if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Int16:
                case TypeFlags.UInt16:
                    if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Int32:
                case TypeFlags.UInt32:
                    if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Int64:
                case TypeFlags.UInt64:
                    if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                    if (nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Single:
                    if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                case TypeFlags.Double:
                    if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

                default:
                    return(MarshallerKind.Invalid);
                }
            }
            else if (type.IsValueType)
            {
                if (type.IsEnum)
                {
                    return(MarshallerKind.Enum);
                }

                if (InteropTypes.IsSystemDateTime(context, type))
                {
                    if (nativeType == NativeTypeKind.Invalid ||
                        nativeType == NativeTypeKind.Struct)
                    {
                        return(MarshallerKind.OleDateTime);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }
                }

                /*
                 *              TODO: Bring HandleRef to CoreLib
                 *              https://github.com/dotnet/corert/issues/2570
                 *
                 *              else if (context.IsHandleRef(type))
                 *              {
                 *                  if (nativeType == NativeType.Invalid)
                 *                      return MarshallerKind.HandleRef;
                 *                  else
                 *                      return MarshallerKind.Invalid;
                 *              }
                 */

                switch (nativeType)
                {
                case NativeTypeKind.Invalid:
                case NativeTypeKind.Struct:
                    if (InteropTypes.IsSystemDecimal(context, type))
                    {
                        return(MarshallerKind.Decimal);
                    }
                    break;

                case NativeTypeKind.LPStruct:
                    if (InteropTypes.IsSystemGuid(context, type) ||
                        InteropTypes.IsSystemDecimal(context, type))
                    {
                        if (isField || isReturn)
                        {
                            return(MarshallerKind.Invalid);
                        }
                        else
                        {
                            return(MarshallerKind.BlittableStructPtr);
                        }
                    }
                    break;

                default:
                    return(MarshallerKind.Invalid);
                }

                if (type is MetadataType)
                {
                    MetadataType metadataType = (MetadataType)type;
                    // the struct type need to be either sequential or explicit. If it is
                    // auto layout we will throw exception.
                    if (!metadataType.IsSequentialLayout && !metadataType.IsExplicitLayout)
                    {
                        throw new InvalidProgramException("The specified structure " + metadataType.Name + " has invalid StructLayout information. It must be either Sequential or Explicit.");
                    }
                }

                if (MarshalHelpers.IsBlittableType(type))
                {
                    return(MarshallerKind.BlittableStruct);
                }
                else
                {
                    return(MarshallerKind.Struct);
                }
            }
            else                  // !ValueType
            {
                if (type.Category == TypeFlags.Class)
                {
                    if (type.IsString)
                    {
                        switch (nativeType)
                        {
                        case NativeTypeKind.LPWStr:
                            return(MarshallerKind.UnicodeString);

                        case NativeTypeKind.LPStr:
                            return(MarshallerKind.AnsiString);

                        case NativeTypeKind.LPTStr:
                            return(MarshallerKind.UnicodeString);

                        case NativeTypeKind.ByValTStr:
                            if (isAnsi)
                            {
                                elementMarshallerKind = MarshallerKind.AnsiChar;
                                return(MarshallerKind.ByValAnsiString);
                            }
                            else
                            {
                                elementMarshallerKind = MarshallerKind.UnicodeChar;
                                return(MarshallerKind.ByValUnicodeString);
                            }

                        case NativeTypeKind.Invalid:
                            if (isAnsi)
                            {
                                return(MarshallerKind.AnsiString);
                            }
                            else
                            {
                                return(MarshallerKind.UnicodeString);
                            }

                        default:
                            return(MarshallerKind.Invalid);
                        }
                    }
                    else if (type.IsDelegate)
                    {
                        if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Func)
                        {
                            return(MarshallerKind.FunctionPointer);
                        }
                        else
                        {
                            return(MarshallerKind.Invalid);
                        }
                    }
                    else if (type.IsObject)
                    {
                        if (nativeType == NativeTypeKind.Invalid)
                        {
                            return(MarshallerKind.Variant);
                        }
                        else
                        {
                            return(MarshallerKind.Invalid);
                        }
                    }
                    else if (InteropTypes.IsStringBuilder(context, type))
                    {
                        switch (nativeType)
                        {
                        case NativeTypeKind.Invalid:
                            if (isAnsi)
                            {
                                return(MarshallerKind.AnsiStringBuilder);
                            }
                            else
                            {
                                return(MarshallerKind.UnicodeStringBuilder);
                            }

                        case NativeTypeKind.LPStr:
                            return(MarshallerKind.AnsiStringBuilder);

                        case NativeTypeKind.LPWStr:
                            return(MarshallerKind.UnicodeStringBuilder);

                        default:
                            return(MarshallerKind.Invalid);
                        }
                    }
                    else if (InteropTypes.IsSafeHandle(context, type))
                    {
                        if (nativeType == NativeTypeKind.Invalid)
                        {
                            return(MarshallerKind.SafeHandle);
                        }
                        else
                        {
                            return(MarshallerKind.Invalid);
                        }
                    }

                    /*
                     *                  TODO: Bring CriticalHandle to CoreLib
                     *                  https://github.com/dotnet/corert/issues/2570
                     *
                     *                  else if (InteropTypes.IsCriticalHandle(context, type))
                     *                  {
                     *                      if (nativeType != NativeType.Invalid || isField)
                     *                      {
                     *                          return MarshallerKind.Invalid;
                     *                      }
                     *                      else
                     *                      {
                     *                          return MarshallerKind.CriticalHandle;
                     *                      }
                     *                  }
                     */
                    return(MarshallerKind.Invalid);
                }
                else if (InteropTypes.IsSystemArray(context, type))
                {
                    return(MarshallerKind.Invalid);
                }
                else if (type.IsSzArray)
                {
                    if (nativeType == NativeTypeKind.Invalid)
                    {
                        nativeType = NativeTypeKind.Array;
                    }

                    switch (nativeType)
                    {
                    case NativeTypeKind.Array:
                    {
                        if (isField || isReturn)
                        {
                            return(MarshallerKind.Invalid);
                        }

                        var arrayType = (ArrayType)type;

                        elementMarshallerKind = GetArrayElementMarshallerKind(
                            arrayType,
                            marshalAs,
                            isAnsi);

                        // If element is invalid type, the array itself is invalid
                        if (elementMarshallerKind == MarshallerKind.Invalid)
                        {
                            return(MarshallerKind.Invalid);
                        }

                        if (elementMarshallerKind == MarshallerKind.AnsiChar)
                        {
                            return(MarshallerKind.AnsiCharArray);
                        }
                        else if (elementMarshallerKind == MarshallerKind.UnicodeChar ||         // Arrays of unicode char should be marshalled as blittable arrays
                                 elementMarshallerKind == MarshallerKind.Enum ||
                                 elementMarshallerKind == MarshallerKind.BlittableValue)
                        {
                            return(MarshallerKind.BlittableArray);
                        }
                        else
                        {
                            return(MarshallerKind.Array);
                        }
                    }

                    case NativeTypeKind.ByValArray:             // fix sized array
                    {
                        var arrayType = (ArrayType)type;
                        elementMarshallerKind = GetArrayElementMarshallerKind(
                            arrayType,
                            marshalAs,
                            isAnsi);

                        // If element is invalid type, the array itself is invalid
                        if (elementMarshallerKind == MarshallerKind.Invalid)
                        {
                            return(MarshallerKind.Invalid);
                        }

                        if (elementMarshallerKind == MarshallerKind.AnsiChar)
                        {
                            return(MarshallerKind.ByValAnsiCharArray);
                        }
                        else
                        {
                            return(MarshallerKind.ByValArray);
                        }
                    }

                    default:
                        return(MarshallerKind.Invalid);
                    }
                }
                else if (type.Category == TypeFlags.Pointer)
                {
                    //
                    // @TODO - add checks for the pointee type in case the pointee type is not blittable
                    // C# already does this and will emit compilation errors (can't declare pointers to
                    // managed type).
                    //
                    if (nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }
                }
            }

            return(MarshallerKind.Invalid);
        }