public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
        {
            if (!type.IsTemplateUniversal() && (layoutKind == InstanceLayoutKind.TypeOnly))
            {
                // Non universal generics can just use the template's layout
                DefType template = (DefType)type.ComputeTemplate();
                return(_noMetadataFieldLayoutAlgorithm.ComputeInstanceLayout(template, InstanceLayoutKind.TypeOnly));
            }

            // Only needed for universal generics, or when looking up an offset for a field for a universal generic
            LowLevelList <LayoutInt> fieldOffsets;

            LayoutInt[] position = ComputeTypeSizeAndAlignment(type, FieldLoadState.Instance, out fieldOffsets);

            int numInstanceFields = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    numInstanceFields++;
                }
            }

            LayoutInt byteCountAlignment = position[InstanceAlignmentEntry];

            byteCountAlignment = type.Context.Target.GetObjectAlignment(byteCountAlignment);

            ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout()
            {
                Offsets            = new FieldAndOffset[numInstanceFields],
                ByteCountAlignment = byteCountAlignment,
                ByteCountUnaligned = position[(int)NativeFormat.FieldStorage.Instance],
                PackValue          = 0 // TODO, as we add more metadata handling logic, find out if its necessary to use a meaningful value here
            };

            if (!type.IsValueType)
            {
                layout.FieldAlignment = type.Context.Target.LayoutPointerSize;
                layout.FieldSize      = type.Context.Target.LayoutPointerSize;
            }
            else
            {
                layout.FieldAlignment = position[InstanceAlignmentEntry];
                layout.FieldSize      = LayoutInt.AlignUp(position[(int)NativeFormat.FieldStorage.Instance], layout.FieldAlignment);
            }

            int curInstanceField = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    layout.Offsets[curInstanceField] = new FieldAndOffset(field, fieldOffsets[curInstanceField]);
                    curInstanceField++;
                }
            }

            return(layout);
        }
        public static LayoutInt FieldBaseOffset(this TypeDesc type)
        {
            LayoutInt baseOffset = type.BaseType.InstanceByteCount;

            if (type.RequiresAlign8())
            {
                baseOffset = LayoutInt.AlignUp(baseOffset, new LayoutInt(8), type.Context.Target);
            }

            return(baseOffset);
        }
