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