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// ZapCode.cpp
6//
7
8//
9// Everything directly related to zapping of native code
10// - The code itself
11// - Code headers
12// - All XXX infos: GC Info, EH Info, Unwind Info, ...
13//
14// ======================================================================================
15
16#include "common.h"
17
18#include "zapcode.h"
19
20#include "zapimport.h"
21
22#include "zapinnerptr.h"
23
24#ifdef FEATURE_READYTORUN_COMPILER
25#include "zapreadytorun.h"
26#endif
27
28#ifdef REDHAWK
29#include "rhcodeinfo.h"
30#include "rhbinder.h"
31#include "modulegcinfoencoder.h"
32#endif // REDHAWK
33
34//
35// The image layout algorithm
36//
37
38ZapVirtualSection * ZapImage::GetCodeSection(CodeType codeType)
39{
40 switch (codeType)
41 {
42 case ProfiledHot:
43 return m_pHotCodeSection;
44 case ProfiledCold:
45 return m_pColdCodeSection;
46 case Unprofiled:
47 return m_pCodeSection;
48 }
49
50 UNREACHABLE();
51}
52
53#if defined(WIN64EXCEPTIONS)
54ZapVirtualSection * ZapImage::GetUnwindDataSection(CodeType codeType)
55{
56#ifdef REDHAWK
57 return m_pUnwindDataSection;
58#else
59 switch (codeType)
60 {
61 case ProfiledHot:
62 return m_pHotUnwindDataSection;
63 case ProfiledCold:
64 return m_pColdUnwindDataSection;
65 case Unprofiled:
66 return m_pUnwindDataSection;
67 }
68
69#endif // REDHAWK
70 UNREACHABLE();
71}
72#endif // defined(WIN64EXCEPTIONS)
73
74ZapVirtualSection * ZapImage::GetRuntimeFunctionSection(CodeType codeType)
75{
76 switch (codeType)
77 {
78 case ProfiledHot:
79 return m_pHotRuntimeFunctionSection;
80 case ProfiledCold:
81 return m_pColdRuntimeFunctionSection;
82 case Unprofiled:
83 return m_pRuntimeFunctionSection;
84 }
85
86 UNREACHABLE();
87}
88
89ZapVirtualSection * ZapImage::GetCodeMethodDescSection(CodeType codeType)
90{
91 switch (codeType)
92 {
93 case ProfiledHot:
94 return m_pHotCodeMethodDescsSection;
95 case Unprofiled:
96 return m_pCodeMethodDescsSection;
97 default:
98 UNREACHABLE();
99 }
100}
101
102ZapVirtualSection* ZapImage::GetUnwindInfoLookupSection(CodeType codeType)
103{
104 switch(codeType)
105 {
106 case ProfiledHot:
107 return m_pHotRuntimeFunctionLookupSection;
108 case Unprofiled:
109 return m_pRuntimeFunctionLookupSection;
110 default:
111 UNREACHABLE();
112 }
113}
114
115void ZapImage::GetCodeCompilationRange(CodeType codeType, COUNT_T * start, COUNT_T * end)
116{
117 _ASSERTE(start && end);
118
119#ifdef REDHAWK
120 *start = 0;
121 *end = m_MethodCompilationOrder.GetCount();
122#else
123 switch (codeType)
124 {
125 case ProfiledHot:
126 *start = 0;
127 *end = m_iUntrainedMethod;
128 break;
129 case ProfiledCold:
130 *start = 0;
131 *end = m_MethodCompilationOrder.GetCount();
132 break;
133 case Unprofiled:
134 *start = m_iUntrainedMethod;
135 *end = m_MethodCompilationOrder.GetCount();
136 break;
137 }
138#endif // REDHAWK
139}
140
141void ZapImage::OutputCode(CodeType codeType)
142{
143 // Note there are three codeTypes: ProfiledHot, Unprofiled and ProfiledCold
144#if defined(REDHAWK)
145 SectionMethodListGenerator map;
146#endif
147
148 bool fCold = (codeType == ProfiledCold);
149 CorInfoRegionKind regionKind = (codeType == ProfiledHot) ? CORINFO_REGION_HOT : CORINFO_REGION_COLD;
150 BeginRegion(regionKind);
151
152 ZapVirtualSection * pCodeSection = GetCodeSection(codeType);
153 ZapVirtualSection * pRuntimeFunctionSection = GetRuntimeFunctionSection(codeType);
154
155#if defined (WIN64EXCEPTIONS)
156 ZapVirtualSection * pUnwindDataSection = GetUnwindDataSection(codeType);
157#endif // defined (WIN64EXCEPTIONS)
158
159 DWORD codeSize = 0;
160
161 // We should start with empty code section
162 _ASSERTE(pRuntimeFunctionSection->GetNodeCount() == 0);
163 _ASSERTE(pCodeSection->GetNodeCount() == 0);
164
165 COUNT_T startMethod, endMethod;
166#ifdef REDHAWK // TritonTBD
167 DWORD currentOffset = 0;
168#endif // REDHAWK
169
170 GetCodeCompilationRange(codeType, &startMethod, &endMethod);
171
172 DWORD dwStartMethodIndex = (codeType == Unprofiled) ? m_pHotRuntimeFunctionSection->GetNodeCount() : 0;
173
174 for (COUNT_T curMethod = startMethod; curMethod < endMethod; curMethod++)
175 {
176 ZapMethodHeader * pMethod = m_MethodCompilationOrder[curMethod];
177
178 ZapBlobWithRelocs * pCode = fCold ? pMethod->m_pColdCode : pMethod->m_pCode;
179 if (pCode == NULL)
180 {
181 continue;
182 }
183
184 if (!fCold)
185 {
186 pMethod->m_methodIndex = dwStartMethodIndex + pRuntimeFunctionSection->GetNodeCount();
187 }
188 else
189 {
190 pMethod->m_methodIndex = (DWORD)-1;
191 }
192
193 //Count the method size for use by ZapUnwindInfoLookupTable
194 codeSize = AlignUp(codeSize, pCode->GetAlignment());
195 codeSize += pCode->GetSize();
196
197 pCodeSection->Place(pCode);
198
199#ifdef REDHAWK
200 DWORD codeOffset = AlignUp(currentOffset, pCode->GetAlignment());
201 codeOffset = map.AlignToMethodStartGranularity(codeOffset);
202 map.NoticeMethod(codeOffset, pCode->GetSize());
203 currentOffset = codeOffset + pCode->GetSize();
204#endif
205
206 ZapReloc * pRelocs = pCode->GetRelocs();
207 if (pRelocs != NULL)
208 {
209 for (ZapReloc * pReloc = pRelocs; pReloc->m_type != IMAGE_REL_INVALID; pReloc++)
210 {
211 ZapNode * pTarget = pReloc->m_pTargetNode;
212
213 ZapNodeType type = pTarget->GetType();
214 if (type == ZapNodeType_InnerPtr)
215 {
216 pTarget = ((ZapInnerPtr *)pTarget)->GetBase();
217 type = pTarget->GetType();
218 }
219
220 switch (type)
221 {
222 case ZapNodeType_StubDispatchCell:
223 // Optimizations may create redundant references to the StubDispatchCell
224 if (!pTarget->IsPlaced())
225 {
226 m_pStubDispatchDataTable->PlaceStubDispatchCell((ZapImport *)pTarget);
227 }
228 break;
229 case ZapNodeType_MethodEntryPoint:
230 pTarget = m_pMethodEntryPoints->CanDirectCall((ZapMethodEntryPoint *)pTarget, pMethod);
231 if (pTarget != NULL)
232 {
233 pReloc->m_pTargetNode = pTarget;
234 }
235 break;
236 case ZapNodeType_Stub:
237 if (!pTarget->IsPlaced())
238 {
239 m_pStubsSection->Place(pTarget);
240 }
241 break;
242 case ZapNodeType_HelperThunk:
243 if (!pTarget->IsPlaced())
244 {
245 // This should place the most frequently used JIT helpers first and together
246 m_pHelperTableSection->Place(pTarget);
247 }
248 break;
249 case ZapNodeType_LazyHelperThunk:
250 if (!pTarget->IsPlaced())
251 {
252 ((ZapLazyHelperThunk *)pTarget)->Place(this);
253 }
254 break;
255 case ZapNodeType_Import_ModuleHandle:
256 case ZapNodeType_Import_ClassHandle:
257 case ZapNodeType_Import_StringHandle:
258 case ZapNodeType_Import_Helper:
259 // Place all potentially eager imports
260 if (!pTarget->IsPlaced())
261 m_pImportTable->PlaceImport((ZapImport *)pTarget);
262 break;
263
264 case ZapNodeType_ExternalMethodThunk:
265 if (!pTarget->IsPlaced())
266 m_pExternalMethodDataTable->PlaceExternalMethodThunk((ZapImport *)pTarget);
267 break;
268
269 case ZapNodeType_ExternalMethodCell:
270 if (!pTarget->IsPlaced())
271 m_pExternalMethodDataTable->PlaceExternalMethodCell((ZapImport *)pTarget);
272 break;
273
274#ifdef FEATURE_READYTORUN_COMPILER
275 case ZapNodeType_DynamicHelperCell:
276 if (!pTarget->IsPlaced())
277 m_pDynamicHelperDataTable->PlaceDynamicHelperCell((ZapImport *)pTarget);
278 break;
279
280 case ZapNodeType_IndirectHelperThunk:
281 if (!pTarget->IsPlaced())
282 m_pImportTable->PlaceIndirectHelperThunk(pTarget);
283 break;
284
285 case ZapNodeType_RVAFieldData:
286 if (!pTarget->IsPlaced())
287 m_pReadOnlyDataSection->Place(pTarget);
288 break;
289#endif
290
291 case ZapNodeType_GenericSignature:
292 if (!pTarget->IsPlaced())
293 m_pImportTable->PlaceBlob((ZapBlob *)pTarget);
294 break;
295 default:
296 break;
297 }
298 }
299 }
300
301#if defined (WIN64EXCEPTIONS)
302 //
303 // Place unwind data
304 //
305
306 InlineSArray<ZapUnwindInfo *, 8> unwindInfos;
307
308 ZapUnwindInfo * pFragment;
309
310 // Go over all fragments and append their unwind infos in this section
311 for (pFragment = pMethod->m_pUnwindInfoFragments;
312 pFragment != NULL;
313 pFragment = pFragment->GetNextFragment())
314 {
315 ZapNode * pFragmentCode = pFragment->GetCode();
316 _ASSERTE(pFragmentCode == pMethod->m_pCode || pFragmentCode == pMethod->m_pColdCode);
317
318 if (pFragmentCode == pCode)
319 {
320 unwindInfos.Append(pFragment);
321 }
322 }
323
324 // The runtime function section must be ordered correctly relative to code layout
325 // in the image. Sort the unwind infos by their offset
326 _ASSERTE(unwindInfos.GetCount() > 0);
327 qsort(&unwindInfos[0], unwindInfos.GetCount(), sizeof(ZapUnwindInfo *), ZapUnwindInfo::CompareUnwindInfo);
328
329 // Set the initial unwind info for the hot and cold sections
330 if (fCold)
331 {
332 _ASSERTE(pMethod->m_pColdUnwindInfo == NULL);
333 pMethod->m_pColdUnwindInfo = unwindInfos[0];
334 }
335 else
336 {
337 _ASSERTE(pMethod->m_pUnwindInfo == NULL);
338 pMethod->m_pUnwindInfo = unwindInfos[0];
339 }
340
341 for (COUNT_T iUnwindInfo = 0; iUnwindInfo < unwindInfos.GetCount(); iUnwindInfo++)
342 {
343 ZapUnwindInfo * pUnwindInfo = unwindInfos[iUnwindInfo];
344 pRuntimeFunctionSection->Place(pUnwindInfo);
345
346 ZapNode * pUnwindData = pUnwindInfo->GetUnwindData();
347
348 if (!pUnwindData->IsPlaced())
349 {
350 pUnwindDataSection->Place(pUnwindData);
351 }
352 }
353
354#else // defined (WIN64EXCEPTIONS)
355
356 ZapUnwindInfo * pUnwindInfo;
357 if (fCold)
358 {
359 // Chained unwind info
360 pUnwindInfo = new (GetHeap()) ZapUnwindInfo(pCode, 0, 0, pMethod->m_pUnwindInfo);
361 pMethod->m_pColdUnwindInfo = pUnwindInfo;
362 }
363 else
364 {
365 pUnwindInfo = new (GetHeap()) ZapUnwindInfo(pCode, 0, 0, pMethod->m_pGCInfo);
366 pMethod->m_pUnwindInfo = pUnwindInfo;
367 }
368 pRuntimeFunctionSection->Place(pUnwindInfo);
369
370#endif // defined (WIN64EXCEPTIONS)
371
372 if (m_stats != NULL)
373 {
374 CorInfoIndirectCallReason reason;
375 BOOL direct = m_pPreloader->CanSkipMethodPreparation(NULL, pMethod->GetHandle(), &reason);
376
377 if (direct && pMethod->m_pFixupList != NULL)
378 {
379 reason = CORINFO_INDIRECT_CALL_FIXUPS;
380 direct = FALSE;
381 }
382
383 if (direct)
384 {
385 m_stats->m_directMethods++;
386 }
387 else
388 {
389 m_stats->m_prestubMethods++;
390 m_stats->m_indirectMethodReasons[reason]++;
391 }
392 }
393 }
394
395#ifdef REDHAWK
396 // Redhawk needs any trailing padding to be 0xcc
397 DWORD cbPad = AlignUp(currentOffset, sizeof(DWORD)) - currentOffset;
398 if (cbPad != 0)
399 {
400 ZapBlob * pBlob = ZapBlob::NewBlob(this, NULL, cbPad);
401 memset(pBlob->GetData(), DEFAULT_CODE_BUFFER_INIT, cbPad);
402 pCodeSection->Place(pBlob);
403 currentOffset += cbPad;
404 }
405
406 map.Output(this, m_pCodeMgrSection, numMethods);
407#else
408 COUNT_T nUnwindInfos = pRuntimeFunctionSection->GetNodeCount();
409
410 if (nUnwindInfos != 0)
411 {
412 if (IsReadyToRunCompilation())
413 {
414 // TODO: Implement
415 }
416 else
417 if (!fCold)
418 {
419 ZapVirtualSection * pCodeMethodDescSection = GetCodeMethodDescSection(codeType);
420 pCodeMethodDescSection->Place(new (GetHeap()) ZapCodeMethodDescs(startMethod, endMethod, nUnwindInfos));
421
422 ZapVirtualSection* pUnwindInfoLookupSection = GetUnwindInfoLookupSection(codeType);
423 pUnwindInfoLookupSection->Place(new (GetHeap()) ZapUnwindInfoLookupTable(pRuntimeFunctionSection, pCodeSection, codeSize));
424 }
425 else
426 {
427 m_pColdCodeMapSection->Place(new (GetHeap()) ZapColdCodeMap(pRuntimeFunctionSection));
428 }
429 }
430#endif
431
432 EndRegion(regionKind);
433}
434
435void ZapImage::OutputCodeInfo(CodeType codeType)
436{
437 CorInfoRegionKind regionKind = (codeType == ProfiledHot) ? CORINFO_REGION_HOT : CORINFO_REGION_COLD;
438 BeginRegion(regionKind);
439
440 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
441 {
442 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
443
444 //
445 // We are either outputing the ProfiledHot methods
446 // or the unprofiled and cold methods
447 //
448 if ((pMethod->m_ProfilingDataFlags & (1 << ReadMethodCode)) != (codeType == ProfiledHot))
449 {
450 // Wrong kind so skip
451 continue;
452 }
453
454 if (pMethod->m_pROData != NULL)
455 m_pReadOnlyDataSection->Place(pMethod->m_pROData);
456
457#ifndef REDHAWK
458 // Note: for Redhawk we place EH info via OutputEHInfo().
459 if (pMethod->m_pExceptionInfo != NULL)
460 {
461 ZapNode* pCode = pMethod->m_pCode;
462 m_pExceptionInfoLookupTable->PlaceExceptionInfoEntry(pCode, pMethod->m_pExceptionInfo);
463 }
464#endif // REDHAWK
465
466 if (pMethod->m_pFixupList != NULL && !IsReadyToRunCompilation())
467 pMethod->m_pFixupInfo = m_pImportTable->PlaceFixups(pMethod->m_pFixupList);
468 }
469
470 EndRegion(regionKind);
471}
472
473void ZapImage::OutputProfileData()
474{
475 if (m_pInstrumentSection == NULL)
476 {
477 return;
478 }
479
480 ZapProfileData * pPrevious = NULL;
481
482 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
483 {
484 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
485
486 if (pMethod->m_pProfileData == NULL)
487 {
488 continue;
489 }
490
491 ZapProfileData * pHeader = new (GetHeap()) ZapProfileData(pMethod);
492
493 m_pInstrumentSection->Place(pHeader);
494 m_pInstrumentSection->Place(pMethod->m_pProfileData);
495
496 if (pPrevious != NULL)
497 {
498 pPrevious->SetNext(pHeader);
499 }
500
501 pPrevious = pHeader;
502 }
503}
504
505void ZapImage::OutputDebugInfo()
506{
507 m_pDebugInfoTable->PrepareLayout();
508 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
509 {
510 m_pDebugInfoTable->PlaceDebugInfo(m_MethodCompilationOrder[i]);
511 }
512 m_pDebugInfoTable->FinishLayout();
513}
514
515void ZapImage::OutputGCInfo()
516{
517#ifndef REDHAWK
518 struct MaskValue
519 {
520 DWORD mask;
521 DWORD value;
522 };
523
524 static const MaskValue gcInfoSequence[] =
525 {
526 { (1 << CommonReadGCInfo) , (1 << CommonReadGCInfo) }, // c flag on, r flag don't care
527 { (1 << CommonReadGCInfo)|(1 << ReadGCInfo), (1 << ReadGCInfo) }, // r flag on, c flag off
528 { (1 << CommonReadGCInfo)|(1 << ReadGCInfo), 0 }, // both flags off
529 { 0, 0 }
530 };
531
532 // Make three passes over the gc infos, emitting them in order of decreasing hotness,
533 // and for stuff that wasn't touched by anyone we put it in the cold section
534 for (const MaskValue *pMaskValue = gcInfoSequence; pMaskValue->mask; pMaskValue++)
535 {
536 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
537 {
538 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
539
540 if ((pMethod->m_ProfilingDataFlags & pMaskValue->mask) != pMaskValue->value)
541 {
542 continue;
543 }
544
545 ZapGCInfo * pGCInfo = pMethod->m_pGCInfo;
546
547 // Given that GC Info can be interned it may have been placed already on
548 // this or a previous pass through the compiled methods. If it hasn't already
549 // been placed then we place it in the appropriate section.
550 if (!pGCInfo->IsPlaced())
551 {
552 // A) it was touched, and here they are placed in order of flags above
553 if (pMaskValue->value)
554 {
555 m_pHotTouchedGCSection->Place(pGCInfo);
556 }
557 // B) the method that it is attached to is in the trained section
558 else if (i<m_iUntrainedMethod)
559 {
560 m_pHotGCSection->Place(pGCInfo);
561 }
562 // C) it wasn't touched _and_ it is related to untrained code
563 else
564 {
565 m_pGCSection->Place(pGCInfo);
566 }
567 }
568 }
569
570 // Just after placing those touched in an IBC scenario, place those that
571 // should be prioritized regardless of the corresponding method's IBC information.
572 // (Currently, this is used to pack the gc info of IL stubs that cannot be directly tracked by IBC.)
573 if (pMaskValue->value == (1 << ReadGCInfo))
574 {
575 for (COUNT_T i = 0; i < m_PrioritizedGCInfo.GetCount(); i++)
576 {
577 ZapGCInfo * pGCInfo = m_PrioritizedGCInfo[i];
578 if (!pGCInfo->IsPlaced())
579 {
580 m_pHotGCSection->Place(pGCInfo);
581 }
582 }
583 }
584 }
585#else // REDHAWK
586 //
587 ModuleGcInfoEncoder * pEncoder = GetGcInfoEncoder();
588
589 m_pUnwindInfoBlob = pEncoder->ConstructUnwindInfoBlob(this);
590 m_pCallsiteInfoBlob = pEncoder->ConstructCallsiteInfoBlob(this);
591 ZapBlob * pShortcutMap = pEncoder->ConstructDeltaShortcutMap(this);
592
593 // @TODO: we could fold this loop into ConstructMethodInfoBlob, but then we'd have to keep a separate
594 // list of method infos inside the ModuleGcInfoEncoder..
595 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
596 {
597 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
598 pEncoder->EncodeMethodInfo(pMethod->m_pGCInfo);
599 }
600 ZapBlob * pMethodInfos = pEncoder->ConstructMethodInfoBlob(this);
601
602 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
603 {
604 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
605 // At this point pMethod->m_pGCInfo is really a pointer that the encoder owns.
606 // We must pass it back to the encoder so it can encode it and pass back a proper ZapBlob *
607 pMethod->m_pGCInfo = pEncoder->FindMethodInfo(this, pMethod->m_pGCInfo);
608 }
609
610 m_pGCSection->Place(pShortcutMap);
611 m_pGCSection->Place(pMethodInfos);
612 if (m_pUnwindInfoBlob)
613 m_pGCSection->Place(m_pUnwindInfoBlob);
614
615 if (m_pCallsiteInfoBlob)
616 m_pGCSection->Place(m_pCallsiteInfoBlob);
617
618 //
619 // Create the method-number-to-gc-info table
620 //
621 UINT32 methodInfoSize = pMethodInfos->GetSize();
622
623 COUNT_T nMethods = m_MethodCompilationOrder.GetCount();
624 UINT16 elemSize = 4;
625
626 if (methodInfoSize <= 0x10000)
627 {
628 elemSize = 2;
629
630 // Remember the element size for this map in the module header
631 m_moduleHeaderFlags |= ModuleHeader::SmallGCInfoListEntriesFlag;
632 }
633
634 // Create the table
635 SIZE_T tableSize = elemSize * nMethods;
636 ZapBlob * pMethodToGcInfoMap = ZapBlob::NewBlob(this, NULL, tableSize);
637
638 UINT16* pwTableEntries = (UINT16*) pMethodToGcInfoMap->GetData();
639 UINT32* pdwTableEntries = (UINT32*) pwTableEntries;
640
641 for (COUNT_T i = 0; i < nMethods; i++)
642 {
643 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
644 ZapGCInfo * pGCInfo = pMethod->m_pGCInfo;
645
646 UINT32 uOffset = 0;
647 if (pGCInfo->GetType() == ZapNodeType_InnerPtr)
648 {
649 uOffset = ((ZapInnerPtr*)pGCInfo)->GetOffset();
650 }
651 else
652 {
653 assert(ZapNodeType_Blob == pGCInfo->GetType());
654 assert(pGCInfo == pMethodInfos);
655 }
656
657 if (2 == elemSize)
658 {
659 assert(uOffset <= 0xFFFF);
660 pwTableEntries[i] = uOffset;
661 }
662 else
663 {
664 pdwTableEntries[i] = uOffset;
665 }
666 }
667
668 m_pMethodToGCInfoMap->Place(pMethodToGcInfoMap);
669#endif // REDHAWK
670}
671
672#ifdef REDHAWK
673// Place all ZapExceptionInfo blobs into the exception section, and form the lookup table that we'll
674// use at runtime to find EH info for a given method.
675void ZapImage::OutputEHInfo()
676{
677 // For non-REDHAWK builds, we output EH info with the other per-method data in OutputCodeInfo().
678
679 // @TODO: consider emitting EH info in order of increasing hotness, like we do for GC info.
680
681 // Place EH info for every method that has EH.
682 for (COUNT_T i = 0; i < m_MethodCompilationOrder.GetCount(); i++)
683 {
684 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
685 ZapExceptionInfo * pEHInfo = pMethod->m_pExceptionInfo;
686
687 if ((pEHInfo != NULL) && !pEHInfo->IsPlaced())
688 {
689 // We add relocs to the exception info here, at the last possible momement before placing
690 // them. That's because adding relocs changes the exception info, but prior to this we
691 // want to be able to use the data of the exception info as a hash key for interning.
692 AddRelocsForEHClauses(pEHInfo);
693 m_pExceptionSection->Place(pEHInfo);
694 }
695 }
696
697 // Get the offsets for each EH blob that we will emit.
698 MapSHash<ZapNode *, UINT32> ehinfoOffsets;
699 UINT32 ehinfoSize;
700
701 ehinfoSize = m_pExceptionSection->FillInNodeOffsetMap(&ehinfoOffsets);
702
703 // Chose a table entry size.
704 COUNT_T nMethods = m_MethodCompilationOrder.GetCount();
705 UINT16 elemSize = 4;
706
707 if (ehinfoSize <= 0x10000)
708 {
709 elemSize = 2;
710
711 // Remember the element size for this map in the module header
712 m_moduleHeaderFlags |= ModuleHeader::SmallEHInfoListEntriesFlag;
713 }
714
715 // Create the table.
716 SIZE_T tableSize = elemSize * nMethods;
717 SArray<BYTE> tableData(tableSize);
718
719 UINT16* pwTableEntries = (UINT16*)&tableData[0];
720 UINT32* pdwTableEntries = (UINT32*) pwTableEntries;
721
722 // Fill in the offset for each method that has EH info. For methods that have no
723 // EH info, we will use a sentinel offset of -1.
724 for (COUNT_T i = 0; i < nMethods; i++)
725 {
726 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
727 ZapExceptionInfo * pEHInfo = pMethod->m_pExceptionInfo;
728
729 UINT32 uOffset = -1;
730
731 if (pEHInfo != NULL)
732 {
733 ehinfoOffsets.Lookup(pEHInfo, &uOffset);
734 assert(uOffset != -1); // Can't have a valid offset match the sentinel!
735 assert((4 == elemSize) || (uOffset <= 0xFFFF)); // Size must fit in 2 bytes if we're using hte small rep.
736 }
737
738 if (2 == elemSize)
739 {
740 pwTableEntries[i] = uOffset;
741 }
742 else
743 {
744 pdwTableEntries[i] = uOffset;
745 }
746 }
747
748 m_pMethodToEHInfoMap->Place(ZapBlob::NewBlob(this, &tableData[0], tableSize));
749}
750#endif // REDHAWK
751
752#ifdef REDHAWK
753// Add relocs for any EEType references in any typed EH clauses for the given EH Info.
754void ZapImage::AddRelocsForEHClauses(ZapExceptionInfo * pExceptionInfo)
755{
756 EE_ILEXCEPTION *pEHInfo = (EE_ILEXCEPTION *)pExceptionInfo->GetData();
757 _ASSERTE(pEHInfo != NULL);
758
759 // One set of relocs for the entire set of clauses. Size assuming that every clause has a token.
760 ZapReloc * pRelocs = (ZapReloc *)
761 new (GetHeap()) BYTE[sizeof(ZapReloc) * pEHInfo->EHCount() + sizeof(ZapRelocationType)];
762
763 DWORD relocIndex = 0;
764
765 // Add relocs for EEType references each typed clause.
766 for (int i = 0; i < pEHInfo->EHCount(); i++)
767 {
768 EE_ILEXCEPTION_CLAUSE *pClause = pEHInfo->EHClause(i);
769
770 if ((pClause->Flags == COR_ILEXCEPTION_CLAUSE_NONE) ||
771 (pClause->Flags == COR_ILEXCEPTION_CLAUSE_INDIRECT_TYPE_REFERENCE))
772 {
773 ZapNode *pEETypeNode = (ZapNode*)pClause->EETypeReference;
774
775 // @TODO: we're using a full pointer for each EEType reference in the EH clause. This will be
776 // 64bits on a 64bit system, though, which is twice as large as it needs to be. We should make
777 // these 32bit RVA's and compute the final address at runtime when we start supporting 64bit
778 // systems. See comments in ZapInfo::setEHinfo() for more details.
779 //
780 // N.B! If we move to RVAs, then the runtime structure that matches the EE_ILEXCEPTION struct
781 // needs to have a padding field removed. (The C++ compiler introduced 4 bytes of padding between
782 // 'DataSize' and 'Clauses' because 'Clauses' has a pointer field in it. This padding will
783 // disappear when we change the pointers to RVAs.)
784 pRelocs[relocIndex].m_type = IMAGE_REL_BASED_PTR;
785 pRelocs[relocIndex].m_pTargetNode = pEETypeNode;
786 pRelocs[relocIndex].m_offset = (BYTE*)pClause - (BYTE*)pEHInfo + offsetof(EE_ILEXCEPTION_CLAUSE, EETypeReference);
787 pExceptionInfo->ZeroPointer(pRelocs[relocIndex].m_offset);
788 relocIndex++;
789 }
790 }
791
792 // Did we end up with any relocs? If so, then add them to the blob.
793 if (relocIndex > 0)
794 {
795 // Set sentinel
796 C_ASSERT(offsetof(ZapReloc, m_type) == 0);
797 pRelocs[relocIndex].m_type = IMAGE_REL_INVALID;
798
799 pExceptionInfo->SetRelocs(pRelocs);
800 }
801}
802#endif // REDHAWK
803
804//
805// ZapMethodHeader
806//
807
808#if defined(_TARGET_X86_)
809
810DWORD ZapCodeBlob::ComputeRVA(ZapWriter * pZapWriter, DWORD dwPos)
811{
812 void * pData = GetData();
813 SIZE_T size = GetSize();
814 DWORD dwAlignment = GetAlignment();
815
816 dwPos = AlignUp(dwPos, dwAlignment);
817
818#ifdef _TARGET_X86_
819 //
820 // Padding for straddler relocations.
821 //
822
823 // The maximum size of padding
824 const DWORD cbAdjustForDynamicBaseMax = 256;
825
826 // Find padding that gives us minimum number of straddlers
827 DWORD nMinStraddlers = MAXDWORD;
828 DWORD bestPad = 0;
829 for (DWORD pad = 0; pad < cbAdjustForDynamicBaseMax; pad += dwAlignment)
830 {
831 COUNT_T nStraddlers = GetCountOfStraddlerRelocations(dwPos + pad);
832 if (nStraddlers < nMinStraddlers)
833 {
834 nMinStraddlers = nStraddlers;
835 bestPad = pad;
836
837 // It won't get better than this.
838 if (nMinStraddlers == 0)
839 break;
840 }
841 }
842
843 DWORD dwPaddedPos = dwPos + bestPad;
844 SetRVA(dwPaddedPos);
845
846 return dwPaddedPos + size;
847#endif // _TARGET_X86_
848}
849
850template <DWORD alignment>
851class ZapCodeBlobConst : public ZapCodeBlob
852{
853protected:
854 ZapCodeBlobConst(SIZE_T cbSize)
855 : ZapCodeBlob(cbSize)
856 {
857 }
858
859public:
860 virtual UINT GetAlignment()
861 {
862 return alignment;
863 }
864
865 static ZapCodeBlob * NewBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize)
866 {
867 S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapCodeBlobConst<alignment>)) + S_SIZE_T(cbSize);
868 if(cbAllocSize.IsOverflow())
869 ThrowHR(COR_E_OVERFLOW);
870
871 void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
872
873 ZapCodeBlob * pZapCodeBlob = new (pMemory) ZapCodeBlobConst<alignment>(cbSize);
874
875 if (pData != NULL)
876 memcpy((void*)(pZapCodeBlob + 1), pData, cbSize);
877
878 return pZapCodeBlob;
879 }
880};
881
882ZapCodeBlob * ZapCodeBlob::NewAlignedBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, SIZE_T cbAlignment)
883{
884 switch (cbAlignment)
885 {
886 case 1:
887 return ZapCodeBlobConst<1>::NewBlob(pWriter, pData, cbSize);
888 case 2:
889 return ZapCodeBlobConst<2>::NewBlob(pWriter, pData, cbSize);
890 case 4:
891 return ZapCodeBlobConst<4>::NewBlob(pWriter, pData, cbSize);
892 case 8:
893 return ZapCodeBlobConst<8>::NewBlob(pWriter, pData, cbSize);
894 case 16:
895 return ZapCodeBlobConst<16>::NewBlob(pWriter, pData, cbSize);
896
897 default:
898 _ASSERTE(!"Requested alignment not supported");
899 return NULL;
900 }
901}
902
903#endif
904
905
906// See function prototype for details on why this iterator is "partial"
907BOOL ZapMethodHeader::PartialTargetMethodIterator::GetNext(CORINFO_METHOD_HANDLE *pHnd)
908{
909 _ASSERTE(pHnd != NULL);
910
911 if (m_pCurReloc == NULL)
912 {
913 return FALSE;
914 }
915
916 while (m_pCurReloc->m_type != IMAGE_REL_INVALID)
917 {
918 ZapNode * pTarget = m_pCurReloc->m_pTargetNode;
919 ZapNodeType type = pTarget->GetType();
920
921 m_pCurReloc++;
922
923 if (type == ZapNodeType_InnerPtr)
924 {
925 pTarget = ((ZapInnerPtr *)pTarget)->GetBase();
926 type = pTarget->GetType();
927 }
928
929 if (type == ZapNodeType_MethodEntryPoint)
930 {
931 *pHnd = ((ZapMethodEntryPoint *)pTarget)->GetHandle();
932 return TRUE;
933 }
934 }
935
936 return FALSE;
937}
938
939void ZapCodeMethodDescs::Save(ZapWriter * pZapWriter)
940{
941 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
942
943 COUNT_T nUnwindInfos = 0;
944
945 for (COUNT_T curMethod = m_iStartMethod; curMethod < m_iEndMethod; curMethod++)
946 {
947 ZapMethodHeader * pMethod = pImage->m_MethodCompilationOrder[curMethod];
948 DWORD dwRVA = pImage->m_pPreloader->MapMethodHandle(pMethod->GetHandle());
949
950 if (pMethod->m_pExceptionInfo != NULL)
951 dwRVA |= HAS_EXCEPTION_INFO_MASK;
952
953 pImage->Write(&dwRVA, sizeof(dwRVA));
954 nUnwindInfos++;
955
956#ifdef WIN64EXCEPTIONS
957 ZapUnwindInfo * pFragment = pMethod->m_pUnwindInfoFragments;
958 while (pFragment != NULL)
959 {
960 if (pFragment != pMethod->m_pUnwindInfo && pFragment->GetCode() == pMethod->m_pCode)
961 {
962 dwRVA = 0;
963 pImage->Write(&dwRVA, sizeof(dwRVA));
964 nUnwindInfos++;
965 }
966
967 pFragment = pFragment->GetNextFragment();
968 }
969#endif
970 }
971 _ASSERTE(nUnwindInfos == m_nUnwindInfos);
972}
973
974//
975// ZapMethodEntryPoint
976//
977
978void ZapMethodEntryPoint::Resolve(ZapImage * pImage)
979{
980 DWORD rvaValue = pImage->m_pPreloader->MapMethodEntryPoint(GetHandle());
981#ifdef _DEBUG
982 if (rvaValue == NULL)
983 {
984 mdMethodDef token;
985 pImage->GetCompileInfo()->GetMethodDef(GetHandle(), &token);
986 pImage->Error(token, S_OK, 0, W("MapMethodEntryPoint failed"));
987 }
988 else
989#endif
990 {
991 SetRVA(rvaValue);
992 }
993}
994
995ZapMethodEntryPoint * ZapMethodEntryPointTable::GetMethodEntryPoint(CORINFO_METHOD_HANDLE handle, CORINFO_ACCESS_FLAGS accessFlags)
996{
997 ZapMethodEntryPoint * pMethodEntryPoint = m_entries.Lookup(MethodEntryPointKey(handle, accessFlags));
998
999 if (pMethodEntryPoint != NULL)
1000 return pMethodEntryPoint;
1001
1002#ifdef _DEBUG
1003 mdMethodDef token;
1004 m_pImage->GetCompileInfo()->GetMethodDef(handle, &token);
1005#endif
1006
1007 pMethodEntryPoint = new (m_pImage->GetHeap()) ZapMethodEntryPoint(handle, accessFlags);
1008 m_entries.Add(pMethodEntryPoint);
1009 return pMethodEntryPoint;
1010}
1011
1012void ZapMethodEntryPointTable::Resolve()
1013{
1014 for (MethodEntryPointTable::Iterator i = m_entries.Begin(), end = m_entries.End(); i != end; i++)
1015 {
1016 ZapMethodEntryPoint * pMethodEntryPoint = *i;
1017
1018 // Skip unused entrypoints - they may be omitted in the image
1019 if (!pMethodEntryPoint->IsUsed())
1020 continue;
1021
1022 pMethodEntryPoint->Resolve(m_pImage);
1023 }
1024}
1025
1026ZapNode * ZapMethodEntryPointTable::CanDirectCall(ZapMethodEntryPoint * pMethodEntryPoint, ZapMethodHeader * pCaller)
1027{
1028 CORINFO_METHOD_HANDLE caller = pCaller->GetHandle();
1029 CORINFO_METHOD_HANDLE callee = pMethodEntryPoint->GetHandle();
1030
1031 CorInfoIndirectCallReason reason;
1032 if (m_pImage->canIntraModuleDirectCall(caller, callee, &reason, pMethodEntryPoint->GetAccessFlags()))
1033 {
1034 ZapNode * pCode = m_pImage->GetCompiledMethod(callee)->GetCode();
1035#ifdef _TARGET_ARM_
1036 pCode = m_pImage->GetInnerPtr(pCode, THUMB_CODE);
1037#endif // _TARGET_ARM_
1038 return pCode;
1039 }
1040 else
1041 {
1042 if (!pMethodEntryPoint->IsUsed())
1043 {
1044 // This method entry point is going to be used for indirect call.
1045 // Record this so that later we will assign it an RVA.
1046 pMethodEntryPoint->SetIsUsed();
1047 }
1048 return NULL;
1049 }
1050}
1051
1052#ifdef WIN64EXCEPTIONS
1053ZapGCInfo * ZapGCInfoTable::GetGCInfo(PVOID pGCInfo, SIZE_T cbGCInfo, PVOID pUnwindInfo, SIZE_T cbUnwindInfo)
1054{
1055 ZapGCInfo * pNode = m_blobs.Lookup(GCInfoKey(pGCInfo, cbGCInfo, pUnwindInfo, cbUnwindInfo));
1056
1057 if (pNode != NULL)
1058 {
1059 return pNode;
1060 }
1061
1062 pNode = ZapGCInfo::NewGCInfo(m_pImage, pGCInfo, cbGCInfo, pUnwindInfo, cbUnwindInfo);
1063 m_blobs.Add(pNode);
1064 return pNode;
1065}
1066
1067ZapGCInfo * ZapGCInfo::NewGCInfo(ZapWriter * pWriter, PVOID pGCInfo, SIZE_T cbGCInfo, PVOID pUnwindInfo, SIZE_T cbUnwindInfo)
1068{
1069 S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapGCInfo)) + S_SIZE_T(cbGCInfo) + S_SIZE_T(cbUnwindInfo);
1070 if(cbAllocSize.IsOverflow())
1071 ThrowHR(COR_E_OVERFLOW);
1072
1073 void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
1074
1075 ZapGCInfo * pZapGCInfo = new (pMemory) ZapGCInfo(cbGCInfo, cbUnwindInfo);
1076
1077 memcpy(pZapGCInfo->GetGCInfo(), pGCInfo, cbGCInfo);
1078 memcpy(pZapGCInfo->GetUnwindInfo(), pUnwindInfo, cbUnwindInfo);
1079
1080#if !defined(_TARGET_X86_)
1081 // Make sure the personality routine thunk is created
1082 pZapGCInfo->GetPersonalityRoutine(ZapImage::GetImage(pWriter));
1083#endif // !defined(_TARGET_X86_)
1084 return pZapGCInfo;
1085}
1086#else
1087ZapGCInfo * ZapGCInfoTable::GetGCInfo(PVOID pBlob, SIZE_T cbBlob)
1088{
1089 ZapGCInfo * pNode = m_blobs.Lookup(ZapBlob::SHashKey(pBlob, cbBlob));
1090
1091 if (pNode != NULL)
1092 {
1093 return pNode;
1094 }
1095
1096 pNode = ZapBlob::NewBlob(m_pImage, pBlob, cbBlob);
1097 m_blobs.Add(pNode);
1098 return pNode;
1099}
1100#endif
1101
1102//
1103// ZapUnwindInfo
1104//
1105
1106void ZapUnwindInfo::Save(ZapWriter * pZapWriter)
1107{
1108 T_RUNTIME_FUNCTION runtimeFunction;
1109
1110#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1111 RUNTIME_FUNCTION__SetBeginAddress(&runtimeFunction, GetStartAddress());
1112 runtimeFunction.UnwindData = m_pUnwindData->GetRVA();
1113#elif defined(_TARGET_AMD64_)
1114 runtimeFunction.BeginAddress = GetStartAddress();
1115 runtimeFunction.EndAddress = GetEndAddress();
1116 ULONG unwindData = m_pUnwindData->GetRVA();
1117 if (m_pUnwindData->GetType() == ZapNodeType_UnwindInfo) // Chained unwind info
1118 unwindData |= RUNTIME_FUNCTION_INDIRECT;
1119 runtimeFunction.UnwindData = unwindData;
1120#elif defined(_TARGET_X86_)
1121 runtimeFunction.BeginAddress = GetStartAddress();
1122 ULONG unwindData = m_pUnwindData->GetRVA();
1123 if (m_pUnwindData->GetType() == ZapNodeType_UnwindInfo) // Chained unwind info
1124 unwindData |= RUNTIME_FUNCTION_INDIRECT;
1125 runtimeFunction.UnwindData = unwindData;
1126#else
1127 PORTABILITY_ASSERT("ZapUnwindInfo");
1128#endif
1129
1130 pZapWriter->Write(&runtimeFunction, sizeof(runtimeFunction));
1131}
1132
1133#if defined(WIN64EXCEPTIONS)
1134// Compare the unwind infos by their offset
1135int __cdecl ZapUnwindInfo::CompareUnwindInfo(const void* a_, const void* b_)
1136{
1137 ZapUnwindInfo * a = *(ZapUnwindInfo **)a_;
1138 ZapUnwindInfo * b = *(ZapUnwindInfo **)b_;
1139
1140 if (a->GetStartOffset() > b->GetStartOffset())
1141 {
1142 _ASSERTE(a->GetStartOffset() >= b->GetEndOffset());
1143 return 1;
1144 }
1145
1146 if (a->GetStartOffset() < b->GetStartOffset())
1147 {
1148 _ASSERTE(a->GetEndOffset() <= b->GetEndOffset());
1149 return -1;
1150 }
1151
1152 _ASSERTE(a == b);
1153 return 0;
1154}
1155
1156#if defined(_TARGET_AMD64_)
1157
1158UINT ZapUnwindData::GetAlignment()
1159{
1160 return sizeof(ULONG);
1161}
1162
1163DWORD ZapUnwindData::GetSize()
1164{
1165 DWORD dwSize = ZapBlob::GetSize();
1166
1167#ifndef REDHAWK
1168 // Add space for personality routine, it must be 4-byte aligned.
1169 // Everything in the UNWIND_INFO has already had its size included in size
1170 dwSize = AlignUp(dwSize, sizeof(ULONG));
1171
1172 dwSize += sizeof(ULONG);
1173#endif //REDHAWK
1174
1175 return dwSize;
1176}
1177
1178void ZapUnwindData::Save(ZapWriter * pZapWriter)
1179{
1180 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1181
1182 PVOID pData = GetData();
1183 DWORD dwSize = GetBlobSize();
1184
1185 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *)pData;
1186
1187 // Check whether the size is what we expect it to be
1188 _ASSERTE(dwSize == offsetof(UNWIND_INFO, UnwindCode) + pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE));
1189#ifndef REDHAWK
1190 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
1191#endif //REDHAWK
1192
1193 pZapWriter->Write(pData, dwSize);
1194
1195#ifndef REDHAWK
1196 DWORD dwPad = AlignmentPad(dwSize, sizeof(DWORD));
1197 if (dwPad != 0)
1198 pZapWriter->WritePad(dwPad);
1199
1200 ULONG personalityRoutine = GetPersonalityRoutine(pImage)->GetRVA();
1201 pZapWriter->Write(&personalityRoutine, sizeof(personalityRoutine));
1202#endif //REDHAWK
1203}
1204
1205#elif defined(_TARGET_X86_)
1206
1207UINT ZapUnwindData::GetAlignment()
1208{
1209 return sizeof(BYTE);
1210}
1211
1212DWORD ZapUnwindData::GetSize()
1213{
1214 return ZapBlob::GetSize();
1215}
1216
1217void ZapUnwindData::Save(ZapWriter * pZapWriter)
1218{
1219 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1220
1221 PVOID pData = GetData();
1222 DWORD dwSize = GetBlobSize();
1223
1224 pZapWriter->Write(pData, dwSize);
1225}
1226
1227#elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1228
1229UINT ZapUnwindData::GetAlignment()
1230{
1231 return sizeof(ULONG);
1232}
1233
1234DWORD ZapUnwindData::GetSize()
1235{
1236 DWORD dwSize = ZapBlob::GetSize();
1237
1238 // Add space for personality routine, it must be 4-byte aligned.
1239 // Everything in the UNWIND_INFO has already had its size included in size
1240 dwSize = AlignUp(dwSize, sizeof(ULONG));
1241 dwSize += sizeof(ULONG);
1242
1243 return dwSize;
1244}
1245
1246void ZapUnwindData::Save(ZapWriter * pZapWriter)
1247{
1248 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1249
1250 PVOID pData = GetData();
1251 DWORD dwSize = GetBlobSize();
1252
1253 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *)pData;
1254
1255 // Set the 'X' bit to indicate that there is a personality routine associated with this method
1256 *(LONG *)pUnwindInfo |= (1<<20);
1257
1258 pZapWriter->Write(pData, dwSize);
1259
1260 DWORD dwPad = AlignmentPad(dwSize, sizeof(DWORD));
1261 if (dwPad != 0)
1262 pZapWriter->WritePad(dwPad);
1263
1264 ULONG personalityRoutine = GetPersonalityRoutine(pImage)->GetRVA();
1265 pZapWriter->Write(&personalityRoutine, sizeof(personalityRoutine));
1266}
1267
1268#else
1269UINT ZapUnwindData::GetAlignment()
1270{
1271 PORTABILITY_ASSERT("ZapUnwindData::GetAlignment");
1272 return sizeof(ULONG);
1273}
1274DWORD ZapUnwindData::GetSize()
1275{
1276 PORTABILITY_ASSERT("ZapUnwindData::GetSize");
1277 return -1;
1278}
1279void ZapUnwindData::Save(ZapWriter * pZapWriter)
1280{
1281 PORTABILITY_ASSERT("ZapUnwindData::Save");
1282}
1283
1284#endif
1285
1286ZapNode * ZapUnwindData::GetPersonalityRoutine(ZapImage * pImage)
1287{
1288 // Use different personality routine pointer for filter funclets so that we can quickly tell at runtime
1289 // whether funclet is a filter.
1290#ifdef FEATURE_READYTORUN_COMPILER
1291 if (IsReadyToRunCompilation())
1292 {
1293 ReadyToRunHelper helperNum = IsFilterFunclet() ? READYTORUN_HELPER_PersonalityRoutineFilterFunclet : READYTORUN_HELPER_PersonalityRoutine;
1294 return pImage->GetImportTable()->GetPlacedIndirectHelperThunk(helperNum);
1295 }
1296#endif
1297 return pImage->GetHelperThunk(IsFilterFunclet() ? CORINFO_HELP_EE_PERSONALITY_ROUTINE_FILTER_FUNCLET : CORINFO_HELP_EE_PERSONALITY_ROUTINE);
1298}
1299
1300ZapUnwindData * ZapUnwindData::NewUnwindData(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, BOOL fIsFilterFunclet)
1301{
1302 SIZE_T cbAllocSize = sizeof(ZapUnwindData) + cbSize;
1303
1304 void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize];
1305
1306 ZapUnwindData * pZapUnwindData = fIsFilterFunclet ?
1307 (new (pMemory) ZapFilterFuncletUnwindData(cbSize)) : (new (pMemory) ZapUnwindData(cbSize));
1308
1309 memcpy((void*)(pZapUnwindData + 1), pData, cbSize);
1310
1311#if !defined(_TARGET_X86_)
1312 // Make sure the personality routine thunk is created
1313 pZapUnwindData->GetPersonalityRoutine(ZapImage::GetImage(pWriter));
1314#endif // !defined(_TARGET_X86_)
1315
1316 return pZapUnwindData;
1317}
1318
1319ZapUnwindData * ZapUnwindDataTable::GetUnwindData(PVOID pBlob, SIZE_T cbBlob, BOOL fIsFilterFunclet)
1320{
1321 ZapUnwindData * pNode = (ZapUnwindData *)m_blobs.Lookup(ZapUnwindDataKey(pBlob, cbBlob, fIsFilterFunclet));
1322
1323 if (pNode != NULL)
1324 {
1325 return pNode;
1326 }
1327
1328 pNode = ZapUnwindData::NewUnwindData(m_pImage, pBlob, cbBlob, fIsFilterFunclet);
1329 m_blobs.Add(pNode);
1330 return pNode;
1331}
1332#endif // WIN64EXCEPTIONS
1333
1334//
1335// ZapDebugInfo
1336//
1337
1338ZapDebugInfo * ZapDebugInfoTable::GetDebugInfo(PVOID pBlob, SIZE_T cbBlob)
1339{
1340 ZapDebugInfo * pNode = m_blobs.Lookup(ZapBlob::SHashKey(pBlob, cbBlob));
1341 m_nCount++;
1342
1343 if (pNode != NULL)
1344 {
1345 return pNode;
1346 }
1347
1348 pNode = ZapBlob::NewBlob(m_pImage, pBlob, cbBlob);
1349 m_blobs.Add(pNode);
1350 return pNode;
1351}
1352
1353void ZapDebugInfoTable::PrepareLayout()
1354{
1355 if (m_nCount == 0)
1356 return;
1357
1358 // Make sure that the number of methods is odd number
1359 m_nCount |= 1;
1360
1361 m_pTable = new (m_pImage->GetHeap()) ZapNode * [m_nCount];
1362}
1363
1364void ZapDebugInfoTable::PlaceDebugInfo(ZapMethodHeader * pMethod)
1365{
1366 // Place the debug info blob if it is not placed yet
1367 ZapBlob * pDebugInfo = pMethod->GetDebugInfo();
1368 if (pDebugInfo == NULL)
1369 {
1370 return;
1371 }
1372
1373 if (!pDebugInfo->IsPlaced())
1374 {
1375 m_pImage->m_pDebugSection->Place(pDebugInfo);
1376 }
1377
1378 mdMethodDef md;
1379 IfFailThrow(m_pImage->GetCompileInfo()->GetMethodDef(pMethod->GetHandle(), &md));
1380
1381 COUNT_T index = GetDebugRidEntryHash(md) % m_nCount;
1382
1383 ZapNode * pHead = m_pTable[index];
1384 if (pHead == NULL)
1385 {
1386 // The common case - single rid entry.
1387 m_pTable[index] = pMethod;
1388 return;
1389 }
1390
1391 // Create linked list of labelled entries if we do not have one yet
1392 if (pHead->GetType() != ZapNodeType_DebugInfoLabelledEntry)
1393 {
1394 m_pTable[index] = new (m_pImage->GetHeap()) LabelledEntry((ZapMethodHeader *)pHead);
1395 }
1396
1397 // Insert the method at the end of the linked list
1398 LabelledEntry * pEntry = (LabelledEntry *)m_pTable[index];
1399 while (pEntry->m_pNext != NULL)
1400 pEntry = pEntry->m_pNext;
1401
1402 pEntry->m_pNext = new (m_pImage->GetHeap()) LabelledEntry(pMethod);
1403}
1404
1405void ZapDebugInfoTable::FinishLayout()
1406{
1407 // Go over the table again and place all labelled entries
1408 for (COUNT_T i = 0; i < m_nCount; i++)
1409 {
1410 ZapNode * pNode = m_pTable[i];
1411
1412 if (pNode == NULL || pNode->GetType() != ZapNodeType_DebugInfoLabelledEntry)
1413 continue;
1414
1415 LabelledEntry * pEntry = (LabelledEntry *)pNode;
1416
1417 while (pEntry != NULL)
1418 {
1419 m_pImage->m_pDebugSection->Place(pEntry);
1420 pEntry = pEntry->m_pNext;
1421 }
1422 }
1423}
1424
1425void ZapDebugInfoTable::Save(ZapWriter * pZapWriter)
1426{
1427 for (COUNT_T i = 0; i < m_nCount; i++)
1428 {
1429 CORCOMPILE_DEBUG_ENTRY entry = 0;
1430
1431 ZapNode * pNode = m_pTable[i];
1432
1433 if (pNode != NULL)
1434 {
1435 if (pNode->GetType() == ZapNodeType_DebugInfoLabelledEntry)
1436 entry |= pNode->GetRVA() | CORCOMPILE_DEBUG_MULTIPLE_ENTRIES;
1437 else
1438 entry = ((ZapMethodHeader *)pNode)->GetDebugInfo()->GetRVA();
1439 }
1440
1441 pZapWriter->Write(&entry, sizeof(entry));
1442 }
1443}
1444
1445void ZapDebugInfoTable::LabelledEntry::Save(ZapWriter * pZapWriter)
1446{
1447 CORCOMPILE_DEBUG_LABELLED_ENTRY entry;
1448
1449 entry.nativeCodeRVA = m_pMethod->GetCode()->GetRVA();
1450 entry.debugInfoOffset = m_pMethod->GetDebugInfo()->GetRVA();
1451
1452 if (m_pNext != NULL)
1453 entry.debugInfoOffset |= CORCOMPILE_DEBUG_MULTIPLE_ENTRIES;
1454
1455 pZapWriter->Write(&entry, sizeof(entry));
1456}
1457
1458//
1459// ZapProfileData
1460//
1461void ZapProfileData::Save(ZapWriter * pZapWriter)
1462{
1463 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1464
1465 CORCOMPILE_METHOD_PROFILE_LIST profileData;
1466
1467 ZeroMemory(&profileData, sizeof(CORCOMPILE_METHOD_PROFILE_LIST));
1468
1469 if (m_pNext != NULL)
1470 pImage->WriteReloc(&profileData,
1471 offsetof(CORCOMPILE_METHOD_PROFILE_LIST, next),
1472 m_pNext, 0, IMAGE_REL_BASED_PTR);
1473
1474 pZapWriter->Write(&profileData, sizeof(CORCOMPILE_METHOD_PROFILE_LIST));
1475}
1476
1477
1478// Zapping of ExeptionInfoTable
1479ZapExceptionInfoLookupTable::ZapExceptionInfoLookupTable(ZapImage *pImage) : m_pImage(pImage)
1480{
1481 _ASSERTE(m_pImage->m_pExceptionSection != NULL);
1482 m_pImage->m_pExceptionSection->Place(this);
1483}
1484
1485void ZapExceptionInfoLookupTable::PlaceExceptionInfoEntry(ZapNode* pCode, ZapExceptionInfo* pExceptionInfo)
1486{
1487 ExceptionInfoEntry entry;
1488 entry.m_pCode = pCode;
1489 entry.m_pExceptionInfo = pExceptionInfo;
1490 m_exceptionInfoEntries.Append(entry);
1491 m_pImage->m_pExceptionSection->Place(pExceptionInfo);
1492}
1493
1494DWORD ZapExceptionInfoLookupTable::GetSize()
1495{
1496 if (m_exceptionInfoEntries.GetCount() == 0)
1497 return 0;
1498
1499 DWORD numExceptionInfoEntries = m_exceptionInfoEntries.GetCount();
1500 // 1 sentential entry at the end of the table.
1501 return (numExceptionInfoEntries + 1) * sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY);
1502}
1503
1504void ZapExceptionInfoLookupTable::Save(ZapWriter* pZapWriter)
1505{
1506
1507 if(m_exceptionInfoEntries.GetCount() == 0)
1508 return;
1509
1510 for(COUNT_T i = 0; i < m_exceptionInfoEntries.GetCount(); ++i)
1511 {
1512 DWORD methodStartRVA = m_exceptionInfoEntries[i].m_pCode->GetRVA();
1513
1514 ZapExceptionInfo* pExceptionInfo = m_exceptionInfoEntries[i].m_pExceptionInfo;
1515
1516 CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY lookupEntry;
1517
1518 lookupEntry.MethodStartRVA = methodStartRVA;
1519 lookupEntry.ExceptionInfoRVA = pExceptionInfo->GetRVA();
1520
1521 pZapWriter->Write(&lookupEntry, sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY));
1522
1523#ifdef _DEBUG
1524 // Make sure there are no gaps between 2 consecutive CORCOMPILE_EXCEPTION_CLAUSE
1525 // We use pointer arithmatic to calculate the number of EHClause for a method.
1526 if (i != 0)
1527 {
1528 ZapExceptionInfo* pPreviousExceptionInfo = m_exceptionInfoEntries[i-1].m_pExceptionInfo;
1529 DWORD size = pExceptionInfo->GetRVA() - pPreviousExceptionInfo->GetRVA();
1530 DWORD ehClauseSize = size % sizeof(CORCOMPILE_EXCEPTION_CLAUSE);
1531 CONSISTENCY_CHECK_MSG(ehClauseSize == 0, "There must be no gaps between 2 successive clause arrays, please check ZapExceptionInfo alignment");
1532 }
1533#endif
1534 }
1535
1536 // write a sentinal entry.. this entry helps to find the number of EHClauses for the last entry
1537 CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY sentinalEntry;
1538
1539 ExceptionInfoEntry lastEntry = m_exceptionInfoEntries[m_exceptionInfoEntries.GetCount() -1];
1540
1541 ZapExceptionInfo* pLastExceptionInfo = lastEntry.m_pExceptionInfo;
1542
1543 sentinalEntry.MethodStartRVA = (DWORD)-1;
1544
1545 // points just after the end of the Exception table
1546 // the sentinal node m_pExceptionInfo pointer actually points to an invalid CORCOMPILE_EXCEPTION_CLAUSE
1547 // area. The lookup algorithm will never dereference the sentinal pointer, and hence this is safe
1548 sentinalEntry.ExceptionInfoRVA = pLastExceptionInfo->GetRVA() + pLastExceptionInfo->GetSize();
1549
1550 pZapWriter->Write(&sentinalEntry, sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY));
1551}
1552
1553
1554DWORD ZapUnwindInfoLookupTable::GetSize()
1555{
1556 // Sentinal entry at the end
1557 return (GetNumEntries() + 1) * sizeof (DWORD);
1558}
1559
1560void ZapUnwindInfoLookupTable::Save(ZapWriter* pZapWriter)
1561{
1562 ZapVirtualSection * pRuntimeFunctionSection = m_pRuntimeFunctionSection;
1563
1564 // Create Lookup entries.
1565 // 1 lookup entry for each RUNTIME_FUNCTION_LOOKUP_STRIDE K of code.
1566 COUNT_T nUnwindInfos = pRuntimeFunctionSection->GetNodeCount();
1567
1568 DWORD dwCodeSectionStartAddress = m_pCodeSection->GetRVA();
1569
1570 DWORD nLookupEntries = 0;
1571 DWORD entry;
1572
1573 DWORD nTotalLookupEntries = GetNumEntries();
1574
1575 // write out the first entry
1576 entry = 0;
1577 pZapWriter->Write(&entry, sizeof(DWORD));
1578 nLookupEntries++;
1579 if (nLookupEntries == nTotalLookupEntries)
1580 goto WriteSentinel;
1581
1582 for (COUNT_T i = 1; i < nUnwindInfos; ++i)
1583 {
1584 ZapUnwindInfo* pUnwindInfo = (ZapUnwindInfo*)pRuntimeFunctionSection->GetNode(i);
1585 DWORD RelativePC = pUnwindInfo->GetStartAddress() - dwCodeSectionStartAddress;
1586
1587 COUNT_T iCurrentIndex = RelativePC / RUNTIME_FUNCTION_LOOKUP_STRIDE;
1588
1589 // Note that we should not be using pUnwindInfo->GetEndAddress() here. The binary search
1590 // in the VM that's accelerated by this table does not look at the EndAddress either, and
1591 // so not using EndAddress here assures consistency.
1592 COUNT_T iPreviousIndex = (RelativePC - 1)/ RUNTIME_FUNCTION_LOOKUP_STRIDE;
1593
1594 while(iPreviousIndex >= nLookupEntries)
1595 {
1596 entry = i - 1;
1597 pZapWriter->Write(&entry, sizeof(DWORD));
1598 nLookupEntries++;
1599 if (nLookupEntries == nTotalLookupEntries)
1600 goto WriteSentinel;
1601 }
1602
1603 if (iCurrentIndex == nLookupEntries)
1604 {
1605 entry = i;
1606 pZapWriter->Write(&entry, sizeof(DWORD));
1607 nLookupEntries++;
1608 if (nLookupEntries == nTotalLookupEntries)
1609 goto WriteSentinel;
1610 }
1611 }
1612
1613WriteSentinel:
1614 // There should always be one sentinel entry at the end. The sentinel entry will
1615 // be good to cover the rest of the section to account for extra padding.
1616 _ASSERTE(nLookupEntries <= nTotalLookupEntries);
1617
1618 while (nLookupEntries <= nTotalLookupEntries)
1619 {
1620 entry = nUnwindInfos - 1;
1621 pZapWriter->Write(&entry, sizeof (DWORD));
1622 nLookupEntries ++;
1623 }
1624}
1625
1626DWORD ZapColdCodeMap::GetSize()
1627{
1628 return m_pRuntimeFunctionSection->GetNodeCount() * sizeof(CORCOMPILE_COLD_METHOD_ENTRY);
1629}
1630
1631void ZapColdCodeMap::Save(ZapWriter* pZapWriter)
1632{
1633 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1634
1635 ZapNode * pPendingCode = NULL;
1636 COUNT_T curMethod = 0;
1637
1638 COUNT_T nUnwindInfos = m_pRuntimeFunctionSection->GetNodeCount();
1639 for (COUNT_T i = 0; i < nUnwindInfos; ++i)
1640 {
1641 CORCOMPILE_COLD_METHOD_ENTRY entry;
1642
1643 ZapUnwindInfo* pUnwindInfo = (ZapUnwindInfo*)m_pRuntimeFunctionSection->GetNode(i);
1644
1645#ifdef WIN64EXCEPTIONS
1646 if (pUnwindInfo->GetCode() == pPendingCode)
1647 {
1648 entry.mainFunctionEntryRVA = 0;
1649 entry.hotCodeSize = 0;
1650 }
1651 else
1652#endif
1653 {
1654 pPendingCode = pUnwindInfo->GetCode();
1655
1656 ZapMethodHeader * pMethod;
1657
1658 for (;;)
1659 {
1660 pMethod = pImage->m_MethodCompilationOrder[curMethod];
1661 if (pMethod->m_pColdCode == pPendingCode)
1662 break;
1663 curMethod++;
1664 }
1665
1666#ifdef WIN64EXCEPTIONS
1667 entry.mainFunctionEntryRVA = pMethod->m_pUnwindInfo->GetRVA();
1668#endif
1669
1670 entry.hotCodeSize = pMethod->m_pCode->GetSize();
1671 }
1672
1673 pZapWriter->Write(&entry, sizeof(entry));
1674 }
1675}
1676
1677DWORD ZapHelperThunk::GetSize()
1678{
1679 return (m_dwHelper & CORCOMPILE_HELPER_PTR) ? TARGET_POINTER_SIZE : HELPER_TABLE_ENTRY_LEN;
1680}
1681
1682void ZapHelperThunk::Save(ZapWriter * pZapWriter)
1683{
1684#ifdef _DEBUG
1685 LOG((LF_ZAP, LL_INFO1000000, "Emitting JIT helper table entry for helper %3d (%s)\n",
1686 (USHORT) m_dwHelper, s_rgHelperNames[(USHORT) m_dwHelper]));
1687#endif // _DEBUG
1688
1689 // Save the index of the helper, the actual code for the thunk will be generated at runtime
1690 pZapWriter->Write(&m_dwHelper, sizeof(DWORD));
1691
1692 DWORD pad = GetSize() - sizeof(DWORD);
1693 if (pad > 0)
1694 {
1695 void * pPad = _alloca(pad);
1696 memset(pPad, DEFAULT_CODE_BUFFER_INIT, pad);
1697 pZapWriter->Write(pPad, pad);
1698 }
1699}
1700
1701void ZapLazyHelperThunk::Place(ZapImage * pImage)
1702{
1703 m_pArg = pImage->m_pPreloadSections[CORCOMPILE_SECTION_MODULE];
1704
1705 m_pTarget = pImage->GetHelperThunk(m_dwHelper);
1706
1707 pImage->m_pLazyHelperSection->Place(this);
1708}
1709
1710DWORD ZapLazyHelperThunk::GetSize()
1711{
1712 return SaveWorker(NULL);
1713}
1714
1715void ZapLazyHelperThunk::Save(ZapWriter * pZapWriter)
1716{
1717 SaveWorker(pZapWriter);
1718}
1719
1720DWORD ZapLazyHelperThunk::SaveWorker(ZapWriter * pZapWriter)
1721{
1722 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1723
1724 BYTE buffer[42]; // Buffer big enough to hold any reasonable helper thunk sequence
1725 BYTE * p = buffer;
1726
1727#if defined(_TARGET_X86_)
1728 // mov edx, module
1729 *p++ = 0xBA;
1730 if (pImage != NULL)
1731 pImage->WriteReloc(buffer, (int)(p - buffer), m_pArg, 0, IMAGE_REL_BASED_PTR);
1732 p += 4;
1733
1734 // jmp JIT_StrCns
1735 *p++ = 0xE9;
1736 if (pImage != NULL)
1737 pImage->WriteReloc(buffer, (int)(p - buffer), m_pTarget, 0, IMAGE_REL_BASED_REL32);
1738 p += 4;
1739#elif defined(_TARGET_AMD64_)
1740 *p++ = 0x48;
1741 *p++ = 0x8D;
1742#ifdef UNIX_AMD64_ABI
1743 // lea rsi, module
1744 *p++ = 0x35;
1745#else
1746 // lea rdx, module
1747 *p++ = 0x15;
1748#endif
1749 if (pImage != NULL)
1750 pImage->WriteReloc(buffer, (int)(p - buffer), m_pArg, 0, IMAGE_REL_BASED_REL32);
1751 p += 4;
1752
1753 // jmp JIT_StrCns
1754 *p++ = 0xE9;
1755 if (pImage != NULL)
1756 pImage->WriteReloc(buffer, (int)(p - buffer), m_pTarget, 0, IMAGE_REL_BASED_REL32);
1757 p += 4;
1758#elif defined(_TARGET_ARM_)
1759 // movw r1, module
1760 *(WORD *)(p + 0) = 0xf240;
1761 *(WORD *)(p + 2) = 1 << 8;
1762 // movt r1, module
1763 *(WORD *)(p + 4) = 0xf2c0;
1764 *(WORD *)(p + 6) = 1 << 8;
1765 if (pImage != NULL)
1766 pImage->WriteReloc(buffer, (int)(p - buffer), m_pArg, 0, IMAGE_REL_BASED_THUMB_MOV32);
1767 p += 8;
1768
1769 // b JIT_StrCns
1770 *(WORD *)(p + 0) = 0xf000;
1771 *(WORD *)(p + 2) = 0xb800;
1772 if (pImage != NULL)
1773 pImage->WriteReloc(buffer, (int)(p - buffer), m_pTarget, 0, IMAGE_REL_BASED_THUMB_BRANCH24);
1774 p += 4;
1775#elif defined(_TARGET_ARM64_)
1776 // ldr x1, [PC+8]
1777 *(DWORD *)(p) =0x58000041;
1778 p += 4;
1779 // b JIT_StrCns
1780 *(DWORD *)(p) = 0x14000000;
1781 if (pImage != NULL)
1782 pImage->WriteReloc(buffer, (int)(p - buffer), m_pTarget, 0, IMAGE_REL_ARM64_BRANCH26);
1783 p += 4;
1784 if (pImage != NULL)
1785 pImage->WriteReloc(buffer, (int)(p - buffer), m_pArg, 0, IMAGE_REL_BASED_PTR);
1786 p += 8;
1787#else
1788 PORTABILITY_ASSERT("ZapLazyHelperThunk::Save");
1789#endif
1790
1791 _ASSERTE(p - buffer <= sizeof(buffer));
1792
1793 if (pZapWriter != NULL)
1794 pZapWriter->Write(&buffer, (int)(p - buffer));
1795
1796 return (DWORD) (p - buffer);
1797}
1798