Esempio n. 3
0
            protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module)
            {
                int typeCountInModule = module.MetadataReader.GetTableRowCount(TableIndex.TypeDef);
                int pointerSize       = module.Context.Target.PointerSize;

                // 0 corresponds to "normal" statics, 1 to thread-local statics
                LayoutInt[] gcStatics = new LayoutInt[StaticIndex.Count]
                {
                    LayoutInt.Zero,
                    LayoutInt.Zero
                };

                LayoutInt[] nonGcStatics = new LayoutInt[StaticIndex.Count]
                {
                    new LayoutInt(DomainLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
                    new LayoutInt(ThreadLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
                };

                Dictionary <TypeDefinitionHandle, OffsetsForType> typeOffsets = new Dictionary <TypeDefinitionHandle, OffsetsForType>();

                foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions)
                {
                    TypeDefinition typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle);
                    if (typeDef.GetGenericParameters().Count != 0)
                    {
                        // Generic types are exempt from the static field layout algorithm, see
                        // <a href="https://github.com/dotnet/coreclr/blob/659af58047a949ed50d11101708538d2e87f2568/src/vm/ceeload.cpp#L2049">this check</a>.
                        continue;
                    }

                    // 0 corresponds to "normal" statics, 1 to thread-local statics
                    int[] nonGcAlignment = new int[StaticIndex.Count] {
                        1, 1,
                    };
                    int[] nonGcBytes = new int[StaticIndex.Count] {
                        0, 0,
                    };
                    int[] gcBytes = new int[StaticIndex.Count] {
                        0, 0,
                    };

                    foreach (FieldDefinitionHandle fieldDefHandle in typeDef.GetFields())
                    {
                        FieldDefinition fieldDef = module.MetadataReader.GetFieldDefinition(fieldDefHandle);
                        if ((fieldDef.Attributes & (FieldAttributes.Static | FieldAttributes.Literal)) == FieldAttributes.Static)
                        {
                            int  index = (IsFieldThreadStatic(in fieldDef, module.MetadataReader) ? StaticIndex.ThreadLocal : StaticIndex.Regular);
                            int  alignment;
                            int  size;
                            bool isGcPointerField;
                            bool isGcBoxedField;

                            CorElementType corElementType;
                            EntityHandle   valueTypeHandle;

                            GetFieldElementTypeAndValueTypeHandle(in fieldDef, module.MetadataReader, out corElementType, out valueTypeHandle);
                            FieldDesc fieldDesc = module.GetField(fieldDefHandle);

                            GetElementTypeInfo(module, fieldDesc, valueTypeHandle, corElementType, pointerSize, moduleLayout: true,
                                               out alignment, out size, out isGcPointerField, out isGcBoxedField);

                            if (size != 0)
                            {
                                nonGcBytes[index]    += size;
                                nonGcAlignment[index] = Math.Max(nonGcAlignment[index], alignment);
                            }
                            if (isGcPointerField || isGcBoxedField)
                            {
                                gcBytes[index] += pointerSize;
                            }
                        }
                    }

                    if (nonGcBytes[StaticIndex.Regular] != 0 ||
                        nonGcBytes[StaticIndex.ThreadLocal] != 0 ||
                        gcBytes[StaticIndex.Regular] != 0 ||
                        gcBytes[StaticIndex.ThreadLocal] != 0)
                    {
                        OffsetsForType offsetsForType = new OffsetsForType(LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate);
                        for (int staticIndex = 0; staticIndex < StaticIndex.Count; staticIndex++)
                        {
                            if (nonGcBytes[staticIndex] != 0)
                            {
                                offsetsForType.NonGcOffsets[staticIndex] = LayoutInt.AlignUp(nonGcStatics[staticIndex], new LayoutInt(nonGcAlignment[staticIndex]), module.Context.Target);
                                nonGcStatics[staticIndex] = offsetsForType.NonGcOffsets[staticIndex] + new LayoutInt(nonGcBytes[staticIndex]);
                            }
                            if (gcBytes[staticIndex] != 0)
                            {
                                offsetsForType.GcOffsets[staticIndex] = gcStatics[staticIndex];
                                gcStatics[staticIndex] += new LayoutInt(gcBytes[staticIndex]);
                            }
                        }

                        typeOffsets.Add(typeDefHandle, offsetsForType);
                    }
                }

                LayoutInt blockAlignment = new LayoutInt(TargetDetails.MaximumPrimitiveSize);

                return(new ModuleFieldLayout(
                           module,
                           gcStatics: new StaticsBlock()
                {
                    Size = gcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment
                },
                           nonGcStatics: new StaticsBlock()
                {
                    Size = nonGcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment
                },
                           threadGcStatics: new StaticsBlock()
                {
                    Size = gcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment
                },
                           threadNonGcStatics: new StaticsBlock()
                {
                    Size = nonGcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment
                },
                           typeOffsets: typeOffsets));
            }
