JIT: Fix bug in finally cloning caused by unsound callfinally reordering
[platform/upstream/coreclr.git] / src / zap / zapmetadata.cpp
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 // ZapMetadata.cpp
6 //
7
8 //
9 // Metadata zapping
10 // 
11 // ======================================================================================
12
13 #include "common.h"
14
15 #include "zapmetadata.h"
16
17 //-----------------------------------------------------------------------------
18 //
19 // ZapMetaData is the barebone ZapNode to save metadata scope
20 //
21
22 void ZapMetaData::SetMetaData(IUnknown * pEmit)
23 {
24     _ASSERTE(m_pEmit == NULL);
25     _ASSERTE(pEmit != NULL);
26
27     IfFailThrow(pEmit->QueryInterface(IID_IMetaDataEmit, (void **)&m_pEmit));
28 }
29
30 DWORD ZapMetaData::GetSize()
31 {
32     if (m_dwSize == 0)
33     {
34         IfFailThrow(m_pEmit->GetSaveSize(cssAccurate, &m_dwSize));
35         _ASSERTE(m_dwSize != 0);
36     }
37     return m_dwSize;
38 }
39
40 void ZapMetaData::Save(ZapWriter * pZapWriter)
41 {
42     IfFailThrow(m_pEmit->SaveToStream(pZapWriter, 0));
43 }
44
45 //-----------------------------------------------------------------------------
46 //
47 // ZapILMetaData copies both the metadata and IL to the NGEN image.
48 //
49
50 void ZapILMetaData::Save(ZapWriter * pZapWriter)
51 {
52     IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
53
54     HENUMInternalHolder hEnum(pMDImport);
55     hEnum.EnumAllInit(mdtMethodDef);
56
57     mdMethodDef md;
58     while (pMDImport->EnumNext(&hEnum, &md))
59     {
60         DWORD flags;
61         ULONG rva;
62         IfFailThrow(pMDImport->GetMethodImplProps(md, &rva, &flags));
63
64         if (!IsMiIL(flags) || (rva == 0))
65             continue;
66
67         // Set the actual RVA of the method
68         const ILMethod * pILMethod = m_ILMethods.LookupPtr(md);
69
70         IfFailThrow(m_pEmit->SetRVA(md, (pILMethod != NULL) ? pILMethod->m_pIL->GetRVA() : 0));
71     }
72
73     if (IsReadyToRunCompilation())
74     {
75         HENUMInternalHolder hEnum(pMDImport);
76         hEnum.EnumAllInit(mdtFieldDef);
77
78         mdFieldDef fd;
79         while (pMDImport->EnumNext(&hEnum, &fd))
80         {
81             DWORD dwRVA = 0;
82             if (pMDImport->GetFieldRVA(fd, &dwRVA) == S_OK)
83             {
84                 PVOID pData = NULL;
85                 DWORD cbSize = 0;
86                 DWORD cbAlignment = 0;
87
88                 m_pImage->m_pPreloader->GetRVAFieldData(fd, &pData, &cbSize, &cbAlignment);
89
90                 ZapRVADataNode * pRVADataNode = m_rvaData.Lookup(pData);
91                 m_pEmit->SetRVA(fd, pRVADataNode->GetRVA());
92             }
93         }
94     }
95     else
96     {
97        ZapImage::GetImage(pZapWriter)->m_pPreloader->SetRVAsForFields(m_pEmit);
98     }
99
100     ZapMetaData::Save(pZapWriter);
101 }
102
103 ZapRVADataNode * ZapILMetaData::GetRVAField(void * pData)
104 {
105     ZapRVADataNode * pRVADataNode = m_rvaData.Lookup(pData);
106
107     if (pRVADataNode == NULL)
108     {
109         pRVADataNode = new (m_pImage->GetHeap()) ZapRVADataNode(pData);
110
111         m_rvaData.Add(pRVADataNode);
112     }
113
114     return pRVADataNode;
115 }
116
117 struct RVAField
118 {
119     PVOID pData;
120     DWORD cbSize;
121     DWORD cbAlignment;
122 };
123
124 // Used by qsort
125 int __cdecl RVAFieldCmp(const void * a_, const void * b_)
126 {
127     RVAField * a = (RVAField *)a_;
128     RVAField * b = (RVAField *)b_;
129
130     if (a->pData != b->pData)
131     {
132         return (a->pData > b->pData) ? 1 : -1;
133     }
134
135     return 0;
136 }
137
138 void ZapILMetaData::CopyRVAFields()
139 {
140     IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
141
142     HENUMInternalHolder hEnum(pMDImport);
143     hEnum.EnumAllInit(mdtFieldDef);
144
145     SArray<RVAField> fields;
146
147     mdFieldDef fd;
148     while (pMDImport->EnumNext(&hEnum, &fd))
149     {
150         DWORD dwRVA = 0;
151         if (pMDImport->GetFieldRVA(fd, &dwRVA) == S_OK)
152         {
153             RVAField field;
154             m_pImage->m_pPreloader->GetRVAFieldData(fd, &field.pData, &field.cbSize, &field.cbAlignment);
155             fields.Append(field);
156         }
157     }
158
159     if (fields.GetCount() == 0)
160         return;
161
162     // Managed C++ binaries depend on the order of RVA fields
163     qsort(&fields[0], fields.GetCount(), sizeof(RVAField), RVAFieldCmp);
164
165     for (COUNT_T i = 0; i < fields.GetCount(); i++)
166     {
167         RVAField field = fields[i];
168
169         ZapRVADataNode * pRVADataNode = GetRVAField(field.pData);
170
171         // Handle overlapping fields by reusing blobs based on the address, and just updating size and alignment.
172         pRVADataNode->UpdateSizeAndAlignment(field.cbSize, field.cbAlignment);
173
174         if (!pRVADataNode->IsPlaced())
175              m_pImage->m_pReadOnlyDataSection->Place(pRVADataNode);
176     }
177 }
178
179 void ZapILMetaData::CopyIL()
180 {
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)
186
187     SArray<ZapBlob *> priorityLists[CORCOMPILE_ILREGION_COUNT];
188
189     IMDInternalImport * pMDImport = m_pImage->m_pMDImport;
190
191     HENUMInternalHolder hEnum(pMDImport);
192     hEnum.EnumAllInit(mdtMethodDef);
193
194     //
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).
198     //
199
200     mdMethodDef md;
201     while (pMDImport->EnumNext(&hEnum, &md))
202     {
203         const ILMethod * pILMethod = m_ILMethods.LookupPtr(md);
204
205         if (pILMethod == NULL)
206             continue;
207
208         CorCompileILRegion region = m_pImage->m_pPreloader->GetILRegion(md);
209         _ASSERTE(region < CORCOMPILE_ILREGION_COUNT);
210
211         // Preallocate space to avoid wasting too much time by reallocations
212         if (priorityLists[region].IsEmpty())
213             priorityLists[region].Preallocate(m_ILMethods.GetCount() / 16);
214
215         priorityLists[region].Append(pILMethod->m_pIL);
216     }
217
218     for (int iList = 0; iList < CORCOMPILE_ILREGION_COUNT; iList++)
219     {
220         SArray<ZapBlob *> & priorityList = priorityLists[iList];
221
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;
224
225         ZapVirtualSection * pSection = m_pImage->m_pILSection;
226
227         COUNT_T nBlobs = priorityList.GetCount();
228         for (COUNT_T iBlob = 0; iBlob < nBlobs; iBlob++)
229         {
230             ZapBlob * pIL = priorityList[iBlob];
231             if (!pIL->IsPlaced())
232                 pSection->Place(pIL);
233         }
234     }
235 }
236
237 void ZapILMetaData::CopyMetaData()
238 {
239     //
240     // Copy metadata from IL image and open it so we can update IL rva's
241     //
242
243     COUNT_T cMeta;
244     const void *pMeta = m_pImage->m_ModuleDecoder.GetMetadata(&cMeta);
245
246     IMetaDataDispenserEx * pMetaDataDispenser = m_pImage->m_zapper->m_pMetaDataDispenser;
247
248     //
249     // Transfer the metadata version string from IL image to native image
250     //
251     LPCSTR pRuntimeVersionString;
252     IfFailThrow(GetImageRuntimeVersionString((PVOID)pMeta, &pRuntimeVersionString));
253
254     SString ssRuntimeVersion;
255     ssRuntimeVersion.SetUTF8(pRuntimeVersionString);
256
257     BSTRHolder strVersion(SysAllocString(ssRuntimeVersion.GetUnicode()));
258
259     VARIANT versionOption;
260     V_VT(&versionOption) = VT_BSTR;
261     V_BSTR(&versionOption) = strVersion;
262     IfFailThrow(pMetaDataDispenser->SetOption(MetaDataRuntimeVersion, &versionOption));
263     
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));
269     
270     // ofNoTransform - Get the raw metadata for WinRT, not the adapter view
271     HRESULT hr = pMetaDataDispenser->OpenScopeOnMemory(pMeta, cMeta,
272                                                        ofWrite | ofNoTransform,
273                                                        IID_IMetaDataEmit,
274                                                        (IUnknown **) &m_pEmit);
275     if (hr == CLDB_E_BADUPDATEMODE)
276     {
277         // This must be incrementally-updated metadata. It needs to be opened
278         // specially.
279         VARIANT incOption;
280         V_VT(&incOption) = VT_UI4;
281         V_UI4(&incOption) = MDUpdateIncremental;
282         IfFailThrow(pMetaDataDispenser->SetOption(MetaDataSetUpdate, &incOption));
283
284         hr = pMetaDataDispenser->OpenScopeOnMemory(pMeta, cMeta,
285                                                    ofWrite | ofNoTransform,
286                                                    IID_IMetaDataEmit,
287                                                    (IUnknown **) &m_pEmit);
288     }
289
290     // Check the result of OpenScopeOnMemory()
291     IfFailThrow(hr);
292
293     if (!IsReadyToRunCompilation())
294     {
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));
299
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));
304         else
305             IfFailThrow(pIMetaDataCorProfileData->SetCorProfileData(m_pImage->GetProfileData()));
306     }
307
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))
312     {
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));
318     }
319 }
320
321 // Emit IL for a method def into the ngen image
322 void ZapILMetaData::EmitMethodIL(mdMethodDef md)
323 {
324     DWORD flags;
325     ULONG rva;
326     IfFailThrow(m_pImage->m_pMDImport->GetMethodImplProps(md, &rva, &flags));
327
328     if (!IsMiIL(flags) || (rva == 0))
329         return;
330
331     if (!m_pImage->m_ModuleDecoder.CheckILMethod(rva))
332         IfFailThrow(COR_E_BADIMAGEFORMAT); // BFA_BAD_IL_RANGE
333
334     PVOID pMethod = (PVOID)m_pImage->m_ModuleDecoder.GetRvaData(rva);
335
336     SIZE_T cMethod = PEDecoder::ComputeILMethodSize((TADDR)pMethod);
337
338     //
339     // Emit copy of IL method in native image.
340     //
341     ZapBlob * pIL = m_blobs.Lookup(ZapBlob::SHashKey(pMethod, cMethod));
342
343     if (pIL == NULL)
344     {
345         pIL = new (m_pImage->GetHeap()) ILBlob(pMethod, cMethod);
346
347         m_blobs.Add(pIL);
348     }
349
350     ILMethod ilMethod;
351     ilMethod.m_md = md;
352     ilMethod.m_pIL = pIL;
353     m_ILMethods.Add(ilMethod);
354 }