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 |
23 | VOID 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 |
72 | BOOL FieldDesc::IsObjRef() |
73 | { |
74 | WRAPPER_NO_CONTRACT; |
75 | SUPPORTS_DAC; |
76 | return CorTypeInfo::IsObjRef_NoThrow(GetFieldType()); |
77 | } |
78 | |
79 | #ifndef DACCESS_COMPILE |
80 | void 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 | |
108 | BOOL 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. |
136 | TypeHandle 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 |
183 | TypeHandle 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 | |
193 | TypeHandle 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 | |
206 | void* 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 | |
229 | MethodTable * 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. |
253 | PTR_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. |
330 | void 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 |
377 | void 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 |
461 | PTR_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 | |
483 | PTR_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 | |
510 | void *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. |
538 | void *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 | |
555 | DWORD 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 |
565 | VOID 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 | |
579 | void* 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 |
589 | VOID FieldDesc::SetValuePtr(OBJECTREF o, void* pValue) |
590 | { |
591 | WRAPPER_NO_CONTRACT; |
592 | |
593 | SetInstanceField(o, (LPVOID)&pValue); |
594 | } |
595 | #endif // #ifndef DACCESS_COMPILE |
596 | |
597 | OBJECTREF 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 |
617 | VOID 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 | |
633 | USHORT 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 |
643 | VOID 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 | |
658 | BYTE 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 |
669 | VOID 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 |
694 | VOID 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 |
713 | void 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 | |
761 | void 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 | |
781 | UINT 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 | |
804 | UINT 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 |
833 | Instantiation 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 | |
853 | TypeHandle 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) |
894 | REFLECTFIELDREF 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 | |