| 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 | |