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 | |
38 | ZapVirtualSection * 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) |
54 | ZapVirtualSection * 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 | |
74 | ZapVirtualSection * 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 | |
89 | ZapVirtualSection * 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 | |
102 | ZapVirtualSection* 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 | |
115 | void 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 | |
141 | void 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 | |
435 | void 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 | |
473 | void 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 * = 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 | |
505 | void 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 | |
515 | void 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. |
675 | void 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. |
754 | void 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 | |
810 | DWORD 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 | |
850 | template <DWORD alignment> |
851 | class ZapCodeBlobConst : public ZapCodeBlob |
852 | { |
853 | protected: |
854 | ZapCodeBlobConst(SIZE_T cbSize) |
855 | : ZapCodeBlob(cbSize) |
856 | { |
857 | } |
858 | |
859 | public: |
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 | |
882 | ZapCodeBlob * 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" |
907 | BOOL ZapMethodHeader::PartialTargetMethodIterator::(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 | |
939 | void 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 | |
978 | void 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 | |
995 | ZapMethodEntryPoint * 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 | |
1012 | void 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 | |
1026 | ZapNode * 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 |
1053 | ZapGCInfo * 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 | |
1067 | ZapGCInfo * 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 |
1087 | ZapGCInfo * 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 | |
1106 | void 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 |
1135 | int __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 | |
1158 | UINT ZapUnwindData::GetAlignment() |
1159 | { |
1160 | return sizeof(ULONG); |
1161 | } |
1162 | |
1163 | DWORD 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 | |
1178 | void 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 | |
1207 | UINT ZapUnwindData::GetAlignment() |
1208 | { |
1209 | return sizeof(BYTE); |
1210 | } |
1211 | |
1212 | DWORD ZapUnwindData::GetSize() |
1213 | { |
1214 | return ZapBlob::GetSize(); |
1215 | } |
1216 | |
1217 | void 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 | |
1229 | UINT ZapUnwindData::GetAlignment() |
1230 | { |
1231 | return sizeof(ULONG); |
1232 | } |
1233 | |
1234 | DWORD 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 | |
1246 | void 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 |
1269 | UINT ZapUnwindData::GetAlignment() |
1270 | { |
1271 | PORTABILITY_ASSERT("ZapUnwindData::GetAlignment" ); |
1272 | return sizeof(ULONG); |
1273 | } |
1274 | DWORD ZapUnwindData::GetSize() |
1275 | { |
1276 | PORTABILITY_ASSERT("ZapUnwindData::GetSize" ); |
1277 | return -1; |
1278 | } |
1279 | void ZapUnwindData::Save(ZapWriter * pZapWriter) |
1280 | { |
1281 | PORTABILITY_ASSERT("ZapUnwindData::Save" ); |
1282 | } |
1283 | |
1284 | #endif |
1285 | |
1286 | ZapNode * 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 | |
1300 | ZapUnwindData * 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 | |
1319 | ZapUnwindData * 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 | |
1338 | ZapDebugInfo * 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 | |
1353 | void 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 | |
1364 | void ZapDebugInfoTable::(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 | |
1405 | void 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 | |
1425 | void 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 | |
1445 | void 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 | // |
1461 | void 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 |
1479 | ZapExceptionInfoLookupTable::ZapExceptionInfoLookupTable(ZapImage *pImage) : m_pImage(pImage) |
1480 | { |
1481 | _ASSERTE(m_pImage->m_pExceptionSection != NULL); |
1482 | m_pImage->m_pExceptionSection->Place(this); |
1483 | } |
1484 | |
1485 | void 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 | |
1494 | DWORD 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 | |
1504 | void 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 | |
1554 | DWORD ZapUnwindInfoLookupTable::GetSize() |
1555 | { |
1556 | // Sentinal entry at the end |
1557 | return (GetNumEntries() + 1) * sizeof (DWORD); |
1558 | } |
1559 | |
1560 | void 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 | |
1613 | WriteSentinel: |
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 | |
1626 | DWORD ZapColdCodeMap::GetSize() |
1627 | { |
1628 | return m_pRuntimeFunctionSection->GetNodeCount() * sizeof(CORCOMPILE_COLD_METHOD_ENTRY); |
1629 | } |
1630 | |
1631 | void 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 | |
1677 | DWORD ZapHelperThunk::GetSize() |
1678 | { |
1679 | return (m_dwHelper & CORCOMPILE_HELPER_PTR) ? TARGET_POINTER_SIZE : HELPER_TABLE_ENTRY_LEN; |
1680 | } |
1681 | |
1682 | void 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 | |
1701 | void 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 | |
1710 | DWORD ZapLazyHelperThunk::GetSize() |
1711 | { |
1712 | return SaveWorker(NULL); |
1713 | } |
1714 | |
1715 | void ZapLazyHelperThunk::Save(ZapWriter * pZapWriter) |
1716 | { |
1717 | SaveWorker(pZapWriter); |
1718 | } |
1719 | |
1720 | DWORD 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 | |