Exemple #1
0
        internal void GetFieldSizeAlignment(TypeDesc fieldType, out LayoutInt size, out LayoutInt alignment)
        {
            Debug.Assert(!fieldType.IsCanonicalSubtype(CanonicalFormKind.Any));

            // All reference and array types are pointer-sized
            if (!fieldType.IsValueType)
            {
                size      = new LayoutInt(IntPtr.Size);
                alignment = new LayoutInt(IntPtr.Size);
                return;
            }

            // Is this a type that already exists? If so, get its size from the EEType directly
            if (fieldType.RetrieveRuntimeTypeHandleIfPossible())
            {
                unsafe
                {
                    EEType *eeType = fieldType.RuntimeTypeHandle.ToEETypePtr();
                    size      = new LayoutInt((int)eeType->ValueTypeSize);
                    alignment = new LayoutInt(eeType->FieldAlignmentRequirement);
                    return;
                }
            }

            // The type of the field must be a generic valuetype that is dynamically being constructed
            Debug.Assert(fieldType.IsValueType);
            DefType fieldDefType = (DefType)fieldType;

            TypeBuilderState state = fieldType.GetOrCreateTypeBuilderState();

            size      = fieldDefType.InstanceFieldSize;
            alignment = fieldDefType.InstanceFieldAlignment;
        }
        public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind)
        {
            TargetDetails targetDetails = defType.Context.Target;

            ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind);

            LayoutInt instanceFieldSize;

            if (targetDetails.MaximumSimdVectorLength == SimdVectorLength.Vector128Bit)
            {
                instanceFieldSize = new LayoutInt(16);
            }
            else if (targetDetails.MaximumSimdVectorLength == SimdVectorLength.Vector256Bit)
            {
                instanceFieldSize = new LayoutInt(32);
            }
            else
            {
                Debug.Assert(targetDetails.MaximumSimdVectorLength == SimdVectorLength.None);
                return(layoutFromMetadata);
            }

            return(new ComputedInstanceFieldLayout
            {
                ByteCountUnaligned = instanceFieldSize,
                ByteCountAlignment = layoutFromMetadata.ByteCountAlignment,
                FieldAlignment = layoutFromMetadata.FieldAlignment,
                FieldSize = instanceFieldSize,
                Offsets = layoutFromMetadata.Offsets,
            });
        }
        private void CommonClassLayoutTestBits(ModuleDesc testModule,
                                               TypeSystemContext context,
                                               LayoutInt expectedIndeterminateByteAlignment,
                                               out InstantiatedType genOfIU,
                                               out InstantiatedType genOfLU,
                                               out InstantiatedType genOfUU,
                                               out InstantiatedType genOfUI,
                                               out InstantiatedType genOfUL)
        {
            MetadataType tDerivedGen = testModule.GetType("GenericTypes", "GenDerivedClass`2");

            genOfIU = tDerivedGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int32), context.UniversalCanonType);
            genOfLU = tDerivedGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int64), context.UniversalCanonType);
            genOfUU = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType);

            genOfUI = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.GetWellKnownType(WellKnownType.Int32));
            genOfUL = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.GetWellKnownType(WellKnownType.Int64));

            // Assert that the class as a whole is known to be of undefined size
            AssertClassIndeterminateSize(context, genOfIU, expectedIndeterminateByteAlignment);
            AssertClassIndeterminateSize(context, genOfLU, expectedIndeterminateByteAlignment);
            AssertClassIndeterminateSize(context, genOfUU, expectedIndeterminateByteAlignment);
            AssertClassIndeterminateSize(context, genOfUI, expectedIndeterminateByteAlignment);
            AssertClassIndeterminateSize(context, genOfUL, expectedIndeterminateByteAlignment);
        }
        protected override void OutputBaseSize(ref ObjectDataBuilder objData)
        {
            bool emitMinimumObjectSize = false;

            if (_type.IsCanonicalSubtype(CanonicalFormKind.Universal) && _type.IsDefType)
            {
                LayoutInt instanceByteCount = ((DefType)_type).InstanceByteCount;

                if (instanceByteCount.IsIndeterminate)
                {
                    // For USG types, they may be of indeterminate size, and the size of the type may be meaningless.
                    // In that case emit a fixed constant.
                    emitMinimumObjectSize = true;
                }
            }

            if (emitMinimumObjectSize)
            {
                objData.EmitInt(MinimumObjectSize);
            }
            else
            {
                base.OutputBaseSize(ref objData);
            }
        }
Exemple #5
0
        protected override void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
        {
            LayoutInt offset = GetGCStaticFieldOffset(context);

            layout.GcStatics.Size       = offset;
            layout.ThreadGcStatics.Size = offset;
        }
        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);
        }
