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// ZapImport.cpp
6//
7
8//
9// Zapping of soft bound references to elements outside the current module
10//
11// ======================================================================================
12
13#include "common.h"
14
15#include "zapimport.h"
16
17#include "nibblestream.h"
18#include "sigbuilder.h"
19
20#if defined(FEATURE_READYTORUN_COMPILER)
21// A flag to indicate that a helper call uses VSD
22const DWORD READYTORUN_HELPER_FLAG_VSD = 0x10000000;
23#endif
24
25//
26// ZapImportTable
27//
28
29ZapImportTable::ModuleReferenceEntry * ZapImportTable::GetModuleReference(CORINFO_MODULE_HANDLE handle)
30{
31 ModuleReferenceEntry * pEntry = m_moduleReferences.Lookup(handle);
32
33 if (pEntry != NULL)
34 return pEntry;
35
36 if (!GetCompileInfo()->IsInCurrentVersionBubble(handle))
37 {
38 // FUTURE TODO: Version resilience
39 _ASSERTE(!"Invalid reference to module outside of current version bubble");
40 ThrowHR(E_FAIL);
41 }
42
43 pEntry = new (m_pImage->GetHeap()) ModuleReferenceEntry();
44 pEntry->m_module = handle;
45
46 GetCompileInfo()->EncodeModuleAsIndex(m_pImage->GetModuleHandle(), handle,
47 &pEntry->m_index,
48 m_pImage->GetAssemblyEmit());
49
50 m_moduleReferences.Add(pEntry);
51
52 return pEntry;
53}
54
55ZapBlob * ZapImportTable::GetBlob(SigBuilder * pSigBuilder, BOOL fEager)
56{
57 DWORD cbBlob;
58 PVOID pSignature = pSigBuilder->GetSignature(&cbBlob);
59
60 if (fEager)
61 {
62 // Use dedicated section for blobs of eager fixups
63 return ZapBlob::NewBlob(m_pImage, pSignature, cbBlob);
64 }
65
66 ZapBlob * pBlob = m_blobs.Lookup(ZapBlob::SHashKey(pSignature, cbBlob));
67
68 if (pBlob == NULL)
69 {
70 pBlob = ZapBlob::NewBlob(m_pImage, pSignature, cbBlob);
71
72 m_blobs.Add(pBlob);
73 }
74
75 return pBlob;
76}
77
78ZapBlob * ZapImportTable::PlaceImportBlob(ZapImport * pImport, BOOL fEager)
79{
80 ZapBlob * pBlob;
81 if (pImport->HasBlob())
82 {
83 pBlob = pImport->GetBlob();
84 }
85 else
86 {
87 SigBuilder sigBuilder;
88 pImport->EncodeSignature(this, &sigBuilder);
89
90 pBlob = GetBlob(&sigBuilder, fEager);
91
92 pImport->SetBlob(pBlob);
93 }
94
95 if (!pBlob->IsPlaced())
96 PlaceBlob(pBlob, fEager);
97
98 return pBlob;
99}
100
101static const struct ImportSectionProperties
102{
103 BYTE Type;
104 BYTE EntrySize;
105 WORD Flags;
106}
107c_ImportSectionProperties[ZapImportSectionType_Count] =
108{
109 { /* ZapImportSectionType_Handle, */ CORCOMPILE_IMPORT_TYPE_UNKNOWN, 0, 0 },
110 { /* ZapImportSectionType_TypeHandle, */ CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE, TARGET_POINTER_SIZE, 0 },
111 { /* ZapImportSectionType_MethodHandle, */ CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE, TARGET_POINTER_SIZE, 0 },
112#ifdef _TARGET_ARM_
113 { /* ZapImportSectionType_PCode, */ CORCOMPILE_IMPORT_TYPE_UNKNOWN, 0, CORCOMPILE_IMPORT_FLAGS_PCODE },
114#endif
115 { /* ZapImportSectionType_StringHandle, */ CORCOMPILE_IMPORT_TYPE_STRING_HANDLE, TARGET_POINTER_SIZE, 0 },
116};
117
118void ZapImportTable::PlaceImport(ZapImport * pImport)
119{
120 BOOL fIsEager, fNeedsSignature;
121 ZapImportSectionType table = pImport->ComputePlacement(m_pImage, &fIsEager, &fNeedsSignature);
122
123 if (fIsEager)
124 {
125 table = ZapImportSectionType_Eager;
126 }
127 else
128 if (!m_pImage->IsCurrentCodeRegionHot())
129 {
130 table = (ZapImportSectionType)(table + ZapImportSectionType_Cold);
131 }
132
133 _ASSERTE(table < ZapImportSectionType_Total);
134
135
136 if (fNeedsSignature)
137 {
138 PlaceImportBlob(pImport, fIsEager);
139 }
140
141 ZapVirtualSection * pVirtualSection = m_pImage->m_pDelayLoadInfoTableSection[table];
142
143 if (m_nImportSectionSizes[table] == 0)
144 {
145 const ImportSectionProperties * pProps = &c_ImportSectionProperties[table % ZapImportSectionType_Count];
146
147 WORD flags = pProps->Flags;
148
149 if (fIsEager)
150 flags |= CORCOMPILE_IMPORT_FLAGS_EAGER;
151
152 m_nImportSectionIndices[table] = m_pImage->GetImportSectionsTable()->Append(pProps->Type, flags, pProps->EntrySize,
153 pVirtualSection, m_pImage->m_pDelayLoadInfoDataTable[table]);
154 }
155
156 pImport->SetSectionIndexAndOffset(m_nImportSectionIndices[table], m_nImportSectionSizes[table]);
157
158 pVirtualSection->Place(pImport);
159
160 m_nImportSectionSizes[table] += pImport->GetSize();
161}
162
163// Sort ZapImport* by CorCompileTokenTable as primary key and offset within the table as secondary key
164static int __cdecl fixupCmp(const void* a_, const void* b_)
165{
166 ZapImport *a = *(ZapImport **)a_;
167 ZapImport *b = *(ZapImport **)b_;
168
169 int tableDiff = a->GetSectionIndex() - b->GetSectionIndex();
170 if (tableDiff != 0)
171 return tableDiff;
172
173 // Sort by offset within the table
174 return (a->GetOffset() - b->GetOffset());
175}
176
177void ZapImportTable::PlaceFixups(ZapImport ** pImports, NibbleWriter& writer)
178{
179 COUNT_T nImports = 0;
180
181 for (;;)
182 {
183 ZapImport * pImport = pImports[nImports];
184 if (pImport == NULL) // end of the list
185 break;
186 if (!pImport->IsPlaced())
187 PlaceImport(pImport);
188 nImports++;
189 }
190
191 qsort(pImports, nImports, sizeof(ZapImport *), fixupCmp);
192
193 //
194 // Build the encoded fixup list
195 //
196
197 int curTableIndex = -1;
198 DWORD curOffset = 0;
199
200 for (COUNT_T iImport = 0; iImport < nImports; iImport++)
201 {
202 ZapImport * pImport = pImports[iImport];
203
204 int tableIndex = pImport->GetSectionIndex();
205 unsigned offset = pImport->GetOffset();
206
207 _ASSERTE(offset % TARGET_POINTER_SIZE == 0);
208 offset /= TARGET_POINTER_SIZE;
209
210 if (tableIndex != curTableIndex)
211 {
212 // Write delta relative to the previous table index
213 _ASSERTE(tableIndex > curTableIndex);
214 if (curTableIndex != -1)
215 {
216 writer.WriteEncodedU32(0); // table separator, so add except for the first entry
217 writer.WriteEncodedU32(tableIndex - curTableIndex); // add table index delta
218 }
219 else
220 {
221 writer.WriteEncodedU32(tableIndex);
222 }
223 curTableIndex = tableIndex;
224
225 // This is the first fixup in the current table.
226 // We will write it out completely (without delta-encoding)
227 writer.WriteEncodedU32(offset);
228 }
229 else
230 {
231 // This is not the first entry in the current table.
232 // We will write out the delta relative to the previous fixup value
233 int delta = offset - curOffset;
234 _ASSERTE(delta > 0);
235 writer.WriteEncodedU32(delta);
236 }
237
238 // future entries for this table would be relative to this rva
239 curOffset = offset;
240 }
241
242 writer.WriteEncodedU32(0); // table separator
243 writer.WriteEncodedU32(0); // fixup list ends
244
245 writer.Flush();
246}
247
248ZapFixupInfo * ZapImportTable::PlaceFixups(ZapImport ** pImports)
249{
250 NibbleWriter writer;
251
252 PlaceFixups(pImports, writer);
253
254 DWORD cbBlob;
255 PVOID pBlob = writer.GetBlob(&cbBlob);
256
257 //
258 // Intern the fixup info
259 //
260
261 ZapFixupInfo * pFixupInfo = m_blobs.Lookup(ZapBlob::SHashKey(pBlob, cbBlob));
262
263 if (pFixupInfo == NULL)
264 {
265 // Fixup infos are mixed with other blobs
266 pFixupInfo = ZapBlob::NewBlob(m_pImage, pBlob, cbBlob);
267 m_blobs.Add(pFixupInfo);
268 }
269
270 if (!pFixupInfo->IsPlaced())
271 PlaceBlob(pFixupInfo);
272
273 return pFixupInfo;
274}
275
276void ZapImportTable::PlaceBlob(ZapBlob * pBlob, BOOL fEager)
277{
278 ZapVirtualSection * pSection;
279 if (fEager)
280 pSection = m_pImage->m_pDelayLoadInfoDelayListSectionEager;
281 else
282 if (m_pImage->IsCurrentCodeRegionHot())
283 pSection = m_pImage->m_pDelayLoadInfoDelayListSectionHot;
284 else
285 pSection = m_pImage->m_pDelayLoadInfoDelayListSectionCold;
286 pSection->Place(pBlob);
287}
288
289// ======================================================================================
290//
291// Generic signatures
292//
293ZapGenericSignature * ZapImportTable::GetGenericSignature(PVOID signature, BOOL fMethod)
294{
295#ifdef REDHAWK
296 _ASSERTE(!"NYI");
297 return NULL;
298#else
299 SigBuilder sigBuilder;
300 GetCompileInfo()->EncodeGenericSignature(signature, fMethod, &sigBuilder, this, EncodeModuleHelper);
301
302 DWORD cbSig;
303 PVOID pSig = sigBuilder.GetSignature(&cbSig);
304
305 ZapGenericSignature * pGenericSignature = (ZapGenericSignature *)m_genericSignatures.Lookup(ZapBlob::SHashKey(pSig, cbSig));
306
307 if (pGenericSignature != NULL)
308 return pGenericSignature;
309
310 S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapGenericSignature)) + S_SIZE_T(cbSig);
311
312 if (cbAllocSize.IsOverflow())
313 ThrowHR(COR_E_OVERFLOW);
314
315 void * pMemory = new (m_pImage->GetHeap()) BYTE[cbAllocSize.Value()];
316
317 pGenericSignature = new (pMemory) ZapGenericSignature(cbSig);
318 memcpy((void *)(pGenericSignature + 1), pSig, cbSig);
319
320 m_genericSignatures.Add(pGenericSignature);
321
322 return pGenericSignature;
323#endif // REDHAWK
324}
325
326// At ngen time Zapper::CompileModule PlaceFixups called from
327// code:ZapSig.GetSignatureForTypeHandle
328//
329/*static*/ DWORD ZapImportTable::EncodeModuleHelper( LPVOID compileContext,
330 CORINFO_MODULE_HANDLE referencedModule)
331{
332 ZapImportTable * pTable = (ZapImportTable *)compileContext;
333 return pTable->GetIndexOfModule(referencedModule);
334}
335
336void ZapImport::Save(ZapWriter * pZapWriter)
337{
338 if (IsReadyToRunCompilation())
339 {
340 TARGET_POINTER_TYPE value = 0;
341 pZapWriter->Write(&value, sizeof(value));
342 return;
343 }
344
345 TARGET_POINTER_TYPE token = CORCOMPILE_TAG_TOKEN(GetBlob()->GetRVA());
346 pZapWriter->Write(&token, sizeof(token));
347}
348
349//
350// CORCOMPILE_CODE_IMPORT_SECTION
351//
352
353COUNT_T ZapImportSectionsTable::Append(BYTE Type, USHORT Flags, BYTE EntrySize, ZapVirtualSection * pSection, ZapNode * pSignatures, ZapNode * pAuxiliaryData)
354{
355 ImportSection entry;
356
357 entry.m_pSection = pSection;
358 entry.m_pSignatures = pSignatures;
359 entry.m_pAuxiliaryData = pAuxiliaryData;
360 entry.m_Flags = Flags;
361 entry.m_Type = Type;
362 entry.m_EntrySize = EntrySize;
363
364 m_ImportSectionsTable.Append(entry);
365
366 return m_ImportSectionsTable.GetCount() - 1;
367}
368
369DWORD ZapImportSectionsTable::GetSize()
370{
371 return m_ImportSectionsTable.GetCount() * sizeof(CORCOMPILE_IMPORT_SECTION);
372}
373
374void ZapImportSectionsTable::Save(ZapWriter * pZapWriter)
375{
376 COUNT_T nSections = m_ImportSectionsTable.GetCount();
377 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
378 {
379 ImportSection * p = &m_ImportSectionsTable[iSection];
380
381 CORCOMPILE_IMPORT_SECTION entry;
382
383 ZapWriter::SetDirectoryData(&entry.Section, p->m_pSection);
384
385 entry.Flags = p->m_Flags;
386 entry.Type = p->m_Type;
387 entry.EntrySize = p->m_EntrySize;
388
389 entry.Signatures = (p->m_pSignatures != NULL) ? p->m_pSignatures->GetRVA() : NULL;
390 entry.AuxiliaryData = (p->m_pAuxiliaryData != NULL) ? p->m_pAuxiliaryData->GetRVA() : NULL;
391
392 pZapWriter->Write(&entry, sizeof(entry));
393 }
394}
395
396
397ZapImportSectionSignatures::ZapImportSectionSignatures(ZapImage * pImage, ZapVirtualSection * pImportSection, ZapVirtualSection * pGCSection)
398 : m_pImportSection(pImportSection), m_pImage(pImage)
399{
400 if (pGCSection != NULL)
401 {
402 m_pGCRefMapTable = new (pImage->GetHeap()) ZapGCRefMapTable(pImage);
403 pGCSection->Place(m_pGCRefMapTable);
404 }
405}
406
407ZapImportSectionSignatures::~ZapImportSectionSignatures()
408{
409 if (m_pGCRefMapTable != NULL)
410 m_pGCRefMapTable->~ZapGCRefMapTable();
411}
412
413DWORD ZapImportSectionSignatures::GetSize()
414{
415 return m_pImportSection->GetNodeCount() * sizeof(DWORD);
416}
417
418void ZapImportSectionSignatures::Save(ZapWriter * pZapWriter)
419{
420 COUNT_T nCount = m_pImportSection->GetNodeCount();
421 for (COUNT_T i = 0; i < nCount; i++)
422 {
423 ZapNode * pNode = m_pImportSection->GetNode(i);
424 DWORD dwRVA = ((ZapImport *)pNode)->GetBlob()->GetRVA();
425 pZapWriter->Write(&dwRVA, sizeof(dwRVA));
426 }
427}
428
429// ======================================================================================
430//
431// Special lazy imports for lazily resolved method calls
432//
433
434//
435// External method thunk is a patchable thunk used for cross-module direct calls
436//
437class ZapExternalMethodThunk : public ZapImport
438{
439public:
440 ZapExternalMethodThunk()
441 {
442 }
443
444 CORINFO_METHOD_HANDLE GetMethod()
445 {
446 return (CORINFO_METHOD_HANDLE)GetHandle();
447 }
448
449 virtual DWORD GetSize()
450 {
451 return sizeof(CORCOMPILE_EXTERNAL_METHOD_THUNK);
452 }
453
454 virtual ZapNodeType GetType()
455 {
456 return ZapNodeType_ExternalMethodThunk;
457 }
458
459 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
460 {
461 CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)GetHandle();
462
463 CORINFO_MODULE_HANDLE referencingModule;
464 mdToken token = pTable->GetCompileInfo()->TryEncodeMethodAsToken(handle, NULL, &referencingModule);
465 if (token != mdTokenNil)
466 {
467 _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef);
468
469 pTable->EncodeModule(
470 (TypeFromToken(token) == mdtMethodDef) ? ENCODE_METHOD_ENTRY_DEF_TOKEN : ENCODE_METHOD_ENTRY_REF_TOKEN,
471 referencingModule, pSigBuilder);
472
473 pSigBuilder->AppendData(RidFromToken(token));
474 }
475 else
476 {
477 pTable->EncodeMethod(ENCODE_METHOD_ENTRY, handle, pSigBuilder);
478 }
479 }
480
481 virtual void Save(ZapWriter * pZapWriter);
482};
483
484void ZapExternalMethodThunk::Save(ZapWriter * pZapWriter)
485{
486 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
487 ZapNode * helper = pImage->GetHelperThunk(CORINFO_HELP_EE_EXTERNAL_FIXUP);
488
489 CORCOMPILE_EXTERNAL_METHOD_THUNK thunk;
490 memset(&thunk, DEFAULT_CODE_BUFFER_INIT, sizeof(thunk));
491#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
492 thunk.callJmp[0] = 0xE8; // call rel32
493 pImage->WriteReloc(&thunk, 1, helper, 0, IMAGE_REL_BASED_REL32);
494 thunk.precodeType = _PRECODE_EXTERNAL_METHOD_THUNK;
495#elif defined(_TARGET_ARM_)
496 // Setup the call to ExternalMethodFixupStub
497 //
498 // mov r12, pc
499 //
500 // Per ARM architecture reference manual section A2.3,
501 // reading the value of PC register will read the address
502 // of the current instruction plus 4. In this case,
503 // R12 will containing the address of "F004" below once
504 // the "mov" is executed.
505 //
506 // Since this is 4 bytes ahead of the start of the thunk,
507 // the assembly helper we will call into will adjust this
508 // so that we point to the start of the thunk correctly.
509 thunk.m_rgCode[0] = 0x46fc;
510
511 // ldr pc, [pc, #4]
512 thunk.m_rgCode[1] = 0xf8df;
513 thunk.m_rgCode[2] = 0xf004;
514
515 // Setup the initial target to be our assembly helper.
516 pImage->WriteReloc(&thunk, offsetof(CORCOMPILE_EXTERNAL_METHOD_THUNK, m_pTarget), helper, 0, IMAGE_REL_BASED_PTR);
517#elif defined(_TARGET_ARM64_)
518
519 thunk.m_rgCode[0] = 0x1000000C; //adr x12, #0
520 thunk.m_rgCode[1] = 0xF940098A; //ldr x10, [x12, #16]
521 thunk.m_rgCode[2] = 0xD61F0140; //br x10
522
523 pImage->WriteReloc(&thunk, offsetof(CORCOMPILE_EXTERNAL_METHOD_THUNK, m_pTarget), helper, 0, IMAGE_REL_BASED_PTR);
524#else
525 PORTABILITY_ASSERT("ZapExternalMethodThunk::Save");
526
527#endif
528
529 pZapWriter->Write(&thunk, sizeof(thunk));
530 _ASSERTE(sizeof(thunk) == GetSize());
531}
532
533void ZapImportSectionSignatures::PlaceExternalMethodThunk(ZapImport * pImport)
534{
535 ZapExternalMethodThunk * pThunk = (ZapExternalMethodThunk *)pImport;
536
537 if (m_pImportSection->GetNodeCount() == 0)
538 {
539 m_dwIndex = m_pImage->GetImportSectionsTable()->Append(CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD, CORCOMPILE_IMPORT_FLAGS_CODE,
540 sizeof(CORCOMPILE_EXTERNAL_METHOD_THUNK), m_pImportSection, this, m_pGCRefMapTable);
541
542 // Make sure the helper created
543 m_pImage->GetHelperThunk(CORINFO_HELP_EE_EXTERNAL_FIXUP);
544 }
545
546 // Add entry to both the the cell and data sections
547 m_pImportSection->Place(pThunk);
548
549 m_pImage->GetImportTable()->PlaceImportBlob(pThunk);
550
551 m_pGCRefMapTable->Append(pThunk->GetMethod());
552}
553
554ZapImport * ZapImportTable::GetExternalMethodThunk(CORINFO_METHOD_HANDLE handle)
555{
556 return GetImport<ZapExternalMethodThunk, ZapNodeType_ExternalMethodThunk>((PVOID)handle);
557}
558
559//
560// Stub dispatch cell is lazily initialized indirection used for virtual stub dispatch
561//
562class ZapStubDispatchCell : public ZapImport
563{
564 ZapNode * m_pDelayLoadHelper;
565
566public:
567 void SetDelayLoadHelper(ZapNode * pDelayLoadHelper)
568 {
569 _ASSERTE(m_pDelayLoadHelper == NULL);
570 m_pDelayLoadHelper = pDelayLoadHelper;
571 }
572
573 CORINFO_METHOD_HANDLE GetMethod()
574 {
575 return (CORINFO_METHOD_HANDLE)GetHandle();
576 }
577
578 CORINFO_CLASS_HANDLE GetClass()
579 {
580 return (CORINFO_CLASS_HANDLE)GetHandle2();
581 }
582
583 virtual DWORD GetSize()
584 {
585 return TARGET_POINTER_SIZE;
586 }
587
588 virtual UINT GetAlignment()
589 {
590 return TARGET_POINTER_SIZE;
591 }
592
593 virtual ZapNodeType GetType()
594 {
595 return ZapNodeType_StubDispatchCell;
596 }
597
598 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
599 {
600 CORINFO_MODULE_HANDLE referencingModule = pTable->GetJitInfo()->getClassModule(GetClass());
601 referencingModule = pTable->TryEncodeModule(ENCODE_VIRTUAL_ENTRY_SLOT, referencingModule, pSigBuilder);
602
603 DWORD slot = pTable->GetCompileInfo()->TryEncodeMethodSlot(GetMethod());
604
605 // We expect the encoding to always succeed
606 _ASSERTE(slot != (DWORD)-1);
607
608 pSigBuilder->AppendData(slot);
609
610 pTable->EncodeClassInContext(referencingModule, GetClass(), pSigBuilder);
611 }
612
613 virtual void Save(ZapWriter * pZapWriter)
614 {
615 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
616
617 TARGET_POINTER_TYPE cell;
618 pImage->WriteReloc(&cell, 0, m_pDelayLoadHelper, 0, IMAGE_REL_BASED_PTR);
619 pZapWriter->Write(&cell, sizeof(cell));
620 }
621};
622
623ZapImport * ZapImportTable::GetStubDispatchCell(CORINFO_CLASS_HANDLE typeHnd, CORINFO_METHOD_HANDLE methHnd)
624{
625 // Do not intern stub dispatch imports. Each callsite should get own cell.
626 ZapImport * pImport = new (m_pImage->GetHeap()) ZapStubDispatchCell();
627 pImport->SetHandle(methHnd);
628 pImport->SetHandle2(typeHnd);
629 return pImport;
630}
631
632void ZapImportSectionSignatures::PlaceStubDispatchCell(ZapImport * pImport)
633{
634 ZapStubDispatchCell * pCell = (ZapStubDispatchCell *)pImport;
635
636 if (m_pImportSection->GetNodeCount() == 0)
637 {
638 m_dwIndex = m_pImage->GetImportSectionsTable()->Append(CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CORCOMPILE_IMPORT_FLAGS_PCODE,
639 TARGET_POINTER_SIZE, m_pImportSection, this, m_pGCRefMapTable);
640 }
641
642#ifdef FEATURE_READYTORUN_COMPILER
643 if (IsReadyToRunCompilation())
644 {
645 // Create the delay load helper
646 ReadyToRunHelper helper = (ReadyToRunHelper)(READYTORUN_HELPER_DelayLoad_MethodCall | READYTORUN_HELPER_FLAG_VSD);
647 ZapNode * pDelayLoadHelper = m_pImage->GetImportTable()->GetPlacedIndirectHelperThunk(helper, (PVOID)(SIZE_T)m_dwIndex);
648 pCell->SetDelayLoadHelper(pDelayLoadHelper);
649 }
650 else
651#endif
652 {
653 pCell->SetDelayLoadHelper(m_pImage->GetHelperThunk(CORINFO_HELP_EE_VSD_FIXUP));
654 }
655
656 // Add entry to both the cell and data sections
657 m_pImportSection->Place(pCell);
658
659 m_pImage->GetImportTable()->PlaceImportBlob(pCell);
660
661 m_pGCRefMapTable->Append(pCell->GetMethod(), true);
662}
663
664//
665// External method cell is lazily initialized indirection used for method calls
666//
667class ZapExternalMethodCell : public ZapImport
668{
669 ZapNode * m_pDelayLoadHelper;
670
671public:
672 void SetDelayLoadHelper(ZapNode * pDelayLoadHelper)
673 {
674 _ASSERTE(m_pDelayLoadHelper == NULL);
675 m_pDelayLoadHelper = pDelayLoadHelper;
676 }
677 CORINFO_METHOD_HANDLE GetMethod()
678 {
679 return (CORINFO_METHOD_HANDLE)GetHandle();
680 }
681
682 virtual DWORD GetSize()
683 {
684 return TARGET_POINTER_SIZE;
685 }
686
687 virtual UINT GetAlignment()
688 {
689 return TARGET_POINTER_SIZE;
690 }
691
692 virtual ZapNodeType GetType()
693 {
694 return ZapNodeType_ExternalMethodCell;
695 }
696
697 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
698 {
699 CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)GetHandle();
700
701 CORINFO_MODULE_HANDLE referencingModule;
702 mdToken token = pTable->GetCompileInfo()->TryEncodeMethodAsToken(handle, NULL, &referencingModule);
703 if (token != mdTokenNil)
704 {
705 _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef);
706
707 pTable->EncodeModule(
708 (TypeFromToken(token) == mdtMethodDef) ? ENCODE_METHOD_ENTRY_DEF_TOKEN : ENCODE_METHOD_ENTRY_REF_TOKEN,
709 referencingModule, pSigBuilder);
710
711 pSigBuilder->AppendData(RidFromToken(token));
712 }
713 else
714 {
715 pTable->EncodeMethod(ENCODE_METHOD_ENTRY, handle, pSigBuilder);
716 }
717 }
718
719 virtual void Save(ZapWriter * pZapWriter)
720 {
721 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
722
723 TARGET_POINTER_TYPE cell;
724 pImage->WriteReloc(&cell, 0, m_pDelayLoadHelper, 0, IMAGE_REL_BASED_PTR);
725 pZapWriter->Write(&cell, sizeof(cell));
726 }
727};
728
729ZapImport * ZapImportTable::GetExternalMethodCell(CORINFO_METHOD_HANDLE handle)
730{
731 return GetImport<ZapExternalMethodCell, ZapNodeType_ExternalMethodCell>((PVOID)handle);
732}
733
734void ZapImportSectionSignatures::PlaceExternalMethodCell(ZapImport * pImport)
735{
736 ZapExternalMethodCell * pCell = (ZapExternalMethodCell *)pImport;
737
738 if (m_pImportSection->GetNodeCount() == 0)
739 {
740 m_dwIndex = m_pImage->GetImportSectionsTable()->Append(CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CORCOMPILE_IMPORT_FLAGS_PCODE,
741 TARGET_POINTER_SIZE, m_pImportSection, this, m_pGCRefMapTable);
742 }
743
744#ifdef FEATURE_READYTORUN_COMPILER
745 if (IsReadyToRunCompilation())
746 {
747 // Create the delay load helper
748 ZapNode * pDelayLoadHelper = m_pImage->GetImportTable()->GetPlacedIndirectHelperThunk(READYTORUN_HELPER_DelayLoad_MethodCall, (PVOID)(SIZE_T)m_dwIndex);
749 pCell->SetDelayLoadHelper(pDelayLoadHelper);
750 }
751 else
752#endif
753 {
754 pCell->SetDelayLoadHelper(m_pImage->GetHelperThunk(CORINFO_HELP_EE_EXTERNAL_FIXUP));
755 }
756
757 // Add entry to both the cell and data sections
758 m_pImportSection->Place(pCell);
759
760 m_pImage->GetImportTable()->PlaceImportBlob(pCell);
761
762 m_pGCRefMapTable->Append(pCell->GetMethod());
763}
764
765//
766// Virtual import thunk is a patchable thunk used for cross-module virtual calls.
767//
768class ZapVirtualMethodThunk : public ZapImport
769{
770public:
771 virtual DWORD GetSize()
772 {
773 return sizeof(CORCOMPILE_VIRTUAL_IMPORT_THUNK);
774 }
775
776 virtual ZapNodeType GetType()
777 {
778 return ZapNodeType_VirtualMethodThunk;
779 }
780
781 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
782 {
783 // Virtual import thunks do not have signatures
784 _ASSERTE(false);
785 }
786
787 virtual void Save(ZapWriter * pZapWriter);
788};
789
790void ZapVirtualMethodThunk::Save(ZapWriter * pZapWriter)
791{
792 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
793
794 CORCOMPILE_VIRTUAL_IMPORT_THUNK thunk;
795 memset(&thunk, DEFAULT_CODE_BUFFER_INIT, sizeof(thunk));
796
797 // On ARM, the helper would already have the thumb-bit set. Refer to
798 // GetHelperThunk implementation.
799 ZapNode * helper = pImage->GetHelperThunk(CORINFO_HELP_EE_VTABLE_FIXUP);
800 _ASSERTE(FitsIn<UINT16>((SIZE_T)GetHandle2() - 1));
801 USHORT slotNum = (USHORT)((SIZE_T)GetHandle2() - 1);
802
803#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
804 thunk.callJmp[0] = 0xE8; // call rel32
805 pImage->WriteReloc(&thunk, 1, helper, 0, IMAGE_REL_BASED_REL32);
806
807 // Mark this as a Virtual Import Thunk
808 thunk.precodeType = _PRECODE_VIRTUAL_IMPORT_THUNK;
809#elif defined(_TARGET_ARM_)
810 // Setup the call to VirtualMethodFixupStub
811 //
812 // mov r12, pc
813 //
814 // Per ARM architecture reference manual section A2.3,
815 // reading the value of PC register will read the address
816 // of the current instruction plus 4. In this case,
817 // R12 will containing the address of "F004" below once
818 // the "mov" is executed.
819 //
820 // Since this is 4 bytes ahead of the start of the thunk,
821 // the assembly helper we will call into will adjust this
822 // so that we point to the start of the thunk correctly.
823 thunk.m_rgCode[0] = 0x46fc;
824
825 // ldr pc, [pc, #4]
826 thunk.m_rgCode[1] = 0xf8df;
827 thunk.m_rgCode[2] = 0xf004;
828
829 // Slot ID is setup below, so now setup the initial target
830 // to be our assembly helper.
831 pImage->WriteReloc(&thunk, offsetof(CORCOMPILE_VIRTUAL_IMPORT_THUNK, m_pTarget), helper, 0, IMAGE_REL_BASED_PTR);
832 #elif defined(_TARGET_ARM64_)
833
834 thunk.m_rgCode[0] = 0x1000000C; //adr x12, #0
835 thunk.m_rgCode[1] = 0xF940098A; //ldr x10, [x12, #16]
836 thunk.m_rgCode[2] = 0xD61F0140; //br x10
837
838 // Slot ID is setup below, so now setup the initial target
839 // to be our assembly helper.
840 pImage->WriteReloc(&thunk, offsetof(CORCOMPILE_VIRTUAL_IMPORT_THUNK, m_pTarget), helper, 0, IMAGE_REL_BASED_PTR);
841#else
842 PORTABILITY_ASSERT("ZapVirtualMethodThunk::Save");
843#endif
844
845 thunk.slotNum = slotNum;
846
847 pZapWriter->Write(&thunk, sizeof(thunk));
848}
849
850void ZapImportTable::PlaceVirtualImportThunk(ZapImport * pVirtualImportThunk)
851{
852 if (m_pImage->m_pVirtualImportThunkSection->GetNodeCount() == 0)
853 {
854 m_pImage->GetImportSectionsTable()->Append(CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD, CORCOMPILE_IMPORT_FLAGS_CODE,
855 sizeof(CORCOMPILE_VIRTUAL_IMPORT_THUNK), m_pImage->m_pVirtualImportThunkSection);
856
857 // Make sure the helper created
858 m_pImage->GetHelperThunk(CORINFO_HELP_EE_VTABLE_FIXUP);
859 }
860
861 m_pImage->m_pVirtualImportThunkSection->Place(pVirtualImportThunk);
862}
863
864ZapImport * ZapImportTable::GetVirtualImportThunk(CORINFO_METHOD_HANDLE handle, int slot)
865{
866 return GetImport<ZapVirtualMethodThunk, ZapNodeType_VirtualMethodThunk>(handle, (PVOID)(SIZE_T)(slot+1));
867}
868
869// ======================================================================================
870//
871// GCRefMapTable is used to encode for GC references locations for lazily resolved calls
872//
873
874void ZapGCRefMapTable::Append(CORINFO_METHOD_HANDLE handle, bool isDispatchCell)
875{
876 m_pImage->GetCompileInfo()->GetCallRefMap(handle, &m_GCRefMapBuilder, isDispatchCell);
877 m_nCount++;
878}
879
880DWORD ZapGCRefMapTable::GetSize()
881{
882 if (m_nCount == 0) return 0;
883
884 COUNT_T nLookupEntries = (1 + m_nCount / GCREFMAP_LOOKUP_STRIDE);
885
886 return (nLookupEntries * sizeof(DWORD)) + m_GCRefMapBuilder.GetBlobLength();
887}
888
889void ZapGCRefMapTable::Save(ZapWriter * pZapWriter)
890{
891 if (m_nCount == 0) return;
892
893 COUNT_T nLookupEntries = (1 + m_nCount / GCREFMAP_LOOKUP_STRIDE);
894
895 DWORD dwBlobLength;
896 BYTE * pBlob = (BYTE *)m_GCRefMapBuilder.GetBlob(&dwBlobLength);
897
898 DWORD pos = 0;
899 COUNT_T iLookupEntry = 0;
900 for (;;)
901 {
902 DWORD relOfs = (nLookupEntries * sizeof(DWORD)) + pos;
903 pZapWriter->Write(&relOfs, sizeof(relOfs));
904 iLookupEntry++;
905
906 if (iLookupEntry >= nLookupEntries)
907 break;
908
909 for (int i = 0; i < GCREFMAP_LOOKUP_STRIDE; i++)
910 {
911 while ((*(pBlob + pos) & 0x80) != 0)
912 pos++;
913 pos++;
914
915 _ASSERTE(pos <= dwBlobLength);
916 }
917 }
918
919 pZapWriter->Write(pBlob, dwBlobLength);
920}
921
922// ======================================================================================
923//
924// Getters for existing imports.
925//
926
927ZapImport * ZapImportTable::GetExistingClassHandleImport(CORINFO_CLASS_HANDLE handle)
928{
929 return GetExistingImport(ZapNodeType_Import_ClassHandle, handle);
930}
931
932ZapImport * ZapImportTable::GetExistingFieldHandleImport(CORINFO_FIELD_HANDLE handle)
933{
934 return GetExistingImport(ZapNodeType_Import_FieldHandle, handle);
935}
936
937ZapImport * ZapImportTable::GetExistingMethodHandleImport(CORINFO_METHOD_HANDLE handle)
938{
939 return GetExistingImport(ZapNodeType_Import_MethodHandle, handle);
940}
941
942CORINFO_MODULE_HANDLE ZapImportTable::TryEncodeModule(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_MODULE_HANDLE module, SigBuilder * pSigBuilder)
943{
944 if (!GetCompileInfo()->IsInCurrentVersionBubble(module))
945 module = GetImage()->GetModuleHandle();
946
947 EncodeModule(kind, module, pSigBuilder);
948 return module;
949}
950
951void ZapImportTable::EncodeModule(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_MODULE_HANDLE module, SigBuilder * pSigBuilder)
952{
953 if (module != GetImage()->GetModuleHandle())
954 {
955 pSigBuilder->AppendByte(kind | ENCODE_MODULE_OVERRIDE);
956 pSigBuilder->AppendData(GetIndexOfModule(module));
957 }
958 else
959 {
960 pSigBuilder->AppendByte(kind);
961 }
962}
963
964void ZapImportTable::EncodeClass(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_CLASS_HANDLE handle, SigBuilder * pSigBuilder)
965{
966 CORINFO_MODULE_HANDLE referencingModule = GetJitInfo()->getClassModule(handle);
967 referencingModule = TryEncodeModule(kind, referencingModule, pSigBuilder);
968 GetCompileInfo()->EncodeClass(referencingModule, handle, pSigBuilder, this, EncodeModuleHelper);
969}
970
971void ZapImportTable::EncodeClassInContext(CORINFO_MODULE_HANDLE context, CORINFO_CLASS_HANDLE handle, SigBuilder * pSigBuilder)
972{
973 GetCompileInfo()->EncodeClass(context, handle, pSigBuilder, this, EncodeModuleHelper);
974}
975
976void ZapImportTable::EncodeField(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, SigBuilder * pSigBuilder,
977 CORINFO_RESOLVED_TOKEN * pResolvedToken, BOOL fEncodeUsingResolvedTokenSpecStreams)
978{
979 CORINFO_CLASS_HANDLE clsHandle = GetJitInfo()->getFieldClass(handle);
980 CORINFO_MODULE_HANDLE referencingModule = GetJitInfo()->getClassModule(clsHandle);
981 referencingModule = TryEncodeModule(kind, referencingModule, pSigBuilder);
982 GetCompileInfo()->EncodeField(referencingModule, handle, pSigBuilder, this, EncodeModuleHelper,
983 pResolvedToken, fEncodeUsingResolvedTokenSpecStreams);
984}
985
986void ZapImportTable::EncodeMethod(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, SigBuilder * pSigBuilder,
987 CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken, BOOL fEncodeUsingResolvedTokenSpecStreams)
988{
989 CORINFO_CLASS_HANDLE clsHandle = GetJitInfo()->getMethodClass(handle);
990 CORINFO_MODULE_HANDLE referencingModule = GetJitInfo()->getClassModule(clsHandle);
991 referencingModule = TryEncodeModule(kind, referencingModule, pSigBuilder);
992 GetCompileInfo()->EncodeMethod(referencingModule, handle, pSigBuilder, this, EncodeModuleHelper,
993 pResolvedToken, pConstrainedResolvedToken, fEncodeUsingResolvedTokenSpecStreams);
994}
995
996// ======================================================================================
997//
998// Actual imports
999//
1000
1001class ZapModuleHandleImport : public ZapImport
1002{
1003public:
1004 virtual ZapNodeType GetType()
1005 {
1006 return ZapNodeType_Import_ModuleHandle;
1007 }
1008
1009 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
1010 {
1011 ZapImport::ComputePlacement(pImage, pfIsEager, pfNeedsSignature);
1012
1013 CORINFO_MODULE_HANDLE handle = (CORINFO_MODULE_HANDLE)GetHandle();
1014 if (pImage->m_pPreloader->CanEmbedModuleHandle(handle))
1015 {
1016 *pfIsEager = TRUE;
1017 }
1018
1019 return ZapImportSectionType_Handle;
1020 }
1021
1022 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1023 {
1024 pTable->EncodeModule(ENCODE_MODULE_HANDLE, (CORINFO_MODULE_HANDLE)GetHandle(), pSigBuilder);
1025 }
1026};
1027
1028ZapImport * ZapImportTable::GetModuleHandleImport(CORINFO_MODULE_HANDLE handle)
1029{
1030 return GetImport<ZapModuleHandleImport, ZapNodeType_Import_ModuleHandle>(handle);
1031}
1032
1033class ZapClassHandleImport : public ZapImport
1034{
1035public:
1036 virtual ZapNodeType GetType()
1037 {
1038 return ZapNodeType_Import_ClassHandle;
1039 }
1040
1041 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
1042 {
1043 ZapImport::ComputePlacement(pImage, pfIsEager, pfNeedsSignature);
1044
1045 if (IsReadyToRunCompilation())
1046 return ZapImportSectionType_Handle;
1047
1048 CORINFO_CLASS_HANDLE handle = (CORINFO_CLASS_HANDLE)GetHandle();
1049 if (pImage->m_pPreloader->CanEmbedClassHandle(handle))
1050 {
1051 // We may have entries pointing to our module that exist in the handle table to trigger restore.
1052 if (pImage->GetCompileInfo()->GetLoaderModuleForEmbeddableType(handle) == pImage->GetModuleHandle())
1053 {
1054 *pfNeedsSignature = FALSE;
1055 }
1056 else
1057 {
1058 *pfIsEager = TRUE;
1059 }
1060 }
1061
1062 return ZapImportSectionType_TypeHandle;
1063 }
1064
1065 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1066 {
1067 pTable->EncodeClass(ENCODE_TYPE_HANDLE, (CORINFO_CLASS_HANDLE)GetHandle(), pSigBuilder);
1068 }
1069
1070 virtual void Save(ZapWriter * pZapWriter)
1071 {
1072 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1073
1074 // We may have entries pointing to our module that exist in the handle table to trigger restore.
1075 if (!HasBlob())
1076 {
1077 PVOID cell;
1078 ZapNode handle(pImage->m_pPreloader->MapClassHandle((CORINFO_CLASS_HANDLE)GetHandle()));
1079 pImage->WriteReloc(&cell, 0, &handle, 0, IMAGE_REL_BASED_PTR);
1080 pZapWriter->Write(&cell, sizeof(cell));
1081 }
1082 else
1083 {
1084 ZapImport::Save(pZapWriter);
1085 }
1086 }
1087};
1088
1089ZapImport * ZapImportTable::GetClassHandleImport(CORINFO_CLASS_HANDLE handle, PVOID pUniqueId)
1090{
1091 // pUniqueId is workaround for loading of generic parent method table. It would be nice to clean it up.
1092 if (pUniqueId != NULL)
1093 {
1094 return GetImport<ZapClassHandleImport, ZapNodeType_Import_ClassHandle>(handle, pUniqueId);
1095 }
1096
1097 ZapImport * pImport = GetImport<ZapClassHandleImport, ZapNodeType_Import_ClassHandle>(handle);
1098
1099 if (IsReadyToRunCompilation() && !pImport->HasBlob())
1100 {
1101 SigBuilder sigBuilder;
1102
1103 EncodeClass(ENCODE_TYPE_HANDLE, handle, &sigBuilder);
1104
1105 pImport->SetBlob(GetBlob(&sigBuilder));
1106 }
1107
1108 return pImport;
1109}
1110
1111class ZapFieldHandleImport : public ZapImport
1112{
1113public:
1114 virtual ZapNodeType GetType()
1115 {
1116 return ZapNodeType_Import_FieldHandle;
1117 }
1118
1119 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1120 {
1121 pTable->EncodeField(ENCODE_FIELD_HANDLE, (CORINFO_FIELD_HANDLE)GetHandle(), pSigBuilder);
1122 }
1123};
1124
1125ZapImport * ZapImportTable::GetFieldHandleImport(CORINFO_FIELD_HANDLE handle)
1126{
1127 return GetImport<ZapFieldHandleImport, ZapNodeType_Import_FieldHandle>(handle);
1128}
1129
1130class ZapMethodHandleImport : public ZapImport
1131{
1132public:
1133 virtual ZapNodeType GetType()
1134 {
1135 return ZapNodeType_Import_MethodHandle;
1136 }
1137
1138 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
1139 {
1140 ZapImport::ComputePlacement(pImage, pfIsEager, pfNeedsSignature);
1141
1142 if (IsReadyToRunCompilation())
1143 return ZapImportSectionType_Handle;
1144
1145 CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)GetHandle();
1146 if (pImage->m_pPreloader->CanEmbedMethodHandle(handle))
1147 {
1148 // We may have entries pointing to our module that exist in the handle table to trigger restore.
1149 if (pImage->GetCompileInfo()->GetLoaderModuleForEmbeddableMethod(handle) == pImage->GetModuleHandle())
1150 {
1151 *pfNeedsSignature = FALSE;
1152 }
1153 }
1154
1155 return ZapImportSectionType_MethodHandle;
1156 }
1157
1158 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1159 {
1160 pTable->EncodeMethod(ENCODE_METHOD_HANDLE, (CORINFO_METHOD_HANDLE)GetHandle(), pSigBuilder);
1161 }
1162
1163 virtual void Save(ZapWriter * pZapWriter)
1164 {
1165 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1166
1167 // We may have entries pointing to our module that exist in the handle table to trigger restore.
1168 if (!HasBlob())
1169 {
1170 PVOID cell;
1171 ZapNode handle(pImage->m_pPreloader->MapMethodHandle((CORINFO_METHOD_HANDLE)GetHandle()));
1172 pImage->WriteReloc(&cell, 0, &handle, 0, IMAGE_REL_BASED_PTR);
1173 pZapWriter->Write(&cell, sizeof(cell));
1174 }
1175 else
1176 {
1177 ZapImport::Save(pZapWriter);
1178 }
1179 }
1180};
1181
1182ZapImport * ZapImportTable::GetMethodHandleImport(CORINFO_METHOD_HANDLE handle)
1183{
1184 return GetImport<ZapMethodHandleImport, ZapNodeType_Import_MethodHandle>(handle);
1185}
1186
1187class ZapStringHandleImport : public ZapImport
1188{
1189public:
1190 virtual ZapNodeType GetType()
1191 {
1192 return ZapNodeType_Import_StringHandle;
1193 }
1194
1195 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
1196 {
1197 ZapImport::ComputePlacement(pImage, pfIsEager, pfNeedsSignature);
1198
1199 // Empty string
1200 if ((mdString)(size_t)GetHandle2() == mdtString)
1201 {
1202 *pfIsEager = TRUE;
1203 return ZapImportSectionType_Handle;
1204 }
1205
1206 return ZapImportSectionType_StringHandle;
1207 }
1208
1209 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1210 {
1211 CORINFO_MODULE_HANDLE referencingModule = (CORINFO_MODULE_HANDLE)GetHandle();
1212
1213 pTable->EncodeModule(ENCODE_STRING_HANDLE, referencingModule, pSigBuilder);
1214
1215 mdString token = (mdString)(size_t)GetHandle2();
1216 pSigBuilder->AppendData(RidFromToken(token));
1217 }
1218};
1219
1220ZapImport * ZapImportTable::GetStringHandleImport(CORINFO_MODULE_HANDLE tokenScope, mdString metaTok)
1221{
1222 return GetImport<ZapStringHandleImport, ZapNodeType_Import_StringHandle>(tokenScope, (PVOID)(size_t)metaTok);
1223}
1224
1225class ZapFunctionEntryImport : public ZapImport
1226{
1227public:
1228 virtual ZapNodeType GetType()
1229 {
1230 return ZapNodeType_Import_FunctionEntry;
1231 }
1232
1233#ifdef _TARGET_ARM_
1234 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
1235 {
1236 ZapImport::ComputePlacement(pImage, pfIsEager, pfNeedsSignature);
1237 return ZapImportSectionType_PCode;
1238 }
1239#endif
1240
1241 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1242 {
1243 CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)GetHandle();
1244
1245 CORINFO_MODULE_HANDLE referencingModule;
1246 mdToken token = pTable->GetCompileInfo()->TryEncodeMethodAsToken(handle, NULL, &referencingModule);
1247 if (token != mdTokenNil)
1248 {
1249 _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef);
1250
1251 // It's a NativeCallable method , then encode it as ENCODE_METHOD_NATIVE_ENTRY
1252 if (pTable->GetCompileInfo()->IsNativeCallableMethod(handle))
1253 {
1254 pTable->EncodeModule(ENCODE_METHOD_NATIVE_ENTRY, referencingModule, pSigBuilder);
1255 }
1256 else
1257 {
1258 pTable->EncodeModule(
1259 (TypeFromToken(token) == mdtMethodDef) ? ENCODE_METHOD_ENTRY_DEF_TOKEN : ENCODE_METHOD_ENTRY_REF_TOKEN,
1260 referencingModule, pSigBuilder);
1261 }
1262
1263 pSigBuilder->AppendData(RidFromToken(token));
1264 }
1265 else
1266 {
1267 pTable->EncodeMethod(ENCODE_METHOD_ENTRY, handle, pSigBuilder);
1268 }
1269 }
1270
1271 virtual void Save(ZapWriter * pZapWriter)
1272 {
1273 SIZE_T token = CORCOMPILE_TAG_PCODE(GetBlob()->GetRVA());
1274 pZapWriter->Write(&token, sizeof(token));
1275 }
1276};
1277
1278ZapImport * ZapImportTable::GetFunctionEntryImport(CORINFO_METHOD_HANDLE handle)
1279{
1280 return GetImport<ZapFunctionEntryImport, ZapNodeType_Import_FunctionEntry>(handle);
1281}
1282
1283class ZapStaticFieldAddressImport : public ZapImport
1284{
1285public:
1286 virtual ZapNodeType GetType()
1287 {
1288 return ZapNodeType_Import_StaticFieldAddress;
1289 }
1290
1291 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1292 {
1293 pTable->EncodeField(ENCODE_STATIC_FIELD_ADDRESS, (CORINFO_FIELD_HANDLE)GetHandle(), pSigBuilder);
1294 }
1295
1296 virtual DWORD GetSize()
1297 {
1298 return 2 * TARGET_POINTER_SIZE;
1299 }
1300
1301 virtual void Save(ZapWriter * pZapWriter)
1302 {
1303 ZapImport::Save(pZapWriter);
1304
1305 TADDR value = 0;
1306 pZapWriter->Write(&value, sizeof(value));
1307 }
1308};
1309
1310ZapImport * ZapImportTable::GetStaticFieldAddressImport(CORINFO_FIELD_HANDLE handle)
1311{
1312 return GetImport<ZapStaticFieldAddressImport, ZapNodeType_Import_StaticFieldAddress>(handle);
1313}
1314
1315class ZapClassDomainIdImport : public ZapImport
1316{
1317public:
1318 virtual ZapNodeType GetType()
1319 {
1320 return ZapNodeType_Import_ClassDomainId;
1321 }
1322
1323 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1324 {
1325 pTable->EncodeClass(ENCODE_CLASS_ID_FOR_STATICS, (CORINFO_CLASS_HANDLE)GetHandle(), pSigBuilder);
1326 }
1327};
1328
1329ZapImport * ZapImportTable::GetClassDomainIdImport(CORINFO_CLASS_HANDLE handle)
1330{
1331 return GetImport<ZapClassDomainIdImport, ZapNodeType_Import_ClassDomainId>(handle);
1332}
1333
1334class ZapModuleDomainIdImport : public ZapImport
1335{
1336public:
1337 virtual ZapNodeType GetType()
1338 {
1339 return ZapNodeType_Import_ModuleDomainId;
1340 }
1341
1342 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1343 {
1344 if (GetHandle() != NULL)
1345 {
1346 pTable->EncodeModule(ENCODE_MODULE_ID_FOR_STATICS, (CORINFO_MODULE_HANDLE)GetHandle(), pSigBuilder);
1347 }
1348 else
1349 {
1350 _ASSERTE(GetHandle2() != NULL);
1351
1352 pTable->EncodeClass(ENCODE_MODULE_ID_FOR_GENERIC_STATICS, (CORINFO_CLASS_HANDLE)GetHandle2(), pSigBuilder);
1353 }
1354 }
1355};
1356
1357ZapImport * ZapImportTable::GetModuleDomainIdImport(CORINFO_MODULE_HANDLE handleToModule, CORINFO_CLASS_HANDLE handleToClass)
1358{
1359 _ASSERTE(((void *)handleToModule != (void *)handleToClass) && ((handleToModule == NULL) || (handleToClass == NULL)));
1360
1361 return GetImport<ZapModuleDomainIdImport, ZapNodeType_Import_ModuleDomainId>(handleToModule, handleToClass);
1362}
1363
1364class ZapSyncLockImport : public ZapImport
1365{
1366public:
1367 virtual ZapNodeType GetType()
1368 {
1369 return ZapNodeType_Import_SyncLock;
1370 }
1371
1372 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1373 {
1374 pTable->EncodeClass(ENCODE_SYNC_LOCK, (CORINFO_CLASS_HANDLE)GetHandle(), pSigBuilder);
1375 }
1376};
1377
1378ZapImport * ZapImportTable::GetSyncLockImport(CORINFO_CLASS_HANDLE handle)
1379{
1380 return GetImport<ZapSyncLockImport, ZapNodeType_Import_SyncLock>(handle);
1381}
1382
1383class ZapIndirectPInvokeTargetImport : public ZapImport
1384{
1385public:
1386 virtual ZapNodeType GetType()
1387 {
1388 return ZapNodeType_Import_IndirectPInvokeTarget;
1389 }
1390
1391 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1392 {
1393 pTable->EncodeMethod(ENCODE_INDIRECT_PINVOKE_TARGET, (CORINFO_METHOD_HANDLE)GetHandle(), pSigBuilder);
1394 }
1395};
1396
1397ZapImport * ZapImportTable::GetIndirectPInvokeTargetImport(CORINFO_METHOD_HANDLE handle)
1398{
1399 return GetImport<ZapIndirectPInvokeTargetImport, ZapNodeType_Import_IndirectPInvokeTarget>(handle);
1400}
1401
1402class ZapProfilingHandleImport : public ZapImport
1403{
1404public:
1405 virtual ZapNodeType GetType()
1406 {
1407 return ZapNodeType_Import_ProfilingHandle;
1408 }
1409
1410 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1411 {
1412 pTable->EncodeMethod(ENCODE_PROFILING_HANDLE, (CORINFO_METHOD_HANDLE)GetHandle(), pSigBuilder);
1413 }
1414
1415 virtual DWORD GetSize()
1416 {
1417 // fixup cell, 3 pointers to interception method (Enter/Leave/Tailcall) and opaque handle
1418 return kZapProfilingHandleImportValueIndexCount * TARGET_POINTER_SIZE;
1419 }
1420
1421 virtual void Save(ZapWriter * pZapWriter)
1422 {
1423 // Save fixup cell
1424 ZapImport::Save(pZapWriter);
1425
1426 // Save zeroes for the rest of the entries
1427
1428 // If this assert fires, someone changed the
1429 // kZapProfilingHandleImportValueIndex... enum values without updating me!
1430 _ASSERTE(kZapProfilingHandleImportValueIndexCount == 5);
1431
1432 TADDR value = 0;
1433 pZapWriter->Write(&value, sizeof(value));
1434 pZapWriter->Write(&value, sizeof(value));
1435 pZapWriter->Write(&value, sizeof(value));
1436 pZapWriter->Write(&value, sizeof(value));
1437 }
1438};
1439
1440ZapImport * ZapImportTable::GetProfilingHandleImport(CORINFO_METHOD_HANDLE handle)
1441{
1442 return GetImport<ZapProfilingHandleImport, ZapNodeType_Import_ProfilingHandle>(handle);
1443}
1444
1445class ZapVarArgImport : public ZapImport
1446{
1447public:
1448 virtual ZapNodeType GetType()
1449 {
1450 return ZapNodeType_Import_VarArg;
1451 }
1452
1453 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1454 {
1455 _ASSERTE((CORINFO_MODULE_HANDLE)GetHandle() == pTable->GetImage()->GetModuleHandle());
1456
1457 mdToken token = (mdToken)(size_t)GetHandle2();
1458 switch (TypeFromToken(token))
1459 {
1460 case mdtSignature:
1461 pSigBuilder->AppendByte(ENCODE_VARARGS_SIG);
1462 break;
1463
1464 case mdtMemberRef:
1465 pSigBuilder->AppendByte(ENCODE_VARARGS_METHODREF);
1466 break;
1467
1468 case mdtMethodDef:
1469 pSigBuilder->AppendByte(ENCODE_VARARGS_METHODDEF);
1470 break;
1471
1472 default:
1473 _ASSERTE(!"Bogus token for signature");
1474 }
1475
1476 pSigBuilder->AppendData(RidFromToken(token));
1477 }
1478};
1479
1480ZapImport * ZapImportTable::GetVarArgImport(CORINFO_MODULE_HANDLE handle, mdToken sigOrMemberRefOrDef)
1481{
1482 return GetImport<ZapVarArgImport, ZapNodeType_Import_VarArg>(handle, (PVOID)(size_t)sigOrMemberRefOrDef);
1483}
1484
1485class ZapActiveDependencyImport : public ZapImport
1486{
1487public:
1488 virtual ZapNodeType GetType()
1489 {
1490 return ZapNodeType_Import_ActiveDependency;
1491 }
1492
1493 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1494 {
1495 pTable->EncodeModule(ENCODE_ACTIVE_DEPENDENCY, (CORINFO_MODULE_HANDLE)GetHandle(), pSigBuilder);
1496 pSigBuilder->AppendData(pTable->GetIndexOfModule((CORINFO_MODULE_HANDLE)GetHandle2()));
1497 }
1498};
1499
1500ZapImport * ZapImportTable::GetActiveDependencyImport(CORINFO_MODULE_HANDLE moduleFrom, CORINFO_MODULE_HANDLE moduleTo)
1501{
1502 return GetImport<ZapActiveDependencyImport, ZapNodeType_Import_ActiveDependency>(moduleFrom, moduleTo);
1503}
1504
1505ZapImport * ZapImportTable::GetClassImport(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_RESOLVED_TOKEN * pResolvedToken)
1506{
1507 CORINFO_CLASS_HANDLE handle = (CORINFO_CLASS_HANDLE) pResolvedToken->hClass;
1508
1509 ZapImport * pImport = GetImport<ZapClassHandleImport, ZapNodeType_Import_ClassHandle>(handle, (PVOID)kind);
1510
1511 if (!pImport->HasBlob())
1512 {
1513 SigBuilder sigBuilder;
1514
1515 EncodeClass(kind, handle, &sigBuilder);
1516
1517 pImport->SetBlob(GetBlob(&sigBuilder));
1518 }
1519
1520 return pImport;
1521}
1522
1523ZapImport * ZapImportTable::GetMethodImport(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle,
1524 CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /*=NULL*/)
1525{
1526 SigBuilder sigBuilder;
1527 EncodeMethod(kind, handle, &sigBuilder, pResolvedToken, pConstrainedResolvedToken);
1528
1529 return GetImportForSignature<ZapMethodHandleImport, ZapNodeType_Import_MethodHandle>((PVOID)handle, &sigBuilder);
1530}
1531
1532ZapImport * ZapImportTable::GetFieldImport(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken)
1533{
1534 SigBuilder sigBuilder;
1535 EncodeField(kind, handle, &sigBuilder, pResolvedToken);
1536
1537 return GetImportForSignature<ZapFieldHandleImport, ZapNodeType_Import_FieldHandle>((PVOID)handle, &sigBuilder);
1538}
1539
1540#ifdef FEATURE_READYTORUN_COMPILER
1541ZapImport * ZapImportTable::GetCheckTypeLayoutImport(CORINFO_CLASS_HANDLE handle)
1542{
1543 ZapImport * pImport = GetImport<ZapClassHandleImport, ZapNodeType_Import_ClassHandle>(handle, (PVOID)ENCODE_CHECK_TYPE_LAYOUT);
1544
1545 if (!pImport->HasBlob())
1546 {
1547 SigBuilder sigBuilder;
1548
1549 sigBuilder.AppendData(ENCODE_CHECK_TYPE_LAYOUT);
1550
1551 GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), handle, &sigBuilder, NULL, NULL);
1552
1553 GetCompileInfo()->EncodeTypeLayout(handle, &sigBuilder);
1554
1555 pImport->SetBlob(GetBlob(&sigBuilder));
1556 }
1557
1558 return pImport;
1559}
1560
1561ZapImport * ZapImportTable::GetCheckFieldOffsetImport(CORINFO_FIELD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken, DWORD offset)
1562{
1563 SigBuilder sigBuilder;
1564
1565 sigBuilder.AppendData(ENCODE_CHECK_FIELD_OFFSET);
1566
1567 sigBuilder.AppendData(offset);
1568
1569 GetCompileInfo()->EncodeField(m_pImage->GetModuleHandle(), handle, &sigBuilder, NULL, NULL, pResolvedToken);
1570
1571 EncodeField(ENCODE_CHECK_FIELD_OFFSET, handle, &sigBuilder, pResolvedToken);
1572
1573 return GetImportForSignature<ZapFieldHandleImport, ZapNodeType_Import_FieldHandle>((PVOID)handle, &sigBuilder);
1574}
1575#endif // FEATURE_READYTORUN_COMPILER
1576
1577ZapImport * ZapImportTable::GetStubDispatchCell(CORINFO_RESOLVED_TOKEN * pResolvedToken)
1578{
1579 CORINFO_METHOD_HANDLE handle = pResolvedToken->hMethod;
1580
1581 SigBuilder sigBuilder;
1582
1583 DWORD slot = GetCompileInfo()->TryEncodeMethodSlot(handle);
1584 if (slot != (DWORD) -1)
1585 {
1586 CORINFO_CLASS_HANDLE clsHandle = pResolvedToken->hClass;
1587
1588 CORINFO_MODULE_HANDLE referencingModule = GetJitInfo()->getClassModule(clsHandle);
1589
1590 referencingModule = TryEncodeModule(ENCODE_VIRTUAL_ENTRY_SLOT, referencingModule, &sigBuilder);
1591
1592 sigBuilder.AppendData(slot);
1593
1594 EncodeClassInContext(referencingModule, clsHandle, &sigBuilder);
1595 }
1596 else
1597 {
1598 CORINFO_MODULE_HANDLE referencingModule;
1599 mdToken token = GetCompileInfo()->TryEncodeMethodAsToken(handle, pResolvedToken, &referencingModule);
1600 if (token != mdTokenNil)
1601 {
1602 _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef);
1603
1604 EncodeModule(
1605 (TypeFromToken(token) == mdtMethodDef) ? ENCODE_VIRTUAL_ENTRY_DEF_TOKEN : ENCODE_VIRTUAL_ENTRY_REF_TOKEN,
1606 referencingModule, &sigBuilder);
1607
1608 sigBuilder.AppendData(RidFromToken(token));
1609 }
1610 else
1611 {
1612 EncodeMethod(ENCODE_VIRTUAL_ENTRY, handle, &sigBuilder, pResolvedToken);
1613 }
1614 }
1615
1616 // For now, always optimize ready to run for size and startup performance - share cells between callsites
1617 return GetImportForSignature<ZapStubDispatchCell, ZapNodeType_StubDispatchCell>((PVOID)handle, &sigBuilder);
1618}
1619
1620ZapImport * ZapImportTable::GetExternalMethodCell(CORINFO_METHOD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken)
1621{
1622 SigBuilder sigBuilder;
1623
1624 CORINFO_MODULE_HANDLE referencingModule;
1625 mdToken token = GetCompileInfo()->TryEncodeMethodAsToken(handle, pResolvedToken, &referencingModule);
1626 if (token != mdTokenNil)
1627 {
1628 _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef);
1629
1630 EncodeModule(
1631 (TypeFromToken(token) == mdtMethodDef) ? ENCODE_METHOD_ENTRY_DEF_TOKEN : ENCODE_METHOD_ENTRY_REF_TOKEN,
1632 referencingModule, &sigBuilder);
1633
1634 sigBuilder.AppendData(RidFromToken(token));
1635 }
1636 else
1637 {
1638 EncodeMethod(ENCODE_METHOD_ENTRY, handle, &sigBuilder, pResolvedToken, pConstrainedResolvedToken);
1639 }
1640
1641 return GetImportForSignature<ZapExternalMethodCell, ZapNodeType_ExternalMethodCell>((PVOID)handle, &sigBuilder);
1642}
1643
1644
1645#ifdef FEATURE_READYTORUN_COMPILER
1646
1647class ZapDynamicHelperCell : public ZapImport
1648{
1649 ZapNode * m_pDelayLoadHelper;
1650
1651public:
1652 void SetDelayLoadHelper(ZapNode * pDelayLoadHelper)
1653 {
1654 _ASSERTE(m_pDelayLoadHelper == NULL);
1655 m_pDelayLoadHelper = pDelayLoadHelper;
1656 }
1657
1658 virtual DWORD GetSize()
1659 {
1660 return TARGET_POINTER_SIZE;
1661 }
1662
1663 virtual UINT GetAlignment()
1664 {
1665 return TARGET_POINTER_SIZE;
1666 }
1667
1668 virtual ZapNodeType GetType()
1669 {
1670 return ZapNodeType_DynamicHelperCell;
1671 }
1672
1673 CORCOMPILE_FIXUP_BLOB_KIND GetKind()
1674 {
1675 int kind = (int)GetHandle();
1676
1677 if ((kind & 1) == 1)
1678 {
1679 return (CORCOMPILE_FIXUP_BLOB_KIND)(kind >> 1);
1680 }
1681 else
1682 {
1683 _ASSERTE(
1684 (GetBlob()->GetSize() > 0) && (
1685 GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_THISOBJ ||
1686 GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_METHOD ||
1687 GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_TYPE));
1688
1689 return (CORCOMPILE_FIXUP_BLOB_KIND)GetBlob()->GetData()[0];
1690 }
1691 }
1692
1693 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1694 {
1695 // Encode should be unreachable for ready-to-run cells
1696 _ASSERTE(false);
1697 }
1698
1699 virtual void Save(ZapWriter * pZapWriter)
1700 {
1701 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1702
1703 TARGET_POINTER_TYPE cell;
1704 pImage->WriteReloc(&cell, 0, m_pDelayLoadHelper, 0, IMAGE_REL_BASED_PTR);
1705 pZapWriter->Write(&cell, sizeof(cell));
1706 }
1707};
1708
1709static ReadyToRunHelper GetDelayLoadHelperForDynamicHelper(CORCOMPILE_FIXUP_BLOB_KIND kind)
1710{
1711 switch (kind)
1712 {
1713 case ENCODE_NEW_HELPER:
1714 case ENCODE_NEW_ARRAY_HELPER:
1715 case ENCODE_STATIC_BASE_NONGC_HELPER:
1716 case ENCODE_STATIC_BASE_GC_HELPER:
1717 case ENCODE_THREAD_STATIC_BASE_NONGC_HELPER:
1718 case ENCODE_THREAD_STATIC_BASE_GC_HELPER:
1719 case ENCODE_CCTOR_TRIGGER:
1720 case ENCODE_FIELD_ADDRESS:
1721 case ENCODE_DICTIONARY_LOOKUP_THISOBJ:
1722 case ENCODE_DICTIONARY_LOOKUP_TYPE:
1723 case ENCODE_DICTIONARY_LOOKUP_METHOD:
1724 return READYTORUN_HELPER_DelayLoad_Helper;
1725
1726 case ENCODE_CHKCAST_HELPER:
1727 case ENCODE_ISINSTANCEOF_HELPER:
1728 return READYTORUN_HELPER_DelayLoad_Helper_Obj;
1729
1730 case ENCODE_VIRTUAL_ENTRY:
1731 // case ENCODE_VIRTUAL_ENTRY_DEF_TOKEN:
1732 // case ENCODE_VIRTUAL_ENTRY_REF_TOKEN:
1733 // case ENCODE_VIRTUAL_ENTRY_SLOT:
1734 return READYTORUN_HELPER_DelayLoad_Helper_Obj;
1735
1736 case ENCODE_DELEGATE_CTOR:
1737 return READYTORUN_HELPER_DelayLoad_Helper_ObjObj;
1738
1739 default:
1740 UNREACHABLE();
1741 }
1742}
1743
1744void ZapImportSectionSignatures::PlaceDynamicHelperCell(ZapImport * pImport)
1745{
1746 ZapDynamicHelperCell * pCell = (ZapDynamicHelperCell *)pImport;
1747
1748 if (m_pImportSection->GetNodeCount() == 0)
1749 {
1750 m_dwIndex = m_pImage->GetImportSectionsTable()->Append(CORCOMPILE_IMPORT_TYPE_UNKNOWN, CORCOMPILE_IMPORT_FLAGS_PCODE,
1751 TARGET_POINTER_SIZE, m_pImportSection, this, m_pGCRefMapTable);
1752 }
1753
1754 // Create the delay load helper
1755 ReadyToRunHelper helperNum = GetDelayLoadHelperForDynamicHelper(
1756 (CORCOMPILE_FIXUP_BLOB_KIND)(pCell->GetKind() & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE));
1757
1758 ZapNode * pDelayLoadHelper = m_pImage->GetImportTable()->GetPlacedIndirectHelperThunk(helperNum, (PVOID)(SIZE_T)m_dwIndex,
1759 (pCell->GetKind() & CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) ? pCell : NULL);
1760
1761 pCell->SetDelayLoadHelper(pDelayLoadHelper);
1762
1763 // Add entry to both the the cell and data sections
1764 m_pImportSection->Place(pCell);
1765
1766 m_pImage->GetImportTable()->PlaceImportBlob(pCell);
1767}
1768
1769ZapImport * ZapImportTable::GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pLookup)
1770{
1771 _ASSERTE(pLookup->needsRuntimeLookup);
1772
1773 SigBuilder sigBuilder;
1774
1775 sigBuilder.AppendData(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE);
1776
1777 if ((kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) == ENCODE_DICTIONARY_LOOKUP_THISOBJ)
1778 {
1779 CORINFO_CLASS_HANDLE hClassContext = GetJitInfo()->getMethodClass(pResolvedToken->tokenContext);
1780 GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), hClassContext, &sigBuilder, NULL, NULL);
1781 }
1782
1783 switch (pLookup->runtimeLookupFlags)
1784 {
1785 case READYTORUN_FIXUP_TypeHandle:
1786 case READYTORUN_FIXUP_DeclaringTypeHandle:
1787 {
1788 if (pResolvedToken->pTypeSpec == NULL)
1789 {
1790 _ASSERTE(!"Invalid IL that directly references __Canon");
1791 ThrowHR(E_NOTIMPL);
1792 }
1793
1794 if (pLookup->runtimeLookupFlags == READYTORUN_FIXUP_DeclaringTypeHandle)
1795 {
1796 _ASSERTE(pLookup->runtimeLookupArgs != NULL);
1797 sigBuilder.AppendData(ENCODE_DECLARINGTYPE_HANDLE);
1798 GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), (CORINFO_CLASS_HANDLE)pLookup->runtimeLookupArgs, &sigBuilder, NULL, NULL);
1799 }
1800 else
1801 {
1802 sigBuilder.AppendData(ENCODE_TYPE_HANDLE);
1803 }
1804
1805 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
1806 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
1807 sigBuilder.AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1808 }
1809 break;
1810
1811 case READYTORUN_FIXUP_MethodHandle:
1812 EncodeMethod(ENCODE_METHOD_HANDLE, pResolvedToken->hMethod, &sigBuilder, pResolvedToken, NULL, TRUE);
1813 break;
1814
1815 case READYTORUN_FIXUP_MethodEntry:
1816 EncodeMethod(ENCODE_METHOD_ENTRY, pResolvedToken->hMethod, &sigBuilder, pResolvedToken, (CORINFO_RESOLVED_TOKEN*)pLookup->runtimeLookupArgs, TRUE);
1817 break;
1818
1819 case READYTORUN_FIXUP_VirtualEntry:
1820 EncodeMethod(ENCODE_VIRTUAL_ENTRY, pResolvedToken->hMethod, &sigBuilder, pResolvedToken, NULL, TRUE);
1821 break;
1822
1823 case READYTORUN_FIXUP_FieldHandle:
1824 EncodeField(ENCODE_FIELD_HANDLE, pResolvedToken->hField, &sigBuilder, pResolvedToken, TRUE);
1825 break;
1826
1827 default:
1828 _ASSERTE(!"Invalid R2R fixup kind!");
1829 ThrowHR(E_NOTIMPL);
1830 }
1831
1832 _ASSERTE(((DWORD)pResolvedToken->tokenContext & 1) == 0);
1833
1834 return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void*)pResolvedToken->tokenContext, &sigBuilder);
1835}
1836
1837ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_CLASS_HANDLE handle)
1838{
1839 ZapImport * pImport = GetImport<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), handle);
1840
1841 if (!pImport->HasBlob())
1842 {
1843 SigBuilder sigBuilder;
1844
1845 sigBuilder.AppendData(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE);
1846
1847 GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), handle, &sigBuilder, NULL, NULL);
1848
1849 pImport->SetBlob(GetBlob(&sigBuilder));
1850 }
1851
1852 return pImport;
1853}
1854
1855ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken,
1856 CORINFO_CLASS_HANDLE delegateType /*=NULL*/)
1857{
1858 SigBuilder sigBuilder;
1859
1860 EncodeMethod((CORCOMPILE_FIXUP_BLOB_KIND)(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE),
1861 handle, &sigBuilder, pResolvedToken);
1862
1863 if (delegateType != NULL)
1864 {
1865 _ASSERTE((CORCOMPILE_FIXUP_BLOB_KIND)(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) == ENCODE_DELEGATE_CTOR);
1866 GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), delegateType, &sigBuilder, NULL, NULL);
1867 }
1868
1869 return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), &sigBuilder);
1870}
1871
1872ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken)
1873{
1874 SigBuilder sigBuilder;
1875
1876 EncodeField((CORCOMPILE_FIXUP_BLOB_KIND)(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE),
1877 handle, &sigBuilder, pResolvedToken);
1878
1879 return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), &sigBuilder);
1880}
1881
1882class ZapIndirectHelperThunk : public ZapImport
1883{
1884 DWORD SaveWorker(ZapWriter * pZapWriter);
1885
1886 ZapNode * m_pCell;
1887
1888public:
1889 void SetCell(ZapNode * pCell)
1890 {
1891 m_pCell = pCell;
1892 }
1893
1894 ReadyToRunHelper GetReadyToRunHelper()
1895 {
1896 return (ReadyToRunHelper)((DWORD)GetHandle() & ~READYTORUN_HELPER_FLAG_VSD);
1897 }
1898
1899 DWORD GetSectionIndex()
1900 {
1901 return (DWORD)GetHandle2();
1902 }
1903
1904 BOOL IsDelayLoadHelper()
1905 {
1906 ReadyToRunHelper helper = GetReadyToRunHelper();
1907 return (helper == READYTORUN_HELPER_DelayLoad_MethodCall) ||
1908 (helper == READYTORUN_HELPER_DelayLoad_Helper) ||
1909 (helper == READYTORUN_HELPER_DelayLoad_Helper_Obj) ||
1910 (helper == READYTORUN_HELPER_DelayLoad_Helper_ObjObj);
1911 }
1912
1913 BOOL IsDelayLoadMethodCallHelper()
1914 {
1915 ReadyToRunHelper helper = GetReadyToRunHelper();
1916 return (helper == READYTORUN_HELPER_DelayLoad_MethodCall);
1917 }
1918
1919 BOOL IsVSD()
1920 {
1921 return ((DWORD)GetHandle() & READYTORUN_HELPER_FLAG_VSD) != 0;
1922 }
1923
1924 BOOL IsLazyHelper()
1925 {
1926 ReadyToRunHelper helper = GetReadyToRunHelper();
1927 return (helper == READYTORUN_HELPER_GetString);
1928 }
1929
1930 DWORD GetSize()
1931 {
1932 return SaveWorker(NULL);
1933 }
1934
1935 void Save(ZapWriter * pZapWriter)
1936 {
1937 SaveWorker(pZapWriter);
1938 }
1939
1940 virtual UINT GetAlignment()
1941 {
1942 return MINIMUM_CODE_ALIGN;
1943 }
1944
1945 virtual ZapNodeType GetType()
1946 {
1947 return ZapNodeType_IndirectHelperThunk;
1948 }
1949
1950 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
1951 {
1952 // Encode should be unreachable for ready-to-run cells
1953 _ASSERTE(false);
1954 }
1955};
1956
1957#ifdef _TARGET_ARM_
1958static void MovRegImm(BYTE* p, int reg)
1959{
1960 *(WORD *)(p + 0) = 0xF240;
1961 *(WORD *)(p + 2) = (UINT16)(reg << 8);
1962 *(WORD *)(p + 4) = 0xF2C0;
1963 *(WORD *)(p + 6) = (UINT16)(reg << 8);
1964}
1965#endif // _TARGET_ARM_
1966
1967DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
1968{
1969 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
1970
1971 BYTE buffer[44];
1972 BYTE * p = buffer;
1973
1974#if defined(_TARGET_X86_)
1975 if (IsDelayLoadHelper())
1976 {
1977 // xor eax, eax
1978 *p++ = 0x33;
1979 *p++ = 0xC0;
1980
1981 // push index
1982 *p++ = 0x6A;
1983 _ASSERTE(GetSectionIndex() <= 0x7F);
1984 *p++ = (BYTE)GetSectionIndex();
1985
1986 // push [module]
1987 *p++ = 0xFF;
1988 *p++ = 0x35;
1989 if (pImage != NULL)
1990 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_PTR);
1991 p += 4;
1992 }
1993 else
1994 if (IsLazyHelper())
1995 {
1996 // mov edx, [module]
1997 *p++ = 0x8B;
1998 *p++ = 0x15;
1999 if (pImage != NULL)
2000 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_PTR);
2001 p += 4;
2002 }
2003
2004 // jmp [helper]
2005 *p++ = 0xFF;
2006 *p++ = 0x25;
2007 if (pImage != NULL)
2008 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_PTR);
2009 p += 4;
2010#elif defined(_TARGET_AMD64_)
2011 if (IsDelayLoadHelper())
2012 {
2013 if (m_pCell != NULL)
2014 {
2015 // lea rax, [pCell]
2016 *p++ = 0x48;
2017 *p++ = 0x8D;
2018 *p++ = 0x05;
2019 if (pImage != NULL)
2020 pImage->WriteReloc(buffer, (int)(p - buffer), m_pCell, 0, IMAGE_REL_BASED_REL32);
2021 p += 4;
2022 }
2023 else
2024 if (IsVSD())
2025 {
2026 // mov rax, r11
2027 *p++ = 0x49;
2028 *p++ = 0x8b;
2029 *p++ = 0xc3;
2030 }
2031 else
2032 {
2033 // xor eax, eax
2034 *p++ = 0x33;
2035 *p++ = 0xC0;
2036 }
2037
2038 // push index
2039 *p++ = 0x6A;
2040 _ASSERTE(GetSectionIndex() <= 0x7F);
2041 *p++ = (BYTE)GetSectionIndex();
2042
2043 // push [module]
2044 *p++ = 0xFF;
2045 *p++ = 0x35;
2046 if (pImage != NULL)
2047 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_REL32);
2048 p += 4;
2049 }
2050 else
2051 if (IsLazyHelper())
2052 {
2053 *p++ = 0x48;
2054 *p++ = 0x8B;
2055#ifdef UNIX_AMD64_ABI
2056 // mov rsi, [module]
2057 *p++ = 0x35;
2058#else
2059 // mov rdx, [module]
2060 *p++ = 0x15;
2061#endif
2062 if (pImage != NULL)
2063 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_REL32);
2064 p += 4;
2065 }
2066
2067 // jmp [helper]
2068 *p++ = 0xFF;
2069 *p++ = 0x25;
2070 if (pImage != NULL)
2071 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_REL32);
2072 p += 4;
2073#elif defined(_TARGET_ARM_)
2074 if (IsDelayLoadHelper())
2075 {
2076 // r4 contains indirection cell
2077 // push r4
2078 *(WORD *)(p + 0) = 0xB410;
2079 p += 2;
2080
2081 // mov r4, index
2082 _ASSERTE(GetSectionIndex() <= 0x7F);
2083 *(WORD *)(p + 0) = 0x2400 | (BYTE)GetSectionIndex();
2084 p += 2;
2085
2086 // push r4
2087 *(WORD *)(p + 0) = 0xB410;
2088 p += 2;
2089
2090 // mov r4, [module]
2091 MovRegImm(p, 4);
2092 if (pImage != NULL)
2093 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_THUMB_MOV32);
2094 p += 8;
2095
2096 // ldr r4, [r4]
2097 *(WORD *)p = 0x6824;
2098 p += 2;
2099
2100 // push r4
2101 *(WORD *)(p + 0) = 0xB410;
2102 p += 2;
2103
2104 // mov r4, [helper]
2105 MovRegImm(p, 4);
2106 if (pImage != NULL)
2107 pImage->WriteReloc(buffer, (int)(p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_THUMB_MOV32);
2108 p += 8;
2109
2110 // ldr r4, [r4]
2111 *(WORD *)p = 0x6824;
2112 p += 2;
2113
2114 // bx r4
2115 *(WORD *)p = 0x4720;
2116 p += 2;
2117 }
2118 else
2119 {
2120 if (IsLazyHelper())
2121 {
2122 // mov r1, [helper]
2123 MovRegImm(p, 1);
2124 if (pImage != NULL)
2125 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_THUMB_MOV32);
2126 p += 8;
2127
2128 // ldr r1, [r1]
2129 *(WORD *)p = 0x6809;
2130 p += 2;
2131 }
2132
2133 // mov r12, [helper]
2134 MovRegImm(p, 12);
2135 if (pImage != NULL)
2136 pImage->WriteReloc(buffer, (int) (p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_THUMB_MOV32);
2137 p += 8;
2138
2139 // ldr r12, [r12]
2140 *(DWORD *)p = 0xC000F8DC;
2141 p += 4;
2142
2143 // bx r12
2144 *(WORD *)p = 0x4760;
2145 p += 2;
2146 }
2147#elif defined(_TARGET_ARM64_)
2148 if (IsDelayLoadHelper())
2149 {
2150 // x11 contains indirection cell
2151 // Do nothing x11 contains our first param
2152
2153 // movz x9, #index
2154 DWORD index = GetSectionIndex();
2155 _ASSERTE(index <= 0x7F);
2156 *(DWORD*)p = 0xd2800009 | (index << 5);
2157 p += 4;
2158
2159 // move Module* -> x10
2160 // ldr x10, [PC+0x14]
2161 *(DWORD*)p = 0x580000AA;
2162 p += 4;
2163
2164 //ldr x10, [x10]
2165 *(DWORD*)p = 0xf940014A;
2166 p += 4;
2167 }
2168 else
2169 if (IsLazyHelper())
2170 {
2171 // Move Module* -> x1
2172 // ldr x1, [PC+0x14]
2173 *(DWORD*)p = 0x580000A1;
2174 p += 4;
2175
2176 // ldr x1, [x1]
2177 *(DWORD*)p = 0xf9400021;
2178 p += 4;
2179 }
2180
2181 // branch to helper
2182 // ldr x12, [PC+0x14]
2183 *(DWORD*)p = 0x580000AC;
2184 p += 4;
2185
2186 // ldr x12, [x12]
2187 *(DWORD *)p = 0xf940018c;
2188 p += 4;
2189
2190 // br x12
2191 *(DWORD *)p = 0xd61f0180;
2192 p += 4;
2193
2194 // [Module*]
2195 if (pImage != NULL)
2196 pImage->WriteReloc(buffer, (int)(p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_PTR);
2197 p += 8;
2198
2199 // [helper]
2200 if (pImage != NULL)
2201 pImage->WriteReloc(buffer, (int)(p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_PTR);
2202 p += 8;
2203#else
2204 PORTABILITY_ASSERT("ZapIndirectHelperThunk::SaveWorker");
2205#endif
2206
2207 _ASSERTE(p - buffer <= sizeof(buffer));
2208
2209 if (pZapWriter != NULL)
2210 pZapWriter->Write(&buffer, (int)(p - buffer));
2211
2212 return (DWORD)(p - buffer);
2213}
2214
2215void ZapImportTable::PlaceIndirectHelperThunk(ZapNode * pImport)
2216{
2217 ZapIndirectHelperThunk * pThunk = (ZapIndirectHelperThunk *)pImport;
2218
2219 if (pThunk->IsDelayLoadMethodCallHelper())
2220 m_pImage->m_pLazyMethodCallHelperSection->Place(pThunk);
2221 else
2222 m_pImage->m_pLazyHelperSection->Place(pThunk);
2223
2224 if (pThunk->IsDelayLoadHelper() || pThunk->IsLazyHelper())
2225 GetPlacedHelperImport(READYTORUN_HELPER_Module);
2226
2227 GetPlacedHelperImport(pThunk->GetReadyToRunHelper());
2228}
2229
2230ZapNode * ZapImportTable::GetIndirectHelperThunk(ReadyToRunHelper helperNum, PVOID pArg)
2231{
2232 ZapNode * pImport = GetImport<ZapIndirectHelperThunk, ZapNodeType_IndirectHelperThunk>((void *)helperNum, pArg);
2233#if defined(_TARGET_ARM_)
2234 pImport = m_pImage->GetInnerPtr(pImport, THUMB_CODE);
2235#endif
2236 return pImport;
2237}
2238
2239ZapNode * ZapImportTable::GetPlacedIndirectHelperThunk(ReadyToRunHelper helperNum, PVOID pArg, ZapNode * pCell)
2240{
2241 ZapNode * pImport;
2242 if (pCell != NULL)
2243 {
2244 ZapIndirectHelperThunk * pIndirectHelperThunk = new (m_pImage->GetHeap()) ZapIndirectHelperThunk();
2245 pIndirectHelperThunk->SetHandle((void *)helperNum);
2246 pIndirectHelperThunk->SetHandle2(pArg);
2247 pIndirectHelperThunk->SetCell(pCell);
2248 pImport = pIndirectHelperThunk;
2249 }
2250 else
2251 {
2252 pImport = GetImport<ZapIndirectHelperThunk, ZapNodeType_IndirectHelperThunk>((void *)helperNum, pArg);
2253 }
2254 if (!pImport->IsPlaced())
2255 PlaceIndirectHelperThunk(pImport);
2256#if defined(_TARGET_ARM_)
2257 pImport = m_pImage->GetInnerPtr(pImport, THUMB_CODE);
2258#endif
2259 return pImport;
2260}
2261
2262class ZapHelperImport : public ZapImport
2263{
2264public:
2265 virtual ZapImportSectionType ComputePlacement(ZapImage * pImage, BOOL * pfIsEager, BOOL * pfNeedsSignature)
2266 {
2267 *pfIsEager = TRUE;
2268 *pfNeedsSignature = TRUE;
2269 return ZapImportSectionType_Handle;
2270 }
2271
2272 virtual ZapNodeType GetType()
2273 {
2274 return ZapNodeType_Import_Helper;
2275 }
2276
2277 virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder)
2278 {
2279 // Encode should be unreachable for ready-to-run cells
2280 _ASSERTE(false);
2281 }
2282};
2283
2284ZapImport * ZapImportTable::GetHelperImport(ReadyToRunHelper helperNum)
2285{
2286 ZapImport * pImport = GetImport<ZapHelperImport, ZapNodeType_Import_Helper>((void *)helperNum);
2287
2288 if (!pImport->HasBlob())
2289 {
2290 SigBuilder sigBuilder;
2291
2292 sigBuilder.AppendByte(ENCODE_READYTORUN_HELPER);
2293 sigBuilder.AppendData(helperNum);
2294
2295 pImport->SetBlob(GetBlob(&sigBuilder));
2296 }
2297
2298 return pImport;
2299}
2300
2301ZapImport * ZapImportTable::GetPlacedHelperImport(ReadyToRunHelper helperNum)
2302{
2303 ZapImport * pImport = GetHelperImport(helperNum);
2304 if (!pImport->IsPlaced())
2305 PlaceImport(pImport);
2306 return pImport;
2307}
2308
2309#endif // FEATURE_READYTORUN_COMPILER
2310