Пример #1
0
        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);
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
        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());
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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);
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
            }
        }
Пример #13
0
        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());
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
        }
Пример #16
0
        //
        // 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");
        }
Пример #17
0
        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());
        }
Пример #18
0
        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);
                    }
                }
            }
        }
Пример #19
0
        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());
        }