Exemple #7
0
        private uint GetArrayTypeIndex(TypeDesc type)
        {
            System.Diagnostics.Debug.Assert(type.IsArray, "GetArrayTypeIndex was called with wrong type");
            ArrayType arrayType = (ArrayType)type;

            uint      elementSize       = (uint)type.Context.Target.PointerSize;
            LayoutInt layoutElementSize = arrayType.GetElementSize();

            if (!layoutElementSize.IsIndeterminate)
            {
                elementSize = (uint)layoutElementSize.AsInt;
            }

            ArrayTypeDescriptor arrayTypeDescriptor = new ArrayTypeDescriptor
            {
                Rank               = (uint)arrayType.Rank,
                ElementType        = GetVariableTypeIndex(arrayType.ElementType, false),
                Size               = elementSize,
                IsMultiDimensional = arrayType.IsMdArray ? 1 : 0
            };

            ClassTypeDescriptor classDescriptor = new ClassTypeDescriptor
            {
                IsStruct    = 0,
                Name        = _objectWriter.GetMangledName(type),
                BaseClassId = GetTypeIndex(arrayType.BaseType, false)
            };

            uint typeIndex = _objectWriter.GetArrayTypeIndex(classDescriptor, arrayTypeDescriptor);

            _knownTypes[type]         = typeIndex;
            _completeKnownTypes[type] = typeIndex;
            return(typeIndex);
        }
        public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind)
        {
            Debug.Assert(IsVectorType(defType));

            LayoutInt alignment;

            string name = defType.Name;

            if (name == "Vector64`1")
            {
                alignment = new LayoutInt(8);
            }
            else if (name == "Vector128`1")
            {
                if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
                {
                    // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128
                    alignment = new LayoutInt(8);
                }
                else
                {
                    alignment = new LayoutInt(16);
                }
            }
            else
            {
                Debug.Assert(name == "Vector256`1");

                if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
                {
                    // No such type exists for the Procedure Call Standard for ARM. We will default
                    // to the same alignment as __m128, which is supported by the ABI.
                    alignment = new LayoutInt(8);
                }
                else if (defType.Context.Target.Architecture == TargetArchitecture.ARM64)
                {
                    // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
                    // 16-byte alignment for __m256.
                    alignment = new LayoutInt(16);
                }
                else
                {
                    alignment = new LayoutInt(32);
                }
            }

            ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind);

            return(new ComputedInstanceFieldLayout
            {
                ByteCountUnaligned = layoutFromMetadata.ByteCountUnaligned,
                ByteCountAlignment = layoutFromMetadata.ByteCountAlignment,
                FieldAlignment = alignment,
                FieldSize = layoutFromMetadata.FieldSize,
                Offsets = layoutFromMetadata.Offsets,
                LayoutAbiStable = _vectorAbiIsStable
            });
        }
Exemple #9
0
        private ComputedStaticFieldLayout ParseStaticRegionSizesFromNativeLayout(TypeDesc type)
        {
            LayoutInt nonGcDataSize  = LayoutInt.Zero;
            LayoutInt gcDataSize     = LayoutInt.Zero;
            LayoutInt threadDataSize = LayoutInt.Zero;

            TypeBuilderState state          = type.GetOrCreateTypeBuilderState();
            NativeParser     typeInfoParser = state.GetParserForNativeLayoutInfo();

            BagElementKind kind;

            while ((kind = typeInfoParser.GetBagElementKind()) != BagElementKind.End)
            {
                switch (kind)
                {
                case BagElementKind.NonGcStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.NonGcStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    nonGcDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                case BagElementKind.GcStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.GcStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    gcDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                case BagElementKind.ThreadStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.ThreadStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    threadDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                default:
                    typeInfoParser.SkipInteger();
                    break;
                }
            }

            ComputedStaticFieldLayout staticLayout = new ComputedStaticFieldLayout()
            {
                GcStatics = new StaticsBlock()
                {
                    Size = gcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
                NonGcStatics = new StaticsBlock()
                {
                    Size = nonGcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
                Offsets       = null, // We're not computing field offsets here, so return null
                ThreadStatics = new StaticsBlock()
                {
                    Size = threadDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
            };

            return(staticLayout);
        }
Exemple #10
0
 public OffsetsForType(LayoutInt nonGcOffset, LayoutInt tlsNonGcOffset, LayoutInt gcOffset, LayoutInt tlsGcOffset)
 {
     NonGcOffsets = new LayoutInt[StaticIndex.Count] {
         nonGcOffset, tlsNonGcOffset
     };
     GcOffsets = new LayoutInt[StaticIndex.Count] {
         gcOffset, tlsGcOffset
     };
 }
 public static string LowLevelToString(this LayoutInt arg)
 {
     if (arg.IsIndeterminate)
     {
         return("Indeterminate");
     }
     else
     {
         return(((uint)arg.AsInt).LowLevelToString());
     }
 }
        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);
        }
        public override ClassLayoutMetadata GetClassLayout()
        {
            ClassLayoutMetadata result;

            result.PackingSize = checked ((int)_typeDefinition.PackingSize);
            result.Size        = checked ((int)_typeDefinition.Size);

            // Skip reading field offsets if this is not explicit layout
            if (IsExplicitLayout)
            {
                var fieldDefinitionHandles = _typeDefinition.Fields;
                var numInstanceFields      = 0;

                foreach (var handle in fieldDefinitionHandles)
                {
                    var fieldDefinition = MetadataReader.GetField(handle);
                    if ((fieldDefinition.Flags & FieldAttributes.Static) != 0)
                    {
                        continue;
                    }

                    numInstanceFields++;
                }

                result.Offsets = new FieldAndOffset[numInstanceFields];

                int index = 0;
                foreach (var handle in fieldDefinitionHandles)
                {
                    var fieldDefinition = MetadataReader.GetField(handle);
                    if ((fieldDefinition.Flags & FieldAttributes.Static) != 0)
                    {
                        continue;
                    }

                    // Note: GetOffset() returns -1 when offset was not set in the metadata
                    int       fieldOffsetInMetadata = (int)fieldDefinition.Offset;
                    LayoutInt fieldOffset           = fieldOffsetInMetadata == -1 ? FieldAndOffset.InvalidOffset : new LayoutInt(fieldOffsetInMetadata);
                    result.Offsets[index] =
                        new FieldAndOffset(_metadataUnit.GetField(handle, this), fieldOffset);

                    index++;
                }
            }
            else
            {
                result.Offsets = null;
            }

            return(result);
        }
        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));
        }
