public static void EncodeStandardGCDesc <T>(ref T builder, GCPointerMap map, int size, int delta) where T : struct, ITargetBinaryWriter { Debug.Assert(size >= map.Size); int pointerSize = builder.TargetPointerSize; int numSeries = 0; for (int cellIndex = map.Size - 1; cellIndex >= 0; cellIndex--) { if (map[cellIndex]) { numSeries++; int seriesSize = pointerSize; while (cellIndex > 0 && map[cellIndex - 1]) { seriesSize += pointerSize; cellIndex--; } builder.EmitNaturalInt(seriesSize - size); builder.EmitNaturalInt(cellIndex * pointerSize + delta); } } Debug.Assert(numSeries > 0); builder.EmitNaturalInt(numSeries); }
public void TestThreadStaticMap() { MetadataType mixedThreadStaticClass = _testModule.GetType("GCPointerMap", "MixedThreadStaticClass"); var map = GCPointerMap.FromThreadStaticLayout(mixedThreadStaticClass); Assert.Equal(map.Size, 14); Assert.Equal("00010010100110", map.ToString()); }
public void TestStaticMap() { MetadataType mixedStaticClass = _testModule.GetType("GCPointerMap", "MixedStaticClass"); var map = GCPointerMap.FromStaticLayout(mixedStaticClass); Assert.Equal(12, map.Size); Assert.Equal("010100101001", map.ToString()); }
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()); } }
private static void EncodeArrayGCDesc <T>(ref T builder, GCPointerMap map, int baseSize) where T : struct, ITargetBinaryWriter { // NOTE: This format cannot properly represent element types with sizes >= 64k bytes. // We guard it with an assert, but it is the responsibility of the code using this // to cap array component sizes. EEType only has a UInt16 field for component sizes too. int numSeries = 0; int leadingNonPointerCount = 0; int pointerSize = builder.TargetPointerSize; for (int cellIndex = 0; cellIndex < map.Size && !map[cellIndex]; cellIndex++) { leadingNonPointerCount++; } int nonPointerCount = leadingNonPointerCount; for (int cellIndex = map.Size - 1; cellIndex >= leadingNonPointerCount; cellIndex--) { if (map[cellIndex]) { numSeries++; int pointerCount = 1; while (cellIndex > leadingNonPointerCount && map[cellIndex - 1]) { cellIndex--; pointerCount++; } Debug.Assert(pointerCount < 64 * 1024); builder.EmitHalfNaturalInt((short)pointerCount); Debug.Assert(nonPointerCount * pointerSize < 64 * 1024); builder.EmitHalfNaturalInt((short)(nonPointerCount * pointerSize)); nonPointerCount = 0; } else { nonPointerCount++; } } Debug.Assert(numSeries > 0); builder.EmitNaturalInt(baseSize + leadingNonPointerCount * pointerSize); builder.EmitNaturalInt(-numSeries); }
/// <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); }
public GCStaticEETypeNode(TargetDetails target, GCPointerMap gcMap) { _gcMap = gcMap; _target = target; }
public ISymbolNode GCStaticEEType(GCPointerMap gcMap) { return(_GCStaticEETypes.GetOrAdd(gcMap)); }
private ISymbolNode GetGCStaticEETypeNode(NodeFactory factory) { GCPointerMap map = GCPointerMap.FromStaticLayout(_type); return(factory.GCStaticEEType(map)); }
public GCStaticDescNode(MetadataType type, bool isThreadStatic) { _type = type; _gcMap = isThreadStatic ? GCPointerMap.FromThreadStaticLayout(type) : GCPointerMap.FromStaticLayout(type); _isThreadStatic = isThreadStatic; }
public GCStaticDescNode(MetadataType type) { _type = type; _gcMap = GCPointerMap.FromStaticLayout(type); }
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); } }