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.
11 // ======================================================================================
15 #include "zapmetadata.h"
17 //-----------------------------------------------------------------------------
19 // ZapMetaData is the barebone ZapNode to save metadata scope
22 void ZapMetaData::SetMetaData(IUnknown * pEmit)
24 _ASSERTE(m_pEmit == NULL);
25 _ASSERTE(pEmit != NULL);
27 IfFailThrow(pEmit->QueryInterface(IID_IMetaDataEmit, (void **)&m_pEmit));
30 DWORD ZapMetaData::GetSize()
34 IfFailThrow(m_pEmit->GetSaveSize(cssAccurate, &m_dwSize));
35 _ASSERTE(m_dwSize != 0);
40 void ZapMetaData::Save(ZapWriter * pZapWriter)
42 IfFailThrow(m_pEmit->SaveToStream(pZapWriter, 0));
45 //-----------------------------------------------------------------------------
47 // ZapILMetaData copies both the metadata and IL to the NGEN image.
50 void ZapILMetaData::Save(ZapWriter * pZapWriter)
52 IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
54 HENUMInternalHolder hEnum(pMDImport);
55 hEnum.EnumAllInit(mdtMethodDef);
58 while (pMDImport->EnumNext(&hEnum, &md))
62 IfFailThrow(pMDImport->GetMethodImplProps(md, &rva, &flags));
64 if (!IsMiIL(flags) || (rva == 0))
67 // Set the actual RVA of the method
68 const ILMethod * pILMethod = m_ILMethods.LookupPtr(md);
70 IfFailThrow(m_pEmit->SetRVA(md, (pILMethod != NULL) ? pILMethod->m_pIL->GetRVA() : 0));
73 if (IsReadyToRunCompilation())
75 HENUMInternalHolder hEnum(pMDImport);
76 hEnum.EnumAllInit(mdtFieldDef);
79 while (pMDImport->EnumNext(&hEnum, &fd))
82 if (pMDImport->GetFieldRVA(fd, &dwRVA) == S_OK)
86 DWORD cbAlignment = 0;
88 m_pImage->m_pPreloader->GetRVAFieldData(fd, &pData, &cbSize, &cbAlignment);
90 ZapRVADataNode * pRVADataNode = m_rvaData.Lookup(pData);
91 m_pEmit->SetRVA(fd, pRVADataNode->GetRVA());
97 ZapImage::GetImage(pZapWriter)->m_pPreloader->SetRVAsForFields(m_pEmit);
100 ZapMetaData::Save(pZapWriter);
103 ZapRVADataNode * ZapILMetaData::GetRVAField(void * pData)
105 ZapRVADataNode * pRVADataNode = m_rvaData.Lookup(pData);
107 if (pRVADataNode == NULL)
109 pRVADataNode = new (m_pImage->GetHeap()) ZapRVADataNode(pData);
111 m_rvaData.Add(pRVADataNode);
125 int __cdecl RVAFieldCmp(const void * a_, const void * b_)
127 RVAField * a = (RVAField *)a_;
128 RVAField * b = (RVAField *)b_;
130 if (a->pData != b->pData)
132 return (a->pData > b->pData) ? 1 : -1;
138 void ZapILMetaData::CopyRVAFields()
140 IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
142 HENUMInternalHolder hEnum(pMDImport);
143 hEnum.EnumAllInit(mdtFieldDef);
145 SArray<RVAField> fields;
148 while (pMDImport->EnumNext(&hEnum, &fd))
151 if (pMDImport->GetFieldRVA(fd, &dwRVA) == S_OK)
154 m_pImage->m_pPreloader->GetRVAFieldData(fd, &field.pData, &field.cbSize, &field.cbAlignment);
155 fields.Append(field);
159 if (fields.GetCount() == 0)
162 // Managed C++ binaries depend on the order of RVA fields
163 qsort(&fields[0], fields.GetCount(), sizeof(RVAField), RVAFieldCmp);
165 for (COUNT_T i = 0; i < fields.GetCount(); i++)
167 RVAField field = fields[i];
169 ZapRVADataNode * pRVADataNode = GetRVAField(field.pData);
171 // Handle overlapping fields by reusing blobs based on the address, and just updating size and alignment.
172 pRVADataNode->UpdateSizeAndAlignment(field.cbSize, field.cbAlignment);
174 if (!pRVADataNode->IsPlaced())
175 m_pImage->m_pReadOnlyDataSection->Place(pRVADataNode);
179 void ZapILMetaData::CopyIL()
181 // The IL is emited into NGen image in the following priority order:
182 // 1. Public inlineable method (may be needed by JIT inliner)
183 // 2. Generic method (may be needed to compile non-NGened instantiations)
184 // 3. Other potentially warm instances (private inlineable methods, methods that failed to NGen)
185 // 4. Everything else (should be touched in rare scenarios like reflection or profiling only)
187 SArray<ZapBlob *> priorityLists[CORCOMPILE_ILREGION_COUNT];
189 IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
191 HENUMInternalHolder hEnum(pMDImport);
192 hEnum.EnumAllInit(mdtMethodDef);
195 // Build the list for each priority in first pass, and then place
196 // the IL blobs in each list. The two passes are needed because of
197 // interning of IL blobs (one IL blob can be on multiple lists).
201 while (pMDImport->EnumNext(&hEnum, &md))
203 const ILMethod * pILMethod = m_ILMethods.LookupPtr(md);
205 if (pILMethod == NULL)
208 CorCompileILRegion region = m_pImage->m_pPreloader->GetILRegion(md);
209 _ASSERTE(region < CORCOMPILE_ILREGION_COUNT);
211 // Preallocate space to avoid wasting too much time by reallocations
212 if (priorityLists[region].IsEmpty())
213 priorityLists[region].Preallocate(m_ILMethods.GetCount() / 16);
215 priorityLists[region].Append(pILMethod->m_pIL);
218 for (int iList = 0; iList < CORCOMPILE_ILREGION_COUNT; iList++)
220 SArray<ZapBlob *> & priorityList = priorityLists[iList];
222 // Use just one section for IL for now. Once the touches of IL for method preparation are fixed change it to:
223 // ZapVirtualSection * pSection = (iList == CORCOMPILE_ILREGION_COLD) ? m_pImage->m_pColdILSection : m_pImage->m_pILSection;
225 ZapVirtualSection * pSection = m_pImage->m_pILSection;
227 COUNT_T nBlobs = priorityList.GetCount();
228 for (COUNT_T iBlob = 0; iBlob < nBlobs; iBlob++)
230 ZapBlob * pIL = priorityList[iBlob];
231 if (!pIL->IsPlaced())
232 pSection->Place(pIL);
237 void ZapILMetaData::CopyMetaData()
240 // Copy metadata from IL image and open it so we can update IL rva's
244 const void *pMeta = m_pImage->m_ModuleDecoder.GetMetadata(&cMeta);
246 IMetaDataDispenserEx * pMetaDataDispenser = m_pImage->m_zapper->m_pMetaDataDispenser;
249 // Transfer the metadata version string from IL image to native image
251 LPCSTR pRuntimeVersionString;
252 IfFailThrow(GetImageRuntimeVersionString((PVOID)pMeta, &pRuntimeVersionString));
254 SString ssRuntimeVersion;
255 ssRuntimeVersion.SetUTF8(pRuntimeVersionString);
257 BSTRHolder strVersion(SysAllocString(ssRuntimeVersion.GetUnicode()));
259 VARIANT versionOption;
260 V_VT(&versionOption) = VT_BSTR;
261 V_BSTR(&versionOption) = strVersion;
262 IfFailThrow(pMetaDataDispenser->SetOption(MetaDataRuntimeVersion, &versionOption));
264 // Preserve local refs. WinMD adapter depends on them at runtime.
265 VARIANT preserveLocalRefsOption;
266 V_VT(&preserveLocalRefsOption) = VT_UI4;
267 V_UI4(&preserveLocalRefsOption) = MDPreserveLocalTypeRef | MDPreserveLocalMemberRef;
268 IfFailThrow(pMetaDataDispenser->SetOption(MetaDataPreserveLocalRefs, &preserveLocalRefsOption));
270 // ofNoTransform - Get the raw metadata for WinRT, not the adapter view
271 HRESULT hr = pMetaDataDispenser->OpenScopeOnMemory(pMeta, cMeta,
272 ofWrite | ofNoTransform,
274 (IUnknown **) &m_pEmit);
275 if (hr == CLDB_E_BADUPDATEMODE)
277 // This must be incrementally-updated metadata. It needs to be opened
280 V_VT(&incOption) = VT_UI4;
281 V_UI4(&incOption) = MDUpdateIncremental;
282 IfFailThrow(pMetaDataDispenser->SetOption(MetaDataSetUpdate, &incOption));
284 hr = pMetaDataDispenser->OpenScopeOnMemory(pMeta, cMeta,
285 ofWrite | ofNoTransform,
287 (IUnknown **) &m_pEmit);
290 // Check the result of OpenScopeOnMemory()
293 if (!IsReadyToRunCompilation())
295 // Communicate the profile data to the meta data emitter so it can hot/cold split it
296 NonVMComHolder<IMetaDataCorProfileData> pIMetaDataCorProfileData;
297 IfFailThrow(m_pEmit->QueryInterface(IID_IMetaDataCorProfileData,
298 (void**)&pIMetaDataCorProfileData));
300 // unless we're producing an instrumented version - the IBC logging for meta data doesn't
301 // work for the hot/cold split version.
302 if (m_pImage->m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
303 IfFailThrow(pIMetaDataCorProfileData->SetCorProfileData(NULL));
305 IfFailThrow(pIMetaDataCorProfileData->SetCorProfileData(m_pImage->GetProfileData()));
308 // If we are ngening with the tuning option, the IBC data that is
309 // generated gets reordered and may be inconsistent with the
310 // metadata in the original IL image. Let's just skip that case.
311 if (!m_pImage->m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
313 // Communicate the reordering option for saving
314 NonVMComHolder<IMDInternalMetadataReorderingOptions> pIMDInternalMetadataReorderingOptions;
315 IfFailThrow(m_pEmit->QueryInterface(IID_IMDInternalMetadataReorderingOptions,
316 (void**)&pIMDInternalMetadataReorderingOptions));
317 IfFailThrow(pIMDInternalMetadataReorderingOptions->SetMetaDataReorderingOptions(ReArrangeStringPool));
321 // Emit IL for a method def into the ngen image
322 void ZapILMetaData::EmitMethodIL(mdMethodDef md)
326 IfFailThrow(m_pImage->m_pMDImport->GetMethodImplProps(md, &rva, &flags));
328 if (!IsMiIL(flags) || (rva == 0))
331 if (!m_pImage->m_ModuleDecoder.CheckILMethod(rva))
332 IfFailThrow(COR_E_BADIMAGEFORMAT); // BFA_BAD_IL_RANGE
334 PVOID pMethod = (PVOID)m_pImage->m_ModuleDecoder.GetRvaData(rva);
336 SIZE_T cMethod = PEDecoder::ComputeILMethodSize((TADDR)pMethod);
339 // Emit copy of IL method in native image.
341 ZapBlob * pIL = m_blobs.Lookup(ZapBlob::SHashKey(pMethod, cMethod));
345 pIL = new (m_pImage->GetHeap()) ILBlob(pMethod, cMethod);
352 ilMethod.m_pIL = pIL;
353 m_ILMethods.Add(ilMethod);