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: CEELOAD.INL
6//
7
8//
9// CEELOAD.INL has inline methods from CEELOAD.H.
10// ===========================================================================
11
12#ifndef CEELOAD_INL_
13#define CEELOAD_INL_
14
15template<typename TYPE>
16inline
17TYPE LookupMap<TYPE>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supportedFlags)
18{
19 WRAPPER_NO_CONTRACT;
20 SUPPORTS_DAC;
21 TYPE value = RelativePointer<TYPE>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pValue));
22
23 if (pFlags)
24 *pFlags = dac_cast<TADDR>(value) & supportedFlags;
25
26 return (TYPE)(dac_cast<TADDR>(value) & ~supportedFlags);
27}
28
29#ifndef DACCESS_COMPILE
30
31template<typename TYPE>
32inline
33void LookupMap<TYPE>::SetValueAt(PTR_TADDR pValue, TYPE value, TADDR flags)
34{
35 WRAPPER_NO_CONTRACT;
36
37 value = (TYPE)(dac_cast<TADDR>(value) | flags);
38
39 RelativePointer<TYPE> *pRelPtr = (RelativePointer<TYPE> *)pValue;
40 pRelPtr->SetValue(value);
41}
42
43//
44// Specialization of Get/SetValueAt methods to support maps of pointer-sized value types
45//
46template<>
47inline
48SIZE_T LookupMap<SIZE_T>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supportedFlags)
49{
50 WRAPPER_NO_CONTRACT;
51
52 TADDR value = *pValue;
53
54 if (pFlags)
55 *pFlags = value & supportedFlags;
56
57 return (value & ~supportedFlags);
58}
59
60template<>
61inline
62void LookupMap<SIZE_T>::SetValueAt(PTR_TADDR pValue, SIZE_T value, TADDR flags)
63{
64 WRAPPER_NO_CONTRACT;
65 *pValue = value | flags;
66}
67#endif // DACCESS_COMPILE
68
69//
70// Specialization of GetValueAt methods for tables with cross-module references
71//
72template<>
73inline
74PTR_TypeRef LookupMap<PTR_TypeRef>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supportedFlags)
75{
76 WRAPPER_NO_CONTRACT;
77 SUPPORTS_DAC;
78
79 // Strip flags before RelativeFixupPointer dereference
80 TADDR value = *pValue;
81
82 TADDR flags = (value & supportedFlags);
83 value -= flags;
84 value = ((RelativeFixupPointer<TADDR>&)(value)).GetValueMaybeNull(dac_cast<TADDR>(pValue));
85
86 if (pFlags)
87 *pFlags = flags;
88
89 return dac_cast<PTR_TypeRef>(value);
90}
91
92template<>
93inline
94PTR_Module LookupMap<PTR_Module>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supportedFlags)
95{
96 WRAPPER_NO_CONTRACT;
97 SUPPORTS_DAC;
98
99 // Strip flags before RelativeFixupPointer dereference
100 TADDR value = *pValue;
101
102 TADDR flags = (value & supportedFlags);
103 value -= flags;
104 value = ((RelativeFixupPointer<TADDR>&)(value)).GetValueMaybeNull(dac_cast<TADDR>(pValue));
105
106 if (pFlags)
107 *pFlags = flags;
108
109 return dac_cast<PTR_Module>(value);
110}
111
112template<>
113inline
114PTR_MemberRef LookupMap<PTR_MemberRef>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supportedFlags)
115{
116 WRAPPER_NO_CONTRACT;
117 SUPPORTS_DAC;
118
119 // Strip flags before RelativeFixupPointer dereference
120 TADDR value = *pValue;
121
122 TADDR flags = (value & supportedFlags);
123 value -= flags;
124 value = ((RelativeFixupPointer<TADDR>&)(value)).GetValueMaybeNull(dac_cast<TADDR>(pValue));
125
126 if (pFlags)
127 *pFlags = flags;
128
129 return dac_cast<PTR_MemberRef>(value);
130
131}
132
133// Retrieve the value associated with a rid
134template<typename TYPE>
135TYPE LookupMap<TYPE>::GetElement(DWORD rid, TADDR* pFlags)
136{
137 WRAPPER_NO_CONTRACT;
138 SUPPORTS_DAC;
139
140#ifdef FEATURE_PREJIT
141 if (MapIsCompressed())
142{
143 // Can't access compressed entries directly: we need to go through the special helper. However we
144 // must still check the hot cache first (this would normally be done by GetElementPtr() below, but
145 // we can't integrate compressed support there since compressed entries don't have addresses, at
146 // least not byte-aligned ones).
147 PTR_TADDR pHotItemValue = FindHotItemValuePtr(rid);
148 if (pHotItemValue)
149 return GetValueAt(pHotItemValue, pFlags, supportedFlags);
150
151 TADDR value = GetValueFromCompressedMap(rid);
152
153 if (value == NULL)
154 {
155 if ((pNext == NULL) || (rid < dwCount))
156 {
157 if (pFlags)
158 *pFlags = NULL;
159 return NULL;
160 }
161
162 return dac_cast<DPTR(LookupMap)>(pNext)->GetElement(rid - dwCount, pFlags);
163 }
164
165 if (pFlags)
166 *pFlags = (value & supportedFlags);
167
168 return (TYPE)(value & ~supportedFlags);
169 }
170#endif // FEATURE_PREJIT
171
172 PTR_TADDR pElement = GetElementPtr(rid);
173 return (pElement != NULL) ? GetValueAt(pElement, pFlags, supportedFlags) : NULL;
174}
175
176// Stores an association in a map that has been previously grown to
177// the required size. Will never throw or fail.
178template<typename TYPE>
179void LookupMap<TYPE>::SetElement(DWORD rid, TYPE value, TADDR flags)
180{
181 WRAPPER_NO_CONTRACT;
182 SUPPORTS_DAC;
183 BOOL fSuccess;
184 fSuccess = TrySetElement(rid, value, flags);
185 _ASSERTE(fSuccess);
186}
187
188
189#ifndef DACCESS_COMPILE
190
191// Try to store an association in a map. Will never throw or fail.
192template<typename TYPE>
193BOOL LookupMap<TYPE>::TrySetElement(DWORD rid, TYPE value, TADDR flags)
194{
195 CONTRACTL
196 {
197 INSTANCE_CHECK;
198 NOTHROW;
199 GC_NOTRIGGER;
200 MODE_ANY;
201 }
202 CONTRACTL_END;
203
204 PTR_TADDR pElement = GetElementPtr(rid);
205 if (pElement == NULL)
206 return FALSE;
207#ifdef _DEBUG
208 // Once set, the values in LookupMap should be immutable.
209 TADDR oldFlags;
210 TYPE oldValue = GetValueAt(pElement, &oldFlags, supportedFlags);
211 _ASSERTE(oldValue == NULL || (oldValue == value && oldFlags == flags));
212#endif
213 // Avoid unnecessary writes - do not overwrite existing value
214 if (*pElement == NULL)
215 {
216 if (!EnsureWritablePagesNoThrow(pElement, sizeof (TYPE)))
217 return FALSE;
218 SetValueAt(pElement, value, flags);
219 }
220 return TRUE;
221}
222
223// Stores an association in a map. Grows the map as necessary.
224template<typename TYPE>
225void LookupMap<TYPE>::AddElement(Module * pModule, DWORD rid, TYPE value, TADDR flags)
226{
227 CONTRACTL
228 {
229 INSTANCE_CHECK;
230 PRECONDITION(CheckPointer(pModule));
231 THROWS;
232 GC_NOTRIGGER;
233 MODE_ANY;
234 INJECT_FAULT(ThrowOutOfMemory(););
235 }
236 CONTRACTL_END;
237
238 PTR_TADDR pElement = GetElementPtr(rid);
239 if (pElement == NULL)
240 pElement = GrowMap(pModule, rid);
241#ifdef _DEBUG
242 // Once set, the values in LookupMap should be immutable.
243 TADDR oldFlags;
244 TYPE oldValue = GetValueAt(pElement, &oldFlags, supportedFlags);
245 _ASSERTE(oldValue == NULL || (oldValue == value && oldFlags == flags));
246#endif
247 // Avoid unnecessary writes - do not overwrite existing value
248 if (*pElement == NULL)
249 {
250 EnsureWritablePages(pElement, sizeof (TYPE));
251 SetValueAt(pElement, value, flags);
252 }
253}
254
255
256// Ensures that the map has space for this element
257template<typename TYPE>
258inline
259void LookupMap<TYPE>::EnsureElementCanBeStored(Module * pModule, DWORD rid)
260{
261 CONTRACTL
262 {
263 INSTANCE_CHECK;
264 PRECONDITION(CheckPointer(pModule));
265 THROWS;
266 GC_NOTRIGGER;
267 MODE_ANY;
268 INJECT_FAULT(ThrowOutOfMemory(););
269 }
270 CONTRACTL_END;
271
272#ifdef FEATURE_PREJIT
273 // don't attempt to call GetElementPtr for rids inside the compressed portion of
274 // a multi-node map
275 if (MapIsCompressed() && rid < dwCount)
276 return;
277#endif
278 PTR_TADDR pElement = GetElementPtr(rid);
279 if (pElement == NULL)
280 GrowMap(pModule, rid);
281
282 EnsureWritablePages(pElement, sizeof (TYPE));
283}
284
285#endif // DACCESS_COMPILE
286
287// Find the given value in the table and return its RID
288template<typename TYPE>
289DWORD LookupMap<TYPE>::Find(TYPE value, TADDR* pFlags)
290{
291 CONTRACTL
292 {
293 INSTANCE_CHECK;
294 NOTHROW;
295 GC_NOTRIGGER;
296 MODE_ANY;
297 }
298 CONTRACTL_END;
299
300 Iterator it(this);
301
302 DWORD rid = 0;
303 while (it.Next())
304 {
305 TADDR flags;
306 if (it.GetElementAndFlags(&flags) == value && (!pFlags || *pFlags == flags))
307 return rid;
308 rid++;
309 }
310
311 return 0;
312}
313
314template<typename TYPE>
315inline
316LookupMap<TYPE>::Iterator::Iterator(LookupMap* map)
317{
318 LIMITED_METHOD_DAC_CONTRACT;
319
320 m_map = map;
321 m_index = (DWORD) -1;
322#ifdef FEATURE_PREJIT
323 // Compressed map support
324 m_currentEntry = 0;
325 if (map->pTable != NULL)
326 m_tableStream = BitStreamReader(dac_cast<PTR_CBYTE>(map->pTable));
327#endif // FEATURE_PREJIT
328}
329
330template<typename TYPE>
331inline BOOL
332LookupMap<TYPE>::Iterator::Next()
333{
334 LIMITED_METHOD_DAC_CONTRACT;
335
336 if (!m_map || !m_map->pTable)
337 {
338 return FALSE;
339 }
340
341 m_index++;
342 if (m_index == m_map->dwCount)
343 {
344 m_map = dac_cast<DPTR(LookupMap)>(m_map->pNext);
345 if (!m_map || !m_map->pTable)
346 {
347 return FALSE;
348 }
349 m_index = 0;
350 }
351
352#ifdef FEATURE_PREJIT
353 // For a compressed map we need to read the encoded delta for the next entry and apply it to our previous
354 // value to obtain the new current value.
355 if (m_map->MapIsCompressed())
356 m_currentEntry = m_map->GetNextCompressedEntry(&m_tableStream, m_currentEntry);
357#endif // FEATURE_PREJIT
358
359 return TRUE;
360}
361
362template<typename TYPE>
363inline TYPE
364LookupMap<TYPE>::Iterator::GetElement(TADDR* pFlags)
365{
366 SUPPORTS_DAC;
367 WRAPPER_NO_CONTRACT;
368
369#ifdef FEATURE_PREJIT
370 // The current value for a compressed map is actually a map-based RVA. A zero RVA indicates a NULL pointer
371 // but otherwise we can recover the full pointer by adding the address of the map we're iterating.
372 // Note that most LookupMaps are embedded structures (in Module) so we can't directly dac_cast<TADDR> our
373 // "this" pointer for DAC builds. Instead we have to use the slightly slower (in DAC) but more flexible
374 // PTR_HOST_INT_TO_TADDR() which copes with interior host pointers.
375 if (m_map->MapIsCompressed())
376 {
377 TADDR value = m_currentEntry ? PTR_HOST_INT_TO_TADDR(m_map) + m_currentEntry : 0;
378
379 if (pFlags)
380 *pFlags = (value & m_map->supportedFlags);
381
382 return (TYPE)(value & ~m_map->supportedFlags);
383 }
384 else
385#endif // FEATURE_PREJIT
386 return GetValueAt(m_map->GetIndexPtr(m_index), pFlags, m_map->supportedFlags);
387}
388
389inline PTR_Assembly Module::GetAssembly() const
390{
391 LIMITED_METHOD_CONTRACT;
392 SUPPORTS_DAC;
393
394 return m_pAssembly;
395}
396
397inline MethodDesc *Module::LookupMethodDef(mdMethodDef token)
398{
399 CONTRACTL
400 {
401 NOTHROW;
402 GC_NOTRIGGER;
403 SO_TOLERANT;
404 MODE_ANY;
405 SUPPORTS_DAC;
406 }
407 CONTRACTL_END
408
409 _ASSERTE(TypeFromToken(token) == mdtMethodDef);
410 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
411
412 return m_MethodDefToDescMap.GetElement(RidFromToken(token));
413}
414
415inline MethodDesc *Module::LookupMemberRefAsMethod(mdMemberRef token)
416{
417 LIMITED_METHOD_DAC_CONTRACT;
418
419 _ASSERTE(TypeFromToken(token) == mdtMemberRef);
420 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
421 BOOL flags = FALSE;
422 PTR_MemberRef pMemberRef = m_pMemberRefToDescHashTable->GetValue(token, &flags);
423 return flags ? dac_cast<PTR_MethodDesc>(pMemberRef) : NULL;
424}
425
426inline Assembly *Module::LookupAssemblyRef(mdAssemblyRef token)
427{
428 WRAPPER_NO_CONTRACT;
429 SUPPORTS_DAC;
430
431 _ASSERTE(TypeFromToken(token) == mdtAssemblyRef);
432 PTR_Module module= m_ManifestModuleReferencesMap.GetElement(RidFromToken(token));
433 return module?module->GetAssembly():NULL;
434}
435
436#ifndef DACCESS_COMPILE
437inline void Module::ForceStoreAssemblyRef(mdAssemblyRef token, Assembly *value)
438{
439 WRAPPER_NO_CONTRACT; // THROWS/GC_NOTRIGGER/INJECT_FAULT()/MODE_ANY
440 _ASSERTE(value->GetManifestModule());
441 _ASSERTE(TypeFromToken(token) == mdtAssemblyRef);
442
443 m_ManifestModuleReferencesMap.AddElement(this, RidFromToken(token), value->GetManifestModule());
444}
445
446inline void Module::StoreAssemblyRef(mdAssemblyRef token, Assembly *value)
447{
448 WRAPPER_NO_CONTRACT;
449 _ASSERTE(value->GetManifestModule());
450 _ASSERTE(TypeFromToken(token) == mdtAssemblyRef);
451 m_ManifestModuleReferencesMap.TrySetElement(RidFromToken(token), value->GetManifestModule());
452}
453
454inline mdAssemblyRef Module::FindAssemblyRef(Assembly *targetAssembly)
455{
456 WRAPPER_NO_CONTRACT;
457
458 return m_ManifestModuleReferencesMap.Find(targetAssembly->GetManifestModule()) | mdtAssemblyRef;
459}
460
461#endif //DACCESS_COMPILE
462
463inline BOOL Module::IsEditAndContinueCapable()
464{
465 WRAPPER_NO_CONTRACT;
466 SUPPORTS_DAC;
467
468 BOOL isEnCCapable = IsEditAndContinueCapable(m_pAssembly, m_file);
469
470 // for now, Module::IsReflection is equivalent to m_file->IsDynamic,
471 // which is checked by IsEditAndContinueCapable(m_pAssembly, m_file)
472 _ASSERTE(!isEnCCapable || (!this->IsReflection()));
473
474 return isEnCCapable;
475}
476
477FORCEINLINE PTR_DomainLocalModule Module::GetDomainLocalModule(AppDomain *pDomain)
478{
479 WRAPPER_NO_CONTRACT;
480 SUPPORTS_DAC;
481
482 if (!Module::IsEncodedModuleIndex(GetModuleID()))
483 {
484 return m_ModuleID;
485 }
486
487#if !defined(DACCESS_COMPILE)
488 if (pDomain == NULL)
489 {
490 pDomain = GetAppDomain();
491 }
492#endif // DACCESS_COMPILE
493
494 // If the module is domain neutral, then you must supply an AppDomain argument.
495 // Use GetDomainLocalModule() if you want to rely on the current AppDomain
496 _ASSERTE(pDomain != NULL);
497
498 return pDomain->GetDomainLocalBlock()->GetModuleSlot(GetModuleIndex());
499}
500
501#ifdef FEATURE_PREJIT
502
503#include "nibblestream.h"
504
505FORCEINLINE BOOL Module::FixupDelayList(TADDR pFixupList)
506{
507 WRAPPER_NO_CONTRACT;
508
509 COUNT_T nImportSections;
510 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = GetImportSections(&nImportSections);
511
512 return FixupDelayListAux(pFixupList, this, &Module::FixupNativeEntry, pImportSections, nImportSections, GetNativeOrReadyToRunImage());
513}
514
515template<typename Ptr, typename FixupNativeEntryCallback>
516BOOL Module::FixupDelayListAux(TADDR pFixupList,
517 Ptr pThis, FixupNativeEntryCallback pfnCB,
518 PTR_CORCOMPILE_IMPORT_SECTION pImportSections, COUNT_T nImportSections,
519 PEDecoder * pNativeImage)
520{
521 CONTRACTL
522 {
523 INSTANCE_CHECK;
524 THROWS;
525 GC_TRIGGERS;
526 MODE_ANY;
527 PRECONDITION(pFixupList != NULL);
528 }
529 CONTRACTL_END;
530
531 // Fixup Encoding:
532 // ==============
533 //
534 // The fixup list is sorted in tables. Within each table, the fixups are a
535 // sorted list of INDEXes. The first INDEX in each table is encoded entirely,
536 // but the remaining INDEXes store only the delta increment from the previous INDEX.
537 // The encoding/compression is done by ZapperModule::CompressFixupList().
538 //
539 //-------------------------------------------------------------------------
540 // Here is the detailed description :
541 //
542 // The first entry stores the m_pFixupBlob table index.
543 //
544 // The next entry stores the INDEX into the particular table.
545 // An "entry" can be one or more nibbles. 3 bits of a nibble are used
546 // to store the value, and the top bit indicates if the following nibble
547 // contains rest of the value. If the top bit is not set, then this
548 // nibble is the last part of the value.
549 //
550 // If the next entry is non-0, it is another (delta-encoded relative to the
551 // previous INDEX) INDEX belonging to the same table. If the next entry is 0,
552 // it indicates that all INDEXes in this table are done.
553 //
554 // When the fixups for the previous table is done, there is entry to
555 // indicate the next table (delta-encoded relative to the previous table).
556 // If the entry is 0, then it is the end of the entire fixup list.
557 //
558 //-------------------------------------------------------------------------
559 // This is what the fixup list looks like:
560 //
561 // CorCompileTokenTable index
562 // absolute INDEX
563 // INDEX delta
564 // ...
565 // INDEX delta
566 // 0
567 // CorCompileTokenTable index delta
568 // absolute INDEX
569 // INDEX delta
570 // ...
571 // INDEX delta
572 // 0
573 // CorCompileTokenTable index delta
574 // absolute INDEX
575 // INDEX delta
576 // ...
577 // INDEX delta
578 // 0
579 // 0
580 //
581 //
582
583 NibbleReader reader(PTR_BYTE(pFixupList), (SIZE_T)-1);
584
585 //
586 // The fixups are sorted by the sections they point to.
587 // Walk the set of fixups in every sections
588 //
589
590 DWORD curTableIndex = reader.ReadEncodedU32();
591
592 while (TRUE)
593 {
594 // Get the correct section to work with. This is stored in the first two nibbles (first byte)
595
596 _ASSERTE(curTableIndex < nImportSections);
597 PTR_CORCOMPILE_IMPORT_SECTION pImportSection = pImportSections + curTableIndex;
598
599 COUNT_T cbData;
600 TADDR pData = pNativeImage->GetDirectoryData(&pImportSection->Section, &cbData);
601
602 // Now iterate thru the fixup entries
603 SIZE_T fixupIndex = reader.ReadEncodedU32(); // Accumulate the real rva from the delta encoded rva
604
605 while (TRUE)
606 {
607 CONSISTENCY_CHECK(fixupIndex * sizeof(TADDR) < cbData);
608
609 if (!(pThis->*pfnCB)(pImportSection, fixupIndex, dac_cast<PTR_SIZE_T>(pData + fixupIndex * sizeof(TADDR))))
610 return FALSE;
611
612 int delta = reader.ReadEncodedU32();
613
614 // Delta of 0 means end of entries in this table
615 if (delta == 0)
616 break;
617
618 fixupIndex += delta;
619 }
620
621 unsigned tableIndex = reader.ReadEncodedU32();
622
623 if (tableIndex == 0)
624 break;
625
626 curTableIndex = curTableIndex + tableIndex;
627
628 } // Done with all entries in this table
629
630 return TRUE;
631}
632
633#endif //FEATURE_PREJIT
634
635inline PTR_LoaderAllocator Module::GetLoaderAllocator()
636{
637 LIMITED_METHOD_DAC_CONTRACT;
638 return GetAssembly()->GetLoaderAllocator();
639}
640
641inline MethodTable* Module::GetDynamicClassMT(DWORD dynamicClassID)
642{
643 LIMITED_METHOD_CONTRACT;
644 _ASSERTE(m_cDynamicEntries > dynamicClassID);
645 return m_pDynamicStaticsInfo[dynamicClassID].pEnclosingMT;
646}
647
648#ifdef FEATURE_CODE_VERSIONING
649inline CodeVersionManager * Module::GetCodeVersionManager()
650{
651 LIMITED_METHOD_CONTRACT;
652 return GetDomain()->GetCodeVersionManager();
653}
654#endif // FEATURE_CODE_VERSIONING
655
656#ifdef FEATURE_TIERED_COMPILATION
657inline CallCounter * Module::GetCallCounter()
658{
659 LIMITED_METHOD_CONTRACT;
660 return GetDomain()->GetCallCounter();
661}
662#endif // FEATURE_TIERED_COMPILATION
663
664#endif // CEELOAD_INL_
665