Exemple #15
0
        protected override void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
        {
            LayoutInt offset = GetGCStaticFieldOffset(context);

            // If the size of GCStatics is equal to the size set in PrepareRuntimeSpecificStaticFieldLayout, we
            // don't have any GC statics
            if (layout.GcStatics.Size == offset)
            {
                layout.GcStatics.Size = LayoutInt.Zero;
            }
            if (layout.ThreadGcStatics.Size == offset)
            {
                layout.ThreadGcStatics.Size = LayoutInt.Zero;
            }

            // NativeAOT makes no distinction between Gc / non-Gc thread statics. All are placed into ThreadGcStatics since thread statics
            // are typically rare.
            Debug.Assert(layout.ThreadNonGcStatics.Size == LayoutInt.Zero);
        }
Exemple #16
0
        /// <summary>
        /// Determine the state of things before we start processing the fields of a specific type.
        /// This will initialize the state to be aware of the size/characteristics of base types,
        /// and whether or not this type is a valuetype.
        /// </summary>
        /// <param name="type">Type we are computing layout for</param>
        /// <param name="initialSize">What the initial Instance size should be</param>
        /// <param name="alignRequired">What is the basic alignment requirement of the base type or 1 if there is no base type to consider</param>
        internal void ComputeTypeSizeBeforeFields(TypeDesc type, out LayoutInt initialSize, out LayoutInt alignRequired)
        {
            // Account for the EEType pointer in objects...
            initialSize   = new LayoutInt(IntPtr.Size);
            alignRequired = LayoutInt.One;

            if (type.IsValueType)
            {
                // ...unless the type is a ValueType which doesn't have the EEType pointer.
                initialSize = LayoutInt.Zero;
            }
            else if (type.BaseType != null)
            {
                // If there is a base type, use the initialSize and alignRequired from that
                DefType baseType = type.BaseType;
                initialSize   = baseType.InstanceByteCountUnaligned;
                alignRequired = baseType.InstanceByteAlignment;
            }
        }
