public static void EncodeGCDesc <T>(ref T builder, TypeDesc type) where T : struct, ITargetBinaryWriter { int initialBuilderPosition = builder.CountBytes; if (type.IsArray) { TypeDesc elementType = ((ArrayType)type).ElementType; // 2 means m_pEEType and _numComponents. Syncblock is sort of appended at the end of the object layout in this case. int baseSize = 2 * builder.TargetPointerSize; if (type.IsMdArray) { // Multi-dim arrays include upper and lower bounds for each rank baseSize += 2 * sizeof(int) * ((ArrayType)type).Rank; } if (elementType.IsGCPointer) { EncodeAllGCPointersArrayGCDesc(ref builder, baseSize); } else if (elementType.IsDefType) { var elementDefType = (DefType)elementType; if (elementDefType.ContainsGCPointers) { GCPointerMap pointerMap = GCPointerMap.FromInstanceLayout(elementDefType); if (pointerMap.IsAllGCPointers) { EncodeAllGCPointersArrayGCDesc(ref builder, baseSize); } else { EncodeArrayGCDesc(ref builder, pointerMap, baseSize); } } } } else { var defType = (DefType)type; if (defType.ContainsGCPointers) { // Computing the layout for the boxed version if this is a value type. int offs = defType.IsValueType ? builder.TargetPointerSize : 0; // Include syncblock int objectSize = defType.InstanceByteCount.AsInt + offs + builder.TargetPointerSize; EncodeStandardGCDesc(ref builder, GCPointerMap.FromInstanceLayout(defType), objectSize, offs); } } Debug.Assert(initialBuilderPosition + GetGCDescSize(type) == builder.CountBytes); }
public void TestInstanceMap() { MetadataType classWithArrayFields = _testModule.GetType("GCPointerMap", "ClassWithArrayFields"); MetadataType classWithStringField = _testModule.GetType("GCPointerMap", "ClassWithStringField"); MetadataType mixedStruct = _testModule.GetType("GCPointerMap", "MixedStruct"); MetadataType structWithSameGCLayoutAsMixedStruct = _testModule.GetType("GCPointerMap", "StructWithSameGCLayoutAsMixedStruct"); MetadataType doubleMixedStructLayout = _testModule.GetType("GCPointerMap", "DoubleMixedStructLayout"); MetadataType explicitlyFarPointer = _testModule.GetType("GCPointerMap", "ExplicitlyFarPointer"); MetadataType struct32GcPointers = _testModule.GetType("GCPointerMap", "Struct32GcPointers"); { var map = GCPointerMap.FromInstanceLayout(classWithArrayFields); Assert.Equal(3, map.Size); Assert.Equal("011", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(classWithStringField); Assert.Equal(4, map.Size); Assert.Equal("0010", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(mixedStruct); Assert.Equal(5, map.Size); Assert.Equal("01001", map.ToString()); } { var map1 = GCPointerMap.FromInstanceLayout(mixedStruct); var map2 = GCPointerMap.FromInstanceLayout(structWithSameGCLayoutAsMixedStruct); Assert.Equal(map1.Size, map2.Size); Assert.Equal(map1.ToString(), map2.ToString()); } { var map = GCPointerMap.FromInstanceLayout(doubleMixedStructLayout); Assert.Equal(10, map.Size); Assert.Equal("0100101001", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(explicitlyFarPointer); Assert.Equal(117, map.Size); Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000001001", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(struct32GcPointers); Assert.Equal(32, map.Size); Assert.Equal("11111111111111111111111111111111", map.ToString()); } }
/// <summary> /// Retrieves size of the GCDesc that describes the instance GC layout for the given type. /// </summary> public static int GetGCDescSize(TypeDesc type) { if (type.IsArray) { TypeDesc elementType = ((ArrayType)type).ElementType; if (elementType.IsGCPointer) { // For efficiency this is special cased and encoded as one serie. return(3 * type.Context.Target.PointerSize); } else if (elementType.IsDefType) { var defType = (DefType)elementType; if (defType.ContainsGCPointers) { GCPointerMap pointerMap = GCPointerMap.FromInstanceLayout(defType); if (pointerMap.IsAllGCPointers) { // For efficiency this is special cased and encoded as one serie. return(3 * type.Context.Target.PointerSize); } else { int numSeries = pointerMap.NumSeries; Debug.Assert(numSeries > 0); return((numSeries + 2) * type.Context.Target.PointerSize); } } } } else { var defType = (DefType)type; if (defType.ContainsGCPointers) { int numSeries = GCPointerMap.FromInstanceLayout(defType).NumSeries; Debug.Assert(numSeries > 0); return((numSeries * 2 + 1) * type.Context.Target.PointerSize); } } return(0); }
private static void EncodeTypeLayout(ObjectDataSignatureBuilder dataBuilder, TypeDesc type) { Debug.Assert(type.IsValueType); MetadataType defType = (MetadataType)type; int pointerSize = type.Context.Target.PointerSize; int size = defType.InstanceFieldSize.AsInt; int alignment = GetClassAlignmentRequirement(defType); ReadyToRunTypeLayoutFlags flags = ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment | ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout; if (alignment == pointerSize) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native; } if (!defType.ContainsGCPointers) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty; } if (defType.IsHomogeneousAggregate) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA; } dataBuilder.EmitUInt((uint)flags); dataBuilder.EmitUInt((uint)size); if (defType.IsHomogeneousAggregate) { CorElementType elementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch { ValueTypeShapeCharacteristics.Float32Aggregate => CorElementType.ELEMENT_TYPE_R4, ValueTypeShapeCharacteristics.Float64Aggregate => CorElementType.ELEMENT_TYPE_R8, ValueTypeShapeCharacteristics.Vector64Aggregate => CorElementType.ELEMENT_TYPE_R8, // See MethodTable::GetHFAType ValueTypeShapeCharacteristics.Vector128Aggregate => CorElementType.ELEMENT_TYPE_VALUETYPE, _ => CorElementType.Invalid }; dataBuilder.EmitUInt((uint)elementType); } if (alignment != pointerSize) { dataBuilder.EmitUInt((uint)alignment); } if (defType.ContainsGCPointers) { // Encode the GC pointer map GCPointerMap gcMap = GCPointerMap.FromInstanceLayout(defType); byte[] encodedGCRefMap = new byte[(size / pointerSize + 7) / 8]; int bitIndex = 0; foreach (bool bit in gcMap) { if (bit) { encodedGCRefMap[bitIndex / 8] |= (byte)(1 << (bitIndex & 7)); } ++bitIndex; } dataBuilder.EmitBytes(encodedGCRefMap); } }
private static void EncodeTypeLayout(ObjectDataSignatureBuilder dataBuilder, TypeDesc type) { Debug.Assert(type.IsValueType); MetadataType defType = (MetadataType)type; int pointerSize = type.Context.Target.PointerSize; int size = defType.InstanceFieldSize.AsInt; int alignment = GetClassAlignmentRequirement(defType); ReadyToRunTypeLayoutFlags flags = ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment | ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout; if (alignment == pointerSize) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native; } if (!defType.ContainsGCPointers) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty; } if (defType.IsHfa) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA; } dataBuilder.EmitUInt((uint)flags); dataBuilder.EmitUInt((uint)size); if (defType.IsHfa) { switch (defType.HfaElementType.Category) { case TypeFlags.Single: dataBuilder.EmitUInt((uint)CorElementType.ELEMENT_TYPE_R4); break; case TypeFlags.Double: dataBuilder.EmitUInt((uint)CorElementType.ELEMENT_TYPE_R8); break; } } if (alignment != pointerSize) { dataBuilder.EmitUInt((uint)alignment); } if (defType.ContainsGCPointers) { // Encode the GC pointer map GCPointerMap gcMap = GCPointerMap.FromInstanceLayout(defType); byte[] encodedGCRefMap = new byte[(size / pointerSize + 7) / 8]; int bitIndex = 0; foreach (bool bit in gcMap) { if (bit) { encodedGCRefMap[bitIndex / 8] |= (byte)(1 << (bitIndex & 7)); } ++bitIndex; } dataBuilder.EmitBytes(encodedGCRefMap); } }