Esempio n. 4
0
        // The layout algorithm should probably compute results and let the caller set things
        internal unsafe LayoutInt[] ComputeTypeSizeAndAlignment(TypeDesc type, FieldLoadState loadRequested, out LowLevelList <LayoutInt> fieldOffsets)
        {
            fieldOffsets = null;
            TypeLoaderLogger.WriteLine("Laying out type " + type.ToString() + ". IsValueType: " + (type.IsValueType ? "true" : "false") + ". LoadRequested = " + ((int)loadRequested).LowLevelToString());

            Debug.Assert(loadRequested != FieldLoadState.None);
            Debug.Assert(type is ArrayType || (type is DefType && ((DefType)type).HasInstantiation));

            bool isArray = type is ArrayType;

            LayoutInt[] position      = new LayoutInt[5];
            LayoutInt   alignRequired = LayoutInt.One;

            if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.Instance)
            {
                ComputeTypeSizeBeforeFields(type, out position[(int)NativeFormat.FieldStorage.Instance], out alignRequired);
            }

            if (!isArray)
            {
                // Once this is done, the NativeLayoutFields on the type are initialized
                EnsureFieldLayoutLoadedForGenericType((DefType)type);
                Debug.Assert(type.NativeLayoutFields != null);
            }

            int instanceFields = 0;

            if (!isArray && type.NativeLayoutFields.Length > 0)
            {
                fieldOffsets = new LowLevelList <LayoutInt>(type.NativeLayoutFields.Length);
                for (int i = 0; i < type.NativeLayoutFields.Length; i++)
                {
                    TypeDesc fieldType    = type.NativeLayoutFields[i].FieldType;
                    int      fieldStorage = (int)type.NativeLayoutFields[i].FieldStorage;

                    if (!ShouldProcessField((NativeFormat.FieldStorage)fieldStorage, loadRequested))
                    {
                        continue;
                    }

                    // For value types, we will attempt to get the size and alignment from
                    // the runtime if possible, otherwise GetFieldSizeAndAlignment will
                    // recurse to lay out nested struct fields.
                    LayoutInt alignment;
                    LayoutInt size;
                    GetFieldSizeAlignment(fieldType, out size, out alignment);

                    Debug.Assert(alignment.AsInt > 0);

                    if (fieldStorage == (int)NativeFormat.FieldStorage.Instance)
                    {
                        instanceFields++;

                        // Ensure alignment of type is sufficient for this field
                        alignRequired = LayoutInt.Max(alignRequired, alignment);
                    }

                    position[fieldStorage] = LayoutInt.AlignUp(position[fieldStorage], alignment);
                    TypeLoaderLogger.WriteLine(" --> Field type " + fieldType.ToString() +
                                               " storage " + ((uint)(type.NativeLayoutFields[i].FieldStorage)).LowLevelToString() +
                                               " offset " + position[fieldStorage].LowLevelToString() +
                                               " alignment " + alignment.LowLevelToString());

                    fieldOffsets.Add(position[fieldStorage]);
                    position[fieldStorage] += size;
                }
            }

            // Pad the length of structs to be 1 if they are empty so we have no zero-length structures
            if ((position[(int)NativeFormat.FieldStorage.Instance] == LayoutInt.Zero) && type.IsValueType)
            {
                position[(int)NativeFormat.FieldStorage.Instance] = LayoutInt.One;
            }

            Debug.Assert(alignRequired == new LayoutInt(1) ||
                         alignRequired == new LayoutInt(2) ||
                         alignRequired == new LayoutInt(4) ||
                         alignRequired == new LayoutInt(8));

            position[InstanceAlignmentEntry] = alignRequired;

            return(position);
        }
        public void TestLayoutIntAlignUp(TargetDetails target)
        {
            // AlignUp testing
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(8), target));

            Assert.Equal(new LayoutInt(1), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(3), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(5), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(7), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(9), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(11), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(13), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(15), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(1), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(1), target));

            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(2), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(2), target));

            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(4), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(4), target));

            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(8), target));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(8), target));

            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(1), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(2), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(3), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(4), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(5), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(6), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(7), LayoutInt.Indeterminate, target));
            if (target.MaximumAlignment > 8)
            {
                Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(8), LayoutInt.Indeterminate, target));
            }
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(9), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(10), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(11), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(12), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(13), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(14), LayoutInt.Indeterminate, target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(15), LayoutInt.Indeterminate, target));
            if (target.MaximumAlignment > 16)
            {
                Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(16), LayoutInt.Indeterminate, target));
            }

            // If we the value is aligned to the maximum supported alignment, we can consider it aligned no matter
            // the value of the alignment.
            Assert.Equal(new LayoutInt(target.MaximumAlignment), LayoutInt.AlignUp(new LayoutInt(target.MaximumAlignment), LayoutInt.Indeterminate, target));
            Assert.Equal(new LayoutInt(target.MaximumAlignment * 2), LayoutInt.AlignUp(new LayoutInt(target.MaximumAlignment * 2), LayoutInt.Indeterminate, target));

            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(1), target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(2), target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(4), target));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(8), target));
        }
