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.
9 // Zapping of ready-to-run specific structures
11 // ======================================================================================
15 #include "zapreadytorun.h"
17 #include "zapimport.h"
19 #include "nativeformatwriter.h"
21 #include "nibblestream.h"
23 using namespace NativeFormat;
25 void ZapReadyToRunHeader::Save(ZapWriter * pZapWriter)
27 ZapImage * pImage = ZapImage::GetImage(pZapWriter);
29 READYTORUN_HEADER readyToRunHeader;
31 ZeroMemory(&readyToRunHeader, sizeof(readyToRunHeader));
33 readyToRunHeader.Signature = READYTORUN_SIGNATURE;
34 readyToRunHeader.MajorVersion = READYTORUN_MAJOR_VERSION;
35 readyToRunHeader.MinorVersion = READYTORUN_MINOR_VERSION;
37 if (pImage->m_ModuleDecoder.IsPlatformNeutral())
38 readyToRunHeader.Flags |= READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE;
40 // If all types loaded succesfully, set a flag to skip type loading sanity checks at runtime
41 if (pImage->GetCompileInfo()->AreAllClassesFullyLoaded(pImage->GetModuleHandle()))
42 readyToRunHeader.Flags |= READYTORUN_FLAG_SKIP_TYPE_VALIDATION;
44 readyToRunHeader.NumberOfSections = m_Sections.GetCount();
46 pZapWriter->Write(&readyToRunHeader, sizeof(readyToRunHeader));
48 qsort(&m_Sections[0], m_Sections.GetCount(), sizeof(Section), SectionCmp);
50 for(COUNT_T i = 0; i < m_Sections.GetCount(); i++)
52 READYTORUN_SECTION section;
53 section.Type = m_Sections[i].type;
54 ZapWriter::SetDirectoryData(§ion.Section, m_Sections[i].pSection);
55 pZapWriter->Write(§ion, sizeof(section));
59 class BlobVertex : public NativeFormat::Vertex
64 BlobVertex(int cbSize)
79 virtual void Save(NativeWriter * pWriter)
81 byte * pData = (byte *)GetData();
82 for (int i = 0; i < m_cbSize; i++)
83 pWriter->WriteByte(pData[i]);
93 BlobVertexKey(PVOID pData, int cbSize)
94 : _pData(pData), _cbSize(cbSize)
109 class BlobVertexSHashTraits : public DefaultSHashTraits<BlobVertex *>
112 typedef BlobVertexKey key_t;
114 static key_t GetKey(element_t e)
116 LIMITED_METHOD_CONTRACT;
117 return key_t(e->GetData(), e->GetSize());
119 static BOOL Equals(key_t k1, key_t k2)
121 LIMITED_METHOD_CONTRACT;
122 if (k1.GetSize() != k2.GetSize())
124 return memcmp(k1.GetData(), k2.GetData(), k1.GetSize()) == 0;
126 static count_t Hash(key_t k)
128 LIMITED_METHOD_CONTRACT;
129 count_t hash = 5381 + (count_t)(k.GetSize() << 7);
131 PBYTE pbData = (PBYTE)k.GetData();
132 PBYTE pbDataEnd = pbData + k.GetSize();
134 for (/**/ ; pbData < pbDataEnd; pbData++)
136 hash = ((hash << 5) + hash) ^ *pbData;
143 class EntryPointVertex : public NativeFormat::Vertex
146 BlobVertex * m_pFixups;
149 EntryPointVertex(DWORD methodIndex, BlobVertex * pFixups)
150 : m_methodIndex(methodIndex), m_pFixups(pFixups)
154 virtual void Save(NativeWriter * pWriter)
156 if (m_pFixups != NULL)
158 int existingOffset = pWriter->GetCurrentOffset(m_pFixups);
159 if (existingOffset != -1)
161 pWriter->WriteUnsigned((m_methodIndex << 2) | 3);
162 pWriter->WriteUnsigned(pWriter->GetCurrentOffset() - existingOffset);
166 pWriter->WriteUnsigned((m_methodIndex << 2) | 1);
167 pWriter->SetCurrentOffset(m_pFixups);
168 m_pFixups->Save(pWriter);
173 pWriter->WriteUnsigned(m_methodIndex << 1);
178 class EntryPointWithBlobVertex : public EntryPointVertex
180 BlobVertex * m_pBlob;
183 EntryPointWithBlobVertex(DWORD methodIndex, BlobVertex * pFixups, BlobVertex * pBlob)
184 : EntryPointVertex(methodIndex, pFixups), m_pBlob(pBlob)
188 virtual void Save(NativeWriter * pWriter)
190 m_pBlob->Save(pWriter);
191 EntryPointVertex::Save(pWriter);
195 void ZapImage::OutputEntrypointsTableForReadyToRun()
197 BeginRegion(CORINFO_REGION_COLD);
199 NativeWriter arrayWriter;
200 NativeWriter hashtableWriter;
202 NativeSection * pArraySection = arrayWriter.NewSection();
203 NativeSection * pHashtableSection = hashtableWriter.NewSection();
205 VertexArray vertexArray(pArraySection);
206 pArraySection->Place(&vertexArray);
207 VertexHashtable vertexHashtable;
208 pHashtableSection->Place(&vertexHashtable);
212 SHash< NoRemoveSHashTraits < BlobVertexSHashTraits > > fixupBlobs;
214 COUNT_T nCount = m_MethodCompilationOrder.GetCount();
215 for (COUNT_T i = 0; i < nCount; i++)
217 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
219 mdMethodDef token = GetJitInfo()->getMethodDefFromMethod(pMethod->GetHandle());
220 CORINFO_SIG_INFO sig;
221 GetJitInfo()->getMethodSig(pMethod->GetHandle(), &sig);
223 int rid = RidFromToken(token);
226 BlobVertex * pFixupBlob = NULL;
228 if (pMethod->m_pFixupList != NULL)
231 m_pImportTable->PlaceFixups(pMethod->m_pFixupList, writer);
234 PVOID pBlob = writer.GetBlob(&cbBlob);
236 pFixupBlob = fixupBlobs.Lookup(BlobVertexKey(pBlob, cbBlob));
237 if (pFixupBlob == NULL)
239 void * pMemory = new (GetHeap()) BYTE[sizeof(BlobVertex) + cbBlob];
240 pFixupBlob = new (pMemory) BlobVertex(cbBlob);
241 memcpy(pFixupBlob->GetData(), pBlob, cbBlob);
243 fixupBlobs.Add(pFixupBlob);
247 if (sig.sigInst.classInstCount > 0 || sig.sigInst.methInstCount > 0)
249 CORINFO_MODULE_HANDLE module = GetJitInfo()->getClassModule(pMethod->GetClassHandle());
250 _ASSERTE(GetCompileInfo()->IsInCurrentVersionBubble(module));
251 SigBuilder sigBuilder;
252 CORINFO_RESOLVED_TOKEN resolvedToken = {};
253 resolvedToken.tokenScope = module;
254 resolvedToken.token = token;
255 resolvedToken.hClass = pMethod->GetClassHandle();
256 resolvedToken.hMethod = pMethod->GetHandle();
257 GetCompileInfo()->EncodeMethod(module, pMethod->GetHandle(), &sigBuilder, NULL, NULL, &resolvedToken);
260 PVOID pBlob = sigBuilder.GetSignature(&cbBlob);
261 void * pMemory = new (GetHeap()) BYTE[sizeof(BlobVertex) + cbBlob];
262 BlobVertex * pSigBlob = new (pMemory) BlobVertex(cbBlob);
263 memcpy(pSigBlob->GetData(), pBlob, cbBlob);
265 int dwHash = GetCompileInfo()->GetVersionResilientMethodHashCode(pMethod->GetHandle());
266 vertexHashtable.Append(dwHash, pHashtableSection->Place(new (GetHeap()) EntryPointWithBlobVertex(pMethod->GetMethodIndex(), pFixupBlob, pSigBlob)));
270 vertexArray.Set(rid - 1, new (GetHeap()) EntryPointVertex(pMethod->GetMethodIndex(), pFixupBlob));
279 vertexArray.ExpandLayout();
281 vector<byte>& arrayBlob = arrayWriter.Save();
282 ZapNode * pArrayBlob = ZapBlob::NewBlob(this, &arrayBlob[0], arrayBlob.size());
283 m_pCodeMethodDescsSection->Place(pArrayBlob);
285 vector<byte>& hashtableBlob = hashtableWriter.Save();
286 ZapNode * pHashtableBlob = ZapBlob::NewBlob(this, &hashtableBlob[0], hashtableBlob.size());
287 m_pCodeMethodDescsSection->Place(pHashtableBlob);
289 ZapReadyToRunHeader * pReadyToRunHeader = GetReadyToRunHeader();
290 pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS, pArrayBlob);
291 pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS, pHashtableBlob);
292 pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS, m_pRuntimeFunctionSection);
294 if (m_pLazyMethodCallHelperSection->GetNodeCount() != 0)
295 pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_DELAYLOAD_METHODCALL_THUNKS, m_pLazyMethodCallHelperSection);
297 if (m_pExceptionInfoLookupTable->GetSize() != 0)
298 pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_EXCEPTION_INFO, m_pExceptionInfoLookupTable);
300 EndRegion(CORINFO_REGION_COLD);
303 class DebugInfoVertex : public NativeFormat::Vertex
305 BlobVertex * m_pDebugInfo;
308 DebugInfoVertex(BlobVertex * pDebugInfo)
309 : m_pDebugInfo(pDebugInfo)
313 virtual void Save(NativeWriter * pWriter)
315 int existingOffset = pWriter->GetCurrentOffset(m_pDebugInfo);
316 if (existingOffset != -1)
318 _ASSERTE(pWriter->GetCurrentOffset() > existingOffset);
319 pWriter->WriteUnsigned(pWriter->GetCurrentOffset() - existingOffset);
323 pWriter->WriteUnsigned(0);
324 pWriter->SetCurrentOffset(m_pDebugInfo);
325 m_pDebugInfo->Save(pWriter);
330 void ZapImage::OutputDebugInfoForReadyToRun()
334 NativeSection * pSection = writer.NewSection();
336 VertexArray vertexArray(pSection);
337 pSection->Place(&vertexArray);
341 SHash< NoRemoveSHashTraits < BlobVertexSHashTraits > > debugInfoBlobs;
343 COUNT_T nCount = m_MethodCompilationOrder.GetCount();
344 for (COUNT_T i = 0; i < nCount; i++)
346 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
348 ZapBlob * pDebugInfo = pMethod->GetDebugInfo();
349 if (pDebugInfo == NULL)
352 DWORD cbBlob = pDebugInfo->GetBlobSize();
353 PVOID pBlob = pDebugInfo->GetData();
355 BlobVertex * pDebugInfoBlob = debugInfoBlobs.Lookup(BlobVertexKey(pBlob, cbBlob));
356 if (pDebugInfoBlob == NULL)
358 void * pMemory = new (GetHeap()) BYTE[sizeof(BlobVertex) + cbBlob];
359 pDebugInfoBlob = new (pMemory) BlobVertex(cbBlob);
360 memcpy(pDebugInfoBlob->GetData(), pBlob, cbBlob);
362 debugInfoBlobs.Add(pDebugInfoBlob);
365 vertexArray.Set(pMethod->GetMethodIndex(), new (GetHeap()) DebugInfoVertex(pDebugInfoBlob));
373 vertexArray.ExpandLayout();
375 vector<byte>& blob = writer.Save();
377 ZapNode * pBlob = ZapBlob::NewBlob(this, &blob[0], blob.size());
378 m_pDebugSection->Place(pBlob);
380 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_DEBUG_INFO, pBlob);
383 void ZapImage::OutputInliningTableForReadyToRun()
385 SBuffer serializedInlineTrackingBuffer;
386 m_pPreloader->GetSerializedInlineTrackingMap(&serializedInlineTrackingBuffer);
387 ZapNode * pBlob = ZapBlob::NewAlignedBlob(this, (PVOID)(const BYTE*) serializedInlineTrackingBuffer, serializedInlineTrackingBuffer.GetSize(), 4);
388 m_pDebugSection->Place(pBlob);
389 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_INLINING_INFO, pBlob);
392 void ZapImage::OutputProfileDataForReadyToRun()
394 if (m_pInstrumentSection != nullptr)
396 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_PROFILEDATA_INFO, m_pInstrumentSection);
400 void ZapImage::OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport)
403 VertexHashtable typesHashtable;
405 NativeSection * pSection = writer.NewSection();
406 pSection->Place(&typesHashtable);
408 // Note on duplicate types with same name: there is not need to perform that check when building
409 // the hashtable. If such types were encountered, the R2R compilation would fail before reaching here.
412 LPCUTF8 pszNameSpace;
414 // Save the TypeDefs to the hashtable
416 HENUMInternalHolder hEnum(pMDImport);
417 hEnum.EnumAllInit(mdtTypeDef);
420 while (pMDImport->EnumNext(&hEnum, &mdTypeToken))
422 mdTypeDef mdCurrentToken = mdTypeToken;
423 DWORD dwHash = GetCompileInfo()->GetVersionResilientTypeHashCode(GetModuleHandle(), mdTypeToken);
425 typesHashtable.Append(dwHash, pSection->Place(new UnsignedConstant(RidFromToken(mdTypeToken) << 1)));
429 // Save the ExportedTypes to the hashtable
431 HENUMInternalHolder hEnum(pMDImport);
432 hEnum.EnumInit(mdtExportedType, mdTokenNil);
435 while (pMDImport->EnumNext(&hEnum, &mdTypeToken))
437 DWORD dwHash = GetCompileInfo()->GetVersionResilientTypeHashCode(GetModuleHandle(), mdTypeToken);
439 typesHashtable.Append(dwHash, pSection->Place(new UnsignedConstant((RidFromToken(mdTypeToken) << 1) | 1)));
443 vector<byte>& blob = writer.Save();
445 ZapNode * pBlob = ZapBlob::NewBlob(this, &blob[0], blob.size());
446 _ASSERTE(m_pAvailableTypesSection);
447 m_pAvailableTypesSection->Place(pBlob);
449 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_AVAILABLE_TYPES, pBlob);
454 // Verify that data structures and flags shared between NGen and ReadyToRun are in sync
458 // READYTORUN_IMPORT_SECTION
460 static_assert_no_msg(sizeof(READYTORUN_IMPORT_SECTION) == sizeof(CORCOMPILE_IMPORT_SECTION));
462 static_assert_no_msg((int)READYTORUN_IMPORT_SECTION_TYPE_UNKNOWN == (int)CORCOMPILE_IMPORT_TYPE_UNKNOWN);
464 static_assert_no_msg((int)READYTORUN_IMPORT_SECTION_FLAGS_EAGER == (int)CORCOMPILE_IMPORT_FLAGS_EAGER);
467 // READYTORUN_METHOD_SIG
469 static_assert_no_msg((int)READYTORUN_METHOD_SIG_UnboxingStub == (int)ENCODE_METHOD_SIG_UnboxingStub);
470 static_assert_no_msg((int)READYTORUN_METHOD_SIG_InstantiatingStub == (int)ENCODE_METHOD_SIG_InstantiatingStub);
471 static_assert_no_msg((int)READYTORUN_METHOD_SIG_MethodInstantiation == (int)ENCODE_METHOD_SIG_MethodInstantiation);
472 static_assert_no_msg((int)READYTORUN_METHOD_SIG_SlotInsteadOfToken == (int)ENCODE_METHOD_SIG_SlotInsteadOfToken);
473 static_assert_no_msg((int)READYTORUN_METHOD_SIG_MemberRefToken == (int)ENCODE_METHOD_SIG_MemberRefToken);
474 static_assert_no_msg((int)READYTORUN_METHOD_SIG_Constrained == (int)ENCODE_METHOD_SIG_Constrained);
475 static_assert_no_msg((int)READYTORUN_METHOD_SIG_OwnerType == (int)ENCODE_METHOD_SIG_OwnerType);
478 // READYTORUN_FIELD_SIG
480 static_assert_no_msg((int)READYTORUN_FIELD_SIG_IndexInsteadOfToken == (int)ENCODE_FIELD_SIG_IndexInsteadOfToken);
481 static_assert_no_msg((int)READYTORUN_FIELD_SIG_MemberRefToken == (int)ENCODE_FIELD_SIG_MemberRefToken);
482 static_assert_no_msg((int)READYTORUN_FIELD_SIG_OwnerType == (int)ENCODE_FIELD_SIG_OwnerType);
487 static_assert_no_msg((int)READYTORUN_FIXUP_ThisObjDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_THISOBJ);
488 static_assert_no_msg((int)READYTORUN_FIXUP_TypeDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_TYPE);
489 static_assert_no_msg((int)READYTORUN_FIXUP_MethodDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_METHOD);
491 static_assert_no_msg((int)READYTORUN_FIXUP_TypeHandle == (int)ENCODE_TYPE_HANDLE);
492 static_assert_no_msg((int)READYTORUN_FIXUP_MethodHandle == (int)ENCODE_METHOD_HANDLE);
493 static_assert_no_msg((int)READYTORUN_FIXUP_FieldHandle == (int)ENCODE_FIELD_HANDLE);
495 static_assert_no_msg((int)READYTORUN_FIXUP_MethodEntry == (int)ENCODE_METHOD_ENTRY);
496 static_assert_no_msg((int)READYTORUN_FIXUP_MethodEntry_DefToken == (int)ENCODE_METHOD_ENTRY_DEF_TOKEN);
497 static_assert_no_msg((int)READYTORUN_FIXUP_MethodEntry_RefToken == (int)ENCODE_METHOD_ENTRY_REF_TOKEN);
499 static_assert_no_msg((int)READYTORUN_FIXUP_VirtualEntry == (int)ENCODE_VIRTUAL_ENTRY);
500 static_assert_no_msg((int)READYTORUN_FIXUP_VirtualEntry_DefToken == (int)ENCODE_VIRTUAL_ENTRY_DEF_TOKEN);
501 static_assert_no_msg((int)READYTORUN_FIXUP_VirtualEntry_RefToken == (int)ENCODE_VIRTUAL_ENTRY_REF_TOKEN);
502 static_assert_no_msg((int)READYTORUN_FIXUP_VirtualEntry_Slot == (int)ENCODE_VIRTUAL_ENTRY_SLOT);
504 static_assert_no_msg((int)READYTORUN_FIXUP_Helper == (int)ENCODE_READYTORUN_HELPER);
505 static_assert_no_msg((int)READYTORUN_FIXUP_StringHandle == (int)ENCODE_STRING_HANDLE);
507 static_assert_no_msg((int)READYTORUN_FIXUP_NewObject == (int)ENCODE_NEW_HELPER);
508 static_assert_no_msg((int)READYTORUN_FIXUP_NewArray == (int)ENCODE_NEW_ARRAY_HELPER);
510 static_assert_no_msg((int)READYTORUN_FIXUP_IsInstanceOf == (int)ENCODE_ISINSTANCEOF_HELPER);
511 static_assert_no_msg((int)READYTORUN_FIXUP_ChkCast == (int)ENCODE_CHKCAST_HELPER);
513 static_assert_no_msg((int)READYTORUN_FIXUP_FieldAddress == (int)ENCODE_FIELD_ADDRESS);
514 static_assert_no_msg((int)READYTORUN_FIXUP_CctorTrigger == (int)ENCODE_CCTOR_TRIGGER);
516 static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseNonGC == (int)ENCODE_STATIC_BASE_NONGC_HELPER);
517 static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseGC == (int)ENCODE_STATIC_BASE_GC_HELPER);
518 static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseNonGC == (int)ENCODE_THREAD_STATIC_BASE_NONGC_HELPER);
519 static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseGC == (int)ENCODE_THREAD_STATIC_BASE_GC_HELPER);
521 static_assert_no_msg((int)READYTORUN_FIXUP_FieldBaseOffset == (int)ENCODE_FIELD_BASE_OFFSET);
522 static_assert_no_msg((int)READYTORUN_FIXUP_FieldOffset == (int)ENCODE_FIELD_OFFSET);
524 static_assert_no_msg((int)READYTORUN_FIXUP_TypeDictionary == (int)ENCODE_TYPE_DICTIONARY);
525 static_assert_no_msg((int)READYTORUN_FIXUP_MethodDictionary == (int)ENCODE_METHOD_DICTIONARY);
527 static_assert_no_msg((int)READYTORUN_FIXUP_Check_TypeLayout == (int)ENCODE_CHECK_TYPE_LAYOUT);
528 static_assert_no_msg((int)READYTORUN_FIXUP_Check_FieldOffset == (int)ENCODE_CHECK_FIELD_OFFSET);
530 static_assert_no_msg((int)READYTORUN_FIXUP_DelegateCtor == (int)ENCODE_DELEGATE_CTOR);
532 static_assert_no_msg((int)READYTORUN_FIXUP_DeclaringTypeHandle == (int)ENCODE_DECLARINGTYPE_HANDLE);
535 // READYTORUN_EXCEPTION
537 static_assert_no_msg(sizeof(READYTORUN_EXCEPTION_LOOKUP_TABLE_ENTRY) == sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY));
538 static_assert_no_msg(sizeof(READYTORUN_EXCEPTION_CLAUSE) == sizeof(CORCOMPILE_EXCEPTION_CLAUSE));