Exemple #17
0
        /// <summary>
        /// Validates that it will be possible to create an EEType for '<paramref name="type"/>'.
        /// </summary>
        public static void CheckCanGenerateEEType(NodeFactory factory, TypeDesc type)
        {
            // Don't validate generic definitons
            if (type.IsGenericDefinition)
            {
                return;
            }

            // System.__Canon or System.__UniversalCanon
            if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
            {
                return;
            }

            // It must be possible to create an EEType for the base type of this type
            TypeDesc baseType = type.BaseType;

            if (baseType != null)
            {
                // Make sure EEType can be created for this.
                factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(baseType));
            }

            // We need EETypes for interfaces
            foreach (var intf in type.RuntimeInterfaces)
            {
                // Make sure EEType can be created for this.
                factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(intf));
            }

            // Validate classes, structs, enums, interfaces, and delegates
            DefType defType = type as DefType;

            if (defType != null)
            {
                // Ensure we can compute the type layout
                defType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields);

                //
                // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor.
                // We need to make sure this is possible.
                //
                if (factory.TypeSystemContext.HasLazyStaticConstructor(defType))
                {
                    defType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields);
                }

                // Make sure instantiation length matches the expectation
                // TODO: it might be more resonable for the type system to enforce this (also for methods)
                if (defType.Instantiation.Length != defType.GetTypeDefinition().Instantiation.Length)
                {
                    throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                foreach (TypeDesc typeArg in defType.Instantiation)
                {
                    // ByRefs, pointers, function pointers, and System.Void are never valid instantiation arguments
                    if (typeArg.IsByRef ||
                        typeArg.IsPointer ||
                        typeArg.IsFunctionPointer ||
                        typeArg.IsVoid ||
                        (typeArg.IsValueType && ((DefType)typeArg).IsByRefLike))
                    {
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }

                    // TODO: validate constraints
                }

                // Check the type doesn't have bogus MethodImpls or overrides and we can get the finalizer.
                defType.GetFinalizer();
            }

            // Validate parameterized types
            ParameterizedType parameterizedType = type as ParameterizedType;

            if (parameterizedType != null)
            {
                TypeDesc parameterType = parameterizedType.ParameterType;

                // Make sure EEType can be created for this.
                factory.NecessaryTypeSymbol(parameterType);

                if (parameterizedType.IsArray)
                {
                    if (parameterType.IsFunctionPointer)
                    {
                        // Arrays of function pointers are not currently supported
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }

                    LayoutInt elementSize = parameterType.GetElementSize();
                    if (!elementSize.IsIndeterminate && elementSize.AsInt >= ushort.MaxValue)
                    {
                        // Element size over 64k can't be encoded in the GCDesc
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, parameterType);
                    }

                    if (((ArrayType)parameterizedType).Rank > 32)
                    {
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadRankTooLarge, type);
                    }

                    if ((parameterType.IsDefType) && ((DefType)parameterType).IsByRefLike)
                    {
                        // Arrays of byref-like types are not allowed
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }
                }

                // Validate we're not constructing a type over a ByRef
                if (parameterType.IsByRef)
                {
                    // CLR compat note: "ldtoken int32&&" will actually fail with a message about int32&; "ldtoken int32&[]"
                    // will fail with a message about being unable to create an array of int32&. This is a middle ground.
                    throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                // It might seem reasonable to disallow array of void, but the CLR doesn't prevent that too hard.
                // E.g. "newarr void" will fail, but "newarr void[]" or "ldtoken void[]" will succeed.
            }

            // Function pointer EETypes are not currently supported
            if (type.IsFunctionPointer)
            {
                throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
            }
        }
Exemple #18
0
        protected virtual void OutputBaseSize(ref ObjectDataBuilder objData)
        {
            int pointerSize = _type.Context.Target.PointerSize;
            int objectSize;

            if (_type.IsDefType)
            {
                LayoutInt instanceByteCount = ((DefType)_type).InstanceByteCount;

                if (instanceByteCount.IsIndeterminate)
                {
                    // Some value must be put in, but the specific value doesn't matter as it
                    // isn't used for specific instantiations, and the universal canon eetype
                    // is never associated with an allocated object.
                    objectSize = pointerSize;
                }
                else
                {
                    objectSize = pointerSize +
                                 ((DefType)_type).InstanceByteCount.AsInt; // +pointerSize for SyncBlock
                }

                if (_type.IsValueType)
                {
                    objectSize += pointerSize; // + EETypePtr field inherited from System.Object
                }
            }
            else if (_type.IsArray)
            {
                objectSize = 3 * pointerSize; // SyncBlock + EETypePtr + Length
                if (_type.IsMdArray)
                {
                    objectSize +=
                        2 * sizeof(int) * ((ArrayType)_type).Rank;
                }
            }
            else if (_type.IsPointer)
            {
                // These never get boxed and don't have a base size. Use a sentinel value recognized by the runtime.
                objData.EmitInt(ParameterizedTypeShapeConstants.Pointer);
                return;
            }
            else if (_type.IsByRef)
            {
                // These never get boxed and don't have a base size. Use a sentinel value recognized by the runtime.
                objData.EmitInt(ParameterizedTypeShapeConstants.ByRef);
                return;
            }
            else
            {
                throw new NotImplementedException();
            }

            objectSize = AlignmentHelper.AlignUp(objectSize, pointerSize);
            objectSize = Math.Max(MinimumObjectSize, objectSize);

            if (_type.IsString)
            {
                // If this is a string, throw away objectSize we computed so far. Strings are special.
                // SyncBlock + EETypePtr + length + firstChar
                objectSize = 2 * pointerSize +
                             sizeof(int) +
                             sizeof(char);
            }

            objData.EmitInt(objectSize);
        }
        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));
        }
