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// File: Field.cpp
6//
7
8// ===========================================================================
9// This file contains the implementation for FieldDesc methods.
10// ===========================================================================
11//
12
13
14#include "common.h"
15
16#include "encee.h"
17#include "field.h"
18#include "generics.h"
19
20#include "peimagelayout.inl"
21
22// called from code:MethodTableBuilder::InitializeFieldDescs#InitCall
23VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttrs, BOOL fIsStatic, BOOL fIsRVA, BOOL fIsThreadLocal, LPCSTR pszFieldName)
24{
25 LIMITED_METHOD_CONTRACT;
26
27 // We allow only a subset of field types here - all objects must be set to TYPE_CLASS
28 // By-value classes are ELEMENT_TYPE_VALUETYPE
29 _ASSERTE(
30 FieldType == ELEMENT_TYPE_I1 ||
31 FieldType == ELEMENT_TYPE_BOOLEAN ||
32 FieldType == ELEMENT_TYPE_U1 ||
33 FieldType == ELEMENT_TYPE_I2 ||
34 FieldType == ELEMENT_TYPE_U2 ||
35 FieldType == ELEMENT_TYPE_CHAR ||
36 FieldType == ELEMENT_TYPE_I4 ||
37 FieldType == ELEMENT_TYPE_U4 ||
38 FieldType == ELEMENT_TYPE_I8 ||
39 FieldType == ELEMENT_TYPE_I ||
40 FieldType == ELEMENT_TYPE_U ||
41 FieldType == ELEMENT_TYPE_U8 ||
42 FieldType == ELEMENT_TYPE_R4 ||
43 FieldType == ELEMENT_TYPE_R8 ||
44 FieldType == ELEMENT_TYPE_CLASS ||
45 FieldType == ELEMENT_TYPE_VALUETYPE ||
46 FieldType == ELEMENT_TYPE_PTR ||
47 FieldType == ELEMENT_TYPE_FNPTR
48 );
49 _ASSERTE(fIsStatic || (!fIsRVA && !fIsThreadLocal));
50 _ASSERTE(fIsRVA + fIsThreadLocal <= 1);
51
52 m_requiresFullMbValue = 0;
53 SetMemberDef(mb);
54
55 m_type = FieldType;
56 m_prot = fdFieldAccessMask & dwMemberAttrs;
57 m_isStatic = fIsStatic != 0;
58 m_isRVA = fIsRVA != 0;
59 m_isThreadLocal = fIsThreadLocal != 0;
60
61#ifdef _DEBUG
62 m_debugName = (LPUTF8)pszFieldName;
63#endif
64
65 _ASSERTE(GetMemberDef() == mb); // no truncation
66 _ASSERTE(GetFieldType() == FieldType);
67 _ASSERTE(GetFieldProtection() == (fdFieldAccessMask & dwMemberAttrs));
68 _ASSERTE((BOOL) IsStatic() == (fIsStatic != 0));
69}
70
71// Return whether the field is a GC ref type
72BOOL FieldDesc::IsObjRef()
73{
74 WRAPPER_NO_CONTRACT;
75 SUPPORTS_DAC;
76 return CorTypeInfo::IsObjRef_NoThrow(GetFieldType());
77}
78
79#ifndef DACCESS_COMPILE
80void FieldDesc::PrecomputeNameHash()
81{
82 CONTRACTL
83 {
84 STANDARD_VM_CHECK;
85 PRECONDITION(IsCompilationProcess());
86 }
87 CONTRACTL_END;
88
89 // We only have space for the name hash when we can use the packed mb layout
90 if (m_requiresFullMbValue)
91 {
92 return;
93 }
94
95 // Store a case-insensitive hash so that we can use this value for
96 // both case-sensitive and case-insensitive name lookups
97 SString name(SString::Utf8Literal, GetName());
98 ULONG nameHashValue = name.HashCaseInsensitive() & enum_packedMbLayout_NameHashMask;
99
100 // We should never overwrite any other bits
101 _ASSERTE((m_mb & enum_packedMbLayout_NameHashMask) == 0 ||
102 (m_mb & enum_packedMbLayout_NameHashMask) == nameHashValue);
103
104 m_mb |= nameHashValue;
105}
106#endif
107
108BOOL FieldDesc::MightHaveName(ULONG nameHashValue)
109{
110 LIMITED_METHOD_CONTRACT;
111
112 g_IBCLogger.LogFieldDescsAccess(this);
113
114 // We only have space for a name hash when we are using the packed mb layout
115 if (m_requiresFullMbValue)
116 {
117 return TRUE;
118 }
119
120 ULONG thisHashValue = m_mb & enum_packedMbLayout_NameHashMask;
121
122 // A zero value might mean no hash has ever been set
123 // (checking this way is better than dedicating a bit to tell us)
124 if (thisHashValue == 0)
125 {
126 return TRUE;
127 }
128
129 ULONG testHashValue = nameHashValue & enum_packedMbLayout_NameHashMask;
130
131 return (thisHashValue == testHashValue);
132}
133
134#ifndef DACCESS_COMPILE //we don't require DAC to special case simple types
135// Return the type of the field, as a class, but only if it's loaded.
136TypeHandle FieldDesc::LookupFieldTypeHandle(ClassLoadLevel level, BOOL dropGenericArgumentLevel)
137{
138
139 CONTRACTL
140 {
141 INSTANCE_CHECK;
142 NOTHROW;
143 GC_NOTRIGGER;
144 MODE_ANY;
145 FORBID_FAULT;
146 SO_TOLERANT;
147 }
148 CONTRACTL_END
149
150 // This function is called during GC promotion.
151 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
152
153 // Caller should have handled all the non-class cases, already.
154 _ASSERTE(GetFieldType() == ELEMENT_TYPE_CLASS ||
155 GetFieldType() == ELEMENT_TYPE_VALUETYPE);
156
157 MetaSig sig(this);
158 CorElementType type;
159
160 type = sig.NextArg();
161
162 // This may be the real type which includes other things
163 // beside class and value class such as arrays
164 _ASSERTE(type == ELEMENT_TYPE_CLASS ||
165 type == ELEMENT_TYPE_VALUETYPE ||
166 type == ELEMENT_TYPE_STRING ||
167 type == ELEMENT_TYPE_SZARRAY ||
168 type == ELEMENT_TYPE_VAR
169 );
170
171 // == FailIfNotLoaded, can also assert that the thing is restored
172 TypeHandle th = NULL;
173
174 BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return NULL);
175 {
176 th = sig.GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes, level, dropGenericArgumentLevel);
177 }
178 END_SO_INTOLERANT_CODE;
179
180 return th;
181}
182#else //simplified version
183TypeHandle FieldDesc::LookupFieldTypeHandle(ClassLoadLevel level, BOOL dropGenericArgumentLevel)
184{
185 WRAPPER_NO_CONTRACT;
186 MetaSig sig(this);
187 CorElementType type;
188 type = sig.NextArg();
189 return sig.GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes, level, dropGenericArgumentLevel);
190}
191#endif //DACCESS_COMPILE
192
193TypeHandle FieldDesc::GetFieldTypeHandleThrowing(ClassLoadLevel level/*=CLASS_LOADED*/,
194 BOOL dropGenericArgumentLevel /*=FALSE*/)
195{
196 WRAPPER_NO_CONTRACT;
197
198 MetaSig sig(this);
199 sig.NextArg();
200
201 return sig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes, level, dropGenericArgumentLevel);
202}
203
204#ifndef DACCESS_COMPILE
205
206void* FieldDesc::GetStaticAddress(void *base)
207{
208 CONTRACTL
209 {
210 NOTHROW;
211 GC_NOTRIGGER;
212 SO_TOLERANT;
213 MODE_ANY; // Needed by profiler and server GC
214 }
215 CONTRACTL_END;
216
217 void* ret = GetStaticAddressHandle(base); // Get the handle
218
219 // For value classes, the handle points at an OBJECTREF
220 // which holds the boxed value class, so derefernce and unbox.
221 if (GetFieldType() == ELEMENT_TYPE_VALUETYPE && !IsRVA())
222 {
223 OBJECTREF obj = ObjectToOBJECTREF(*(Object**) ret);
224 ret = obj->GetData();
225 }
226 return ret;
227}
228
229MethodTable * FieldDesc::GetExactDeclaringType(MethodTable * ownerOrSubType)
230{
231 CONTRACTL
232 {
233 NOTHROW;
234 GC_NOTRIGGER;
235 SO_TOLERANT;
236 MODE_ANY;
237 }
238 CONTRACTL_END;
239
240 MethodTable * pMT = GetApproxEnclosingMethodTable();
241
242 // Fast path for typical case.
243 if (ownerOrSubType == pMT)
244 return pMT;
245
246 return ownerOrSubType->GetMethodTableMatchingParentClass(pMT);
247}
248
249#endif // #ifndef DACCESS_COMPILE
250
251 // static value classes are actually stored in their boxed form.
252 // this means that their address moves.
253PTR_VOID FieldDesc::GetStaticAddressHandle(PTR_VOID base)
254{
255
256 CONTRACTL
257 {
258 INSTANCE_CHECK;
259 NOTHROW;
260 GC_NOTRIGGER;
261 MODE_ANY;
262 FORBID_FAULT;
263 SO_TOLERANT;
264 PRECONDITION(IsStatic());
265 PRECONDITION(GetEnclosingMethodTable()->IsRestored_NoLogging());
266 }
267 CONTRACTL_END
268
269 g_IBCLogger.LogFieldDescsAccess(this);
270
271 _ASSERTE(IsStatic());
272#ifdef EnC_SUPPORTED
273 if (IsEnCNew())
274 {
275 EnCFieldDesc * pFD = dac_cast<PTR_EnCFieldDesc>(this);
276 _ASSERTE_IMPL(pFD->GetApproxEnclosingMethodTable()->SanityCheck());
277 _ASSERTE(pFD->GetModule()->IsEditAndContinueEnabled());
278
279 EditAndContinueModule *pModule = (EditAndContinueModule*)pFD->GetModule();
280 _ASSERTE(pModule->IsEditAndContinueEnabled());
281
282 PTR_VOID retVal = NULL;
283
284 // BEGIN_SO_INTOLERANT_CODE will throw if we don't have enough stack
285 // and GetStaticAddressHandle has no failure semantics, so we need
286 // to just do the SO policy (e.g. rip the appdomain or process).
287 CONTRACT_VIOLATION(ThrowsViolation)
288
289#ifdef DACCESS_COMPILE
290 DacNotImpl();
291#else
292 BEGIN_SO_INTOLERANT_CODE(GetThread());
293 {
294 GCX_COOP();
295 // This routine doesn't have a failure semantic - but Resolve*Field(...) does.
296 // Something needs to be rethought here and I think it's E&C.
297 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation); //B#25680 (Fix Enc violations)
298 retVal = (void *)(pModule->ResolveOrAllocateField(NULL, pFD));
299 }
300 END_SO_INTOLERANT_CODE;
301#endif // !DACCESS_COMPILE
302 return retVal;
303 }
304#endif // EnC_SUPPORTED
305
306
307 if (IsRVA())
308 {
309 Module* pModule = GetModule();
310 PTR_VOID ret = pModule->GetRvaField(GetOffset(), IsZapped());
311
312 _ASSERTE(!pModule->IsPEFile() || !pModule->IsRvaFieldTls(GetOffset()));
313
314 return(ret);
315 }
316
317 CONSISTENCY_CHECK(CheckPointer(base));
318
319 PTR_VOID ret = PTR_VOID(dac_cast<PTR_BYTE>(base) + GetOffset());
320
321
322 return ret;
323}
324
325
326#ifndef CROSSGEN_COMPILE
327
328// These routines encapsulate the operation of getting and setting
329// fields.
330void FieldDesc::GetInstanceField(OBJECTREF o, VOID * pOutVal)
331{
332 CONTRACTL
333 {
334 INSTANCE_CHECK;
335 if (FORBIDGC_LOADER_USE_ENABLED() ) NOTHROW; else THROWS;
336 if (FORBIDGC_LOADER_USE_ENABLED() ) GC_NOTRIGGER; else GC_TRIGGERS;
337 MODE_ANY;
338 if (FORBIDGC_LOADER_USE_ENABLED() ) FORBID_FAULT; else INJECT_FAULT(COMPlusThrowOM(););
339 }
340 CONTRACTL_END
341
342 // We know that it isn't going to be null here. Tell PREFIX that we know it.
343 PREFIX_ASSUME(o != NULL);
344
345 // Check whether we are getting a field value on a proxy. If so, then ask
346 // remoting services to extract the value from the instance.
347
348 // Unbox the value class
349 TADDR pFieldAddress = (TADDR)GetInstanceAddress(o);
350 UINT cbSize = GetSize();
351
352 switch (cbSize)
353 {
354 case 1:
355 *(INT8*)pOutVal = VolatileLoad<INT8>(PTR_INT8(pFieldAddress));
356 break;
357
358 case 2:
359 *(INT16*)pOutVal = VolatileLoad<INT16>(PTR_INT16(pFieldAddress));
360 break;
361
362 case 4:
363 *(INT32*)pOutVal = VolatileLoad<INT32>(PTR_INT32(pFieldAddress));
364 break;
365
366 case 8:
367 *(INT64*)pOutVal = VolatileLoad<INT64>(PTR_INT64(pFieldAddress));
368 break;
369
370 default:
371 UNREACHABLE();
372 break;
373 }
374}
375
376#ifndef DACCESS_COMPILE
377void FieldDesc::SetInstanceField(OBJECTREF o, const VOID * pInVal)
378{
379 CONTRACTL
380 {
381 INSTANCE_CHECK;
382 THROWS;
383 GC_TRIGGERS;
384 MODE_ANY;
385 INJECT_FAULT(COMPlusThrowOM(););
386 }
387 CONTRACTL_END
388
389#ifdef _DEBUG
390 //
391 // assert that o is derived from MT of enclosing class
392 //
393 // walk up o's inheritence chain to make sure m_pMTOfEnclosingClass is along it
394 //
395 MethodTable* pCursor = o->GetMethodTable();
396
397 //<TODO>@todo : work out exactly why instantiations aren't matching; probably
398 // because of approx loads on field types in the loader</TODO>
399 while (pCursor && (GetApproxEnclosingMethodTable()->HasSameTypeDefAs(pCursor)))
400 {
401 pCursor = pCursor->GetParentMethodTable();
402 }
403 _ASSERTE(pCursor != NULL);
404#endif // _DEBUG
405
406 // Unbox the value class
407 LPVOID pFieldAddress = GetInstanceAddress(o);
408
409 CorElementType fieldType = GetFieldType();
410
411 if (fieldType == ELEMENT_TYPE_CLASS)
412 {
413 OBJECTREF ref = ObjectToOBJECTREF(*(Object**)pInVal);
414
415 SetObjectReference((OBJECTREF*)pFieldAddress, ref,
416 o->GetAppDomain());
417 }
418 else if (fieldType == ELEMENT_TYPE_VALUETYPE)
419 {
420 CONSISTENCY_CHECK(!LookupFieldTypeHandle().IsNull());
421 // The Approximate MT is enough to do the copy
422 CopyValueClass(pFieldAddress,
423 (void*)pInVal,
424 LookupFieldTypeHandle().GetMethodTable(),
425 o->GetAppDomain());
426 }
427 else
428 {
429 UINT cbSize = LoadSize();
430
431 switch (cbSize)
432 {
433 case 1:
434 VolatileStore<INT8>((INT8*)pFieldAddress, *(INT8*)pInVal);
435 break;
436
437 case 2:
438 VolatileStore<INT16>((INT16*)pFieldAddress, *(INT16*)pInVal);
439 break;
440
441 case 4:
442 VolatileStore<INT32>((INT32*)pFieldAddress, *(INT32*)pInVal);
443 break;
444
445 case 8:
446 VolatileStore<INT64>((INT64*)pFieldAddress, *(INT64*)pInVal);
447 break;
448
449 default:
450 UNREACHABLE();
451 break;
452 }
453 }
454}
455#endif // #ifndef DACCESS_COMPILE
456
457
458// This function is used for BYREF support of fields. Since it generates
459// interior pointers, you really have to watch the lifetime of the pointer
460// so that GCs don't happen while you have the reference active
461PTR_VOID FieldDesc::GetAddressNoThrowNoGC(PTR_VOID o)
462{
463 CONTRACTL
464 {
465 NOTHROW;
466 GC_NOTRIGGER;
467 MODE_COOPERATIVE;
468 SO_TOLERANT;
469 PRECONDITION(!IsEnCNew());
470 SO_TOLERANT;
471 SUPPORTS_DAC;
472 }
473 CONTRACTL_END;
474
475 DWORD dwOffset = GetOffset();
476 if (!IsFieldOfValueType())
477 {
478 dwOffset += sizeof(Object);
479 }
480 return dac_cast<PTR_BYTE>(o) + dwOffset;
481}
482
483PTR_VOID FieldDesc::GetAddress(PTR_VOID o)
484{
485 CONTRACTL
486 {
487 if(IsEnCNew()) {THROWS;} else {DISABLED(THROWS);};
488 if(IsEnCNew()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
489 SUPPORTS_DAC;
490 }
491 CONTRACTL_END;
492
493#ifdef DACCESS_COMPILE
494 _ASSERTE(!IsEnCNew()); // when we call this while finding an EnC field via the DAC,
495 // the field desc is for the EnCHelper, not the new EnC field
496#endif
497 g_IBCLogger.LogFieldDescsAccess(this);
498
499#if defined(EnC_SUPPORTED) && !defined(DACCESS_COMPILE)
500 // EnC added fields aren't at a simple offset like normal fields.
501 if (IsEnCNew())
502 {
503 // We'll have to go through some effort to compute the address of this field.
504 return ((EnCFieldDesc *)this)->GetAddress(o);
505 }
506#endif // defined(EnC_SUPPORTED) && !defined(DACCESS_COMPILE)
507 return GetAddressNoThrowNoGC(o);
508}
509
510void *FieldDesc::GetInstanceAddress(OBJECTREF o)
511{
512 CONTRACTL
513 {
514 if(IsEnCNew()) {THROWS;} else {DISABLED(THROWS);};
515 if(IsEnCNew()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
516 }
517 CONTRACTL_END;
518
519 g_IBCLogger.LogFieldDescsAccess(this);
520
521 DWORD dwOffset = m_dwOffset; // GetOffset()
522
523#ifdef EnC_SUPPORTED
524 // EnC added fields aren't at a simple offset like normal fields.
525 if (dwOffset == FIELD_OFFSET_NEW_ENC) // IsEnCNew()
526 {
527 // We'll have to go through some effort to compute the address of this field.
528 return ((EnCFieldDesc *)this)->GetAddress(OBJECTREFToObject(o));
529 }
530#endif
531
532 return (void *) (dac_cast<TADDR>(o->GetData()) + dwOffset);
533}
534
535// And here's the equivalent, when you are guaranteed that the enclosing instance of
536// the field is in the GC Heap. So if the enclosing instance is a value type, it had
537// better be boxed. We ASSERT this.
538void *FieldDesc::GetAddressGuaranteedInHeap(void *o)
539{
540 CONTRACTL
541 {
542 NOTHROW;
543 GC_NOTRIGGER;
544 MODE_COOPERATIVE;
545 SO_TOLERANT;
546 }
547 CONTRACTL_END;
548
549 _ASSERTE(!IsEnCNew());
550
551 return ((BYTE*)(o)) + sizeof(Object) + m_dwOffset;
552}
553
554
555DWORD FieldDesc::GetValue32(OBJECTREF o)
556{
557 WRAPPER_NO_CONTRACT;
558
559 DWORD val;
560 GetInstanceField(o, (LPVOID)&val);
561 return val;
562}
563
564#ifndef DACCESS_COMPILE
565VOID FieldDesc::SetValue32(OBJECTREF o, DWORD dwValue)
566{
567 CONTRACTL
568 {
569 THROWS;
570 GC_TRIGGERS;
571 MODE_COOPERATIVE;
572 }
573 CONTRACTL_END;
574
575 SetInstanceField(o, (LPVOID)&dwValue);
576}
577#endif // #ifndef DACCESS_COMPILE
578
579void* FieldDesc::GetValuePtr(OBJECTREF o)
580{
581 WRAPPER_NO_CONTRACT;
582
583 void* val;
584 GetInstanceField(o, (LPVOID)&val);
585 return val;
586}
587
588#ifndef DACCESS_COMPILE
589VOID FieldDesc::SetValuePtr(OBJECTREF o, void* pValue)
590{
591 WRAPPER_NO_CONTRACT;
592
593 SetInstanceField(o, (LPVOID)&pValue);
594}
595#endif // #ifndef DACCESS_COMPILE
596
597OBJECTREF FieldDesc::GetRefValue(OBJECTREF o)
598{
599 WRAPPER_NO_CONTRACT;
600
601 OBJECTREF val = NULL;
602
603#ifdef PROFILING_SUPPORTED
604 GCPROTECT_BEGIN(val);
605#endif
606
607 GetInstanceField(o, (LPVOID)&val);
608
609#ifdef PROFILING_SUPPORTED
610 GCPROTECT_END();
611#endif
612
613 return val;
614}
615
616#ifndef DACCESS_COMPILE
617VOID FieldDesc::SetRefValue(OBJECTREF o, OBJECTREF orValue)
618{
619 CONTRACTL
620 {
621 THROWS;
622 GC_TRIGGERS;
623 MODE_COOPERATIVE;
624 }
625 CONTRACTL_END;
626 VALIDATEOBJECTREF(o);
627 VALIDATEOBJECTREF(orValue);
628
629 SetInstanceField(o, (LPVOID)&orValue);
630}
631#endif // #ifndef DACCESS_COMPILE
632
633USHORT FieldDesc::GetValue16(OBJECTREF o)
634{
635 WRAPPER_NO_CONTRACT;
636
637 USHORT val;
638 GetInstanceField(o, (LPVOID)&val);
639 return val;
640}
641
642#ifndef DACCESS_COMPILE
643VOID FieldDesc::SetValue16(OBJECTREF o, DWORD dwValue)
644{
645 CONTRACTL
646 {
647 THROWS;
648 GC_TRIGGERS;
649 MODE_COOPERATIVE;
650 }
651 CONTRACTL_END;
652
653 USHORT val = (USHORT)dwValue;
654 SetInstanceField(o, (LPVOID)&val);
655}
656#endif // #ifndef DACCESS_COMPILE
657
658BYTE FieldDesc::GetValue8(OBJECTREF o)
659{
660 WRAPPER_NO_CONTRACT;
661
662 BYTE val;
663 GetInstanceField(o, (LPVOID)&val);
664 return val;
665
666}
667
668#ifndef DACCESS_COMPILE
669VOID FieldDesc::SetValue8(OBJECTREF o, DWORD dwValue)
670{
671 CONTRACTL
672 {
673 THROWS;
674 GC_TRIGGERS;
675 MODE_COOPERATIVE;
676 }
677 CONTRACTL_END;
678
679 BYTE val = (BYTE)dwValue;
680 SetInstanceField(o, (LPVOID)&val);
681}
682#endif // #ifndef DACCESS_COMPILE
683
684__int64 FieldDesc::GetValue64(OBJECTREF o)
685{
686 WRAPPER_NO_CONTRACT;
687 __int64 val;
688 GetInstanceField(o, (LPVOID)&val);
689 return val;
690
691}
692
693#ifndef DACCESS_COMPILE
694VOID FieldDesc::SetValue64(OBJECTREF o, __int64 value)
695{
696 CONTRACTL
697 {
698 THROWS;
699 GC_TRIGGERS;
700 MODE_COOPERATIVE;
701 }
702 CONTRACTL_END;
703 SetInstanceField(o, (LPVOID)&value);
704}
705#endif // #ifndef DACCESS_COMPILE
706
707#endif // !CROSSGEN_COMPILE
708
709
710#ifndef DACCESS_COMPILE
711
712#ifdef FEATURE_NATIVE_IMAGE_GENERATION
713void FieldDesc::SaveContents(DataImage *image)
714{
715 STANDARD_VM_CONTRACT;
716
717#ifdef _DEBUG
718 if (m_debugName && !image->IsStored((void*) m_debugName))
719 image->StoreStructure((void *) m_debugName,
720 (ULONG)(strlen(m_debugName) + 1),
721 DataImage::ITEM_DEBUG,
722 1);
723#endif
724
725 //
726 // If we are compiling an IL only image, and our RVA fits
727 // in the designated range, copy the RVA data over to the prejit
728 // image.
729 //
730
731 if (IsRVA())
732 {
733 //
734 // Move the RVA data into the prejit image.
735 //
736
737 UINT size = LoadSize();
738
739 //
740 // Compute an alignment for the data based on the alignment
741 // of the RVA. We'll align up to 8 bytes.
742 //
743
744 UINT align = 1;
745 DWORD rva = GetOffset();
746 DWORD rvaTemp = rva;
747
748 while ((rvaTemp&1) == 0 && align < 8 && align < size)
749 {
750 align <<= 1;
751 rvaTemp >>= 1;
752 }
753
754 image->StoreRvaInfo(this,
755 rva,
756 size,
757 align);
758 }
759}
760
761void FieldDesc::Fixup(DataImage *image)
762{
763 STANDARD_VM_CONTRACT;
764
765 LOG((LF_ZAP, LL_INFO10000, "FieldDesc::Fixup %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName));
766 image->FixupRelativePointerField(this, offsetof(FieldDesc, m_pMTOfEnclosingClass));
767
768#ifdef _DEBUG
769 image->FixupPointerField(this, offsetof(FieldDesc, m_debugName));
770#endif
771
772 // if (IsRVAFieldWithLessThanBigOffset())
773 // {
774 // offset of RVA fields is fixed up in DataImage::FixupRvaStructure
775 // }
776}
777#endif // FEATURE_NATIVE_IMAGE_GENERATION
778
779#endif // #ifndef DACCESS_COMPILE
780
781UINT FieldDesc::LoadSize()
782{
783 CONTRACTL
784 {
785 INSTANCE_CHECK;
786 THROWS;
787 GC_TRIGGERS;
788 MODE_ANY;
789 }
790 CONTRACTL_END
791
792 CorElementType type = GetFieldType();
793 UINT size = GetSizeForCorElementType(type);
794 if (size == (UINT) -1)
795 {
796 // LOG((LF_CLASSLOADER, LL_INFO10000, "FieldDesc::LoadSize %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName));
797 CONSISTENCY_CHECK(GetFieldType() == ELEMENT_TYPE_VALUETYPE);
798 size = GetApproxFieldTypeHandleThrowing().GetMethodTable()->GetNumInstanceFieldBytes();
799 }
800
801 return size;
802}
803
804UINT FieldDesc::GetSize()
805{
806 CONTRACTL
807 {
808 INSTANCE_CHECK;
809 NOTHROW;
810 GC_NOTRIGGER;
811 MODE_ANY;
812 FORBID_FAULT;
813 }
814 CONTRACTL_END
815
816 CorElementType type = GetFieldType();
817 UINT size = GetSizeForCorElementType(type);
818 if (size == (UINT) -1)
819 {
820 LOG((LF_CLASSLOADER, LL_INFO10000, "FieldDesc::GetSize %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName));
821 CONSISTENCY_CHECK(GetFieldType() == ELEMENT_TYPE_VALUETYPE);
822 TypeHandle t = LookupApproxFieldTypeHandle();
823 if (!t.IsNull())
824 {
825 size = t.GetMethodTable()->GetNumInstanceFieldBytes();
826 }
827 }
828
829 return size;
830}
831
832// See field.h for details
833Instantiation FieldDesc::GetExactClassInstantiation(TypeHandle possibleObjType)
834{
835 WRAPPER_NO_CONTRACT;
836
837 // We know that it isn't going to be null here. Tell PREFIX that we know it.
838 PREFIX_ASSUME(GetApproxEnclosingMethodTable()!=NULL);
839 if (possibleObjType.IsNull())
840 {
841 return GetApproxEnclosingMethodTable()->GetInstantiation();
842 }
843 else
844 {
845 PREFIX_ASSUME(GetApproxEnclosingMethodTable()!=NULL);
846 return possibleObjType.GetInstantiationOfParentClass(GetApproxEnclosingMethodTable());
847 }
848}
849
850// Given, { List<String>, List<__Canon>._items } where _items is of type T[],
851// it returns String[].
852
853TypeHandle FieldDesc::GetExactFieldType(TypeHandle owner)
854{
855 CONTRACT(TypeHandle)
856 {
857 THROWS;
858 GC_TRIGGERS;
859 MODE_ANY;
860 PRECONDITION(CheckPointer(owner, NULL_OK));
861 POSTCONDITION(CheckPointer(RETVAL));
862 }
863 CONTRACT_END
864
865 if (GetApproxEnclosingMethodTable() == owner.AsMethodTable())
866 {
867 //Yes, this is exactly the type I was looking for.
868 RETURN(GetFieldTypeHandleThrowing());
869 }
870 else
871 {
872 //This FieldDesc doesn't exactly represent the owner type. Go look up the exact type.
873
874 // We need to figure out the precise type of the field.
875 // First, get the signature of the field
876 PCCOR_SIGNATURE pSig;
877 DWORD cSig;
878 GetSig(&pSig, &cSig);
879 SigPointer sig(pSig, cSig);
880
881 ULONG callConv;
882 IfFailThrow(sig.GetCallingConv(&callConv));
883 _ASSERTE(callConv == IMAGE_CEE_CS_CALLCONV_FIELD);
884
885 // Get the generics information
886 SigTypeContext sigTypeContext(GetExactClassInstantiation(owner), Instantiation());
887
888 // Load the exact type
889 RETURN (sig.GetTypeHandleThrowing(GetModule(), &sigTypeContext));
890 }
891}
892
893#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
894REFLECTFIELDREF FieldDesc::GetStubFieldInfo()
895{
896 CONTRACTL
897 {
898 THROWS;
899 GC_TRIGGERS;
900 INJECT_FAULT(COMPlusThrowOM());
901 MODE_COOPERATIVE;
902 }
903 CONTRACTL_END;
904
905 REFLECTFIELDREF retVal;
906 REFLECTFIELDREF fieldRef = (REFLECTFIELDREF)AllocateObject(MscorlibBinder::GetClass(CLASS__STUBFIELDINFO));
907 GCPROTECT_BEGIN(fieldRef);
908
909 fieldRef->SetField(this);
910 LoaderAllocator *pLoaderAllocatorOfMethod = this->GetApproxEnclosingMethodTable()->GetLoaderAllocator();
911 if (pLoaderAllocatorOfMethod->IsCollectible())
912 fieldRef->SetKeepAlive(pLoaderAllocatorOfMethod->GetExposedObject());
913
914 retVal = fieldRef;
915 GCPROTECT_END();
916
917 return retVal;
918}
919#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
920