Esempio n. 6
0
            protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module)
            {
                int typeCountInModule = module.MetadataReader.GetTableRowCount(TableIndex.TypeDef);
                int pointerSize       = module.Context.Target.PointerSize;

                // 0 corresponds to "normal" statics, 1 to thread-local statics
                LayoutInt[] gcStatics = new LayoutInt[StaticIndexCount]
                {
                    LayoutInt.Zero,
                    LayoutInt.Zero
                };
                LayoutInt[] nonGcStatics = new LayoutInt[StaticIndexCount]
                {
                    new LayoutInt(DomainLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
                    new LayoutInt(ThreadLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
                };
                Dictionary <TypeDefinitionHandle, FieldAndOffset[]> typeToFieldMap = new Dictionary <TypeDefinitionHandle, FieldAndOffset[]>();

                foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions)
                {
                    TypeDefinition        typeDef       = module.MetadataReader.GetTypeDefinition(typeDefHandle);
                    List <FieldAndOffset> fieldsForType = null;
                    if (typeDef.GetGenericParameters().Count != 0)
                    {
                        // Generic types are exempt from the static field layout algorithm, see
                        // <a href="https://github.com/dotnet/coreclr/blob/659af58047a949ed50d11101708538d2e87f2568/src/vm/ceeload.cpp#L2049">this check</a>.
                        continue;
                    }

                    foreach (FieldDefinitionHandle fieldDefHandle in typeDef.GetFields())
                    {
                        FieldDefinition fieldDef = module.MetadataReader.GetFieldDefinition(fieldDefHandle);
                        if ((fieldDef.Attributes & (FieldAttributes.Static | FieldAttributes.Literal)) == FieldAttributes.Static)
                        {
                            int  index = (IsFieldThreadStatic(in fieldDef, module.MetadataReader) ? StaticIndexThreadLocal : StaticIndexRegular);
                            int  alignment;
                            int  size;
                            bool isGcPointerField;
                            bool isGcBoxedField;

                            CorElementType corElementType;
                            EntityHandle   valueTypeHandle;

                            GetFieldElementTypeAndValueTypeHandle(in fieldDef, module.MetadataReader, out corElementType, out valueTypeHandle);
                            FieldDesc fieldDesc = module.GetField(fieldDefHandle);

                            GetElementTypeInfo(module, fieldDesc, valueTypeHandle, corElementType, pointerSize, out alignment, out size, out isGcPointerField, out isGcBoxedField);

                            LayoutInt offset = LayoutInt.Zero;
                            if (size != 0)
                            {
                                offset = LayoutInt.AlignUp(nonGcStatics[index], new LayoutInt(alignment));
                                nonGcStatics[index] = offset + new LayoutInt(size);
                            }
                            if (isGcPointerField || isGcBoxedField)
                            {
                                offset           = LayoutInt.AlignUp(gcStatics[index], new LayoutInt(pointerSize));
                                gcStatics[index] = offset + new LayoutInt(pointerSize);
                            }
                            if (fieldsForType == null)
                            {
                                fieldsForType = new List <FieldAndOffset>();
                            }
                            fieldsForType.Add(new FieldAndOffset(fieldDesc, offset));
                        }
                    }

                    if (fieldsForType != null)
                    {
                        typeToFieldMap.Add(typeDefHandle, fieldsForType.ToArray());
                    }
                }

                LayoutInt blockAlignment = new LayoutInt(TargetDetails.MaximumPrimitiveSize);

                return(new ModuleFieldLayout(
                           module,
                           gcStatics: new StaticsBlock()
                {
                    Size = gcStatics[StaticIndexRegular], LargestAlignment = blockAlignment
                },
                           nonGcStatics: new StaticsBlock()
                {
                    Size = nonGcStatics[StaticIndexRegular], LargestAlignment = blockAlignment
                },
                           threadGcStatics: new StaticsBlock()
                {
                    Size = gcStatics[StaticIndexThreadLocal], LargestAlignment = blockAlignment
                },
                           threadNonGcStatics: new StaticsBlock()
                {
                    Size = nonGcStatics[StaticIndexThreadLocal], LargestAlignment = blockAlignment
                },
                           typeToFieldMap: typeToFieldMap));
            }
        public void LayoutIntTests()
        {
            Assert.Throws <ArgumentException>(() => { return(new LayoutInt(int.MinValue)); });
            Assert.Throws <ArgumentException>(() => { return(new LayoutInt(-1)); });

            Assert.Equal(LayoutInt.Zero, new LayoutInt(0));
            Assert.Equal(LayoutInt.One, new LayoutInt(1));

            Assert.True(LayoutInt.Zero == new LayoutInt(0));
            Assert.True(LayoutInt.One == new LayoutInt(1));
            Assert.False(LayoutInt.Zero == new LayoutInt(1));
            Assert.False(LayoutInt.One == new LayoutInt(0));
#pragma warning disable 1718 // Allow comparison to same variable
            Assert.True(LayoutInt.Indeterminate == LayoutInt.Indeterminate);
#pragma warning restore 1718

            Assert.False(LayoutInt.Zero != new LayoutInt(0));
            Assert.False(LayoutInt.One != new LayoutInt(1));
            Assert.True(LayoutInt.Zero != new LayoutInt(1));
            Assert.True(LayoutInt.One != new LayoutInt(0));
#pragma warning disable 1718 // Allow comparison to same variable
            Assert.False(LayoutInt.Indeterminate != LayoutInt.Indeterminate);
#pragma warning restore 1718

            Assert.Equal(0, new LayoutInt(0).AsInt);
            Assert.Equal(1, new LayoutInt(1).AsInt);
            Assert.Equal(Int32.MaxValue, new LayoutInt(Int32.MaxValue).AsInt);
            Assert.Throws <InvalidOperationException>(() => { return(LayoutInt.Indeterminate.AsInt); });

            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Indeterminate + LayoutInt.Indeterminate);
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.One + LayoutInt.Indeterminate);
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Indeterminate + LayoutInt.One);
            Assert.Equal(new LayoutInt(2), LayoutInt.One + LayoutInt.One);
            Assert.Throws <OverflowException>(() => { return(new LayoutInt(int.MaxValue) + LayoutInt.One); });
            Assert.Throws <OverflowException>(() => { return(new LayoutInt(int.MaxValue) + LayoutInt.One); });

            Assert.Equal(LayoutInt.One, LayoutInt.Max(LayoutInt.One, LayoutInt.Zero));
            Assert.Equal(LayoutInt.One, LayoutInt.Max(LayoutInt.Zero, LayoutInt.One));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Indeterminate, LayoutInt.Zero));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Zero, LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Indeterminate, LayoutInt.Indeterminate));

            Assert.Equal(LayoutInt.Zero, LayoutInt.Min(LayoutInt.One, LayoutInt.Zero));
            Assert.Equal(LayoutInt.Zero, LayoutInt.Min(LayoutInt.Zero, LayoutInt.One));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Indeterminate, LayoutInt.Zero));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Zero, LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Indeterminate, LayoutInt.Indeterminate));

            // AlignUp testing
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(8)));

            Assert.Equal(new LayoutInt(1), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(3), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(5), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(7), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(9), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(11), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(13), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(15), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(1)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(1)));

            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(2)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(2)));

            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(4)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(4)));

            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(8)));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(8)));

            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(1), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(2), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(3), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(4), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(5), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(6), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(7), LayoutInt.Indeterminate));
            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(9), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(10), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(11), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(12), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(13), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(14), LayoutInt.Indeterminate));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(15), LayoutInt.Indeterminate));
            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), LayoutInt.Indeterminate));

            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(1)));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(2)));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(4)));
            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(8)));
        }