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 | // File: compile.h |
6 | // |
7 | // Interfaces and support for zap compiler and zap files |
8 | // |
9 | |
10 | // =========================================================================== |
11 | |
12 | |
13 | /* |
14 | |
15 | The preloader is used to serialize internal EE data structures in the |
16 | zapped image. The object model looks like the following: |
17 | |
18 | +--------------------+ |
19 | | | |
20 | | ZapperModule | |
21 | | | |
22 | +--------------------+ |
23 | | |
24 | * |
25 | ICorCompileDataStore Zapper |
26 | |
27 | ===================================================== |
28 | |
29 | ICorCompilePreloader EE |
30 | * |
31 | | |
32 | +--------------------+ |
33 | | | |
34 | | CEEPreloader | |
35 | | | |
36 | +--------------------+ |
37 | | |
38 | * |
39 | DataImage::IDataStore |
40 | |
41 | |
42 | +--------------------+ |
43 | | | |
44 | | DataImage | |
45 | | | |
46 | +--------------------+ |
47 | |
48 | ZapperModule - Created by the zapper for each module. It implements the |
49 | ICorCompileDataStore interface that the preloader uses to |
50 | allocate space for the EE data structures. Currently it |
51 | allocates space in a single PE section (though the DataImage |
52 | has logic to further subdivide the space into subsections). |
53 | |
54 | CEEPreloader - Created by ZapperModule in order to serialize EE |
55 | data structures. It implements two interfaces. |
56 | ICorCompilePreloader is used by ZapperModule to inquire |
57 | about the offsets of various EE data structures inside |
58 | the preloader section. DataImage::IDataStore is used |
59 | by DataImage to manage the PE section memory, and the |
60 | implementation in the CEEPreloader mostly forwards the calls |
61 | to the zapper (ICorCompileDataStore). |
62 | |
63 | DataImage - Created by CEEPreloader to keep track of memory used by |
64 | EE data structures. Even though it uses only one PE |
65 | section, it allows the EE to allocate memory in multiple |
66 | subsections. This is accomplished by splitting the work into |
67 | three phases (there are comments in dataimage.h that explain |
68 | this in detail). |
69 | |
70 | |
71 | The CEEPreloader is created when ZapperModule::Preload calls |
72 | m_zapper->m_pEECompileInfo->PreloadModule. PreloadModule creates |
73 | the CEEPreloader and then calls its Preload method, which explicitely |
74 | loads all the EE objects into memory (Module::ExpandAll), and then |
75 | allocates space for them in the preloader section (Module::Save). |
76 | |
77 | Each EE data structure that needs to be serialized implements a Save |
78 | method. A Save method is required to: |
79 | 1) Store all of its data (including strings and other buffers that it |
80 | uses) in the preloader section. This is accomplished by calling on |
81 | one of the DataImage storage methods (such as DataImage::StoreStructure). |
82 | 2) Call the Save method on the objects that it owns. The interesting |
83 | part of the hierarchy looks like: |
84 | |
85 | Module::Save |
86 | MethodTable::Save (in profile order) |
87 | EEClass::Save |
88 | MethodDescChunk::Save (method desc chunks can be split into hot |
89 | and cold based on profile info) |
90 | MethodDesc::Save |
91 | |
92 | Note that while the architecture requires the data structures in the |
93 | preloader sections to look like their EE counterparts, it is possible |
94 | to work around that limitation by constructing multiple submappings of |
95 | these data structures. Sometimes the submappings require a change to the actual |
96 | data (i.e. each method desc has information that tells you how far it is |
97 | from the MethodDescChunk, and that needs to change when reordering method |
98 | descs). In such cases you create new copies of that memory and construct |
99 | a regular copying map for each of the new updated copies (DataImage::StoreStructure), |
100 | and a pointer update map for each of the original EE data structures |
101 | (DataImage::StoreStructureUsingSurrogate). See MethodDescChunk::Save for |
102 | an example on how to do this. |
103 | |
104 | Fixups: once everything has been layout out in memory, the ZapperModule |
105 | calls CEEPreloader::Link to generate fixups for the data. CEEPreloader::Link |
106 | calls Module::Fixup, which results in a data structure walk very similar to |
107 | that of Module::Save. Each data structure calls one of the FixupPointerField |
108 | methods on the DataImage, which in turn forwards the call to |
109 | CEEPreloader::AddFixup, which forwards it to the zapper |
110 | (ZapperModule::AddFixup). |
111 | |
112 | */ |
113 | |
114 | #ifndef COMPILE_H_ |
115 | #define COMPILE_H_ |
116 | |
117 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
118 | |
119 | struct ZapperLoaderModuleTableKey { |
120 | ZapperLoaderModuleTableKey(Module *pDefinitionModule, |
121 | mdToken token, |
122 | Instantiation classInst, |
123 | Instantiation methodInst) |
124 | : m_inst(classInst, methodInst) |
125 | { WRAPPER_NO_CONTRACT; |
126 | this->m_pDefinitionModule = pDefinitionModule; |
127 | this->m_token = token; } |
128 | |
129 | Module *m_pDefinitionModule; |
130 | mdToken m_token; |
131 | SigTypeContext m_inst; |
132 | } ; |
133 | |
134 | struct ZapperLoaderModuleTableEntry { |
135 | ZapperLoaderModuleTableEntry(): key(0,0,Instantiation(),Instantiation()) { WRAPPER_NO_CONTRACT; this->result = 0; } |
136 | ZapperLoaderModuleTableEntry(const ZapperLoaderModuleTableKey &_key,Module *_result) |
137 | : key(_key) |
138 | { this->result = _result; } |
139 | |
140 | ZapperLoaderModuleTableKey key; |
141 | Module *result; |
142 | } ; |
143 | |
144 | class ZapperLoaderModuleTableTraits : public NoRemoveSHashTraits<DefaultSHashTraits<ZapperLoaderModuleTableEntry> > |
145 | { |
146 | |
147 | public: |
148 | typedef const ZapperLoaderModuleTableKey *key_t; |
149 | static const ZapperLoaderModuleTableKey * GetKey(const ZapperLoaderModuleTableEntry &e) { return &e.key; } |
150 | static count_t Hash(const ZapperLoaderModuleTableKey * k) |
151 | { |
152 | LIMITED_METHOD_CONTRACT; |
153 | |
154 | DWORD dwHash = 5381; |
155 | |
156 | dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)k->m_pDefinitionModule; |
157 | dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)k->m_token; |
158 | dwHash = ((dwHash << 5) + dwHash) ^ EEInstantiationHashTableHelper:: Hash(&k->m_inst); |
159 | return dwHash; |
160 | } |
161 | |
162 | static BOOL Equals(const ZapperLoaderModuleTableKey *e1, const ZapperLoaderModuleTableKey *e2) |
163 | { |
164 | WRAPPER_NO_CONTRACT; |
165 | return e1->m_pDefinitionModule == e2->m_pDefinitionModule && |
166 | e1->m_token == e2->m_token && |
167 | SigTypeContext::Equal(&e1->m_inst, &e2->m_inst); |
168 | } |
169 | static const ZapperLoaderModuleTableEntry Null() |
170 | { return ZapperLoaderModuleTableEntry(); } |
171 | |
172 | static bool IsNull(const ZapperLoaderModuleTableEntry &e) |
173 | { LIMITED_METHOD_CONTRACT; return e.key.m_pDefinitionModule == 0 && e.key.m_token == 0 && e.key.m_inst.IsEmpty(); } |
174 | |
175 | }; |
176 | |
177 | |
178 | typedef SHash<ZapperLoaderModuleTableTraits> ZapperLoaderModuleTable; |
179 | |
180 | class CEECompileInfo : public ICorCompileInfo |
181 | { |
182 | public: |
183 | CEECompileInfo() |
184 | : m_fGeneratingNgenPDB(FALSE) |
185 | { |
186 | } |
187 | |
188 | virtual ~CEECompileInfo() |
189 | { |
190 | WRAPPER_NO_CONTRACT; |
191 | } |
192 | |
193 | HRESULT Startup( BOOL fForceDebug, |
194 | BOOL fForceProfiling, |
195 | BOOL fForceInstrument); |
196 | |
197 | HRESULT CreateDomain(ICorCompilationDomain **ppDomain, |
198 | IMetaDataAssemblyEmit *pEmitter, |
199 | BOOL fForceDebug, |
200 | BOOL fForceProfiling, |
201 | BOOL fForceInstrument); |
202 | |
203 | HRESULT MakeCrossDomainCallback( |
204 | ICorCompilationDomain* pDomain, |
205 | CROSS_DOMAIN_CALLBACK pfnCallback, |
206 | LPVOID pArgs); |
207 | |
208 | HRESULT DestroyDomain(ICorCompilationDomain *pDomain); |
209 | |
210 | HRESULT LoadAssemblyByPath(LPCWSTR wzPath, |
211 | BOOL fExplicitBindToNativeImage, |
212 | CORINFO_ASSEMBLY_HANDLE *pHandle); |
213 | |
214 | |
215 | #ifdef FEATURE_COMINTEROP |
216 | HRESULT LoadTypeRefWinRT(IMDInternalImport *pAssemblyImport, |
217 | mdTypeRef ref, |
218 | CORINFO_ASSEMBLY_HANDLE *pHandle); |
219 | #endif |
220 | |
221 | BOOL IsInCurrentVersionBubble(CORINFO_MODULE_HANDLE hModule); |
222 | |
223 | HRESULT LoadAssemblyModule(CORINFO_ASSEMBLY_HANDLE assembly, |
224 | mdFile file, |
225 | CORINFO_MODULE_HANDLE *pHandle); |
226 | |
227 | |
228 | BOOL CheckAssemblyZap( |
229 | CORINFO_ASSEMBLY_HANDLE assembly, |
230 | __out_ecount_opt(*cAssemblyManifestModulePath) |
231 | LPWSTR assemblyManifestModulePath, |
232 | LPDWORD cAssemblyManifestModulePath); |
233 | |
234 | HRESULT SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE assembly, |
235 | CORINFO_MODULE_HANDLE module); |
236 | |
237 | IMDInternalImport * GetAssemblyMetaDataImport(CORINFO_ASSEMBLY_HANDLE scope); |
238 | |
239 | IMDInternalImport * GetModuleMetaDataImport(CORINFO_MODULE_HANDLE scope); |
240 | |
241 | CORINFO_MODULE_HANDLE GetAssemblyModule(CORINFO_ASSEMBLY_HANDLE module); |
242 | |
243 | CORINFO_ASSEMBLY_HANDLE GetModuleAssembly(CORINFO_MODULE_HANDLE module); |
244 | |
245 | PEDecoder * GetModuleDecoder(CORINFO_MODULE_HANDLE scope); |
246 | |
247 | void GetModuleFileName(CORINFO_MODULE_HANDLE module, |
248 | SString &result); |
249 | |
250 | void EncodeModuleAsIndex( CORINFO_MODULE_HANDLE fromHandle, |
251 | CORINFO_MODULE_HANDLE handle, |
252 | DWORD *pIndex, |
253 | IMetaDataAssemblyEmit *pAssemblyEmit); |
254 | |
255 | void EncodeClass( CORINFO_MODULE_HANDLE referencingModule, |
256 | CORINFO_CLASS_HANDLE classHandle, |
257 | SigBuilder *pSigBuilder, |
258 | LPVOID encodeContext, |
259 | ENCODEMODULE_CALLBACK pfnEncodeModule); |
260 | |
261 | void EncodeMethod( CORINFO_MODULE_HANDLE referencingModule, |
262 | CORINFO_METHOD_HANDLE methHnd, |
263 | SigBuilder *pSigBuilder, |
264 | LPVOID encodeContext, |
265 | ENCODEMODULE_CALLBACK pfnEncodeModule, |
266 | CORINFO_RESOLVED_TOKEN *pResolvedToken, |
267 | CORINFO_RESOLVED_TOKEN *pConstrainedResolvedToken, |
268 | BOOL fEncodeUsingResolvedTokenSpecStreams); |
269 | |
270 | virtual mdToken TryEncodeMethodAsToken(CORINFO_METHOD_HANDLE handle, |
271 | CORINFO_RESOLVED_TOKEN * pResolvedToken, |
272 | CORINFO_MODULE_HANDLE * referencingModule); |
273 | |
274 | virtual DWORD TryEncodeMethodSlot(CORINFO_METHOD_HANDLE handle); |
275 | |
276 | void EncodeField( CORINFO_MODULE_HANDLE referencingModule, |
277 | CORINFO_FIELD_HANDLE handle, |
278 | SigBuilder *pSigBuilder, |
279 | LPVOID encodeContext, |
280 | ENCODEMODULE_CALLBACK pfnEncodeModule, |
281 | CORINFO_RESOLVED_TOKEN *pResolvedToken, |
282 | BOOL fEncodeUsingResolvedTokenSpecStreams); |
283 | |
284 | // Encode generic dictionary signature |
285 | virtual void EncodeGenericSignature( |
286 | LPVOID signature, |
287 | BOOL fMethod, |
288 | SigBuilder * pSigBuilder, |
289 | LPVOID encodeContext, |
290 | ENCODEMODULE_CALLBACK pfnEncodeModule); |
291 | |
292 | |
293 | BOOL IsEmptyString(mdString token, |
294 | CORINFO_MODULE_HANDLE module); |
295 | |
296 | BOOL IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle); |
297 | |
298 | BOOL IsCachingOfInliningHintsEnabled() |
299 | { |
300 | return m_fCachingOfInliningHintsEnabled; |
301 | } |
302 | |
303 | void DisableCachingOfInliningHints() |
304 | { |
305 | m_fCachingOfInliningHintsEnabled = FALSE; |
306 | } |
307 | |
308 | HRESULT GetTypeDef( CORINFO_CLASS_HANDLE classHandle, |
309 | mdTypeDef *token); |
310 | HRESULT GetMethodDef( CORINFO_METHOD_HANDLE methodHandle, |
311 | mdMethodDef *token); |
312 | HRESULT GetFieldDef( CORINFO_FIELD_HANDLE fieldHandle, |
313 | mdFieldDef *token); |
314 | |
315 | void SetAssemblyHardBindList(__in_ecount( cHardBindList ) |
316 | LPWSTR *pHardBindList, |
317 | DWORD cHardBindList); |
318 | |
319 | CORINFO_MODULE_HANDLE GetLoaderModuleForMscorlib(); |
320 | CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableType(CORINFO_CLASS_HANDLE classHandle); |
321 | CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableMethod(CORINFO_METHOD_HANDLE methodHandle); |
322 | CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableField(CORINFO_FIELD_HANDLE fieldHandle); |
323 | |
324 | ICorCompilePreloader * PreloadModule(CORINFO_MODULE_HANDLE moduleHandle, |
325 | ICorCompileDataStore *pData, |
326 | CorProfileData *profileData); |
327 | |
328 | |
329 | HRESULT GetLoadHint(CORINFO_ASSEMBLY_HANDLE hAssembly, |
330 | CORINFO_ASSEMBLY_HANDLE hAssemblyDependency, |
331 | LoadHintEnum *loadHint, |
332 | LoadHintEnum *defaultLoadHint); |
333 | |
334 | HRESULT GetAssemblyVersionInfo(CORINFO_ASSEMBLY_HANDLE Handle, |
335 | CORCOMPILE_VERSION_INFO *pInfo); |
336 | |
337 | void GetAssemblyCodeBase(CORINFO_ASSEMBLY_HANDLE hAssembly, |
338 | SString &result); |
339 | |
340 | void GetCallRefMap(CORINFO_METHOD_HANDLE hMethod, |
341 | GCRefMapBuilder * pBuilder, |
342 | bool isDispatchCell); |
343 | |
344 | void CompressDebugInfo( |
345 | IN ICorDebugInfo::OffsetMapping * pOffsetMapping, |
346 | IN ULONG iOffsetMapping, |
347 | IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo, |
348 | IN ULONG iNativeVarInfo, |
349 | IN OUT SBuffer * pDebugInfoBuffer); |
350 | |
351 | HRESULT SetVerboseLevel( |
352 | IN VerboseLevel level); |
353 | |
354 | HRESULT GetBaseJitFlags( |
355 | IN CORINFO_METHOD_HANDLE hMethod, |
356 | OUT CORJIT_FLAGS *pFlags); |
357 | |
358 | ICorJitHost* GetJitHost(); |
359 | |
360 | void* GetStubSize(void *pStubAddress, DWORD *pSizeToCopy); |
361 | |
362 | HRESULT GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize); |
363 | |
364 | BOOL GetIsGeneratingNgenPDB(); |
365 | void SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB); |
366 | |
367 | #ifdef FEATURE_READYTORUN_COMPILER |
368 | CORCOMPILE_FIXUP_BLOB_KIND GetFieldBaseOffset( |
369 | CORINFO_CLASS_HANDLE classHnd, |
370 | DWORD * pBaseOffset); |
371 | |
372 | BOOL NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd); |
373 | void EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder); |
374 | |
375 | BOOL AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle); |
376 | |
377 | int GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token); |
378 | |
379 | int GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle); |
380 | #endif |
381 | |
382 | BOOL HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName); |
383 | |
384 | //-------------------------------------------------------------------- |
385 | // ZapperLoaderModules and the ZapperLoaderModuleTable |
386 | // |
387 | // When NGEN'ing we want to adjust the |
388 | // places where some items (i.e. generic instantiations) are placed, in order to get some of them |
389 | // placed into the module we are compiling. However, the |
390 | // results of ComputeLoaderModule must be stable for the duration |
391 | // of an entire instance of the VM, i.e. for the duration of a compilation |
392 | // process. Thus each time we place an item into a non-standard LoaderModule we record |
393 | // that fact. |
394 | |
395 | Module *LookupZapperLoaderModule(const ZapperLoaderModuleTableKey *pKey) |
396 | { |
397 | WRAPPER_NO_CONTRACT; |
398 | const ZapperLoaderModuleTableEntry *pEntry = m_ZapperLoaderModuleTable.LookupPtr(pKey); |
399 | if (pEntry) |
400 | return pEntry->result; |
401 | return NULL; |
402 | } |
403 | |
404 | void RecordZapperLoaderModule(const ZapperLoaderModuleTableKey *pKey, |
405 | Module *pZapperLoaderModuleTable) |
406 | { |
407 | CONTRACTL |
408 | { |
409 | THROWS; |
410 | GC_NOTRIGGER; |
411 | SO_TOLERANT; |
412 | MODE_ANY; |
413 | } |
414 | CONTRACTL_END; |
415 | ZapperLoaderModuleTableEntry entry(*pKey, pZapperLoaderModuleTable); |
416 | m_ZapperLoaderModuleTable.Add(entry); |
417 | } |
418 | |
419 | ZapperLoaderModuleTable m_ZapperLoaderModuleTable; |
420 | |
421 | private: |
422 | BOOL m_fCachingOfInliningHintsEnabled; |
423 | BOOL m_fGeneratingNgenPDB; |
424 | }; |
425 | |
426 | extern CEECompileInfo *g_pCEECompileInfo; |
427 | |
428 | BOOL IsNgenPDBCompilationProcess(); |
429 | |
430 | // |
431 | // See comment at top of file for an explanation on the preloader |
432 | // architecture. |
433 | // |
434 | |
435 | class CEEPreloader : public ICorCompilePreloader |
436 | { |
437 | private: |
438 | DataImage *m_image; |
439 | ICorCompileDataStore *m_pData; |
440 | |
441 | class MethodSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodDesc *> > |
442 | { |
443 | public: |
444 | typedef MethodDesc *key_t; |
445 | static MethodDesc * GetKey(MethodDesc *md) { return md; } |
446 | static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; } |
447 | static BOOL Equals(MethodDesc *md1, MethodDesc *md2) |
448 | { |
449 | return md1 == md2; |
450 | } |
451 | }; |
452 | |
453 | class TypeSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<TypeHandle> > |
454 | { |
455 | public: |
456 | typedef TypeHandle key_t; |
457 | static const TypeHandle Null() { return TypeHandle(); } |
458 | static bool IsNull(const TypeHandle &th) { return !!th.IsNull(); } |
459 | static TypeHandle GetKey(TypeHandle th) { return th; } |
460 | static count_t Hash(TypeHandle th) { return (count_t) th.AsTAddr(); } |
461 | static BOOL Equals(TypeHandle th1, TypeHandle th2) { return th1 == th2; } |
462 | }; |
463 | |
464 | // Cached results of instantiations triage |
465 | SHash<TypeSetTraits> m_acceptedTypes; |
466 | SHash<MethodSetTraits> m_acceptedMethods; |
467 | SHash<TypeSetTraits> m_rejectedTypes; |
468 | SHash<MethodSetTraits> m_rejectedMethods; |
469 | |
470 | #ifdef FEATURE_FULL_NGEN |
471 | // Tentatively accepted instantiations |
472 | InlineSArray<TypeHandle, 20> m_speculativeTypes; |
473 | BOOL m_fSpeculativeTriage; |
474 | BOOL m_fDictionariesPopulated; |
475 | #endif |
476 | |
477 | struct CompileMethodEntry |
478 | { |
479 | MethodDesc * pMD; |
480 | #ifndef FEATURE_FULL_NGEN // Unreferenced methods |
481 | bool fReferenced; // true when this method was referenced by other code |
482 | bool fScheduled; // true when this method was scheduled for compilation |
483 | #endif |
484 | }; |
485 | |
486 | class CompileMethodSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<CompileMethodEntry> > |
487 | { |
488 | public: |
489 | typedef MethodDesc *key_t; |
490 | static MethodDesc * GetKey(CompileMethodEntry e) { return e.pMD; } |
491 | static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; } |
492 | static BOOL Equals(MethodDesc *md1, MethodDesc *md2) |
493 | { |
494 | return md1 == md2; |
495 | } |
496 | static const CompileMethodEntry Null() { CompileMethodEntry e; e.pMD = NULL; return e; } |
497 | static bool IsNull(const CompileMethodEntry &e) { return e.pMD == NULL; } |
498 | }; |
499 | |
500 | SHash<CompileMethodSetTraits> m_compileMethodsHash; |
501 | |
502 | // Array of methods that we need to compile. |
503 | SArray<MethodDesc*> m_uncompiledMethods; |
504 | |
505 | int m_methodCompileLimit; |
506 | |
507 | void AppendUncompiledMethod(MethodDesc *pMD) |
508 | { |
509 | STANDARD_VM_CONTRACT; |
510 | if (m_methodCompileLimit > 0) |
511 | { |
512 | m_uncompiledMethods.Append(pMD); |
513 | m_methodCompileLimit--; |
514 | } |
515 | } |
516 | |
517 | struct DuplicateMethodEntry |
518 | { |
519 | MethodDesc * pMD; |
520 | MethodDesc * pDuplicateMD; |
521 | }; |
522 | |
523 | class DuplicateMethodTraits : public NoRemoveSHashTraits< DefaultSHashTraits<DuplicateMethodEntry> > |
524 | { |
525 | public: |
526 | typedef MethodDesc *key_t; |
527 | static MethodDesc * GetKey(DuplicateMethodEntry e) { return e.pMD; } |
528 | static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; } |
529 | static BOOL Equals(MethodDesc *md1, MethodDesc *md2) |
530 | { |
531 | return md1 == md2; |
532 | } |
533 | static const DuplicateMethodEntry Null() { DuplicateMethodEntry e; e.pMD = NULL; return e; } |
534 | static bool IsNull(const DuplicateMethodEntry &e) { return e.pMD == NULL; } |
535 | }; |
536 | |
537 | SHash<DuplicateMethodTraits> m_duplicateMethodsHash; |
538 | |
539 | MethodDesc * CompileMethodStubIfNeeded( |
540 | MethodDesc *pMD, |
541 | MethodDesc *pStubMD, |
542 | ICorCompilePreloader::CORCOMPILE_CompileStubCallback pfnCallback, |
543 | LPVOID pCallbackContext); |
544 | |
545 | public: |
546 | CEEPreloader(Module *pModule, |
547 | ICorCompileDataStore *pData); |
548 | virtual ~CEEPreloader(); |
549 | |
550 | void Preload(CorProfileData * profileData); |
551 | DataImage * GetDataImage() { LIMITED_METHOD_CONTRACT; return m_image; } |
552 | ICorCompileDataStore * GetDataStore() { LIMITED_METHOD_CONTRACT; return m_pData; } |
553 | |
554 | // |
555 | // ICorCompilerPreloader |
556 | // |
557 | |
558 | DWORD MapMethodEntryPoint(CORINFO_METHOD_HANDLE handle); |
559 | DWORD MapClassHandle(CORINFO_CLASS_HANDLE handle); |
560 | DWORD MapMethodHandle(CORINFO_METHOD_HANDLE handle); |
561 | DWORD MapFieldHandle(CORINFO_FIELD_HANDLE handle); |
562 | DWORD MapAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE handle); |
563 | DWORD MapGenericHandle(CORINFO_GENERIC_HANDLE handle); |
564 | DWORD MapModuleIDHandle(CORINFO_MODULE_HANDLE handle); |
565 | |
566 | void AddMethodToTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle); |
567 | void AddTypeToTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle); |
568 | BOOL IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle); |
569 | BOOL IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle); |
570 | |
571 | void MethodReferencedByCompiledCode(CORINFO_METHOD_HANDLE handle); |
572 | |
573 | BOOL IsUncompiledMethod(CORINFO_METHOD_HANDLE handle); |
574 | |
575 | private: |
576 | void AddToUncompiledMethods(MethodDesc *pMethod, BOOL fForStubs); |
577 | |
578 | void ApplyTypeDependencyProductionsForType(TypeHandle t); |
579 | void ApplyTypeDependencyForSZArrayHelper(MethodTable * pInterfaceMT, TypeHandle elemTypeHnd); |
580 | |
581 | friend class Module; |
582 | void TriageTypeForZap(TypeHandle th, BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE); |
583 | void TriageMethodForZap(MethodDesc* pMethod, BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE); |
584 | |
585 | void ExpandTypeDependencies(TypeHandle th); |
586 | void ExpandMethodDependencies(MethodDesc * pMD); |
587 | |
588 | void TriageTypeSpecsFromSoftBoundModule(Module * pSoftBoundModule); |
589 | void TriageTypeFromSoftBoundModule(TypeHandle th, Module * pSoftBoundModule); |
590 | void TriageSpeculativeType(TypeHandle th); |
591 | void TriageSpeculativeInstantiations(); |
592 | |
593 | // Returns TRUE if new types or methods have been added by the triage |
594 | BOOL TriageForZap(BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE); |
595 | |
596 | public: |
597 | CORINFO_METHOD_HANDLE NextUncompiledMethod(); |
598 | |
599 | void PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod); |
600 | |
601 | void GenerateMethodStubs( |
602 | CORINFO_METHOD_HANDLE hMethod, |
603 | bool fNgenProfileImage, |
604 | CORCOMPILE_CompileStubCallback pfnCallback, |
605 | LPVOID pCallbackContext); |
606 | |
607 | bool IsDynamicMethod(CORINFO_METHOD_HANDLE hMethod); |
608 | void SetMethodProfilingFlags(CORINFO_METHOD_HANDLE hMethod, DWORD flags); |
609 | |
610 | bool CanSkipMethodPreparation ( |
611 | CORINFO_METHOD_HANDLE callerHnd, /* IN */ |
612 | CORINFO_METHOD_HANDLE calleeHnd, /* IN */ |
613 | CorInfoIndirectCallReason *pReason = NULL, |
614 | CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY); |
615 | |
616 | BOOL CanEmbedClassID (CORINFO_CLASS_HANDLE typeHandle); |
617 | BOOL CanEmbedModuleID (CORINFO_MODULE_HANDLE moduleHandle); |
618 | BOOL CanEmbedModuleHandle(CORINFO_MODULE_HANDLE moduleHandle); |
619 | BOOL CanEmbedClassHandle (CORINFO_CLASS_HANDLE typeHandle); |
620 | BOOL CanEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHandle, |
621 | CORINFO_METHOD_HANDLE contextHandle); |
622 | BOOL CanEmbedFieldHandle (CORINFO_FIELD_HANDLE fieldHandle); |
623 | |
624 | BOOL CanPrerestoreEmbedClassHandle (CORINFO_CLASS_HANDLE classHnd); |
625 | BOOL CanPrerestoreEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHnd); |
626 | |
627 | BOOL CanEmbedFunctionEntryPoint(CORINFO_METHOD_HANDLE methodHandle, |
628 | CORINFO_METHOD_HANDLE contextHandle, |
629 | CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY); |
630 | |
631 | BOOL DoesMethodNeedRestoringBeforePrestubIsRun(CORINFO_METHOD_HANDLE methodHandle); |
632 | |
633 | BOOL CanSkipDependencyActivation(CORINFO_METHOD_HANDLE context, |
634 | CORINFO_MODULE_HANDLE moduleFrom, |
635 | CORINFO_MODULE_HANDLE moduleTo); |
636 | |
637 | CORINFO_MODULE_HANDLE GetPreferredZapModuleForClassHandle(CORINFO_CLASS_HANDLE classHnd); |
638 | |
639 | void NoteDeduplicatedCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod); |
640 | |
641 | CORINFO_METHOD_HANDLE LookupMethodDef(mdMethodDef token); |
642 | bool GetMethodInfo(mdMethodDef token, CORINFO_METHOD_HANDLE ftnHnd, CORINFO_METHOD_INFO * methInfo); |
643 | |
644 | CorCompileILRegion GetILRegion(mdMethodDef token); |
645 | |
646 | CORINFO_METHOD_HANDLE FindMethodForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry); |
647 | |
648 | void ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee); |
649 | |
650 | void Link(); |
651 | void FixupRVAs(); |
652 | |
653 | void SetRVAsForFields(IMetaDataEmit * pEmit); |
654 | |
655 | void GetRVAFieldData(mdFieldDef fd, PVOID * ppData, DWORD * pcbSize, DWORD * pcbAlignment); |
656 | |
657 | ULONG Release(); |
658 | |
659 | #ifdef FEATURE_READYTORUN_COMPILER |
660 | void GetSerializedInlineTrackingMap(SBuffer* pBuffer); |
661 | #endif |
662 | |
663 | void Error(mdToken token, Exception * pException); |
664 | }; |
665 | |
666 | |
667 | struct RefCache |
668 | { |
669 | RefCache(Module *pModule) |
670 | { |
671 | CONTRACTL |
672 | { |
673 | NOTHROW; |
674 | GC_NOTRIGGER; |
675 | FORBID_FAULT; |
676 | } |
677 | CONTRACTL_END |
678 | |
679 | |
680 | m_pModule = pModule; |
681 | |
682 | { |
683 | // HashMap::Init can throw due to OOM. Our ctor can't. Since this whole |
684 | // thing is for use inside CEECompileInfo methods, it doesn't make sense to |
685 | // use an exception model. Thus we probably have to move the hashmap init |
686 | // calls out of the ctor so can catch these exceptions and translate them to |
687 | // hresults. |
688 | // |
689 | CONTRACT_VIOLATION(ThrowsViolation|FaultViolation); |
690 | |
691 | m_sAssemblyRefMap.Init(FALSE,NULL); |
692 | } |
693 | } |
694 | |
695 | Module *m_pModule; |
696 | |
697 | HashMap m_sAssemblyRefMap; |
698 | }; |
699 | |
700 | struct AssemblySpecDefRefMapEntry { |
701 | AssemblySpec * m_pDef; |
702 | AssemblySpec * m_pRef; |
703 | }; |
704 | |
705 | class AssemblySpecDefRefMapTraits : public NoRemoveSHashTraits<DefaultSHashTraits<AssemblySpecDefRefMapEntry> > |
706 | { |
707 | public: |
708 | typedef const AssemblySpec *key_t; |
709 | static const AssemblySpec * GetKey(const AssemblySpecDefRefMapEntry &e) { return e.m_pDef; } |
710 | |
711 | static count_t Hash(const AssemblySpec * k) |
712 | { |
713 | return const_cast<AssemblySpec *>(k)->Hash(); |
714 | } |
715 | |
716 | static BOOL Equals(const AssemblySpec * lhs, const AssemblySpec * rhs) |
717 | { |
718 | return const_cast<AssemblySpec *>(lhs)->CompareEx(const_cast<AssemblySpec *>(rhs), AssemblySpec::ASC_DefinitionEquality); |
719 | } |
720 | |
721 | static const AssemblySpecDefRefMapEntry Null() { AssemblySpecDefRefMapEntry e; e.m_pDef = NULL; return e; } |
722 | static bool IsNull(const AssemblySpecDefRefMapEntry &e) { return e.m_pDef == NULL; } |
723 | |
724 | void OnDestructPerEntryCleanupAction(const AssemblySpecDefRefMapEntry& e) |
725 | { |
726 | WRAPPER_NO_CONTRACT; |
727 | delete e.m_pDef; |
728 | delete e.m_pRef; |
729 | } |
730 | static const bool s_DestructPerEntryCleanupAction = true; |
731 | }; |
732 | |
733 | typedef SHash<AssemblySpecDefRefMapTraits> AssemblySpecMapDefRefMapTable; |
734 | |
735 | class CompilationDomain : public AppDomain, |
736 | public ICorCompilationDomain |
737 | { |
738 | |
739 | public: |
740 | BOOL m_fForceDebug; |
741 | BOOL m_fForceProfiling; |
742 | BOOL m_fForceInstrument; |
743 | |
744 | // TODO: During ngen, we need to determine whether we can call NeedsRestore |
745 | // before the preloader has been initialized. This is accomplished via this |
746 | // method. This code needs to be cleaned up. See bug #284709 for background. |
747 | BOOL canCallNeedsRestore() { return (m_pTargetImage != NULL); }; |
748 | |
749 | // DDB 175659: Make sure that canCallNeedsRestore() returns FALSE during compilation |
750 | // domain shutdown. |
751 | void setCannotCallNeedsRestore() { m_pTargetImage = NULL; } |
752 | |
753 | private: |
754 | |
755 | Assembly *m_pTargetAssembly; // Assembly being compiled |
756 | Module *m_pTargetModule; // Module currently being compiled. Needed for multi-module assemblies |
757 | DataImage *m_pTargetImage; // Data image |
758 | CEEPreloader *m_pTargetPreloader; |
759 | |
760 | ReleaseHolder<IMetaDataAssemblyEmit> m_pEmit; |
761 | |
762 | NewHolder<AssemblySpecHash> m_pDependencyRefSpecs; |
763 | |
764 | AssemblySpecMapDefRefMapTable m_dependencyDefRefMap; |
765 | |
766 | CORCOMPILE_DEPENDENCY *m_pDependencies; |
767 | USHORT m_cDependenciesCount, m_cDependenciesAlloc; |
768 | |
769 | CQuickArray<RefCache*> m_rRefCaches; |
770 | |
771 | HRESULT AddDependencyEntry(PEAssembly *pFile, mdAssemblyRef ref,mdAssemblyRef def); |
772 | void ReleaseDependencyEmitter(); |
773 | |
774 | |
775 | public: |
776 | |
777 | #ifndef DACCESS_COMPILE |
778 | CompilationDomain(BOOL fForceDebug = FALSE, |
779 | BOOL fForceProfiling = FALSE, |
780 | BOOL fForceInstrument = FALSE); |
781 | ~CompilationDomain(); |
782 | #endif |
783 | |
784 | void Init(); |
785 | |
786 | HRESULT AddDependency(AssemblySpec *pRefSpec, PEAssembly *pFile); |
787 | |
788 | AssemblySpec* FindAssemblyRefSpecForDefSpec( |
789 | AssemblySpec* pDefSpec); |
790 | |
791 | PEAssembly *BindAssemblySpec( |
792 | AssemblySpec *pSpec, |
793 | BOOL fThrowOnFileNotFound, |
794 | BOOL fUseHostBinderIfAvailable = TRUE) DAC_EMPTY_RET(NULL); |
795 | |
796 | BOOL CanEagerBindToZapFile(Module *targetModule, BOOL limitToHardBindList = TRUE); |
797 | |
798 | |
799 | |
800 | // Returns NULL on out-of-memory |
801 | RefCache *GetRefCache(Module *pModule) |
802 | { |
803 | CONTRACTL |
804 | { |
805 | NOTHROW; |
806 | GC_NOTRIGGER; |
807 | INJECT_FAULT(return NULL;); |
808 | } |
809 | CONTRACTL_END |
810 | |
811 | unsigned uSize = (unsigned) m_rRefCaches.Size(); |
812 | for (unsigned i = 0; i < uSize; i++) |
813 | if (m_rRefCaches[i]->m_pModule == pModule) |
814 | return m_rRefCaches[i]; |
815 | |
816 | // Add a new cache entry |
817 | HRESULT hr; |
818 | |
819 | if (FAILED(hr = m_rRefCaches.ReSizeNoThrow(uSize + 1))) |
820 | { |
821 | _ASSERTE(hr == E_OUTOFMEMORY); |
822 | return NULL; |
823 | } |
824 | |
825 | m_rRefCaches[uSize] = new (nothrow) RefCache(pModule); |
826 | return m_rRefCaches[uSize]; |
827 | } |
828 | |
829 | void SetTarget(Assembly * pAssembly, Module *pModule); |
830 | |
831 | void SetTargetImage(DataImage * pImage, CEEPreloader * pPreloader); |
832 | DataImage * GetTargetImage() { LIMITED_METHOD_CONTRACT; return m_pTargetImage; } |
833 | |
834 | Assembly * GetTargetAssembly() |
835 | { LIMITED_METHOD_CONTRACT; return m_pTargetAssembly; } |
836 | Module * GetTargetModule() |
837 | { LIMITED_METHOD_CONTRACT; return m_pTargetModule; } |
838 | |
839 | // ICorCompilationDomain |
840 | |
841 | HRESULT SetContextInfo(LPCWSTR exePath, BOOL isExe) DAC_EMPTY_RET(E_FAIL); |
842 | HRESULT GetDependencies(CORCOMPILE_DEPENDENCY **ppDependencies, |
843 | DWORD *cDependencies) DAC_EMPTY_RET(E_FAIL); |
844 | |
845 | #ifdef CROSSGEN_COMPILE |
846 | HRESULT SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths) DAC_EMPTY_RET(E_FAIL); |
847 | #endif |
848 | |
849 | void SetDependencyEmitter(IMetaDataAssemblyEmit *pEmitter); |
850 | }; |
851 | |
852 | #endif // FEATURE_NATIVE_IMAGE_GENERATION |
853 | |
854 | #endif // COMPILE_H_ |
855 | |