Exemple #20
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));
            }
 private void AssertClassIndeterminateSize(TypeSystemContext context, MetadataType type, LayoutInt expectedIndeterminateByteAlignment)
 {
     Assert.Equal(context.Target.LayoutPointerSize, type.InstanceFieldAlignment);
     Assert.Equal(context.Target.LayoutPointerSize, type.InstanceFieldSize);
     Assert.Equal(expectedIndeterminateByteAlignment, type.InstanceByteAlignment);
     Assert.Equal(LayoutInt.Indeterminate, type.InstanceByteCount);
     Assert.Equal(LayoutInt.Indeterminate, type.InstanceByteCountUnaligned);
 }
        private uint GetClassTypeIndex(TypeDesc type, bool needsCompleteType)
        {
            DefType defType = type as DefType;

            System.Diagnostics.Debug.Assert(defType != null, "GetClassTypeIndex was called with non def type");
            ClassTypeDescriptor classTypeDescriptor = new ClassTypeDescriptor
            {
                IsStruct     = type.IsValueType ? 1 : 0,
                Name         = _objectWriter.GetMangledName(type),
                BaseClassId  = 0,
                InstanceSize = 0
            };

            uint typeIndex = _objectWriter.GetClassTypeIndex(classTypeDescriptor);

            _knownTypes[type] = typeIndex;

            if (!defType.InstanceByteCount.IsIndeterminate)
            {
                classTypeDescriptor.InstanceSize = (ulong)defType.InstanceByteCount.AsInt;
            }

            if (type.HasBaseType && !type.IsValueType)
            {
                classTypeDescriptor.BaseClassId = GetTypeIndex(defType.BaseType, true);
            }

            List <DataFieldDescriptor>       fieldsDescs        = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       nonGcStaticFields  = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       gcStaticFields     = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       threadStaticFields = new List <DataFieldDescriptor>();
            List <StaticDataFieldDescriptor> staticsDescs       = new List <StaticDataFieldDescriptor>();

            string nonGcStaticDataName  = NodeFactory.NameMangler.NodeMangler.NonGCStatics(type);
            string gcStaticDataName     = NodeFactory.NameMangler.NodeMangler.GCStatics(type);
            string threadStaticDataName = NodeFactory.NameMangler.NodeMangler.ThreadStatics(type);
            bool   IsCoreRTAbi          = Abi == TargetAbi.CoreRT;

            bool isCanonical = defType.IsCanonicalSubtype(CanonicalFormKind.Any);

            foreach (var fieldDesc in defType.GetFields())
            {
                if (fieldDesc.HasRva || fieldDesc.IsLiteral)
                {
                    continue;
                }

                if (isCanonical && fieldDesc.IsStatic)
                {
                    continue;
                }

                LayoutInt           fieldOffset     = fieldDesc.Offset;
                int                 fieldOffsetEmit = fieldOffset.IsIndeterminate ? 0xBAAD : fieldOffset.AsInt;
                DataFieldDescriptor field           = new DataFieldDescriptor
                {
                    FieldTypeIndex = GetVariableTypeIndex(GetFieldDebugType(fieldDesc), false),
                    Offset         = (ulong)fieldOffsetEmit,
                    Name           = fieldDesc.Name
                };

                if (fieldDesc.IsStatic)
                {
                    if (NodeFactory.Target.OperatingSystem != TargetOS.Windows)
                    {
                        StaticDataFieldDescriptor staticDesc = new StaticDataFieldDescriptor
                        {
                            StaticOffset = (ulong)fieldOffsetEmit
                        };

                        // Mark field as static
                        field.Offset = 0xFFFFFFFF;

                        if (fieldDesc.IsThreadStatic)
                        {
                            staticDesc.StaticDataName       = threadStaticDataName;
                            staticDesc.IsStaticDataInObject = IsCoreRTAbi ? 1 : 0;
                        }
                        else if (fieldDesc.HasGCStaticBase)
                        {
                            staticDesc.StaticDataName       = gcStaticDataName;
                            staticDesc.IsStaticDataInObject = IsCoreRTAbi ? 1 : 0;
                        }
                        else
                        {
                            staticDesc.StaticDataName       = nonGcStaticDataName;
                            staticDesc.IsStaticDataInObject = 0;
                        }

                        staticsDescs.Add(staticDesc);
                    }

                    if (fieldDesc.IsThreadStatic)
                    {
                        threadStaticFields.Add(field);
                    }
                    else if (fieldDesc.HasGCStaticBase)
                    {
                        gcStaticFields.Add(field);
                    }
                    else
                    {
                        nonGcStaticFields.Add(field);
                    }
                }
                else
                {
                    fieldsDescs.Add(field);
                }
            }

            if (NodeFactory.Target.OperatingSystem == TargetOS.Windows)
            {
                InsertStaticFieldRegionMember(fieldsDescs, defType, nonGcStaticFields, WindowsNodeMangler.NonGCStaticMemberName, "__type_" + WindowsNodeMangler.NonGCStaticMemberName, false);
                InsertStaticFieldRegionMember(fieldsDescs, defType, gcStaticFields, WindowsNodeMangler.GCStaticMemberName, "__type_" + WindowsNodeMangler.GCStaticMemberName, IsCoreRTAbi);
                InsertStaticFieldRegionMember(fieldsDescs, defType, threadStaticFields, WindowsNodeMangler.ThreadStaticMemberName, "__type_" + WindowsNodeMangler.ThreadStaticMemberName, IsCoreRTAbi);
            }
            else
            {
                fieldsDescs.AddRange(nonGcStaticFields);
                fieldsDescs.AddRange(gcStaticFields);
                fieldsDescs.AddRange(threadStaticFields);
            }

            DataFieldDescriptor[] fields = new DataFieldDescriptor[fieldsDescs.Count];
            for (int i = 0; i < fieldsDescs.Count; ++i)
            {
                fields[i] = fieldsDescs[i];
            }

            StaticDataFieldDescriptor[] statics = new StaticDataFieldDescriptor[staticsDescs.Count];
            for (int i = 0; i < staticsDescs.Count; ++i)
            {
                statics[i] = staticsDescs[i];
            }

            LayoutInt elementSize     = defType.GetElementSize();
            int       elementSizeEmit = elementSize.IsIndeterminate ? 0xBAAD : elementSize.AsInt;
            ClassFieldsTypeDescriptor fieldsDescriptor = new ClassFieldsTypeDescriptor
            {
                Size        = (ulong)elementSizeEmit,
                FieldsCount = fieldsDescs.Count,
            };

            uint completeTypeIndex = _objectWriter.GetCompleteClassTypeIndex(classTypeDescriptor, fieldsDescriptor, fields, statics);

            _completeKnownTypes[type] = completeTypeIndex;

            if (needsCompleteType)
            {
                return(completeTypeIndex);
            }
            else
            {
                return(typeIndex);
            }
        }
