Welcome to mirror list, hosted at ThFree Co, Russian Federation.

EETypeBuilderHelpers.cs « Runtime « Internal « Common « tools « coreclr « src - github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a225665dcee12b1ac5f73edc5c7e2c1ef116c494 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

using Internal.TypeSystem;

namespace Internal.Runtime
{
    internal static class EETypeBuilderHelpers
    {
        private static EETypeElementType ComputeEETypeElementType(TypeDesc type)
        {
            // Enums are represented as their underlying type
            type = type.UnderlyingType;

            if (type.IsWellKnownType(WellKnownType.Array))
            {
                // SystemArray is a special EETypeElementType that doesn't exist in TypeFlags
                return EETypeElementType.SystemArray;
            }
            else
            {
                // The rest of TypeFlags should be directly castable to EETypeElementType.
                // Spot check the enums match.
                Debug.Assert((int)TypeFlags.Void == (int)EETypeElementType.Void);
                Debug.Assert((int)TypeFlags.IntPtr == (int)EETypeElementType.IntPtr);
                Debug.Assert((int)TypeFlags.Single == (int)EETypeElementType.Single);
                Debug.Assert((int)TypeFlags.UInt32 == (int)EETypeElementType.UInt32);
                Debug.Assert((int)TypeFlags.Pointer == (int)EETypeElementType.Pointer);
                Debug.Assert((int)TypeFlags.Array == (int)EETypeElementType.Array);

                EETypeElementType elementType = (EETypeElementType)type.Category;

                // Would be surprising to get these here though.
                Debug.Assert(elementType != EETypeElementType.SystemArray);
                Debug.Assert(elementType <= EETypeElementType.Pointer);

                return elementType;

            }
        }

        public static ushort ComputeFlags(TypeDesc type)
        {
            ushort flags = type.IsParameterizedType ?
                (ushort)EETypeKind.ParameterizedEEType : (ushort)EETypeKind.CanonicalEEType;

            // The top 5 bits of flags are used to convey enum underlying type, primitive type, or mark the type as being System.Array
            EETypeElementType elementType = ComputeEETypeElementType(type);
            flags |= (ushort)((ushort)elementType << (ushort)EETypeFlags.ElementTypeShift);

            if (type.IsGenericDefinition)
            {
                flags |= (ushort)EETypeKind.GenericTypeDefEEType;

                // Generic type definition EETypes don't set the other flags.
                return flags;
            }

            if (type.HasFinalizer)
            {
                flags |= (ushort)EETypeFlags.HasFinalizerFlag;
            }

            if (type.IsDefType
                && !type.IsCanonicalSubtype(CanonicalFormKind.Universal)
                && ((DefType)type).ContainsGCPointers)
            {
                flags |= (ushort)EETypeFlags.HasPointersFlag;
            }
            else if (type.IsArray && !type.IsCanonicalSubtype(CanonicalFormKind.Universal))
            {
                var arrayElementType = ((ArrayType)type).ElementType;
                if ((arrayElementType.IsValueType && ((DefType)arrayElementType).ContainsGCPointers) || arrayElementType.IsGCPointer)
                {
                    flags |= (ushort)EETypeFlags.HasPointersFlag;
                }
            }

            if (type.HasInstantiation)
            {
                flags |= (ushort)EETypeFlags.IsGenericFlag;

                if (type.HasVariance)
                {
                    flags |= (ushort)EETypeFlags.GenericVarianceFlag;
                }
            }

            return flags;
        }

        // These masks and paddings have been chosen so that the ValueTypePadding field can always fit in a byte of data
        // if the alignment is 8 bytes or less. If the alignment is higher then there may be a need for more bits to hold
        // the rest of the padding data.
        // If paddings of greater than 7 bytes are necessary, then the high bits of the field represent that padding
        private const uint ValueTypePaddingLowMask = 0x7;
        private const uint ValueTypePaddingHighMask = 0xFFFFFF00;
        private const uint ValueTypePaddingMax = 0x07FFFFFF;
        private const int ValueTypePaddingHighShift = 8;
        private const uint ValueTypePaddingAlignmentMask = 0xF8;
        private const int ValueTypePaddingAlignmentShift = 3;

        /// <summary>
        /// Compute the encoded value type padding and alignment that are stored as optional fields on an
        /// <c>MethodTable</c>. This padding as added to naturally align value types when laid out as fields
        /// of objects on the GCHeap. The amount of padding is recorded to allow unboxing to locals /
        /// arrays of value types which don't need it.
        /// </summary>
        internal static uint ComputeValueTypeFieldPaddingFieldValue(uint padding, uint alignment, int targetPointerSize)
        {
            // For the default case, return 0
            if ((padding == 0) && (alignment == targetPointerSize))
                return 0;

            uint alignmentLog2 = 0;
            Debug.Assert(alignment != 0);

            while ((alignment & 1) == 0)
            {
                alignmentLog2++;
                alignment >>= 1;
            }
            Debug.Assert(alignment == 1);

            Debug.Assert(ValueTypePaddingMax >= padding);

            // Our alignment values here are adjusted by one to allow for a default of 0 (which represents pointer alignment)
            alignmentLog2++;

            uint paddingLowBits = padding & ValueTypePaddingLowMask;
            uint paddingHighBits = ((padding & ~ValueTypePaddingLowMask) >> ValueTypePaddingAlignmentShift) << ValueTypePaddingHighShift;
            uint alignmentLog2Bits = alignmentLog2 << ValueTypePaddingAlignmentShift;
            Debug.Assert((alignmentLog2Bits & ~ValueTypePaddingAlignmentMask) == 0);
            return paddingLowBits | paddingHighBits | alignmentLog2Bits;
        }
    }
}