예제 #1
0
        public static AlignAndSize AlignAndSizeOfType(MetadataType mtype, int bits)
        {
            if (mtype == MetadataType.Boolean || mtype == MetadataType.Byte || mtype == MetadataType.SByte)
            {
                return(AlignAndSize.One);
            }
            if (mtype == MetadataType.Int16 || mtype == MetadataType.UInt16 || mtype == MetadataType.Char)
            {
                return(AlignAndSize.Two);
            }
            if (mtype == MetadataType.Int32 || mtype == MetadataType.UInt32 || mtype == MetadataType.Single)
            {
                return(AlignAndSize.Four);
            }
            if (mtype == MetadataType.Int64 || mtype == MetadataType.UInt64 || mtype == MetadataType.Double)
            {
                return(AlignAndSize.Eight);
            }
            if (mtype == MetadataType.IntPtr || mtype == MetadataType.UIntPtr)
            {
                return(AlignAndSize.Pointer(bits));
            }
            if (mtype == MetadataType.String)
            {
                return(AlignAndSize.NativeString(bits));
            }

            throw new ArgumentException($"Metadata type {mtype} is a special type which is not supported");
        }
예제 #2
0
        public static AlignAndSize AlignAndSizeOfType(TypeReference typeRef, int bits)
        {
            // This is a gross hack and i'm not proud of it; we use bits as an array index,
            // and we call this method recursively.
            if (bits == 32)
            {
                bits = 0;
            }
            else if (bits == 64)
            {
                bits = 1;
            }

            if (typeRef.IsPointer)
            {
                return(AlignAndSize.Pointer(bits));
            }

            TypeDefinition fixedSpecialType = typeRef.FixedSpecialType();

            if (fixedSpecialType != null)
            {
                return(AlignAndSizeOfType(fixedSpecialType.MetadataType, bits));
            }

            var type = typeRef.Resolve();

            // Handle the case where we have a fixed buffer. Cecil will name it: "<MyMemberName>e_FixedBuffer"
            if (type.ClassSize != -1 && typeRef.Name.Contains(">e__FixedBuffer"))
            {
                // Fixed buffers can only be of primitive types so inspect the fields of the buffer (there should only be one)
                // and determine the packing requirement for the type
                if (type.Fields.Count() != 1)
                {
                    throw new ArgumentException("A FixedBuffer type contains more than one field, this should not happen");
                }

                var fieldAlignAndSize = AlignAndSizeOfType(type.Fields[0].FieldType.MetadataType, bits);
                return(new AlignAndSize(fieldAlignAndSize.align, type.ClassSize));
            }
            else if (type.IsExplicitLayout && type.ClassSize > 0 && type.PackingSize > 0)
            {
                return(new AlignAndSize(type.PackingSize, type.ClassSize));
            }

            if (ValueTypeAlignment[bits].ContainsKey(typeRef))
            {
                var sz = ValueTypeAlignment[bits][typeRef];

                if (sz.IsSentinel)
                {
                    throw new ArgumentException($"Type {typeRef} triggered sentinel; recursive value type definition");
                }

                return(sz);
            }

            if (typeRef.IsArray)
            {
                throw new ArgumentException($"Can't represent {typeRef}: C# array types cannot be represented directly, use DynamicArray<T>");
            }

            if (typeRef.IsDynamicArray())
            {
                var elementType = typeRef.DynamicArrayElementType();
                //Console.WriteLine($"{nts.TypeArguments[0]}");
                // call this just for the side effect checks
                if (AlignAndSizeOfType(elementType, bits).size == 0)
                {
                    throw new Exception("Unexpected type with size 0: " + elementType);
                }

                // arrays match std::array, for emscripten at least
                return(AlignAndSize.DynamicArray(bits));
            }

            if (type.IsEnum)
            {
                // Inspect the __value member to determine the underlying type size
                var enumBaseType = type.Fields.First(f => f.Name == "value__").FieldType;
                return(AlignAndSizeOfType(enumBaseType, bits));
            }

            if (!type.IsValueType)
            {
                // Why not throw? Really should expect this:
                //throw new ArgumentException($"Type {type} ({type.Name}) was expected to be a value type");
                // However, the DisposeSentinel is a ManagedType that sits in the NativeContainers.
                // Treat it as an opaque pointer and skip over it.
                return(AlignAndSizeOfType(MetadataType.IntPtr, bits));
            }

            ValueTypeAlignment[bits].Add(typeRef, AlignAndSize.Sentinel);
            PreprocessTypeFields(typeRef, bits);
            return(ValueTypeAlignment[bits][typeRef]);
        }