コード例 #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 void PreprocessTypeFields(TypeDefinition valuetype, int bits)
        {
            if (bits == 32)
            {
                bits = 0;
            }
            else if (bits == 64)
            {
                bits = 1;
            }

            int  size = 0;
            int  highestFieldAlignment = 0;
            bool isComplex             = false;

            // have we already preprocessed this?
            if (ValueTypeAlignment[bits].ContainsKey(valuetype) &&
                !ValueTypeAlignment[bits][valuetype].IsSentinel)
            {
                return;
            }

            // For each field, calculate its layout as if it was a C++ struct
            //Console.WriteLine($"Type {valuetype}");
            foreach (var fs in valuetype.Fields)
            {
                if (fs.IsStatic)
                {
                    continue;
                }

                var sz = AlignAndSizeOfType(fs.FieldType, bits);
                isComplex = isComplex || fs.FieldType.IsComplex();

                // In C++, all members of a struct must have their own address.
                // If we have a "struct {}" as a member, treat its size as at least one byte.
                sz = new AlignAndSize(sz.align, Math.Max(sz.size, 1));
                highestFieldAlignment = Math.Max(highestFieldAlignment, sz.align);
                size = AlignUp(size, sz.align);
                //Console.WriteLine($"  Field: {fs.Name} ({fs.GetType()}) - offset: {size} alignment {sz.align} sz {sz.size}");
                StructFieldAlignment[bits].Add(fs /*VERIFY*/, new AlignAndSize(sz.align, sz.size, size));
                size += sz.size;
            }
            // same min size for outer struct
            size = Math.Max(size, 1);

            // C++ aligns struct sizes up to the highest alignment required
            size = AlignUp(size, highestFieldAlignment);

            // Alignment requirements are > 0
            highestFieldAlignment = Math.Max(highestFieldAlignment, 1);

            ValueTypeAlignment[bits].Remove(valuetype);
            ValueTypeAlignment[bits].Add(valuetype, new AlignAndSize(highestFieldAlignment, size, 0, valuetype.Fields.Count == 0));
            //Console.WriteLine($"ValueType: {valuetype.Name} ({valuetype.GetType()}) - alignment {highestFieldAlignment} sz {size}");
            ValueTypeIsComplex[bits].Add(valuetype, isComplex);
        }
コード例 #3
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]);
        }