Exemple #23
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);
        }
        private static TypeDesc EnsureLoadableTypeUncached(TypeDesc type)
        {
            if (type.IsParameterizedType)
            {
                // Validate parameterized types
                var parameterizedType = (ParameterizedType)type;

                TypeDesc parameterType = parameterizedType.ParameterType;

                // Make sure type of the parameter is loadable.
                ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(parameterType);

                // Validate we're not constructing a type over a ByRef
                if (parameterType.IsByRef)
                {
                    // CLR compat note: "ldtoken int32&&" will actually fail with a message about int32&; "ldtoken int32&[]"
                    // will fail with a message about being unable to create an array of int32&. This is a middle ground.
                    ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                // Validate the parameter is not an uninstantiated generic.
                if (parameterType.IsGenericDefinition)
                {
                    ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                if (parameterizedType.IsArray)
                {
                    if (parameterType.IsFunctionPointer)
                    {
                        // Arrays of function pointers are not currently supported
                        ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }

                    if (!parameterType.IsRuntimeDeterminedSubtype)
                    {
                        LayoutInt elementSize = parameterType.GetElementSize();
                        if (!elementSize.IsIndeterminate && elementSize.AsInt >= ushort.MaxValue)
                        {
                            // Element size over 64k can't be encoded in the GCDesc
                            ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, parameterType);
                        }
                    }

                    if (((ArrayType)parameterizedType).Rank > 32)
                    {
                        ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadRankTooLarge, type);
                    }

                    if (parameterType.IsByRefLike)
                    {
                        // Arrays of byref-like types are not allowed
                        ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }

                    // It might seem reasonable to disallow array of void, but the CLR doesn't prevent that too hard.
                    // E.g. "newarr void" will fail, but "newarr void[]" or "ldtoken void[]" will succeed.
                }
            }
            else if (type.IsFunctionPointer)
            {
                ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
            }
            else
            {
                // Validate classes, structs, enums, interfaces, and delegates
                Debug.Assert(type.IsDefType);

                // Don't validate generic definitons or runtime determined subtypes
                if (type.IsGenericDefinition || type.IsRuntimeDeterminedSubtype)
                {
                    return(type);
                }

                // System.__Canon or System.__UniversalCanon
                if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
                {
                    return(type);
                }

                // We need to be able to load interfaces
                foreach (var intf in type.RuntimeInterfaces)
                {
                    ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(intf.NormalizeInstantiation());
                }

                if (type.BaseType != null)
                {
                    ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(type.BaseType);
                }

                var defType = (DefType)type;

                // Ensure we can compute the type layout
                defType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields);
                defType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields);

                // Make sure instantiation length matches the expectation
                if (defType.Instantiation.Length != defType.GetTypeDefinition().Instantiation.Length)
                {
                    ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                foreach (TypeDesc typeArg in defType.Instantiation)
                {
                    // ByRefs, pointers, function pointers, and System.Void are never valid instantiation arguments
                    if (typeArg.IsByRef ||
                        typeArg.IsPointer ||
                        typeArg.IsFunctionPointer ||
                        typeArg.IsVoid ||
                        typeArg.IsByRefLike)
                    {
                        ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                    }

                    // TODO: validate constraints
                }

                // Check the type doesn't have bogus MethodImpls or overrides and we can get the finalizer.
                defType.GetFinalizer();
            }

            return(type);
        }
