private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData) { UInt16 flags = EETypeBuilderHelpers.ComputeFlags(_type); if (_type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) { // Generic array enumerators use special variance rules recognized by the runtime flags |= (UInt16)EETypeFlags.GenericVarianceFlag; } if (factory.TypeSystemContext.IsGenericArrayInterfaceType(_type)) { // Runtime casting logic relies on all interface types implemented on arrays // to have the variant flag set (even if all the arguments are non-variant). // This supports e.g. casting uint[] to ICollection<int> flags |= (UInt16)EETypeFlags.GenericVarianceFlag; } ISymbolNode relatedTypeNode = GetRelatedTypeNode(factory); // If the related type (base type / array element type / pointee type) is not part of this compilation group, and // the output binaries will be multi-file (not multiple object files linked together), indicate to the runtime // that it should indirect through the import address table if (relatedTypeNode != null && relatedTypeNode.RepresentsIndirectionCell) { flags |= (UInt16)EETypeFlags.RelatedTypeViaIATFlag; } if (HasOptionalFields) { flags |= (UInt16)EETypeFlags.OptionalFieldsFlag; } objData.EmitShort((short)flags); }
protected virtual void ComputeValueTypeFieldPadding() { // All objects that can have appreciable which can be derived from size compute ValueTypeFieldPadding. // Unfortunately, the name ValueTypeFieldPadding is now wrong to avoid integration conflicts. // Interfaces, sealed types, and non-DefTypes cannot be derived from if (_type.IsInterface || !_type.IsDefType || (_type.IsSealed() && !_type.IsValueType)) { return; } DefType defType = _type as DefType; Debug.Assert(defType != null); uint valueTypeFieldPaddingEncoded; if (defType.InstanceByteCount.IsIndeterminate) { valueTypeFieldPaddingEncoded = EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue(0, 1); } else { uint valueTypeFieldPadding = checked ((uint)(defType.InstanceByteCount.AsInt - defType.InstanceByteCountUnaligned.AsInt)); valueTypeFieldPaddingEncoded = EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue(valueTypeFieldPadding, (uint)defType.InstanceFieldAlignment.AsInt); } if (valueTypeFieldPaddingEncoded != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded); } }
void ComputeRareFlags(NodeFactory factory) { uint flags = 0; if (_type.IsNullable) { flags |= (uint)EETypeRareFlags.IsNullableFlag; } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { flags |= (uint)EETypeRareFlags.HasCctorFlag; } if (EETypeBuilderHelpers.ComputeRequiresAlign8(_type)) { flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } if (_type.IsDefType && ((DefType)_type).IsHfa) { flags |= (uint)EETypeRareFlags.IsHFAFlag; } if (flags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, flags); } }
void ComputeRareFlags() { uint flags = 0; if (_type.IsNullable) { flags |= (uint)EETypeRareFlags.IsNullableFlag; } if (_type.HasStaticConstructor) { flags |= (uint)EETypeRareFlags.HasCctorFlag; } if (EETypeBuilderHelpers.ComputeRequiresAlign8(_type)) { flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } if (_type is DefType && ((DefType)_type).IsHFA()) { flags |= (uint)EETypeRareFlags.IsHFAFlag; } if (flags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldsElement.RareFlags, flags); } }
private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData) { UInt16 flags = EETypeBuilderHelpers.ComputeFlags(_type); if (_type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) { // Generic array enumerators use special variance rules recognized by the runtime flags |= (UInt16)EETypeFlags.GenericVarianceFlag; } ISymbolNode relatedTypeNode = GetRelatedTypeNode(factory); // If the related type (base type / array element type / pointee type) is not part of this compilation group, and // the output binaries will be multi-file (not multiple object files linked together), indicate to the runtime // that it should indirect through the import address table if (relatedTypeNode != null && relatedTypeNode.RepresentsIndirectionCell) { flags |= (UInt16)EETypeFlags.RelatedTypeViaIATFlag; } // Todo: Generic Type Definition EETypes if (HasOptionalFields) { flags |= (UInt16)EETypeFlags.OptionalFieldsFlag; } objData.EmitShort((short)flags); }
void ComputeRareFlags(NodeFactory factory) { uint flags = 0; MetadataType metadataType = _type as MetadataType; if (_type.IsNullable) { flags |= (uint)EETypeRareFlags.IsNullableFlag; // If the nullable type is not part of this compilation group, and // the output binaries will be multi-file (not multiple object files linked together), indicate to the runtime // that it should indirect through the import address table if (factory.NecessaryTypeSymbol(_type.Instantiation[0]).RepresentsIndirectionCell) { flags |= (uint)EETypeRareFlags.NullableTypeViaIATFlag; } } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { flags |= (uint)EETypeRareFlags.HasCctorFlag; } if (EETypeBuilderHelpers.ComputeRequiresAlign8(_type)) { flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } if (metadataType != null && metadataType.IsHfa) { flags |= (uint)EETypeRareFlags.IsHFAFlag; } foreach (DefType itf in _type.RuntimeInterfaces) { if (itf == factory.ICastableInterface) { flags |= (uint)EETypeRareFlags.ICastableFlag; break; } } if (metadataType != null && !_type.IsInterface && metadataType.IsAbstract) { flags |= (uint)EETypeRareFlags.IsAbstractClassFlag; } if (metadataType != null && metadataType.IsByRefLike) { flags |= (uint)EETypeRareFlags.IsByRefLikeFlag; } if (flags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, flags); } }
static public string GetNewArrayHelperForType(TypeDesc type) { if (EETypeBuilderHelpers.ComputeRequiresAlign8(type)) { return("RhpNewArrayAlign8"); } return("RhpNewArray"); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder dataBuilder = new ObjectDataBuilder(factory, relocsOnly); dataBuilder.RequireInitialPointerAlignment(); dataBuilder.AddSymbol(this); EETypeRareFlags rareFlags = 0; short flags = (short)EETypeKind.GenericTypeDefEEType; if (_type.IsValueType) { flags |= (short)EETypeFlags.ValueTypeFlag; } if (_type.IsInterface) { flags |= (short)EETypeFlags.IsInterfaceFlag; } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { rareFlags = rareFlags | EETypeRareFlags.HasCctorFlag; } if (_type.IsByRefLike) { rareFlags |= EETypeRareFlags.IsByRefLikeFlag; } if (rareFlags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, (uint)rareFlags); } if (HasOptionalFields) { flags |= (short)EETypeFlags.OptionalFieldsFlag; } if (_type.IsEnum) { flags |= (short)EETypeBuilderHelpers.ComputeElementTypeFlags(_type); } dataBuilder.EmitShort((short)_type.Instantiation.Length); dataBuilder.EmitShort(flags); dataBuilder.EmitInt(0); // Base size is always 0 dataBuilder.EmitZeroPointer(); // No related type dataBuilder.EmitShort(0); // No VTable dataBuilder.EmitShort(0); // No interface map dataBuilder.EmitInt(_type.GetHashCode()); dataBuilder.EmitPointerReloc(factory.TypeManagerIndirection); if (HasOptionalFields) { dataBuilder.EmitPointerReloc(_optionalFieldsNode); } return(dataBuilder.ToObjectData()); }
void ComputeRareFlags(NodeFactory factory) { uint flags = 0; MetadataType metadataType = _type as MetadataType; if (_type.IsNullable) { flags |= (uint)EETypeRareFlags.IsNullableFlag; } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { flags |= (uint)EETypeRareFlags.HasCctorFlag; } if (EETypeBuilderHelpers.ComputeRequiresAlign8(_type)) { flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } if (metadataType != null && metadataType.IsHfa) { flags |= (uint)EETypeRareFlags.IsHFAFlag; } foreach (DefType itf in _type.RuntimeInterfaces) { if (itf == factory.ICastableInterface) { flags |= (uint)EETypeRareFlags.ICastableFlag; break; } } if (metadataType != null && !_type.IsInterface && metadataType.IsAbstract) { flags |= (uint)EETypeRareFlags.IsAbstractClassFlag; } if (metadataType != null && metadataType.IsByRefLike) { flags |= (uint)EETypeRareFlags.IsByRefLikeFlag; } if (flags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, flags); } }
protected internal override void ComputeOptionalEETypeFields(NodeFactory factory, bool relocsOnly) { if (_type.IsCanonicalDefinitionType(CanonicalFormKind.Universal)) { // Value types should have at least 1 byte of size to avoid zero-length structures // Add pointer-size to the number of instance field bytes to consistently represents the boxed size. uint numInstanceFieldBytes = 1 + (uint)factory.Target.PointerSize; uint valueTypeFieldPadding = (uint)(MinimumObjectSize - factory.Target.PointerSize) - numInstanceFieldBytes; uint valueTypeFieldPaddingEncoded = EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue(valueTypeFieldPadding, 1, _type.Context.Target.PointerSize); Debug.Assert(valueTypeFieldPaddingEncoded != 0); _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded); } }
private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData) { UInt16 flags = EETypeBuilderHelpers.ComputeFlags(_type); // Todo: RelatedTypeViaIATFlag when we support cross-module EETypes // Todo: GenericVarianceFlag when we support variance // Todo: Generic Type Definition EETypes if (_optionalFieldsBuilder.IsAtLeastOneFieldUsed()) { flags |= (UInt16)EETypeFlags.OptionalFieldsFlag; } objData.EmitShort((short)flags); }
void ComputeValueTypeFieldPadding() { if (!_type.IsValueType) { return; } DefType defType = _type as DefType; Debug.Assert(defType != null); uint valueTypeFieldPadding = checked ((uint)(defType.InstanceByteCount - defType.InstanceByteCountUnaligned)); uint valueTypeFieldPaddingEncoded = EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue(valueTypeFieldPadding, (uint)defType.InstanceFieldAlignment); if (valueTypeFieldPaddingEncoded != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldsElement.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded); } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder dataBuilder = new ObjectDataBuilder(factory, relocsOnly); dataBuilder.RequireInitialPointerAlignment(); dataBuilder.AddSymbol(this); EETypeRareFlags rareFlags = 0; ushort flags = EETypeBuilderHelpers.ComputeFlags(_type); if (factory.PreinitializationManager.HasLazyStaticConstructor(_type)) { rareFlags = rareFlags | EETypeRareFlags.HasCctorFlag; } if (_type.IsByRefLike) { rareFlags |= EETypeRareFlags.IsByRefLikeFlag; } if (rareFlags != 0) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, (uint)rareFlags); } if (HasOptionalFields) { flags |= (ushort)EETypeFlags.OptionalFieldsFlag; } dataBuilder.EmitShort((short)_type.Instantiation.Length); dataBuilder.EmitUShort(flags); dataBuilder.EmitInt(0); // Base size is always 0 dataBuilder.EmitZeroPointer(); // No related type dataBuilder.EmitShort(0); // No VTable dataBuilder.EmitShort(0); // No interface map dataBuilder.EmitInt(_type.GetHashCode()); OutputTypeManagerIndirection(factory, ref dataBuilder); OutputWritableData(factory, ref dataBuilder); OutputOptionalFields(factory, ref dataBuilder); return(dataBuilder.ToObjectData()); }
private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData) { UInt16 flags = EETypeBuilderHelpers.ComputeFlags(_type); if (_type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) { // Generic array enumerators use special variance rules recognized by the runtime flags |= (UInt16)EETypeFlags.GenericVarianceFlag; } // Todo: RelatedTypeViaIATFlag when we support cross-module EETypes // Todo: Generic Type Definition EETypes if (HasOptionalFields) { flags |= (UInt16)EETypeFlags.OptionalFieldsFlag; } objData.EmitShort((short)flags); }
private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData) { UInt16 flags = EETypeBuilderHelpers.ComputeFlags(_type); if (_type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) { // Generic array enumerators use special variance rules recognized by the runtime flags |= (UInt16)EETypeFlags.GenericVarianceFlag; } TypeDesc relatedType = null; if (_type.IsArray || _type.IsPointer || _type.IsByRef) { relatedType = ((ParameterizedType)_type).ParameterType; } else { relatedType = _type.BaseType; } // If the related type (base type / array element type / pointee type) is not part of this compilation group, and // the output binaries will be multi-file (not multiple object files linked together), indicate to the runtime // that it should indirect through the import address table if (relatedType != null && factory.CompilationModuleGroup.ShouldReferenceThroughImportTable(relatedType)) { flags |= (UInt16)EETypeFlags.RelatedTypeViaIATFlag; } // Todo: Generic Type Definition EETypes if (HasOptionalFields) { flags |= (UInt16)EETypeFlags.OptionalFieldsFlag; } objData.EmitShort((short)flags); }
// // These methods are static compiler equivalent of RhGetRuntimeHelperForType // static public string GetNewObjectHelperForType(TypeDesc type) { if (EETypeBuilderHelpers.ComputeRequiresAlign8(type)) { if (type.HasFinalizer) { return("RhpNewFinalizableAlign8"); } if (type.IsValueType) { return("RhpNewFastMisalign"); } return("RhpNewFastAlign8"); } if (type.HasFinalizer) { return("RhpNewFinalizable"); } return("RhpNewFast"); }
private String GetCodeForType(TypeDesc type) { var sb = new CppGenerationBuffer(); int totalSlots = 0; TypeDesc t = type; while (t != null) { IReadOnlyList <MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(t).Slots; totalSlots += virtualSlots.Count; t = t.BaseType; } UInt16 flags = 0; try { flags = EETypeBuilderHelpers.ComputeFlags(type); } catch { // TODO: Handling of missing dependencies flags = 0; } sb.Append("MethodTable * "); sb.Append(GetCppMethodDeclarationName(type, "__getMethodTable")); sb.Append("()"); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("static struct {"); sb.Indent(); // sb.Append(GCDesc); sb.AppendLine(); sb.Append("RawEEType EEType;"); if (totalSlots != 0) { sb.AppendLine(); sb.Append("void * slots["); sb.Append(totalSlots); sb.Append("];"); } sb.Exdent(); sb.AppendLine(); sb.Append("} mt = {"); sb.Indent(); // gcdesc if (type.IsString) { // String has non-standard layout sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("sizeof(uint16_t),"); sb.AppendLine(); sb.Append("0x"); // EEType::_usComponentSize sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags sb.Append(","); sb.AppendLine(); sb.Append("2 * sizeof(void*) + sizeof(int32_t) + 2,"); // EEType::_uBaseSize } else if (type.IsSzArray) { sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("sizeof("); sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize sb.Append("),"); sb.AppendLine(); sb.Append("0x"); sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags sb.Append(","); sb.AppendLine(); sb.Append("3 * sizeof(void*),"); // EEType::_uBaseSize } else if (type.IsArray) { sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("sizeof("); sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize sb.Append("),"); sb.AppendLine(); sb.Append("0x"); sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags sb.Append(","); sb.AppendLine(); sb.Append("3 * sizeof(void*) + "); // EEType::_uBaseSize sb.Append(((ArrayType)type).Rank.ToStringInvariant()); sb.Append("* sizeof(int32_t) * 2,"); } else { // sizeof(void*) == size of object header sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("0,"); sb.AppendLine(); sb.Append("0x"); // EEType::_usComponentSize sb.Append(flags.ToStringInvariant("x")); // EEType::_usFlags sb.Append(","); sb.AppendLine(); sb.Append("AlignBaseSize(sizeof(void*)+sizeof("); // EEType::_uBaseSize sb.Append(GetCppTypeName(type)); sb.Append(")),"); } sb.AppendLine(); // base type if (type.IsArray) { sb.Append(GetCppMethodDeclarationName(((ArrayType)type).ElementType, "__getMethodTable")); sb.Append("()"); } else { var baseType = type.BaseType; if (baseType != null) { sb.Append(GetCppMethodDeclarationName(type.BaseType, "__getMethodTable")); sb.Append("()"); } else { sb.Append("NULL"); } } sb.Exdent(); sb.AppendLine(); sb.Append("},"); // virtual slots if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(type)).Marked) { AppendVirtualSlots(sb, type, type); } sb.Exdent(); sb.AppendLine(); sb.Append("};"); sb.AppendLine(); sb.Append("return (MethodTable *)&mt.EEType;"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); return(sb.ToString()); }
private static void CreateEETypeWorker(EEType *pTemplateEEType, UInt32 hashCodeOfNewType, int arity, bool requireVtableSlotMapping, TypeBuilderState state) { bool successful = false; IntPtr eeTypePtrPlusGCDesc = IntPtr.Zero; IntPtr dynamicDispatchMapPtr = IntPtr.Zero; DynamicModule *dynamicModulePtr = null; try { Debug.Assert((pTemplateEEType != null) || (state.TypeBeingBuilt as MetadataType != null)); // In some situations involving arrays we can find as a template a dynamically generated type. // In that case, the correct template would be the template used to create the dynamic type in the first // place. if (pTemplateEEType != null && pTemplateEEType->IsDynamicType) { pTemplateEEType = pTemplateEEType->DynamicTemplateType; } ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(state.TypeBeingBuilt); dynamicModulePtr = moduleInfo.DynamicModulePtr; Debug.Assert(dynamicModulePtr != null); bool requiresDynamicDispatchMap = requireVtableSlotMapping && (pTemplateEEType != null) && pTemplateEEType->HasDispatchMap; uint valueTypeFieldPaddingEncoded = 0; int baseSize = 0; bool isValueType; bool hasFinalizer; bool isNullable; bool isArray; bool isGeneric; ushort componentSize = 0; ushort flags; ushort runtimeInterfacesLength = 0; bool isGenericEETypeDef = false; if (state.RuntimeInterfaces != null) { runtimeInterfacesLength = checked ((ushort)state.RuntimeInterfaces.Length); } if (pTemplateEEType != null) { valueTypeFieldPaddingEncoded = EEType.ComputeValueTypeFieldPaddingFieldValue( pTemplateEEType->ValueTypeFieldPadding, (uint)pTemplateEEType->FieldAlignmentRequirement); baseSize = (int)pTemplateEEType->BaseSize; isValueType = pTemplateEEType->IsValueType; hasFinalizer = pTemplateEEType->IsFinalizable; isNullable = pTemplateEEType->IsNullable; componentSize = pTemplateEEType->ComponentSize; flags = pTemplateEEType->Flags; isArray = pTemplateEEType->IsArray; isGeneric = pTemplateEEType->IsGeneric; Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength); } else if (state.TypeBeingBuilt.IsGenericDefinition) { flags = (ushort)EETypeKind.GenericTypeDefEEType; isValueType = state.TypeBeingBuilt.IsValueType; if (isValueType) { flags |= (ushort)EETypeFlags.ValueTypeFlag; } if (state.TypeBeingBuilt.IsInterface) { flags |= (ushort)EETypeFlags.IsInterfaceFlag; } hasFinalizer = false; isArray = false; isNullable = false; isGeneric = false; isGenericEETypeDef = true; componentSize = checked ((ushort)state.TypeBeingBuilt.Instantiation.Length); baseSize = 0; } else { isValueType = state.TypeBeingBuilt.IsValueType; hasFinalizer = state.TypeBeingBuilt.HasFinalizer; isNullable = state.TypeBeingBuilt.GetTypeDefinition().IsNullable; flags = EETypeBuilderHelpers.ComputeFlags(state.TypeBeingBuilt); isArray = false; isGeneric = state.TypeBeingBuilt.HasInstantiation; if (state.TypeBeingBuilt.HasVariance) { state.GenericVarianceFlags = new int[state.TypeBeingBuilt.Instantiation.Length]; int i = 0; foreach (GenericParameterDesc gpd in state.TypeBeingBuilt.GetTypeDefinition().Instantiation) { state.GenericVarianceFlags[i] = (int)gpd.Variance; i++; } Debug.Assert(i == state.GenericVarianceFlags.Length); } } // TODO! Change to if template is Universal or non-Existent if (state.TypeSize.HasValue) { baseSize = state.TypeSize.Value; int baseSizeBeforeAlignment = baseSize; baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size); if (isValueType) { // Compute the valuetype padding size based on size before adding the object type pointer field to the size uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment); // Add Object type pointer field to base size baseSize += IntPtr.Size; valueTypeFieldPaddingEncoded = (uint)EEType.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value); } // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type if (baseSize <= IntPtr.Size) { // ValueTypes should already have had their size bumped up by the normal type layout process Debug.Assert(!isValueType); baseSize += IntPtr.Size; } // Add sync block skew baseSize += IntPtr.Size; // Minimum basesize is 3 pointers Debug.Assert(baseSize >= (IntPtr.Size * 3)); } // Optional fields encoding int cbOptionalFieldsSize; OptionalFieldsRuntimeBuilder optionalFields; { optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null); UInt32 rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0); rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeFlag; // Set the IsDynamicTypeFlag rareFlags &= ~(uint)EETypeRareFlags.NullableTypeViaIATFlag; // Remove the NullableTypeViaIATFlag flag rareFlags &= ~(uint)EETypeRareFlags.HasSealedVTableEntriesFlag; // Remove the HasSealedVTableEntriesFlag // we'll set IsDynamicTypeWithSealedVTableEntriesFlag instead // Set the IsDynamicTypeWithSealedVTableEntriesFlag if needed if (state.NumSealedVTableEntries > 0) { rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithSealedVTableEntriesFlag; } if (requiresDynamicDispatchMap) { rareFlags |= (uint)EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag; } if (state.NonGcDataSize != 0) { rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics; } if (state.GcDataSize != 0) { rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics; } if (state.ThreadDataSize != 0) { rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics; } #if ARM if (state.FieldAlignment == 8) { rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } else { rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag; } if (state.IsHFA) { rareFlags |= (uint)EETypeRareFlags.IsHFAFlag; } else { rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag; } #endif if (state.HasStaticConstructor) { rareFlags |= (uint)EETypeRareFlags.HasCctorFlag; } else { rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag; } rareFlags |= (uint)EETypeRareFlags.HasDynamicModuleFlag; optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags); // Dispatch map is fetched either from template type, or from the dynamically allocated DispatchMap field optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap); optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding); if (valueTypeFieldPaddingEncoded != 0) { optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded); } // Compute size of optional fields encoding cbOptionalFieldsSize = optionalFields.Encode(); Debug.Assert(cbOptionalFieldsSize > 0); } // Note: The number of vtable slots on the EEType to create is not necessary equal to the number of // vtable slots on the template type for universal generics (see ComputeVTableLayout) ushort numVtableSlots = state.NumVTableSlots; // Compute the EEType size and allocate it EEType *pEEType; { // In order to get the size of the EEType to allocate we need the following information // 1) The number of VTable slots (from the TypeBuilderState) // 2) The number of Interfaces (from the template) // 3) Whether or not there is a finalizer (from the template) // 4) Optional fields size // 5) Whether or not the type is nullable (from the template) // 6) Whether or not the type has sealed virtuals (from the TypeBuilderState) int cbEEType = (int)EEType.GetSizeofEEType( numVtableSlots, runtimeInterfacesLength, hasFinalizer, true, isNullable, state.NumSealedVTableEntries > 0, isGeneric, state.NonGcDataSize != 0, state.GcDataSize != 0, state.ThreadDataSize != 0); // Dynamic types have an extra pointer-sized field that contains a pointer to their template type cbEEType += IntPtr.Size; // Check if we need another pointer sized field for a dynamic DispatchMap cbEEType += (requiresDynamicDispatchMap ? IntPtr.Size : 0); // Add another pointer sized field for a DynamicModule cbEEType += IntPtr.Size; int cbGCDesc = GetInstanceGCDescSize(state, pTemplateEEType, isValueType, isArray); int cbGCDescAligned = MemoryHelpers.AlignUp(cbGCDesc, IntPtr.Size); // Allocate enough space for the EEType + gcDescSize eeTypePtrPlusGCDesc = MemoryHelpers.AllocateMemory(cbGCDescAligned + cbEEType + cbOptionalFieldsSize); // Get the EEType pointer, and the template EEType pointer pEEType = (EEType *)(eeTypePtrPlusGCDesc + cbGCDescAligned); state.HalfBakedRuntimeTypeHandle = pEEType->ToRuntimeTypeHandle(); // Set basic EEType fields pEEType->ComponentSize = componentSize; pEEType->Flags = flags; pEEType->BaseSize = (uint)baseSize; pEEType->NumVtableSlots = numVtableSlots; pEEType->NumInterfaces = runtimeInterfacesLength; pEEType->HashCode = hashCodeOfNewType; // Write the GCDesc bool isSzArray = isArray ? state.ArrayRank < 1 : false; int arrayRank = isArray ? state.ArrayRank.Value : 0; CreateInstanceGCDesc(state, pTemplateEEType, pEEType, baseSize, cbGCDesc, isValueType, isArray, isSzArray, arrayRank); Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0)); #if GENERICS_FORCE_USG if (state.NonUniversalTemplateType != null) { Debug.Assert(state.NonUniversalInstanceGCDescSize == cbGCDesc, "Non-universal instance GCDesc size not matching with universal GCDesc size!"); Debug.Assert(cbGCDesc == 0 || pEEType->HasGCPointers); // The TestGCDescsForEquality helper will compare 2 GCDescs for equality, 4 bytes at a time (GCDesc contents treated as integers), and will read the // GCDesc data in *reverse* order for instance GCDescs (subtracts 4 from the pointer values at each iteration). // - For the first GCDesc, we use (pEEType - 4) to point to the first 4-byte integer directly preceeding the EEType // - For the second GCDesc, given that the state.NonUniversalInstanceGCDesc already points to the first byte preceeding the template EEType, we // subtract 3 to point to the first 4-byte integer directly preceeding the template EEtype TestGCDescsForEquality(new IntPtr((byte *)pEEType - 4), state.NonUniversalInstanceGCDesc - 3, cbGCDesc, true); } #endif // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the EEType // It is important to set the optional fields first on the newly created EEType, because all other 'setters' // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types pEEType->OptionalFieldsPtr = (byte *)pEEType + cbEEType; optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize); #if CORERT pEEType->PointerToTypeManager = PermanentAllocatedMemoryBlobs.GetPointerToIntPtr(moduleInfo.Handle); #endif pEEType->DynamicModule = dynamicModulePtr; // Copy VTable entries from template type int numSlotsFilled = 0; IntPtr *pVtable = (IntPtr *)((byte *)pEEType + sizeof(EEType)); if (pTemplateEEType != null) { IntPtr *pTemplateVtable = (IntPtr *)((byte *)pTemplateEEType + sizeof(EEType)); for (int i = 0; i < pTemplateEEType->NumVtableSlots; i++) { int vtableSlotInDynamicType = requireVtableSlotMapping ? state.VTableSlotsMapping.GetVTableSlotInTargetType(i) : i; if (vtableSlotInDynamicType != -1) { Debug.Assert(vtableSlotInDynamicType < numVtableSlots); IntPtr dictionaryPtrValue; if (requireVtableSlotMapping && state.VTableSlotsMapping.IsDictionarySlot(i, out dictionaryPtrValue)) { // This must be the dictionary pointer value of one of the base types of the // current universal generic type being constructed. pVtable[vtableSlotInDynamicType] = dictionaryPtrValue; // Assert that the current template vtable slot is also a NULL value since all // universal generic template types have NULL dictionary slot values in their vtables Debug.Assert(pTemplateVtable[i] == IntPtr.Zero); } else { pVtable[vtableSlotInDynamicType] = pTemplateVtable[i]; } numSlotsFilled++; } } } else if (isGenericEETypeDef) { // If creating a Generic Type Definition Debug.Assert(pEEType->NumVtableSlots == 0); } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING // Dynamically loaded type // Fill the vtable with vtable resolution thunks in all slots except for // the dictionary slots, which should be filled with dictionary pointers if those // dictionaries are already published. TypeDesc nextTypeToExamineForDictionarySlot = state.TypeBeingBuilt; TypeDesc typeWithDictionary; int nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary); for (int iSlot = pEEType->NumVtableSlots - 1; iSlot >= 0; iSlot--) { bool isDictionary = iSlot == nextDictionarySlot; if (!isDictionary) { pVtable[iSlot] = LazyVTableResolver.GetThunkForSlot(iSlot); } else { if (typeWithDictionary.RetrieveRuntimeTypeHandleIfPossible()) { pVtable[iSlot] = typeWithDictionary.RuntimeTypeHandle.GetDictionary(); } nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary); } numSlotsFilled++; } #else Environment.FailFast("Template type loader is null, but metadata based type loader is not in use"); #endif } Debug.Assert(numSlotsFilled == numVtableSlots); // Copy Pointer to finalizer method from the template type if (hasFinalizer) { if (pTemplateEEType != null) { pEEType->FinalizerCode = pTemplateEEType->FinalizerCode; } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING pEEType->FinalizerCode = LazyVTableResolver.GetFinalizerThunk(); #else Environment.FailFast("Template type loader is null, but metadata based type loader is not in use"); #endif } } } // Copy the sealed vtable entries if they exist on the template type if (state.NumSealedVTableEntries > 0) { state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size); UInt32 cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots); *((IntPtr *)((byte *)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable; for (UInt16 i = 0; i < state.NumSealedVTableEntries; i++) { IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i); pEEType->SetSealedVirtualSlot(value, i); } } // Create a new DispatchMap for the type if (requiresDynamicDispatchMap) { DispatchMap *pTemplateDispatchMap = (DispatchMap *)RuntimeAugments.GetDispatchMapForType(pTemplateEEType->ToRuntimeTypeHandle()); dynamicDispatchMapPtr = MemoryHelpers.AllocateMemory(pTemplateDispatchMap->Size); UInt32 cbDynamicDispatchMapOffset = pEEType->GetFieldOffset(EETypeField.ETF_DynamicDispatchMap); *((IntPtr *)((byte *)pEEType + cbDynamicDispatchMapOffset)) = dynamicDispatchMapPtr; DispatchMap *pDynamicDispatchMap = (DispatchMap *)dynamicDispatchMapPtr; pDynamicDispatchMap->NumEntries = pTemplateDispatchMap->NumEntries; for (int i = 0; i < pTemplateDispatchMap->NumEntries; i++) { DispatchMap.DispatchMapEntry *pTemplateEntry = (*pTemplateDispatchMap)[i]; DispatchMap.DispatchMapEntry *pDynamicEntry = (*pDynamicDispatchMap)[i]; pDynamicEntry->_usInterfaceIndex = pTemplateEntry->_usInterfaceIndex; pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot; if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots) { pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot); Debug.Assert(pDynamicEntry->_usImplMethodSlot < numVtableSlots); } else { // This is an entry in the sealed vtable. We need to adjust the slot number based on the number of vtable slots // in the dynamic EEType pDynamicEntry->_usImplMethodSlot = (ushort)(pTemplateEntry->_usImplMethodSlot - pTemplateEEType->NumVtableSlots + numVtableSlots); Debug.Assert(state.NumSealedVTableEntries > 0 && pDynamicEntry->_usImplMethodSlot >= numVtableSlots && (pDynamicEntry->_usImplMethodSlot - numVtableSlots) < state.NumSealedVTableEntries); } } } if (pTemplateEEType != null) { pEEType->DynamicTemplateType = pTemplateEEType; } else { // Use object as the template type for non-template based EETypes. This will // allow correct Module identification for types. if (state.TypeBeingBuilt.HasVariance) { // TODO! We need to have a variant EEType here if the type has variance, as the // CreateGenericInstanceDescForType requires it. However, this is a ridiculous api surface // When we remove GenericInstanceDescs from the product, get rid of this weird special // case pEEType->DynamicTemplateType = typeof(IEnumerable <int>).TypeHandle.ToEETypePtr(); } else { pEEType->DynamicTemplateType = typeof(object).TypeHandle.ToEETypePtr(); } } int nonGCStaticDataOffset = 0; if (!isArray && !isGenericEETypeDef) { nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0; // create GC desc if (state.GcDataSize != 0 && state.GcStaticDesc == IntPtr.Zero) { int cbStaticGCDesc; state.GcStaticDesc = CreateStaticGCDesc(state.StaticGCLayout, out state.AllocatedStaticGCDesc, out cbStaticGCDesc); #if GENERICS_FORCE_USG TestGCDescsForEquality(state.GcStaticDesc, state.NonUniversalStaticGCDesc, cbStaticGCDesc, false); #endif } if (state.ThreadDataSize != 0 && state.ThreadStaticDesc == IntPtr.Zero) { int cbThreadStaticGCDesc; state.ThreadStaticDesc = CreateStaticGCDesc(state.ThreadStaticGCLayout, out state.AllocatedThreadStaticGCDesc, out cbThreadStaticGCDesc); #if GENERICS_FORCE_USG TestGCDescsForEquality(state.ThreadStaticDesc, state.NonUniversalThreadStaticGCDesc, cbThreadStaticGCDesc, false); #endif } // If we have a class constructor, our NonGcDataSize MUST be non-zero Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0)); } if (isGeneric) { if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, arity, state.NonGcDataSize, nonGCStaticDataOffset, state.GcDataSize, (int)state.ThreadStaticOffset, state.GcStaticDesc, state.ThreadStaticDesc, state.GenericVarianceFlags)) { throw new OutOfMemoryException(); } } else { Debug.Assert(arity == 0 || isGenericEETypeDef); // We don't need to report the non-gc and gc static data regions and allocate them for non-generics, // as we currently place these fields directly into the image if (!isGenericEETypeDef && state.ThreadDataSize != 0) { // Types with thread static fields ALWAYS get a GID. The GID is used to perform GC // and lifetime management of the thread static data. However, these GIDs are only used for that // so the specified GcDataSize, etc are 0 if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, 0, 0, 0, 0, (int)state.ThreadStaticOffset, IntPtr.Zero, state.ThreadStaticDesc, null)) { throw new OutOfMemoryException(); } } } if (state.Dictionary != null) { state.HalfBakedDictionary = state.Dictionary.Allocate(); } Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull()); Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero)); Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero)); successful = true; } finally { if (!successful) { if (eeTypePtrPlusGCDesc != IntPtr.Zero) { MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc); } if (dynamicDispatchMapPtr != IntPtr.Zero) { MemoryHelpers.FreeMemory(dynamicDispatchMapPtr); } if (state.HalfBakedSealedVTable != IntPtr.Zero) { MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable); } if (state.HalfBakedDictionary != IntPtr.Zero) { MemoryHelpers.FreeMemory(state.HalfBakedDictionary); } if (state.AllocatedStaticGCDesc) { MemoryHelpers.FreeMemory(state.GcStaticDesc); } if (state.AllocatedThreadStaticGCDesc) { MemoryHelpers.FreeMemory(state.ThreadStaticDesc); } } } }
private String GetCodeForType(TypeDesc type) { StringBuilder sb = new StringBuilder(); int totalSlots = 0; TypeDesc t = type; while (t != null) { List <MethodDesc> virtualSlots; _compilation.NodeFactory.VirtualSlots.TryGetValue(t, out virtualSlots); if (virtualSlots != null) { totalSlots += virtualSlots.Count; } t = t.BaseType; } UInt16 flags = 0; try { flags = EETypeBuilderHelpers.ComputeFlags(type); } catch { // TODO: Handling of missing dependencies flags = 0; } sb.Append("MethodTable * "); sb.Append(GetCppTypeName(type)); sb.AppendLine("::__getMethodTable() {"); sb.Append("static struct {"); // sb.Append(GCDesc); sb.Append("RawEEType EEType;"); if (totalSlots != 0) { sb.Append("void * slots["); sb.Append(totalSlots); sb.Append("];"); } sb.AppendLine("} mt = {"); // gcdesc if (type.IsString) { // String has non-standard layout sb.Append("{ sizeof(uint16_t), 0x"); // EEType::_usComponentSize sb.Append(flags.ToString("x4", CultureInfo.InvariantCulture)); // EEType::_usFlags sb.Append(", 2 * sizeof(void*) + sizeof(int32_t) + 2, "); // EEType::_uBaseSize } else if (type.IsArray && ((ArrayType)type).Rank == 1) { sb.Append("{ sizeof("); sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize sb.Append("), 0x"); sb.Append(flags.ToString("x4", CultureInfo.InvariantCulture)); // EEType::_usFlags sb.Append(", 3 * sizeof(void*), "); // EEType::_uBaseSize } else if (type.IsArray) { Debug.Assert(((ArrayType)type).Rank > 1); sb.Append("{ sizeof("); sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize sb.Append("), 0x"); sb.Append(flags.ToString("x4", CultureInfo.InvariantCulture)); // EEType::_usFlags sb.Append(", 3 * sizeof(void*) + "); // EEType::_uBaseSize sb.Append(((ArrayType)type).Rank.ToString()); sb.Append("* sizeof(int32_t) * 2, "); } else { // sizeof(void*) == size of object header sb.Append("{ 0, 0x"); // EEType::_usComponentSize sb.Append(flags.ToString("x", CultureInfo.InvariantCulture)); // EEType::_usFlags sb.Append(", AlignBaseSize(sizeof(void*)+sizeof("); // EEType::_uBaseSize sb.Append(GetCppTypeName(type)); sb.Append(")), "); } // base type if (type.IsArray) { sb.Append(GetCppTypeName(((ArrayType)type).ElementType)); sb.Append("::__getMethodTable()"); } else { var baseType = type.BaseType; if (baseType != null) { sb.Append(GetCppTypeName(type.BaseType)); sb.Append("::__getMethodTable()"); } else { sb.Append("NULL"); } } sb.AppendLine("},"); // virtual slots if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(type)).Marked) { AppendVirtualSlots(sb, type, type); } sb.AppendLine("};"); sb.AppendLine("return (MethodTable *)&mt.EEType;"); sb.AppendLine("}"); return(sb.ToString()); }