| 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 | // COM+ Data Field Abstraction |
| 7 | // |
| 8 | |
| 9 | |
| 10 | #ifndef _FIELD_H_ |
| 11 | #define _FIELD_H_ |
| 12 | |
| 13 | #include "excep.h" |
| 14 | |
| 15 | // Temporary values stored in FieldDesc m_dwOffset during loading |
| 16 | // The high 5 bits must be zero (because in field.h we steal them for other uses), so we must choose values > 0 |
| 17 | #define FIELD_OFFSET_MAX ((1<<27)-1) |
| 18 | #define FIELD_OFFSET_UNPLACED FIELD_OFFSET_MAX |
| 19 | #define FIELD_OFFSET_UNPLACED_GC_PTR (FIELD_OFFSET_MAX-1) |
| 20 | #define FIELD_OFFSET_VALUE_CLASS (FIELD_OFFSET_MAX-2) |
| 21 | #define FIELD_OFFSET_NOT_REAL_FIELD (FIELD_OFFSET_MAX-3) |
| 22 | |
| 23 | // Offset to indicate an EnC added field. They don't have offsets as aren't placed in the object. |
| 24 | #define FIELD_OFFSET_NEW_ENC (FIELD_OFFSET_MAX-4) |
| 25 | #define FIELD_OFFSET_BIG_RVA (FIELD_OFFSET_MAX-5) |
| 26 | #define FIELD_OFFSET_LAST_REAL_OFFSET (FIELD_OFFSET_MAX-6) // real fields have to be smaller than this |
| 27 | |
| 28 | |
| 29 | // |
| 30 | // This describes a field - one of this is allocated for every field, so don't make this structure any larger. |
| 31 | // |
| 32 | // @GENERICS: |
| 33 | // Field descriptors for fields in instantiated types may be shared between compatible instantiations |
| 34 | // Hence for reflection it's necessary to pair a field desc with the exact owning type handle |
| 35 | class FieldDesc |
| 36 | { |
| 37 | friend class MethodTableBuilder; |
| 38 | #ifdef DACCESS_COMPILE |
| 39 | friend class NativeImageDumper; |
| 40 | #endif |
| 41 | |
| 42 | protected: |
| 43 | RelativePointer<PTR_MethodTable> m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck. |
| 44 | |
| 45 | // See also: FieldDesc::InitializeFrom method |
| 46 | |
| 47 | #if defined(DACCESS_COMPILE) |
| 48 | union { //create a union so I can get the correct offset for ClrDump. |
| 49 | unsigned m_dword1; |
| 50 | struct { |
| 51 | #endif |
| 52 | // Note that we may store other information in the high bits if available -- |
| 53 | // see enum_packedMBLayout and m_requiresFullMbValue for details. |
| 54 | unsigned m_mb : 24; |
| 55 | |
| 56 | // 8 bits... |
| 57 | unsigned m_isStatic : 1; |
| 58 | unsigned m_isThreadLocal : 1; |
| 59 | unsigned m_isRVA : 1; |
| 60 | unsigned m_prot : 3; |
| 61 | // Does this field's mb require all 24 bits |
| 62 | unsigned m_requiresFullMbValue : 1; |
| 63 | #if defined(DACCESS_COMPILE) |
| 64 | }; |
| 65 | }; |
| 66 | #endif |
| 67 | |
| 68 | #if defined(DACCESS_COMPILE) |
| 69 | union { //create a union so I can get the correct offset for ClrDump |
| 70 | unsigned m_dword2; |
| 71 | struct { |
| 72 | #endif |
| 73 | // Note: this has been as low as 22 bits in the past & seemed to be OK. |
| 74 | // we can steal some more bits here if we need them. |
| 75 | unsigned m_dwOffset : 27; |
| 76 | unsigned m_type : 5; |
| 77 | #if defined(DACCESS_COMPILE) |
| 78 | }; |
| 79 | }; |
| 80 | #endif |
| 81 | |
| 82 | #ifdef _DEBUG |
| 83 | LPUTF8 m_debugName; |
| 84 | #endif |
| 85 | |
| 86 | public: |
| 87 | // Allocated by special heap means, don't construct me |
| 88 | FieldDesc() =delete; |
| 89 | |
| 90 | #ifndef DACCESS_COMPILE |
| 91 | void InitializeFrom(const FieldDesc& sourceField, MethodTable *pMT) |
| 92 | { |
| 93 | m_pMTOfEnclosingClass.SetValue(pMT); |
| 94 | |
| 95 | m_mb = sourceField.m_mb; |
| 96 | m_isStatic = sourceField.m_isStatic; |
| 97 | m_isThreadLocal = sourceField.m_isThreadLocal; |
| 98 | m_isRVA = sourceField.m_isRVA; |
| 99 | m_prot = sourceField.m_prot; |
| 100 | m_requiresFullMbValue = sourceField.m_requiresFullMbValue; |
| 101 | |
| 102 | m_dwOffset = sourceField.m_dwOffset; |
| 103 | m_type = sourceField.m_type; |
| 104 | |
| 105 | #ifdef _DEBUG |
| 106 | m_debugName = sourceField.m_debugName; |
| 107 | #endif // _DEBUG |
| 108 | } |
| 109 | #endif // !DACCESS_COMPILE |
| 110 | |
| 111 | #ifdef _DEBUG |
| 112 | inline LPUTF8 GetDebugName() |
| 113 | { |
| 114 | LIMITED_METHOD_CONTRACT; |
| 115 | return m_debugName; |
| 116 | } |
| 117 | #endif // _DEBUG |
| 118 | |
| 119 | #ifndef DACCESS_COMPILE |
| 120 | // This should be called. It was added so that Reflection |
| 121 | // can create FieldDesc's for the static primitive fields that aren't |
| 122 | // stored with the EEClass. |
| 123 | void SetMethodTable(MethodTable* mt) |
| 124 | { |
| 125 | LIMITED_METHOD_CONTRACT; |
| 126 | m_pMTOfEnclosingClass.SetValue(mt); |
| 127 | } |
| 128 | #endif |
| 129 | |
| 130 | VOID Init(mdFieldDef mb, |
| 131 | CorElementType FieldType, |
| 132 | DWORD dwMemberAttrs, |
| 133 | BOOL fIsStatic, |
| 134 | BOOL fIsRVA, |
| 135 | BOOL fIsThreadLocal, |
| 136 | LPCSTR pszFieldName); |
| 137 | |
| 138 | enum { |
| 139 | enum_packedMbLayout_MbMask = 0x01FFFF, |
| 140 | enum_packedMbLayout_NameHashMask = 0xFE0000 |
| 141 | }; |
| 142 | |
| 143 | void SetMemberDef(mdFieldDef mb) |
| 144 | { |
| 145 | WRAPPER_NO_CONTRACT; |
| 146 | |
| 147 | // Check if we have to avoid using the packed mb layout |
| 148 | if (RidFromToken(mb) > enum_packedMbLayout_MbMask) |
| 149 | { |
| 150 | m_requiresFullMbValue = 1; |
| 151 | } |
| 152 | |
| 153 | // Set only the portion of m_mb we are using |
| 154 | if (!m_requiresFullMbValue) |
| 155 | { |
| 156 | m_mb &= ~enum_packedMbLayout_MbMask; |
| 157 | m_mb |= RidFromToken(mb); |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | m_mb = RidFromToken(mb); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | mdFieldDef GetMemberDef() const |
| 166 | { |
| 167 | LIMITED_METHOD_DAC_CONTRACT; |
| 168 | |
| 169 | // Check if this FieldDesc is using the packed mb layout |
| 170 | if (!m_requiresFullMbValue) |
| 171 | { |
| 172 | return TokenFromRid(m_mb & enum_packedMbLayout_MbMask, mdtFieldDef); |
| 173 | } |
| 174 | |
| 175 | return TokenFromRid(m_mb, mdtFieldDef); |
| 176 | } |
| 177 | |
| 178 | CorElementType GetFieldType() |
| 179 | { |
| 180 | LIMITED_METHOD_DAC_CONTRACT; |
| 181 | |
| 182 | // Set in code:FieldDesc.Init which in turn is called from |
| 183 | // code:MethodTableBuilder.InitializeFieldDescs#InitCall which in turn calls |
| 184 | // code:MethodTableBuilder.InitializeFieldDescs#FieldDescTypeMorph |
| 185 | return (CorElementType) m_type; |
| 186 | } |
| 187 | |
| 188 | DWORD GetFieldProtection() |
| 189 | { |
| 190 | LIMITED_METHOD_CONTRACT; |
| 191 | |
| 192 | // Set in code:FieldDesc.Init which in turn is called from code:MethodTableBuilder::InitializeFieldDescs#InitCall |
| 193 | return m_prot; |
| 194 | } |
| 195 | |
| 196 | // Please only use this in a path that you have already guarenteed |
| 197 | // the assert is true |
| 198 | DWORD GetOffsetUnsafe() |
| 199 | { |
| 200 | LIMITED_METHOD_CONTRACT; |
| 201 | |
| 202 | g_IBCLogger.LogFieldDescsAccess(this); |
| 203 | _ASSERTE(m_dwOffset <= FIELD_OFFSET_LAST_REAL_OFFSET); |
| 204 | return m_dwOffset; |
| 205 | } |
| 206 | |
| 207 | DWORD GetOffset() |
| 208 | { |
| 209 | LIMITED_METHOD_DAC_CONTRACT; |
| 210 | g_IBCLogger.LogFieldDescsAccess(this); |
| 211 | return GetOffset_NoLogging(); |
| 212 | } |
| 213 | |
| 214 | // During class load m_pMTOfEnclosingClass has the field size in it, so it has to use this version of |
| 215 | // GetOffset during that time |
| 216 | DWORD GetOffset_NoLogging() |
| 217 | { |
| 218 | LIMITED_METHOD_DAC_CONTRACT; |
| 219 | |
| 220 | // Note FieldDescs are no longer on "hot" paths so the optimized code here |
| 221 | // does not look necessary. |
| 222 | |
| 223 | if (m_dwOffset != FIELD_OFFSET_BIG_RVA) { |
| 224 | // Assert that the big RVA case handling doesn't get out of sync |
| 225 | // with the normal RVA case. |
| 226 | #ifdef _DEBUG |
| 227 | // The OutOfLine_BigRVAOffset() can't be correctly evaluated during the time |
| 228 | // that we repurposed m_pMTOfEnclosingClass for holding the field size |
| 229 | // I don't see any good way to determine when this is so hurray for |
| 230 | // heuristics! |
| 231 | // |
| 232 | // As of 4/11/2012 I could repro this by turning on the COMPLUS log and |
| 233 | // the LOG() at line methodtablebuilder.cpp:7845 |
| 234 | // MethodTableBuilder::PlaceRegularStaticFields() calls GetOffset_NoLogging() |
| 235 | if((DWORD)(DWORD_PTR&)m_pMTOfEnclosingClass > 16) |
| 236 | { |
| 237 | _ASSERTE(!this->IsRVA() || (m_dwOffset == OutOfLine_BigRVAOffset())); |
| 238 | } |
| 239 | #endif |
| 240 | return m_dwOffset; |
| 241 | } |
| 242 | |
| 243 | return OutOfLine_BigRVAOffset(); |
| 244 | } |
| 245 | |
| 246 | DWORD OutOfLine_BigRVAOffset() |
| 247 | { |
| 248 | LIMITED_METHOD_DAC_CONTRACT; |
| 249 | |
| 250 | DWORD rva; |
| 251 | |
| 252 | // <NICE>I'm discarding a potential error here. According to the code in MDInternalRO.cpp, |
| 253 | // we won't get an error if we initially found the RVA. So I'm going to just |
| 254 | // assert it never happens. |
| 255 | // |
| 256 | // This is a small sin, but I don't see a good alternative. --cwb.</NICE> |
| 257 | HRESULT hr; |
| 258 | hr = GetMDImport()->GetFieldRVA(GetMemberDef(), &rva); |
| 259 | _ASSERTE(SUCCEEDED(hr)); |
| 260 | return rva; |
| 261 | } |
| 262 | |
| 263 | HRESULT SetOffset(DWORD dwOffset) |
| 264 | { |
| 265 | LIMITED_METHOD_CONTRACT; |
| 266 | |
| 267 | // |
| 268 | // value class fields must be aligned to pointer-sized boundaries |
| 269 | // |
| 270 | // |
| 271 | // This is commented out because it isn't valid in all cases. |
| 272 | // This is still here because it is useful for finding alignment |
| 273 | // problems on IA64. |
| 274 | // |
| 275 | //_ASSERTE((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) || |
| 276 | // (ELEMENT_TYPE_VALUETYPE != GetFieldType()) || |
| 277 | // (IS_ALIGNED(dwOffset, sizeof(void*)))); |
| 278 | |
| 279 | m_dwOffset = dwOffset; |
| 280 | return((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) ? COR_E_TYPELOAD : S_OK); |
| 281 | } |
| 282 | |
| 283 | // Okay, we've stolen too many bits from FieldDescs. In the RVA case, there's no |
| 284 | // reason to believe they will be limited to 22 bits. So use a sentinel for the |
| 285 | // huge cases, and recover them from metadata on-demand. |
| 286 | void SetOffsetRVA(DWORD dwOffset) |
| 287 | { |
| 288 | LIMITED_METHOD_CONTRACT; |
| 289 | |
| 290 | m_dwOffset = (dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) |
| 291 | ? FIELD_OFFSET_BIG_RVA |
| 292 | : dwOffset; |
| 293 | } |
| 294 | |
| 295 | DWORD IsStatic() const |
| 296 | { |
| 297 | LIMITED_METHOD_DAC_CONTRACT; |
| 298 | |
| 299 | return m_isStatic; |
| 300 | } |
| 301 | |
| 302 | BOOL IsSpecialStatic() |
| 303 | { |
| 304 | LIMITED_METHOD_CONTRACT; |
| 305 | |
| 306 | return m_isStatic && (m_isRVA || m_isThreadLocal |
| 307 | ); |
| 308 | } |
| 309 | |
| 310 | BOOL IsRVA() const // Has an explicit RVA associated with it |
| 311 | { |
| 312 | LIMITED_METHOD_DAC_CONTRACT; |
| 313 | |
| 314 | return m_isRVA; |
| 315 | } |
| 316 | |
| 317 | BOOL IsThreadStatic() const // Static relative to a thread |
| 318 | { |
| 319 | LIMITED_METHOD_DAC_CONTRACT; |
| 320 | |
| 321 | return m_isThreadLocal; |
| 322 | } |
| 323 | |
| 324 | // Indicate that this field was added by EnC |
| 325 | // Must only be called on instances of EnCFieldDesc |
| 326 | void SetEnCNew() |
| 327 | { |
| 328 | WRAPPER_NO_CONTRACT; |
| 329 | |
| 330 | // EnC added fields don't live in the actual object, so don't have a real offset |
| 331 | SetOffset(FIELD_OFFSET_NEW_ENC); |
| 332 | } |
| 333 | |
| 334 | // Was this field added by EnC? |
| 335 | // If this is true, then this object is an instance of EnCFieldDesc |
| 336 | BOOL IsEnCNew() |
| 337 | { |
| 338 | LIMITED_METHOD_DAC_CONTRACT; |
| 339 | |
| 340 | // EnC added fields don't have a real offset |
| 341 | return m_dwOffset == FIELD_OFFSET_NEW_ENC; |
| 342 | } |
| 343 | |
| 344 | BOOL IsByValue() |
| 345 | { |
| 346 | LIMITED_METHOD_DAC_CONTRACT; |
| 347 | |
| 348 | return GetFieldType() == ELEMENT_TYPE_VALUETYPE; |
| 349 | } |
| 350 | |
| 351 | BOOL IsPrimitive() |
| 352 | { |
| 353 | LIMITED_METHOD_DAC_CONTRACT; |
| 354 | |
| 355 | return (CorIsPrimitiveType(GetFieldType()) != FALSE); |
| 356 | } |
| 357 | |
| 358 | BOOL IsObjRef(); |
| 359 | |
| 360 | #ifdef FEATURE_PREJIT |
| 361 | void SaveContents(DataImage *image); |
| 362 | void Fixup(DataImage *image); |
| 363 | #endif // FEATURE_PREJIT |
| 364 | |
| 365 | UINT LoadSize(); |
| 366 | |
| 367 | // Return -1 if the type isn't loaded yet (i.e. if LookupFieldTypeHandle() would return null) |
| 368 | UINT GetSize(); |
| 369 | |
| 370 | // These routines encapsulate the operation of getting and setting |
| 371 | // fields. |
| 372 | void GetInstanceField(OBJECTREF o, VOID * pOutVal); |
| 373 | void SetInstanceField(OBJECTREF o, const VOID * pInVal); |
| 374 | |
| 375 | void* GetInstanceAddress(OBJECTREF o); |
| 376 | |
| 377 | // Get the address of a field within object 'o' |
| 378 | PTR_VOID GetAddress(PTR_VOID o); |
| 379 | |
| 380 | PTR_VOID GetAddressNoThrowNoGC(PTR_VOID o); |
| 381 | void* GetAddressGuaranteedInHeap(void *o); |
| 382 | |
| 383 | void* GetValuePtr(OBJECTREF o); |
| 384 | VOID SetValuePtr(OBJECTREF o, void* pValue); |
| 385 | DWORD GetValue32(OBJECTREF o); |
| 386 | VOID SetValue32(OBJECTREF o, DWORD dwValue); |
| 387 | OBJECTREF GetRefValue(OBJECTREF o); |
| 388 | VOID SetRefValue(OBJECTREF o, OBJECTREF orValue); |
| 389 | USHORT GetValue16(OBJECTREF o); |
| 390 | VOID SetValue16(OBJECTREF o, DWORD dwValue); |
| 391 | BYTE GetValue8(OBJECTREF o); |
| 392 | VOID SetValue8(OBJECTREF o, DWORD dwValue); |
| 393 | __int64 GetValue64(OBJECTREF o); |
| 394 | VOID SetValue64(OBJECTREF o, __int64 value); |
| 395 | |
| 396 | PTR_MethodTable GetApproxEnclosingMethodTable_NoLogging() |
| 397 | { |
| 398 | LIMITED_METHOD_DAC_CONTRACT; |
| 399 | return m_pMTOfEnclosingClass.GetValue(PTR_HOST_MEMBER_TADDR(FieldDesc, this, m_pMTOfEnclosingClass)); |
| 400 | } |
| 401 | |
| 402 | PTR_MethodTable GetApproxEnclosingMethodTable() |
| 403 | { |
| 404 | LIMITED_METHOD_DAC_CONTRACT; |
| 405 | g_IBCLogger.LogFieldDescsAccess(this); |
| 406 | return GetApproxEnclosingMethodTable_NoLogging(); |
| 407 | } |
| 408 | |
| 409 | PTR_MethodTable GetEnclosingMethodTable() |
| 410 | { |
| 411 | LIMITED_METHOD_DAC_CONTRACT; |
| 412 | _ASSERTE(!IsSharedByGenericInstantiations()); |
| 413 | return GetApproxEnclosingMethodTable(); |
| 414 | } |
| 415 | |
| 416 | // FieldDesc can be shared between generic instantiations. So List<String>._items |
| 417 | // is really the same as List<__Canon>._items. Hence, the FieldDesc itself |
| 418 | // cannot know the exact enclosing type. You need to provide the exact owner |
| 419 | // like List<String> or a subtype like MyInheritedList<String>. |
| 420 | MethodTable * GetExactDeclaringType(MethodTable * ownerOrSubType); |
| 421 | |
| 422 | BOOL IsSharedByGenericInstantiations() |
| 423 | { |
| 424 | LIMITED_METHOD_DAC_CONTRACT; |
| 425 | return (!IsStatic()) && GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations(); |
| 426 | } |
| 427 | |
| 428 | BOOL IsFieldOfValueType() |
| 429 | { |
| 430 | WRAPPER_NO_CONTRACT; |
| 431 | return GetApproxEnclosingMethodTable()->IsValueType(); |
| 432 | } |
| 433 | |
| 434 | DWORD GetNumGenericClassArgs() |
| 435 | { |
| 436 | WRAPPER_NO_CONTRACT; |
| 437 | return GetApproxEnclosingMethodTable()->GetNumGenericArgs(); |
| 438 | } |
| 439 | |
| 440 | PTR_BYTE GetBaseInDomainLocalModule(DomainLocalModule * pLocalModule) |
| 441 | { |
| 442 | WRAPPER_NO_CONTRACT; |
| 443 | |
| 444 | if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE) |
| 445 | { |
| 446 | return pLocalModule->GetGCStaticsBasePointer(GetEnclosingMethodTable()); |
| 447 | } |
| 448 | else |
| 449 | { |
| 450 | return pLocalModule->GetNonGCStaticsBasePointer(GetEnclosingMethodTable()); |
| 451 | } |
| 452 | } |
| 453 | |
| 454 | #ifndef DACCESS_COMPILE |
| 455 | PTR_BYTE GetBase() |
| 456 | { |
| 457 | CONTRACTL |
| 458 | { |
| 459 | THROWS; |
| 460 | GC_TRIGGERS; |
| 461 | INJECT_FAULT(COMPlusThrowOM()); |
| 462 | } |
| 463 | CONTRACTL_END |
| 464 | |
| 465 | MethodTable *pMT = GetEnclosingMethodTable(); |
| 466 | |
| 467 | return GetBaseInDomainLocalModule(pMT->GetDomainLocalModule()); |
| 468 | } |
| 469 | |
| 470 | #endif //!DACCESS_COMPILE |
| 471 | |
| 472 | PTR_BYTE GetBaseInDomain(AppDomain * appDomain) |
| 473 | { |
| 474 | CONTRACTL |
| 475 | { |
| 476 | NOTHROW; |
| 477 | GC_NOTRIGGER; |
| 478 | } |
| 479 | CONTRACTL_END; |
| 480 | |
| 481 | Module *pModule = GetEnclosingMethodTable()->GetModuleForStatics(); |
| 482 | if (pModule == NULL) |
| 483 | return NULL; |
| 484 | |
| 485 | DomainLocalModule *pLocalModule = pModule->GetDomainLocalModule(appDomain); |
| 486 | if (pLocalModule == NULL) |
| 487 | return NULL; |
| 488 | |
| 489 | return GetBaseInDomainLocalModule(pLocalModule); |
| 490 | } |
| 491 | |
| 492 | // returns the address of the field |
| 493 | void* GetStaticAddress(void *base); |
| 494 | |
| 495 | // In all cases except Value classes, the AddressHandle is |
| 496 | // simply the address of the static. For the case of value |
| 497 | // types, however, it is the address of OBJECTREF that holds |
| 498 | // the boxed value used to hold the value type. This is needed |
| 499 | // because the OBJECTREF moves, and the JIT needs to embed something |
| 500 | // in the code that does not move. Thus the jit has to |
| 501 | // dereference and unbox before the access. |
| 502 | PTR_VOID GetStaticAddressHandle(PTR_VOID base); |
| 503 | |
| 504 | #ifndef DACCESS_COMPILE |
| 505 | OBJECTREF GetStaticOBJECTREF() |
| 506 | { |
| 507 | WRAPPER_NO_CONTRACT; |
| 508 | return *(OBJECTREF *)GetCurrentStaticAddress(); |
| 509 | } |
| 510 | |
| 511 | VOID SetStaticOBJECTREF(OBJECTREF objRef) |
| 512 | { |
| 513 | CONTRACTL |
| 514 | { |
| 515 | THROWS; |
| 516 | GC_TRIGGERS; |
| 517 | MODE_COOPERATIVE; |
| 518 | INJECT_FAULT(COMPlusThrowOM()); |
| 519 | } |
| 520 | CONTRACTL_END |
| 521 | |
| 522 | GCPROTECT_BEGIN(objRef); |
| 523 | OBJECTREF *pObjRef = (OBJECTREF *)GetCurrentStaticAddress(); |
| 524 | SetObjectReference(pObjRef, objRef, GetAppDomain()); |
| 525 | GCPROTECT_END(); |
| 526 | } |
| 527 | |
| 528 | void* GetStaticValuePtr() |
| 529 | { |
| 530 | WRAPPER_NO_CONTRACT; |
| 531 | return *(void**)GetCurrentStaticAddress(); |
| 532 | } |
| 533 | |
| 534 | VOID SetStaticValuePtr(void *value) |
| 535 | { |
| 536 | WRAPPER_NO_CONTRACT; |
| 537 | *(void**)GetCurrentStaticAddress() = value; |
| 538 | } |
| 539 | |
| 540 | DWORD GetStaticValue32() |
| 541 | { |
| 542 | WRAPPER_NO_CONTRACT; |
| 543 | return *(DWORD*)GetCurrentStaticAddress(); |
| 544 | } |
| 545 | |
| 546 | VOID SetStaticValue32(DWORD dwValue) |
| 547 | { |
| 548 | WRAPPER_NO_CONTRACT; |
| 549 | *(DWORD*)GetCurrentStaticAddress() = dwValue; |
| 550 | } |
| 551 | |
| 552 | USHORT GetStaticValue16() |
| 553 | { |
| 554 | WRAPPER_NO_CONTRACT; |
| 555 | return *(USHORT*)GetCurrentStaticAddress(); |
| 556 | } |
| 557 | |
| 558 | VOID SetStaticValue16(DWORD dwValue) |
| 559 | { |
| 560 | WRAPPER_NO_CONTRACT; |
| 561 | *(USHORT*)GetCurrentStaticAddress() = (USHORT)dwValue; |
| 562 | } |
| 563 | |
| 564 | BYTE GetStaticValue8() |
| 565 | { |
| 566 | WRAPPER_NO_CONTRACT; |
| 567 | return *(BYTE*)GetCurrentStaticAddress(); |
| 568 | } |
| 569 | |
| 570 | VOID SetStaticValue8(DWORD dwValue) |
| 571 | { |
| 572 | WRAPPER_NO_CONTRACT; |
| 573 | *(BYTE*)GetCurrentStaticAddress() = (BYTE)dwValue; |
| 574 | } |
| 575 | |
| 576 | __int64 GetStaticValue64() |
| 577 | { |
| 578 | WRAPPER_NO_CONTRACT; |
| 579 | return *(__int64*)GetCurrentStaticAddress(); |
| 580 | } |
| 581 | |
| 582 | VOID SetStaticValue64(__int64 qwValue) |
| 583 | { |
| 584 | WRAPPER_NO_CONTRACT; |
| 585 | *(__int64*)GetCurrentStaticAddress() = qwValue; |
| 586 | } |
| 587 | |
| 588 | void* GetCurrentStaticAddress() |
| 589 | { |
| 590 | CONTRACTL |
| 591 | { |
| 592 | THROWS; |
| 593 | GC_TRIGGERS; |
| 594 | MODE_COOPERATIVE; |
| 595 | INJECT_FAULT(COMPlusThrowOM()); |
| 596 | } |
| 597 | CONTRACTL_END |
| 598 | |
| 599 | _ASSERTE(IsStatic()); |
| 600 | |
| 601 | if (IsThreadStatic()) |
| 602 | { |
| 603 | return Thread::GetStaticFieldAddress(this); |
| 604 | } |
| 605 | else { |
| 606 | PTR_BYTE base = 0; |
| 607 | if (!IsRVA()) // for RVA the base is ignored |
| 608 | base = GetBase(); |
| 609 | return GetStaticAddress((void *)dac_cast<TADDR>(base)); |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | VOID CheckRunClassInitThrowing() |
| 614 | { |
| 615 | CONTRACTL |
| 616 | { |
| 617 | THROWS; |
| 618 | GC_TRIGGERS; |
| 619 | INJECT_FAULT(COMPlusThrowOM()); |
| 620 | } |
| 621 | CONTRACTL_END; |
| 622 | |
| 623 | GetEnclosingMethodTable()->CheckRunClassInitThrowing(); |
| 624 | } |
| 625 | #endif //DACCESS_COMPILE |
| 626 | |
| 627 | Module *GetModule() |
| 628 | { |
| 629 | LIMITED_METHOD_DAC_CONTRACT; |
| 630 | |
| 631 | return GetApproxEnclosingMethodTable()->GetModule(); |
| 632 | } |
| 633 | |
| 634 | BOOL IsZapped() |
| 635 | { |
| 636 | WRAPPER_NO_CONTRACT; |
| 637 | |
| 638 | // Field Desc's are currently always saved into the same module as their |
| 639 | // corresponding method table. |
| 640 | return GetApproxEnclosingMethodTable()->IsZapped(); |
| 641 | } |
| 642 | |
| 643 | Module *GetLoaderModule() |
| 644 | { |
| 645 | WRAPPER_NO_CONTRACT; |
| 646 | |
| 647 | // Field Desc's are currently always saved into the same module as their |
| 648 | // corresponding method table. |
| 649 | return GetApproxEnclosingMethodTable()->GetLoaderModule(); |
| 650 | } |
| 651 | |
| 652 | void GetSig(PCCOR_SIGNATURE *ppSig, DWORD *pcSig) |
| 653 | { |
| 654 | CONTRACTL |
| 655 | { |
| 656 | NOTHROW; |
| 657 | GC_NOTRIGGER; |
| 658 | MODE_ANY; |
| 659 | SO_TOLERANT; |
| 660 | } |
| 661 | CONTRACTL_END |
| 662 | |
| 663 | if (FAILED(GetMDImport()->GetSigOfFieldDef(GetMemberDef(), pcSig, ppSig))) |
| 664 | { // Class loader already asked for signature, so this should always succeed (unless there's a |
| 665 | // bug or a new code path) |
| 666 | _ASSERTE(!"If this ever fires, then this method should return HRESULT" ); |
| 667 | *ppSig = NULL; |
| 668 | *pcSig = 0; |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | SigPointer GetSigPointer() |
| 673 | { |
| 674 | WRAPPER_NO_CONTRACT; |
| 675 | |
| 676 | PCCOR_SIGNATURE pSig; |
| 677 | DWORD cSig; |
| 678 | |
| 679 | GetSig(&pSig, &cSig); |
| 680 | |
| 681 | return SigPointer(pSig, cSig); |
| 682 | } |
| 683 | |
| 684 | // This is slow (uses MetaData), don't use it! |
| 685 | LPCUTF8 GetName() |
| 686 | { |
| 687 | CONTRACTL |
| 688 | { |
| 689 | THROWS; |
| 690 | GC_NOTRIGGER; |
| 691 | MODE_ANY; |
| 692 | } |
| 693 | CONTRACTL_END |
| 694 | |
| 695 | LPCSTR szName; |
| 696 | IfFailThrow(GetMDImport()->GetNameOfFieldDef(GetMemberDef(), &szName)); |
| 697 | _ASSERTE(szName != NULL); |
| 698 | return szName; |
| 699 | } |
| 700 | // This is slow (uses MetaData), don't use it! |
| 701 | __checkReturn |
| 702 | HRESULT GetName_NoThrow(LPCUTF8 *pszName) |
| 703 | { |
| 704 | CONTRACTL |
| 705 | { |
| 706 | NOTHROW; |
| 707 | GC_NOTRIGGER; |
| 708 | MODE_ANY; |
| 709 | SO_TOLERANT; |
| 710 | } |
| 711 | CONTRACTL_END |
| 712 | |
| 713 | return GetMDImport()->GetNameOfFieldDef(GetMemberDef(), pszName); |
| 714 | } |
| 715 | |
| 716 | void PrecomputeNameHash(); |
| 717 | BOOL MightHaveName(ULONG nameHashValue); |
| 718 | |
| 719 | // <TODO>@TODO: </TODO>This is slow, don't use it! |
| 720 | DWORD GetAttributes() |
| 721 | { |
| 722 | CONTRACTL |
| 723 | { |
| 724 | NOTHROW; |
| 725 | GC_NOTRIGGER; |
| 726 | MODE_ANY; |
| 727 | SO_TOLERANT; |
| 728 | } |
| 729 | CONTRACTL_END |
| 730 | |
| 731 | DWORD dwAttributes; |
| 732 | if (FAILED(GetMDImport()->GetFieldDefProps(GetMemberDef(), &dwAttributes))) |
| 733 | { // Class loader already asked for attributes, so this should always succeed (unless there's a |
| 734 | // bug or a new code path) |
| 735 | _ASSERTE(!"If this ever fires, then this method should return HRESULT" ); |
| 736 | return 0; |
| 737 | } |
| 738 | return dwAttributes; |
| 739 | } |
| 740 | |
| 741 | // Mini-Helpers |
| 742 | DWORD IsPublic() |
| 743 | { |
| 744 | WRAPPER_NO_CONTRACT; |
| 745 | |
| 746 | return IsFdPublic(GetFieldProtection()); |
| 747 | } |
| 748 | |
| 749 | DWORD IsProtected() |
| 750 | { |
| 751 | WRAPPER_NO_CONTRACT; |
| 752 | return IsFdFamily(GetFieldProtection()); |
| 753 | } |
| 754 | |
| 755 | DWORD IsPrivate() |
| 756 | { |
| 757 | WRAPPER_NO_CONTRACT; |
| 758 | |
| 759 | return IsFdPrivate(GetFieldProtection()); |
| 760 | } |
| 761 | |
| 762 | IMDInternalImport *GetMDImport() |
| 763 | { |
| 764 | LIMITED_METHOD_DAC_CONTRACT; |
| 765 | |
| 766 | return GetModule()->GetMDImport(); |
| 767 | } |
| 768 | |
| 769 | #ifndef DACCESS_COMPILE |
| 770 | IMetaDataImport *GetRWImporter() |
| 771 | { |
| 772 | WRAPPER_NO_CONTRACT; |
| 773 | |
| 774 | return GetModule()->GetRWImporter(); |
| 775 | } |
| 776 | #endif // DACCESS_COMPILE |
| 777 | |
| 778 | TypeHandle LookupFieldTypeHandle(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE); |
| 779 | |
| 780 | TypeHandle LookupApproxFieldTypeHandle() |
| 781 | { |
| 782 | WRAPPER_NO_CONTRACT; |
| 783 | return LookupFieldTypeHandle(CLASS_LOAD_APPROXPARENTS, TRUE); |
| 784 | } |
| 785 | |
| 786 | // Instance FieldDesc can be shared between generic instantiations. So List<String>._items |
| 787 | // is really the same as List<__Canon>._items. Hence, the FieldDesc itself |
| 788 | // cannot know the exact field type. This function returns the approximate field type. |
| 789 | // For eg. this will return "__Canon[]" for List<String>._items. |
| 790 | TypeHandle GetFieldTypeHandleThrowing(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE); |
| 791 | |
| 792 | TypeHandle GetApproxFieldTypeHandleThrowing() |
| 793 | { |
| 794 | WRAPPER_NO_CONTRACT; |
| 795 | return GetFieldTypeHandleThrowing(CLASS_LOAD_APPROXPARENTS, TRUE); |
| 796 | } |
| 797 | |
| 798 | // Given a type handle of an object and a method that comes from some |
| 799 | // superclass of the class of that object, find the instantiation of |
| 800 | // that superclass, i.e. the class instantiation which will be relevant |
| 801 | // to interpreting the signature of the method. The type handle of |
| 802 | // the object does not need to be given in all circumstances, in |
| 803 | // particular it is only needed for FieldDescs pFD that |
| 804 | // return true for pFD->GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations(). |
| 805 | // In other cases it is allowed to be null and will be ignored. |
| 806 | // |
| 807 | // Will return NULL if the field is not in a generic class. |
| 808 | Instantiation GetExactClassInstantiation(TypeHandle possibleObjType); |
| 809 | |
| 810 | // Instance FieldDesc can be shared between generic instantiations. So List<String>._items |
| 811 | // is really the same as List<__Canon>._items. Hence, the FieldDesc itself |
| 812 | // cannot know the exact field type. You need to specify the owner |
| 813 | // like List<String> in order to get the exact type which would be "String[]" |
| 814 | TypeHandle GetExactFieldType(TypeHandle owner); |
| 815 | |
| 816 | #ifdef DACCESS_COMPILE |
| 817 | void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
| 818 | { |
| 819 | SUPPORTS_DAC; |
| 820 | DAC_ENUM_DTHIS(); |
| 821 | } |
| 822 | #endif |
| 823 | |
| 824 | #ifndef DACCESS_COMPILE |
| 825 | REFLECTFIELDREF GetStubFieldInfo(); |
| 826 | #endif |
| 827 | }; |
| 828 | |
| 829 | #endif // _FIELD_H_ |
| 830 | |
| 831 | |