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 | |