Merge pull request #14619 from briansull/emitter-cleanup
[platform/upstream/coreclr.git] / src / vm / threadstatics.cpp
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 // ThreadStatics.cpp
6 // 
7
8 // 
9 // 
10
11
12 #include "common.h"
13
14 #include "threadstatics.h"
15 #include "field.h"
16
17
18 #ifndef DACCESS_COMPILE
19
20 void ThreadLocalBlock::FreeTLM(SIZE_T i)
21 {
22     CONTRACTL
23     {
24         NOTHROW;
25         GC_NOTRIGGER;
26         SO_TOLERANT;
27         MODE_ANY;
28     }
29     CONTRACTL_END;
30     _ASSERTE(m_pTLMTable != NULL);
31
32     PTR_ThreadLocalModule pThreadLocalModule = m_pTLMTable[i].pTLM;
33     m_pTLMTable[i].pTLM = NULL;
34
35     if (pThreadLocalModule != NULL)
36     {
37         if (pThreadLocalModule->m_pDynamicClassTable != NULL)
38         {
39             for (DWORD k = 0; k < pThreadLocalModule->m_aDynamicEntries; ++k)
40             {
41                 if (pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry != NULL)
42                 {
43                     delete pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry;
44                     pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry = NULL;
45                 }
46             }
47             delete pThreadLocalModule->m_pDynamicClassTable;
48             pThreadLocalModule->m_pDynamicClassTable = NULL;
49         }
50
51         delete pThreadLocalModule;
52     }
53 }
54
55 void ThreadLocalBlock::FreeTable()
56 {
57     CONTRACTL
58     {
59         NOTHROW;
60         GC_NOTRIGGER;
61         SO_INTOLERANT;
62         MODE_COOPERATIVE;
63     }
64     CONTRACTL_END;
65     // Free the TLM table
66     if (m_pTLMTable != NULL)
67     {
68         // Iterate over the table and free each TLM
69         for (SIZE_T i = 0; i < m_TLMTableSize; ++i)
70         {
71             if (m_pTLMTable[i].pTLM != NULL)
72             {
73                 FreeTLM(i);
74             }
75         }
76
77         // Free the table itself
78         delete m_pTLMTable;
79         m_pTLMTable = NULL;
80     }
81
82     // Set table size to zero
83     m_TLMTableSize = 0;
84
85     // Free the ThreadStaticHandleTable
86     if (m_pThreadStaticHandleTable != NULL)
87     {
88         delete m_pThreadStaticHandleTable;
89         m_pThreadStaticHandleTable = NULL;
90     }
91
92     // Free any pinning handles we may have created
93     FreePinningHandles();
94 }
95
96 void ThreadLocalBlock::EnsureModuleIndex(ModuleIndex index)
97 {
98     CONTRACTL {
99         THROWS;
100         GC_NOTRIGGER;
101     } CONTRACTL_END;
102
103     if (m_TLMTableSize > index.m_dwIndex)
104     {
105         _ASSERTE(m_pTLMTable != NULL);
106         return;
107     }
108
109     SIZE_T aModuleIndices = max(16, m_TLMTableSize);
110     while (aModuleIndices <= index.m_dwIndex)
111     {
112         aModuleIndices *= 2;
113     }
114
115     // If this allocation fails, we will throw. If it succeeds,
116     // then we are good to go
117     PTR_TLMTableEntry pNewModuleSlots = (PTR_TLMTableEntry) (void*) new BYTE[sizeof(TLMTableEntry) * aModuleIndices];
118
119     // Zero out the new TLM table
120     memset(pNewModuleSlots, 0 , sizeof(TLMTableEntry) * aModuleIndices);
121
122     if (m_pTLMTable != NULL)
123     {
124         memcpy(pNewModuleSlots, m_pTLMTable, sizeof(TLMTableEntry) * m_TLMTableSize);
125     }
126     else
127     {
128         _ASSERTE(m_TLMTableSize == 0);
129     }
130
131     PTR_TLMTableEntry pOldModuleSlots = m_pTLMTable;
132     
133     m_pTLMTable = pNewModuleSlots;
134     m_TLMTableSize = aModuleIndices;
135
136     if (pOldModuleSlots != NULL)
137         delete pOldModuleSlots;
138 }
139
140 #endif
141
142 void ThreadLocalBlock::SetModuleSlot(ModuleIndex index, PTR_ThreadLocalModule pLocalModule) 
143 {
144     CONTRACTL {
145         NOTHROW;
146         GC_NOTRIGGER;
147     } CONTRACTL_END;
148
149     // This method will not grow the table. You need to grow
150     // the table explicitly before calling SetModuleSlot()
151
152     _ASSERTE(index.m_dwIndex < m_TLMTableSize);
153
154     m_pTLMTable[index.m_dwIndex].pTLM = pLocalModule;
155 }
156
157 #ifdef DACCESS_COMPILE
158
159 void
160 ThreadLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
161 {
162     SUPPORTS_DAC;
163
164     // Enumerate the ThreadLocalModule itself. TLMs are allocated to be larger than
165     // sizeof(ThreadLocalModule) to make room for ClassInit flags and non-GC statics.
166     // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
167     // all of the ClassInit flags and non-GC statics.
168     DAC_ENUM_DTHIS();
169
170     if (m_pDynamicClassTable != NULL)
171     {
172         DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable),
173                             m_aDynamicEntries * sizeof(DynamicClassInfo));
174
175         for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
176         {
177             PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry);
178             if (entry.IsValid())
179             {
180                 entry.EnumMem();
181             }
182         }
183     }
184 }
185
186 void
187 ThreadLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
188 {
189     SUPPORTS_DAC;
190
191     // Enumerate the ThreadLocalBlock itself
192     DAC_ENUM_DTHIS();
193
194     if (m_pTLMTable.IsValid())
195     {
196         DacEnumMemoryRegion(dac_cast<TADDR>(m_pTLMTable),
197                             m_TLMTableSize * sizeof(TADDR));
198
199         for (SIZE_T i = 0; i < m_TLMTableSize; i++)
200         {
201             PTR_ThreadLocalModule domMod = m_pTLMTable[i].pTLM;
202             if (domMod.IsValid())
203             {
204                 domMod->EnumMemoryRegions(flags);
205             }
206         }
207     }
208 }
209
210 #endif
211
212 DWORD ThreadLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex) // iClassIndex defaults to (DWORD)-1
213 {
214     CONTRACTL {
215         NOTHROW;
216         GC_NOTRIGGER;
217         SO_TOLERANT;
218     } CONTRACTL_END;
219
220     if (pMT->IsDynamicStatics())
221     {
222         DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
223         if(m_aDynamicEntries <= dynamicClassID)
224             return FALSE;
225         return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
226     }
227     else
228     {
229         if (iClassIndex == (DWORD)-1)
230             iClassIndex = pMT->GetClassIndex();
231         return GetPrecomputedStaticsClassData()[iClassIndex];
232     }
233 }
234
235 #ifndef DACCESS_COMPILE
236
237 void ThreadLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
238 {
239     CONTRACTL {
240         THROWS;
241         GC_NOTRIGGER;
242     } CONTRACTL_END;
243
244     if (pMT->IsDynamicStatics())
245     {
246         DWORD dwID = pMT->GetModuleDynamicEntryID();
247         EnsureDynamicClassIndex(dwID);
248         m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
249     }
250     else
251     {
252         GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
253     }
254 }
255
256 void ThreadLocalBlock::AddPinningHandleToList(OBJECTHANDLE oh)
257 {
258     CONTRACTL
259     {
260         THROWS;
261         GC_NOTRIGGER;
262         SO_TOLERANT;
263         MODE_ANY;
264     }
265     CONTRACTL_END;
266     ObjectHandleList::NodeType* pNewNode = new ObjectHandleList::NodeType(oh);
267     m_PinningHandleList.LinkHead(pNewNode);
268 }
269
270 void ThreadLocalBlock::FreePinningHandles()
271 {
272     CONTRACTL
273     {
274         NOTHROW;
275         GC_NOTRIGGER;
276         SO_TOLERANT;
277         MODE_ANY;
278     }
279     CONTRACTL_END;
280     // Destroy all pinning handles in the list, and free the nodes
281     ObjectHandleList::NodeType* pHandleNode; 
282     while ((pHandleNode = m_PinningHandleList.UnlinkHead()) != NULL)
283     {
284         DestroyPinningHandle(pHandleNode->data);
285         delete pHandleNode;
286     }
287 }
288
289 void ThreadLocalBlock::AllocateThreadStaticHandles(Module * pModule, PTR_ThreadLocalModule pThreadLocalModule)
290 {
291     CONTRACTL
292     {
293         THROWS;
294         GC_TRIGGERS;
295     }
296     CONTRACTL_END;
297
298     _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandleAddress() != NULL);
299     _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandle() == NULL);
300
301     if (pModule->GetNumGCThreadStaticHandles() > 0)
302     {
303         AllocateStaticFieldObjRefPtrs(pModule->GetNumGCThreadStaticHandles(),
304                                       pThreadLocalModule->GetPrecomputedGCStaticsBaseHandleAddress());
305
306         // We should throw if we fail to allocate and never hit this assert
307         _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandle() != NULL);
308         _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBasePointer() != NULL);
309     }
310 }
311
312 OBJECTHANDLE ThreadLocalBlock::AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTHANDLE * ppLazyAllocate)
313 {
314     CONTRACTL
315     {
316         THROWS;
317         GC_TRIGGERS;
318         MODE_COOPERATIVE;
319         PRECONDITION((nRequested > 0));
320         INJECT_FAULT(COMPlusThrowOM(););
321     }
322     CONTRACTL_END;
323
324     if (ppLazyAllocate && *ppLazyAllocate)
325     {
326         // Allocation already happened
327         return *ppLazyAllocate;
328     }
329
330     // Make sure the large heap handle table is initialized.
331     if (!m_pThreadStaticHandleTable)
332         InitThreadStaticHandleTable();
333
334     // Allocate the handles.
335     OBJECTHANDLE result = m_pThreadStaticHandleTable->AllocateHandles(nRequested);
336
337     if (ppLazyAllocate)
338     {
339         *ppLazyAllocate = result;
340     }
341
342     return result;
343 }
344
345 void ThreadLocalBlock::InitThreadStaticHandleTable()
346 {
347     CONTRACTL
348     {
349         THROWS;
350         GC_NOTRIGGER;
351         MODE_ANY;
352         PRECONDITION(m_pThreadStaticHandleTable==NULL);
353         INJECT_FAULT(COMPlusThrowOM(););
354     }
355     CONTRACTL_END;
356     
357     // If the allocation fails this will throw; callers need
358     // to account for this possibility
359     m_pThreadStaticHandleTable = new ThreadStaticHandleTable(GetAppDomain());
360 }
361
362 void ThreadLocalBlock::AllocateThreadStaticBoxes(MethodTable * pMT)
363 {
364     CONTRACTL
365     {
366         THROWS;
367         GC_TRIGGERS;
368         MODE_COOPERATIVE;
369         PRECONDITION(pMT->GetNumBoxedThreadStatics() > 0);
370         INJECT_FAULT(COMPlusThrowOM(););
371     }
372     CONTRACTL_END;
373
374     FieldDesc *pField = pMT->HasGenericsStaticsInfo() ? 
375         pMT->GetGenericsStaticFieldDescs() : (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields());
376
377     // Move pField to point to the list of thread statics
378     pField += pMT->GetNumStaticFields() - pMT->GetNumThreadStaticFields();
379
380     FieldDesc *pFieldEnd = pField + pMT->GetNumThreadStaticFields();
381
382     while (pField < pFieldEnd)
383     {
384         _ASSERTE(pField->IsThreadStatic());
385
386         // We only care about thread statics which are value types
387         if (pField->IsByValue())
388         {
389             TypeHandle  th = pField->GetFieldTypeHandleThrowing();
390             MethodTable* pFieldMT = th.GetMethodTable();
391
392             // AllocateStaticBox will pin this object if this class is FixedAddressVTStatics.
393             // We save this pinning handle in a list attached to the ThreadLocalBlock. When
394             // the thread dies, we release all the pinning handles in the list.
395
396             OBJECTHANDLE handle;
397             OBJECTREF obj = MethodTable::AllocateStaticBox(pFieldMT, pMT->HasFixedAddressVTStatics(), &handle);
398
399             PTR_BYTE pStaticBase = pMT->GetGCThreadStaticsBasePointer();
400             _ASSERTE(pStaticBase != NULL);
401
402             SetObjectReference( (OBJECTREF*)(pStaticBase + pField->GetOffset()), obj, GetAppDomain() );
403
404             // If we created a pinning handle, save it to the list
405             if (handle != NULL)
406                 AddPinningHandleToList(handle);
407         }
408
409         pField++;
410     }
411 }
412
413 #endif
414
415 #ifndef DACCESS_COMPILE
416
417 void    ThreadLocalModule::EnsureDynamicClassIndex(DWORD dwID)
418 {
419     CONTRACTL
420     {
421         THROWS;
422         GC_NOTRIGGER;
423         MODE_ANY;
424         INJECT_FAULT(COMPlusThrowOM(););
425     }
426     CONTRACTL_END;
427
428     if (dwID < m_aDynamicEntries)
429     {
430         _ASSERTE(m_pDynamicClassTable != NULL);
431         return;
432     }
433
434     SIZE_T aDynamicEntries = max(16, m_aDynamicEntries);
435     while (aDynamicEntries <= dwID)
436     {
437         aDynamicEntries *= 2;
438     }
439
440     DynamicClassInfo* pNewDynamicClassTable;
441
442     // If this allocation fails, we throw. If it succeeds,
443     // then we are good to go
444     pNewDynamicClassTable = (DynamicClassInfo*)(void*)new BYTE[sizeof(DynamicClassInfo) * aDynamicEntries];
445
446     // Zero out the dynamic class table
447     memset(pNewDynamicClassTable, 0, sizeof(DynamicClassInfo) * aDynamicEntries);
448
449     // We might always be guaranteed that this will be non-NULL, but just to be safe
450     if (m_pDynamicClassTable != NULL)
451     {
452         memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
453     }
454     else
455     {
456         _ASSERTE(m_aDynamicEntries == 0);
457     }
458
459     _ASSERTE(m_aDynamicEntries%2 == 0);
460
461     DynamicClassInfo* pOldDynamicClassTable = m_pDynamicClassTable;
462
463     m_pDynamicClassTable = pNewDynamicClassTable;
464     m_aDynamicEntries = aDynamicEntries;
465
466     if (pOldDynamicClassTable != NULL)
467         delete pOldDynamicClassTable;
468 }
469
470 void    ThreadLocalModule::AllocateDynamicClass(MethodTable *pMT)
471 {
472     CONTRACTL
473     {
474         THROWS;
475         GC_TRIGGERS;
476         MODE_COOPERATIVE;
477         INJECT_FAULT(COMPlusThrowOM(););
478     }
479     CONTRACTL_END;
480
481     _ASSERTE(!pMT->IsSharedByGenericInstantiations());
482     _ASSERTE(pMT->IsDynamicStatics());
483
484     DWORD dwID = pMT->GetModuleDynamicEntryID();
485
486     EnsureDynamicClassIndex(dwID);
487
488     _ASSERTE(m_aDynamicEntries > dwID);
489
490     EEClass *pClass = pMT->GetClass();
491     DWORD dwStaticBytes = pClass->GetNonGCThreadStaticFieldBytes();
492     DWORD dwNumHandleStatics = pClass->GetNumHandleThreadStatics();
493
494     _ASSERTE(!IsClassAllocated(pMT));
495     _ASSERTE(!IsClassInitialized(pMT));
496     _ASSERTE(!IsClassInitError(pMT));
497
498     DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dwID].m_pDynamicEntry;
499
500     // We need this check because maybe a class had a cctor but no statics
501     if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
502     {
503         // Collectible types do not support static fields yet
504         if (pMT->Collectible())
505             COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleNotYet"));
506
507         if (pDynamicStatics == NULL)
508         {            
509             // If this allocation fails, we will throw
510             pDynamicStatics = (DynamicEntry*)new BYTE[sizeof(DynamicEntry) + dwStaticBytes];
511
512 #ifdef FEATURE_64BIT_ALIGNMENT
513             // The memory block has be aligned at MAX_PRIMITIVE_FIELD_SIZE to guarantee alignment of statics
514             static_assert_no_msg(sizeof(DynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
515             _ASSERTE(IS_ALIGNED(pDynamicStatics, MAX_PRIMITIVE_FIELD_SIZE));
516 #endif
517
518             // Zero out the new DynamicEntry
519             memset((BYTE*)pDynamicStatics, 0, sizeof(DynamicEntry) + dwStaticBytes);
520
521             // Save the DynamicEntry in the DynamicClassTable
522             m_pDynamicClassTable[dwID].m_pDynamicEntry = pDynamicStatics;
523         }
524
525         if (dwNumHandleStatics > 0)
526         {
527             PTR_ThreadLocalBlock pThreadLocalBlock = GetThread()->m_pThreadLocalBlock;
528             _ASSERTE(pThreadLocalBlock != NULL);
529             pThreadLocalBlock->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
530                                                              &pDynamicStatics->m_pGCStatics);
531         }
532     }
533 }
534
535 void ThreadLocalModule::PopulateClass(MethodTable *pMT)
536 {
537     CONTRACTL
538     {
539         THROWS;
540         GC_TRIGGERS;
541         MODE_COOPERATIVE;
542         INJECT_FAULT(COMPlusThrowOM(););
543     }
544     CONTRACTL_END;
545
546     _ASSERTE(this != NULL);
547     _ASSERTE(pMT != NULL);
548     _ASSERTE(!IsClassAllocated(pMT));
549
550     // If this is a dynamic class then we need to allocate
551     // an entry in our dynamic class table
552     if (pMT->IsDynamicStatics())
553         AllocateDynamicClass(pMT);
554
555     // We need to allocate boxes any value-type statics that are not
556     // primitives or enums, because these statics may contain references
557     // to objects on the GC heap
558     if (pMT->GetNumBoxedThreadStatics() > 0)
559     {
560         PTR_ThreadLocalBlock pThreadLocalBlock = ThreadStatics::GetCurrentTLB();
561         _ASSERTE(pThreadLocalBlock != NULL);
562         pThreadLocalBlock->AllocateThreadStaticBoxes(pMT);
563     }
564
565     // Mark the class as allocated
566     SetClassAllocated(pMT);
567 }
568
569 PTR_ThreadLocalModule ThreadStatics::AllocateAndInitTLM(ModuleIndex index, PTR_ThreadLocalBlock pThreadLocalBlock, Module * pModule) //static
570 {
571     CONTRACTL
572     {
573         THROWS;
574         GC_TRIGGERS;
575         MODE_COOPERATIVE;
576         INJECT_FAULT(COMPlusThrowOM(););
577     }
578     CONTRACTL_END;
579
580     pThreadLocalBlock->EnsureModuleIndex(index);
581
582     _ASSERTE(pThreadLocalBlock != NULL);
583     _ASSERTE(pModule != NULL);
584
585     NewHolder<ThreadLocalModule> pThreadLocalModule = AllocateTLM(pModule);
586
587     pThreadLocalBlock->AllocateThreadStaticHandles(pModule, pThreadLocalModule);
588
589     pThreadLocalBlock->SetModuleSlot(index, pThreadLocalModule);
590     pThreadLocalModule.SuppressRelease();
591
592     return pThreadLocalModule;
593 }
594
595
596 PTR_ThreadLocalModule ThreadStatics::GetTLM(ModuleIndex index, Module * pModule) //static
597 {
598     CONTRACTL
599     {
600         THROWS;
601         GC_TRIGGERS;
602         MODE_COOPERATIVE;
603     }
604     CONTRACTL_END;
605
606     // Get the TLM if it already exists
607     PTR_ThreadLocalModule pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
608
609     // If the TLM does not exist, create it now
610     if (pThreadLocalModule == NULL)
611     {
612         // Get the current ThreadLocalBlock
613         PTR_ThreadLocalBlock pThreadLocalBlock = ThreadStatics::GetCurrentTLB();
614         _ASSERTE(pThreadLocalBlock != NULL);
615
616         // Allocate and initialize the TLM, and add it to the TLB's table
617         pThreadLocalModule = AllocateAndInitTLM(index, pThreadLocalBlock, pModule);
618     }
619
620     return pThreadLocalModule;
621 }
622
623 PTR_ThreadLocalModule ThreadStatics::GetTLM(MethodTable * pMT) //static
624 {
625     Module * pModule = pMT->GetModuleForStatics();
626     return GetTLM(pModule->GetModuleIndex(), pModule);
627 }
628
629 PTR_ThreadLocalBlock ThreadStatics::AllocateTLB(PTR_Thread pThread, ADIndex index) //static
630 {
631     CONTRACTL
632     {
633         THROWS;
634         GC_NOTRIGGER;
635         SO_TOLERANT;
636         MODE_ANY;
637     }
638     CONTRACTL_END;
639     _ASSERTE(pThread->m_pThreadLocalBlock == NULL);
640
641     // Grow the TLB table so that it has room to store the newly allocated 
642     // ThreadLocalBlock. If this growing the table fails we cannot proceed.
643     ThreadStatics::EnsureADIndex(pThread, index);
644
645     // Allocate a new TLB and update this Thread's pointer to the current 
646     // ThreadLocalBlock. Constructor zeroes out everything for us.
647     pThread->m_pThreadLocalBlock = new ThreadLocalBlock();
648
649     // Store the newly allocated ThreadLocalBlock in the TLB table
650     if (pThread->m_pThreadLocalBlock != NULL)
651     {
652         // We grew the TLB table earlier, so it should have room
653         _ASSERTE(index.m_dwIndex >= 0 && index.m_dwIndex < pThread->m_TLBTableSize);
654         pThread->m_pTLBTable[index.m_dwIndex] = pThread->m_pThreadLocalBlock;
655     }
656
657     return pThread->m_pThreadLocalBlock;
658 }
659
660 PTR_ThreadLocalModule ThreadStatics::AllocateTLM(Module * pModule)
661 {
662     CONTRACTL
663     {
664         THROWS;
665         GC_NOTRIGGER;
666         MODE_ANY;
667         INJECT_FAULT(COMPlusThrowOM(););
668     }
669     CONTRACTL_END;
670
671     SIZE_T size = pModule->GetThreadLocalModuleSize();
672
673     _ASSERTE(size >= ThreadLocalModule::OffsetOfDataBlob());
674
675     PTR_ThreadLocalModule pThreadLocalModule = (ThreadLocalModule*)new BYTE[size];
676
677     // We guarantee alignment for 64-bit regular thread statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons.
678
679     // The memory block has to be aligned at MAX_PRIMITIVE_FIELD_SIZE to guarantee alignment of statics
680     _ASSERTE(IS_ALIGNED(pThreadLocalModule, MAX_PRIMITIVE_FIELD_SIZE));
681     
682     // Zero out the part of memory where the TLM resides
683     memset(pThreadLocalModule, 0, size);
684     
685     return pThreadLocalModule;
686 }
687
688 #endif
689
690 PTR_ThreadLocalBlock ThreadStatics::GetTLBIfExists(PTR_Thread pThread, ADIndex index) //static
691 {
692     CONTRACTL
693     {
694         NOTHROW;
695         GC_NOTRIGGER;
696         MODE_ANY;
697         SUPPORTS_DAC;
698         SO_TOLERANT;
699     }
700     CONTRACTL_END;
701
702     // Check to see if we have a ThreadLocalBlock for the this AppDomain, 
703     if (index.m_dwIndex < pThread->m_TLBTableSize)
704     {
705         return pThread->m_pTLBTable[index.m_dwIndex];
706     }
707     
708     return NULL;
709 }