Exemple #25
0
            private FieldAndOffset[] CreateDynamicLayout(DefType defType, EcmaModule module)
            {
                List <FieldAndOffset> fieldsForType = null;
                int pointerSize = module.Context.Target.PointerSize;

                // In accordance with CoreCLR runtime conventions,
                // index 0 corresponds to regular statics, index 1 to thread-local statics.
                int[][] nonGcStaticsCount = new int[StaticIndexCount][]
                {
                    new int[TargetDetails.MaximumLog2PrimitiveSize + 1],
                    new int[TargetDetails.MaximumLog2PrimitiveSize + 1],
                };

                int[] gcPointerCount = new int[StaticIndexCount];
                int[] gcBoxedCount   = new int[StaticIndexCount];

                foreach (FieldDesc field in defType.GetFields())
                {
                    FieldDefinition fieldDef = module.MetadataReader.GetFieldDefinition(((EcmaField)field.GetTypicalFieldDefinition()).Handle);
                    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);

                        GetElementTypeInfo(module, field, valueTypeHandle, corElementType, pointerSize, out alignment, out size, out isGcPointerField, out isGcBoxedField);
                        if (isGcPointerField)
                        {
                            gcPointerCount[index]++;
                        }
                        else if (isGcBoxedField)
                        {
                            gcBoxedCount[index]++;
                        }
                        if (size != 0)
                        {
                            int log2Size = GetLog2Size(size);
                            nonGcStaticsCount[index][log2Size]++;
                        }
                    }
                }

                int nonGcInitialOffset;

                switch (pointerSize)
                {
                case 4:
                    nonGcInitialOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlob32Bit;
                    break;

                case 8:
                    nonGcInitialOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlob64Bit;
                    break;

                default:
                    throw new NotImplementedException();
                }

                LayoutInt[] nonGcStaticFieldOffsets = new LayoutInt[StaticIndexCount]
                {
                    new LayoutInt(nonGcInitialOffset),
                    new LayoutInt(nonGcInitialOffset),
                };

                LayoutInt[][] nonGcStatics = new LayoutInt[StaticIndexCount][]
                {
                    new LayoutInt[TargetDetails.MaximumLog2PrimitiveSize + 1],
                    new LayoutInt[TargetDetails.MaximumLog2PrimitiveSize + 1],
                };

                for (int log2Size = TargetDetails.MaximumLog2PrimitiveSize; log2Size >= 0; log2Size--)
                {
                    for (int index = 0; index < StaticIndexCount; index++)
                    {
                        LayoutInt offset = nonGcStaticFieldOffsets[index];
                        nonGcStatics[index][log2Size] = offset;
                        offset += new LayoutInt(nonGcStaticsCount[index][log2Size] << log2Size);
                        nonGcStaticFieldOffsets[index] = offset;
                    }
                }

                LayoutInt[] gcBoxedFieldOffsets   = new LayoutInt[StaticIndexCount];
                LayoutInt[] gcPointerFieldOffsets = new LayoutInt[StaticIndexCount]
                {
                    new LayoutInt(gcBoxedCount[StaticIndexRegular] * pointerSize),
                    new LayoutInt(gcBoxedCount[StaticIndexThreadLocal] * pointerSize)
                };

                foreach (FieldDesc field in defType.GetFields())
                {
                    FieldDefinitionHandle fieldDefHandle = ((EcmaField)field.GetTypicalFieldDefinition()).Handle;
                    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);

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

                        LayoutInt offset = LayoutInt.Zero;

                        if (size != 0)
                        {
                            int log2Size = GetLog2Size(size);
                            offset = nonGcStatics[index][log2Size];
                            nonGcStatics[index][log2Size] += new LayoutInt(1 << log2Size);
                        }
                        if (isGcPointerField)
                        {
                            offset = gcPointerFieldOffsets[index];
                            gcPointerFieldOffsets[index] += new LayoutInt(pointerSize);
                        }
                        else if (isGcBoxedField)
                        {
                            offset = gcBoxedFieldOffsets[index];
                            gcBoxedFieldOffsets[index] += new LayoutInt(pointerSize);
                        }

                        if (fieldsForType == null)
                        {
                            fieldsForType = new List <FieldAndOffset>();
                        }
                        fieldsForType.Add(new FieldAndOffset(field, offset));
                    }
                }

                return(fieldsForType == null ? null : fieldsForType.ToArray());
            }
