1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5//
6// GC Object Pointer Location Series Stuff
7//
8
9
10
11#ifndef _GCDESC_H_
12#define _GCDESC_H_
13
14#ifdef BIT64
15typedef uint32_t HALF_SIZE_T;
16#else // BIT64
17typedef uint16_t HALF_SIZE_T;
18#endif
19
20
21typedef size_t *JSlot;
22
23
24//
25// These two classes make up the apparatus with which the object references
26// within an object can be found.
27//
28// CGCDescSeries:
29//
30// The CGCDescSeries class describes a series of object references within an
31// object by describing the size of the series (which has an adjustment which
32// will be explained later) and the starting point of the series.
33//
34// The series size is adjusted when the map is created by subtracting the
35// GetBaseSize() of the object. On retieval of the size the total size
36// of the object is added back. For non-array objects the total object
37// size is equal to the base size, so this returns the same value. For
38// array objects this will yield the size of the data portion of the array.
39// Since arrays containing object references will contain ONLY object references
40// this is a fast way of handling arrays and normal objects without a
41// conditional test
42//
43//
44//
45// CGCDesc:
46//
47// The CGCDesc is a collection of CGCDescSeries objects to describe all the
48// different runs of pointers in a particular object. <TODO> [add more on the strange
49// way the CGCDesc grows backwards in memory behind the MethodTable]
50//</TODO>
51
52struct val_serie_item
53{
54 HALF_SIZE_T nptrs;
55 HALF_SIZE_T skip;
56 void set_val_serie_item (HALF_SIZE_T nptrs, HALF_SIZE_T skip)
57 {
58 this->nptrs = nptrs;
59 this->skip = skip;
60 }
61};
62
63struct val_array_series
64{
65 val_serie_item items[1];
66 size_t m_startOffset;
67 size_t m_count;
68};
69
70typedef DPTR(class CGCDescSeries) PTR_CGCDescSeries;
71typedef DPTR(class MethodTable) PTR_MethodTable;
72class CGCDescSeries
73{
74public:
75 union
76 {
77 size_t seriessize; // adjusted length of series (see above) in bytes
78 val_serie_item val_serie[1]; //coded serie for value class array
79 };
80
81 size_t startoffset;
82
83 size_t GetSeriesCount ()
84 {
85 return seriessize/sizeof(JSlot);
86 }
87
88 void SetSeriesCount (size_t newcount)
89 {
90 seriessize = newcount * sizeof(JSlot);
91 }
92
93 void IncSeriesCount (size_t increment = 1)
94 {
95 seriessize += increment * sizeof(JSlot);
96 }
97
98 size_t GetSeriesSize ()
99 {
100 return seriessize;
101 }
102
103 void SetSeriesSize (size_t newsize)
104 {
105 seriessize = newsize;
106 }
107
108 void SetSeriesValItem (val_serie_item item, int index)
109 {
110 val_serie [index] = item;
111 }
112
113 void SetSeriesOffset (size_t newoffset)
114 {
115 startoffset = newoffset;
116 }
117
118 size_t GetSeriesOffset ()
119 {
120 return startoffset;
121 }
122};
123
124
125
126
127
128typedef DPTR(class CGCDesc) PTR_CGCDesc;
129class CGCDesc
130{
131 // Don't construct me, you have to hand me a ptr to the *top* of my storage in Init.
132 CGCDesc () {}
133
134 //
135 // NOTE: for alignment reasons, NumSeries is stored as a size_t.
136 // This makes everything nicely 8-byte aligned on IA64.
137 //
138public:
139 static size_t ComputeSize (size_t NumSeries)
140 {
141 _ASSERTE (ptrdiff_t(NumSeries) > 0);
142
143 return sizeof(size_t) + NumSeries*sizeof(CGCDescSeries);
144 }
145
146 // For value type array
147 static size_t ComputeSizeRepeating (size_t NumSeries)
148 {
149 _ASSERTE (ptrdiff_t(NumSeries) > 0);
150
151 return sizeof(size_t) + sizeof(CGCDescSeries) +
152 (NumSeries-1)*sizeof(val_serie_item);
153 }
154
155#ifndef DACCESS_COMPILE
156 static void Init (void* mem, size_t NumSeries)
157 {
158 *((size_t*)mem-1) = NumSeries;
159 }
160
161 static void InitValueClassSeries (void* mem, size_t NumSeries)
162 {
163 *((ptrdiff_t*)mem-1) = -((ptrdiff_t)NumSeries);
164 }
165#endif
166
167 static PTR_CGCDesc GetCGCDescFromMT (MethodTable * pMT)
168 {
169 // If it doesn't contain pointers, there isn't a GCDesc
170 PTR_MethodTable mt(pMT);
171
172 _ASSERTE(mt->ContainsPointersOrCollectible());
173
174 return PTR_CGCDesc(mt);
175 }
176
177 size_t GetNumSeries ()
178 {
179 return *(PTR_size_t(PTR_CGCDesc(this))-1);
180 }
181
182 // Returns lowest series in memory.
183 // Cannot be used for valuetype arrays
184 PTR_CGCDescSeries GetLowestSeries ()
185 {
186 _ASSERTE (ptrdiff_t(GetNumSeries()) > 0);
187 return PTR_CGCDescSeries(PTR_uint8_t(PTR_CGCDesc(this))
188 - ComputeSize(GetNumSeries()));
189 }
190
191 // Returns highest series in memory.
192 PTR_CGCDescSeries GetHighestSeries ()
193 {
194 return PTR_CGCDescSeries(PTR_size_t(PTR_CGCDesc(this))-1)-1;
195 }
196
197 // Returns number of immediate pointers this object has.
198 // size is only used if you have an array of value types.
199#ifndef DACCESS_COMPILE
200 static size_t GetNumPointers (MethodTable* pMT, size_t ObjectSize, size_t NumComponents)
201 {
202 size_t NumOfPointers = 0;
203 CGCDesc* map = GetCGCDescFromMT(pMT);
204 CGCDescSeries* cur = map->GetHighestSeries();
205 ptrdiff_t cnt = (ptrdiff_t) map->GetNumSeries();
206
207 if (cnt > 0)
208 {
209 CGCDescSeries* last = map->GetLowestSeries();
210 while (cur >= last)
211 {
212 NumOfPointers += (cur->GetSeriesSize() + ObjectSize) / sizeof(JSlot);
213 cur--;
214 }
215 }
216 else
217 {
218 /* Handle the repeating case - array of valuetypes */
219 for (ptrdiff_t __i = 0; __i > cnt; __i--)
220 {
221 NumOfPointers += cur->val_serie[__i].nptrs;
222 }
223
224 NumOfPointers *= NumComponents;
225 }
226
227 return NumOfPointers;
228 }
229#endif
230
231 // Size of the entire slot map.
232 size_t GetSize ()
233 {
234 ptrdiff_t numSeries = (ptrdiff_t) GetNumSeries();
235 if (numSeries < 0)
236 {
237 return ComputeSizeRepeating(-numSeries);
238 }
239 else
240 {
241 return ComputeSize(numSeries);
242 }
243 }
244
245 uint8_t *GetStartOfGCData()
246 {
247 return ((uint8_t *)this) - GetSize();
248 }
249
250private:
251
252 BOOL IsValueClassSeries()
253 {
254 return ((ptrdiff_t) GetNumSeries()) < 0;
255 }
256
257};
258
259#define MAX_SIZE_FOR_VALUECLASS_IN_ARRAY 0xffff
260#define MAX_PTRS_FOR_VALUECLASSS_IN_ARRAY 0xffff
261
262
263#endif // _GCDESC_H_
264