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
15 typedef uint32_t HALF_SIZE_T;
16 #else   // BIT64
17 typedef uint16_t HALF_SIZE_T;
18 #endif
19 
20 
21 typedef 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 
52 struct val_serie_item
53 {
54     HALF_SIZE_T nptrs;
55     HALF_SIZE_T skip;
set_val_serie_itemval_serie_item56     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 
63 struct val_array_series
64 {
65     val_serie_item  items[1];
66     size_t          m_startOffset;
67     size_t          m_count;
68 };
69 
70 typedef DPTR(class CGCDescSeries) PTR_CGCDescSeries;
71 typedef DPTR(class MethodTable) PTR_MethodTable;
72 class CGCDescSeries
73 {
74 public:
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 
GetSeriesCount()83     size_t GetSeriesCount ()
84     {
85         return seriessize/sizeof(JSlot);
86     }
87 
SetSeriesCount(size_t newcount)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 
GetSeriesSize()98     size_t GetSeriesSize ()
99     {
100         return seriessize;
101     }
102 
SetSeriesSize(size_t newsize)103     void SetSeriesSize (size_t newsize)
104     {
105         seriessize = newsize;
106     }
107 
SetSeriesValItem(val_serie_item item,int index)108     void SetSeriesValItem (val_serie_item item, int index)
109     {
110         val_serie [index] = item;
111     }
112 
SetSeriesOffset(size_t newoffset)113     void SetSeriesOffset (size_t newoffset)
114     {
115         startoffset = newoffset;
116     }
117 
GetSeriesOffset()118     size_t GetSeriesOffset ()
119     {
120         return startoffset;
121     }
122 };
123 
124 
125 
126 
127 
128 typedef DPTR(class CGCDesc) PTR_CGCDesc;
129 class CGCDesc
130 {
131     // Don't construct me, you have to hand me a ptr to the *top* of my storage in Init.
CGCDesc()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     //
138 public:
ComputeSize(size_t NumSeries)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
ComputeSizeRepeating(size_t NumSeries)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
Init(void * mem,size_t NumSeries)156     static void Init (void* mem, size_t NumSeries)
157     {
158         *((size_t*)mem-1) = NumSeries;
159     }
160 
InitValueClassSeries(void * mem,size_t NumSeries)161     static void InitValueClassSeries (void* mem, size_t NumSeries)
162     {
163         *((ptrdiff_t*)mem-1) = -((ptrdiff_t)NumSeries);
164     }
165 #endif
166 
GetCGCDescFromMT(MethodTable * pMT)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 
GetNumSeries()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
GetLowestSeries()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.
GetHighestSeries()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
GetNumPointers(MethodTable * pMT,size_t ObjectSize,size_t NumComponents)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.
GetSize()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 
GetStartOfGCData()245     uint8_t *GetStartOfGCData()
246     {
247         return ((uint8_t *)this) - GetSize();
248     }
249 
250 private:
251 
IsValueClassSeries()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