Exemple #26
0
        private uint GetClassTypeIndex(TypeDesc type, bool needsCompleteType)
        {
            DefType defType = type as DefType;

            System.Diagnostics.Debug.Assert(defType != null, "GetClassTypeIndex was called with non def type");
            ClassTypeDescriptor classTypeDescriptor = new ClassTypeDescriptor
            {
                IsStruct    = type.IsValueType ? 1 : 0,
                Name        = _objectWriter.GetMangledName(type),
                BaseClassId = 0
            };

            uint typeIndex = _objectWriter.GetClassTypeIndex(classTypeDescriptor);

            _knownTypes[type] = typeIndex;

            if (type.HasBaseType && !type.IsValueType)
            {
                classTypeDescriptor.BaseClassId = GetTypeIndex(defType.BaseType, true);
            }

            List <DataFieldDescriptor> fieldsDescs        = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> nonGcStaticFields  = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> gcStaticFields     = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> threadStaticFields = new List <DataFieldDescriptor>();

            bool isCanonical = defType.IsCanonicalSubtype(CanonicalFormKind.Any);

            foreach (var fieldDesc in defType.GetFields())
            {
                if (fieldDesc.HasRva || fieldDesc.IsLiteral)
                {
                    continue;
                }

                if (isCanonical && fieldDesc.IsStatic)
                {
                    continue;
                }

                LayoutInt           fieldOffset     = fieldDesc.Offset;
                int                 fieldOffsetEmit = fieldOffset.IsIndeterminate ? 0xBAAD : fieldOffset.AsInt;
                DataFieldDescriptor field           = new DataFieldDescriptor
                {
                    FieldTypeIndex = GetVariableTypeIndex(GetFieldDebugType(fieldDesc), false),
                    Offset         = (ulong)fieldOffsetEmit,
                    Name           = fieldDesc.Name
                };

                if (fieldDesc.IsStatic)
                {
                    if (fieldDesc.IsThreadStatic)
                    {
                        threadStaticFields.Add(field);
                    }
                    else if (fieldDesc.HasGCStaticBase)
                    {
                        gcStaticFields.Add(field);
                    }
                    else
                    {
                        nonGcStaticFields.Add(field);
                    }
                }
                else
                {
                    fieldsDescs.Add(field);
                }
            }

            InsertStaticFieldRegionMember(fieldsDescs, defType, nonGcStaticFields, WindowsNodeMangler.NonGCStaticMemberName, "__type_" + WindowsNodeMangler.NonGCStaticMemberName, false);
            InsertStaticFieldRegionMember(fieldsDescs, defType, gcStaticFields, WindowsNodeMangler.GCStaticMemberName, "__type_" + WindowsNodeMangler.GCStaticMemberName, Abi == TargetAbi.CoreRT);
            InsertStaticFieldRegionMember(fieldsDescs, defType, threadStaticFields, WindowsNodeMangler.ThreadStaticMemberName, "__type_" + WindowsNodeMangler.ThreadStaticMemberName, Abi == TargetAbi.CoreRT);

            DataFieldDescriptor[] fields = new DataFieldDescriptor[fieldsDescs.Count];
            for (int i = 0; i < fieldsDescs.Count; ++i)
            {
                fields[i] = fieldsDescs[i];
            }

            LayoutInt elementSize     = defType.GetElementSize();
            int       elementSizeEmit = elementSize.IsIndeterminate ? 0xBAAD : elementSize.AsInt;
            ClassFieldsTypeDescriptor fieldsDescriptor = new ClassFieldsTypeDescriptor
            {
                Size        = (ulong)elementSizeEmit,
                FieldsCount = fieldsDescs.Count
            };

            uint completeTypeIndex = _objectWriter.GetCompleteClassTypeIndex(classTypeDescriptor, fieldsDescriptor, fields);

            _completeKnownTypes[type] = completeTypeIndex;

            if (needsCompleteType)
            {
                return(completeTypeIndex);
            }
            else
            {
                return(typeIndex);
            }
        }
Exemple #27
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));
            }