summaryrefslogtreecommitdiff
path: root/src/gc/gcdesc.h
blob: 7cc132a6407eac2aa4d2f9f7ee6fe9ba739a800b (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
//
// GC Object Pointer Location Series Stuff
//



#ifndef _GCDESC_H_
#define _GCDESC_H_

#ifdef BIT64
typedef uint32_t HALF_SIZE_T;
#else   // BIT64
typedef uint16_t HALF_SIZE_T;
#endif


typedef size_t *JSlot;


//
// These two classes make up the apparatus with which the object references
// within an object can be found.
//
// CGCDescSeries:
//
// The CGCDescSeries class describes a series of object references within an
// object by describing the size of the series (which has an adjustment which
// will be explained later) and the starting point of the series.
//
// The series size is adjusted when the map is created by subtracting the
// GetBaseSize() of the object.   On retieval of the size the total size
// of the object is added back.   For non-array objects the total object
// size is equal to the base size, so this returns the same value.   For
// array objects this will yield the size of the data portion of the array.
// Since arrays containing object references will contain ONLY object references
// this is a fast way of handling arrays and normal objects without a
// conditional test
//
//
//
// CGCDesc:
//
// The CGCDesc is a collection of CGCDescSeries objects to describe all the
// different runs of pointers in a particular object.   <TODO> [add more on the strange
// way the CGCDesc grows backwards in memory behind the MethodTable]
//</TODO>

struct val_serie_item
{
    HALF_SIZE_T nptrs;
    HALF_SIZE_T skip;
    void set_val_serie_item (HALF_SIZE_T nptrs, HALF_SIZE_T skip)
    {
        this->nptrs = nptrs;
        this->skip = skip;
    }
};

struct val_array_series
{
    val_serie_item  items[1];
    size_t          m_startOffset;
    size_t          m_count;
};

typedef DPTR(class CGCDescSeries) PTR_CGCDescSeries;
typedef DPTR(class MethodTable) PTR_MethodTable;
class CGCDescSeries
{
public:
    union 
    {
        size_t seriessize;              // adjusted length of series (see above) in bytes
        val_serie_item val_serie[1];    //coded serie for value class array
    };

    size_t startoffset;

    size_t GetSeriesCount () 
    { 
        return seriessize/sizeof(JSlot); 
    }

    void SetSeriesCount (size_t newcount)
    {
        seriessize = newcount * sizeof(JSlot);
    }

    void IncSeriesCount (size_t increment = 1)
    {
        seriessize += increment * sizeof(JSlot);
    }

    size_t GetSeriesSize ()
    {
        return seriessize;
    }

    void SetSeriesSize (size_t newsize)
    {
        seriessize = newsize;
    }

    void SetSeriesValItem (val_serie_item item, int index)
    {
        val_serie [index] = item;
    }

    void SetSeriesOffset (size_t newoffset)
    {
        startoffset = newoffset;
    }

    size_t GetSeriesOffset ()
    {
        return startoffset;
    }
};





typedef DPTR(class CGCDesc) PTR_CGCDesc;
class CGCDesc
{
    // Don't construct me, you have to hand me a ptr to the *top* of my storage in Init.
    CGCDesc () {}

    //
    // NOTE: for alignment reasons, NumSeries is stored as a size_t.
    //       This makes everything nicely 8-byte aligned on IA64.
    //
public:
    static size_t ComputeSize (size_t NumSeries)
    {
        _ASSERTE (ptrdiff_t(NumSeries) > 0);
        
        return sizeof(size_t) + NumSeries*sizeof(CGCDescSeries);
    }

    // For value type array
    static size_t ComputeSizeRepeating (size_t NumSeries)
    {
        _ASSERTE (ptrdiff_t(NumSeries) > 0);
        
        return sizeof(size_t) + sizeof(CGCDescSeries) +
               (NumSeries-1)*sizeof(val_serie_item);
    }

#ifndef DACCESS_COMPILE
    static void Init (void* mem, size_t NumSeries)
    {
        *((size_t*)mem-1) = NumSeries;
    }

    static void InitValueClassSeries (void* mem, size_t NumSeries)
    {
        *((ptrdiff_t*)mem-1) = -((ptrdiff_t)NumSeries);
    }
#endif

    static PTR_CGCDesc GetCGCDescFromMT (MethodTable * pMT)
    {
        // If it doesn't contain pointers, there isn't a GCDesc
        PTR_MethodTable mt(pMT);

        _ASSERTE(mt->ContainsPointersOrCollectible());

        return PTR_CGCDesc(mt);
    }

    size_t GetNumSeries ()
    {
        return *(PTR_size_t(PTR_CGCDesc(this))-1);
    }

    // Returns lowest series in memory.
    // Cannot be used for valuetype arrays
    PTR_CGCDescSeries GetLowestSeries ()
    {
        _ASSERTE (ptrdiff_t(GetNumSeries()) > 0);
        return PTR_CGCDescSeries(PTR_uint8_t(PTR_CGCDesc(this))
                                 - ComputeSize(GetNumSeries()));
    }

    // Returns highest series in memory.
    PTR_CGCDescSeries GetHighestSeries ()
    {
        return PTR_CGCDescSeries(PTR_size_t(PTR_CGCDesc(this))-1)-1;
    }

    // Returns number of immediate pointers this object has.
    // size is only used if you have an array of value types.
#ifndef DACCESS_COMPILE
    static size_t GetNumPointers (MethodTable* pMT, size_t ObjectSize, size_t NumComponents)
    {
        size_t NumOfPointers = 0;
        CGCDesc* map = GetCGCDescFromMT(pMT);
        CGCDescSeries* cur = map->GetHighestSeries();
        ptrdiff_t cnt = (ptrdiff_t) map->GetNumSeries();

        if (cnt > 0)
        {
            CGCDescSeries* last = map->GetLowestSeries();
            while (cur >= last)
            {
                NumOfPointers += (cur->GetSeriesSize() + ObjectSize) / sizeof(JSlot);
                cur--;
            }
        }
        else
        {
            /* Handle the repeating case - array of valuetypes */
            for (ptrdiff_t __i = 0; __i > cnt; __i--)
            {
                NumOfPointers += cur->val_serie[__i].nptrs;
            }

            NumOfPointers *= NumComponents;
        }

        return NumOfPointers;
    }
#endif

    // Size of the entire slot map.
    size_t GetSize ()
    {
        ptrdiff_t numSeries = (ptrdiff_t) GetNumSeries();
        if (numSeries < 0)
        {
            return ComputeSizeRepeating(-numSeries);
        }
        else
        {
            return ComputeSize(numSeries);
        }
    }

    uint8_t *GetStartOfGCData()
    {
        return ((uint8_t *)this) - GetSize();
    }

private:
    
    BOOL IsValueClassSeries()
    {
        return ((ptrdiff_t) GetNumSeries()) < 0;
    }

};

#define MAX_SIZE_FOR_VALUECLASS_IN_ARRAY 0xffff
#define MAX_PTRS_FOR_VALUECLASSS_IN_ARRAY 0xffff


#endif // _GCDESC_H_