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 // ===========================================================================
7 // ===========================================================================
10 #ifndef CODE_VERSION_H
11 #define CODE_VERSION_H
13 class NativeCodeVersion;
15 typedef DWORD NativeCodeVersionId;
17 #ifdef FEATURE_CODE_VERSIONING
18 class NativeCodeVersionNode;
19 typedef DPTR(class NativeCodeVersionNode) PTR_NativeCodeVersionNode;
20 class NativeCodeVersionCollection;
21 class NativeCodeVersionIterator;
22 class ILCodeVersionNode;
23 typedef DPTR(class ILCodeVersionNode) PTR_ILCodeVersionNode;
24 class ILCodeVersionCollection;
25 class ILCodeVersionIterator;
26 class MethodDescVersioningState;
27 typedef DPTR(class MethodDescVersioningState) PTR_MethodDescVersioningState;
29 class ILCodeVersioningState;
30 typedef DPTR(class ILCodeVersioningState) PTR_ILCodeVersioningState;
31 class CodeVersionManager;
32 typedef DPTR(class CodeVersionManager) PTR_CodeVersionManager;
34 // This HRESULT is only used as a private implementation detail. Corerror.xml has a comment in it
35 // reserving this value for our use but it doesn't appear in the public headers.
36 #define CORPROF_E_RUNTIME_SUSPEND_REQUIRED 0x80131381
43 class NativeCodeVersion
45 #ifdef FEATURE_CODE_VERSIONING
46 friend class MethodDescVersioningState;
47 friend class ILCodeVersion;
52 NativeCodeVersion(const NativeCodeVersion & rhs);
53 #ifdef FEATURE_CODE_VERSIONING
54 NativeCodeVersion(PTR_NativeCodeVersionNode pVersionNode);
56 NativeCodeVersion(PTR_MethodDesc pMethod);
58 PTR_MethodDesc GetMethodDesc() const;
59 NativeCodeVersionId GetVersionId() const;
60 BOOL IsDefaultVersion() const;
61 PCODE GetNativeCode() const;
62 ILCodeVersion GetILCodeVersion() const;
63 ReJITID GetILCodeVersionId() const;
64 #ifndef DACCESS_COMPILE
65 BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected = NULL);
72 #ifdef FEATURE_TIERED_COMPILATION
73 OptimizationTier GetOptimizationTier() const;
74 #endif // FEATURE_TIERED_COMPILATION
75 bool operator==(const NativeCodeVersion & rhs) const;
76 bool operator!=(const NativeCodeVersion & rhs) const;
77 #if defined(DACCESS_COMPILE) && defined(FEATURE_CODE_VERSIONING)
78 // The DAC is privy to the backing node abstraction
79 PTR_NativeCodeVersionNode AsNode() const;
84 #ifndef FEATURE_CODE_VERSIONING
85 MethodDesc* m_pMethodDesc;
86 #else // FEATURE_CODE_VERSIONING
88 #ifndef DACCESS_COMPILE
89 NativeCodeVersionNode* AsNode() const;
90 NativeCodeVersionNode* AsNode();
91 void SetActiveChildFlag(BOOL isActive);
92 MethodDescVersioningState* GetMethodDescVersioningState();
95 BOOL IsActiveChildVersion() const;
96 PTR_MethodDescVersioningState GetMethodDescVersioningState() const;
105 StorageKind m_storageKind;
108 PTR_NativeCodeVersionNode m_pVersionNode;
109 struct SyntheticStorage
111 PTR_MethodDesc m_pMethodDesc;
114 #endif // FEATURE_CODE_VERSIONING
119 #ifdef FEATURE_CODE_VERSIONING
125 friend class NativeCodeVersionIterator;
129 ILCodeVersion(const ILCodeVersion & ilCodeVersion);
130 ILCodeVersion(PTR_ILCodeVersionNode pILCodeVersionNode);
131 ILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);
133 bool operator==(const ILCodeVersion & rhs) const;
134 bool operator!=(const ILCodeVersion & rhs) const;
135 BOOL HasDefaultIL() const;
137 BOOL IsDefaultVersion() const;
138 PTR_Module GetModule() const;
139 mdMethodDef GetMethodDef() const;
140 ReJITID GetVersionId() const;
141 NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pClosedMethodDesc) const;
142 NativeCodeVersion GetActiveNativeCodeVersion(PTR_MethodDesc pClosedMethodDesc) const;
143 PTR_COR_ILMETHOD GetIL() const;
144 PTR_COR_ILMETHOD GetILNoThrow() const;
145 DWORD GetJitFlags() const;
146 const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
148 #ifndef DACCESS_COMPILE
149 void SetIL(COR_ILMETHOD* pIL);
150 void SetJitFlags(DWORD flags);
151 void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
152 HRESULT AddNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion);
153 HRESULT GetOrCreateActiveNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion);
154 HRESULT SetActiveNativeCodeVersion(NativeCodeVersion activeNativeCodeVersion, BOOL fEESuspended);
155 #endif //DACCESS_COMPILE
159 // The profiler has requested a ReJit, so we've allocated stuff, but we haven't
160 // called back to the profiler to get any info or indicate that the ReJit has
161 // started. (This Info can be 'reused' for a new ReJit if the
162 // profiler calls RequestRejit again before we transition to the next state.)
163 kStateRequested = 0x00000000,
165 // The CLR has initiated the call to the profiler's GetReJITParameters() callback
166 // but it hasn't completed yet. At this point we have to assume the profiler has
167 // commited to a specific IL body, even if the CLR doesn't know what it is yet.
168 // If the profiler calls RequestRejit we need to allocate a new ILCodeVersion
169 // and call GetReJITParameters() again.
170 kStateGettingReJITParameters = 0x00000001,
172 // We have asked the profiler about this method via ICorProfilerFunctionControl,
173 // and have thus stored the IL and codegen flags the profiler specified.
174 kStateActive = 0x00000002,
176 kStateMask = 0x0000000F,
179 RejitFlags GetRejitState() const;
180 #ifndef DACCESS_COMPILE
181 void SetRejitState(RejitFlags newState);
184 #ifdef DACCESS_COMPILE
185 // The DAC is privy to the backing node abstraction
186 PTR_ILCodeVersionNode AsNode() const;
191 #ifndef DACCESS_COMPILE
192 PTR_ILCodeVersionNode AsNode();
193 PTR_ILCodeVersionNode AsNode() const;
203 StorageKind m_storageKind;
206 PTR_ILCodeVersionNode m_pVersionNode;
207 struct SyntheticStorage
209 PTR_Module m_pModule;
210 mdMethodDef m_methodDef;
216 class NativeCodeVersionNode
218 friend NativeCodeVersionIterator;
219 friend MethodDescVersioningState;
220 friend ILCodeVersionNode;
222 #ifndef DACCESS_COMPILE
223 NativeCodeVersionNode(NativeCodeVersionId id, MethodDesc* pMethod, ReJITID parentId, NativeCodeVersion::OptimizationTier optimizationTier);
226 BOOL LockOwnedByCurrentThread() const;
228 PTR_MethodDesc GetMethodDesc() const;
229 NativeCodeVersionId GetVersionId() const;
230 PCODE GetNativeCode() const;
231 ReJITID GetILVersionId() const;
232 ILCodeVersion GetILCodeVersion() const;
233 BOOL IsActiveChildVersion() const;
234 #ifndef DACCESS_COMPILE
235 BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected);
236 void SetActiveChildFlag(BOOL isActive);
238 #ifdef FEATURE_TIERED_COMPILATION
239 NativeCodeVersion::OptimizationTier GetOptimizationTier() const;
243 //union - could save a little memory?
246 PTR_MethodDesc m_pMethodDesc;
250 PTR_NativeCodeVersionNode m_pNextMethodDescSibling;
251 NativeCodeVersionId m_id;
252 #ifdef FEATURE_TIERED_COMPILATION
253 NativeCodeVersion::OptimizationTier m_optTier;
256 enum NativeCodeVersionNodeFlags
258 IsActiveChildFlag = 1
263 class NativeCodeVersionCollection
265 friend class NativeCodeVersionIterator;
267 NativeCodeVersionCollection(PTR_MethodDesc pMethodDescFilter, ILCodeVersion ilCodeFilter);
268 NativeCodeVersionIterator Begin();
269 NativeCodeVersionIterator End();
272 PTR_MethodDesc m_pMethodDescFilter;
273 ILCodeVersion m_ilCodeFilter;
276 class NativeCodeVersionIterator : public Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>
278 friend class Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>;
281 NativeCodeVersionIterator(NativeCodeVersionCollection* pCollection);
282 CHECK Check() const { CHECK_OK; }
285 const NativeCodeVersion & Get() const;
288 bool Equal(const NativeCodeVersionIterator &i) const;
290 CHECK DoCheck() const { CHECK_OK; }
300 IterationStage m_stage;
301 NativeCodeVersionCollection* m_pCollection;
302 PTR_NativeCodeVersionNode m_pLinkedListCur;
303 NativeCodeVersion m_cur;
306 class ILCodeVersionNode
310 #ifndef DACCESS_COMPILE
311 ILCodeVersionNode(Module* pModule, mdMethodDef methodDef, ReJITID id);
314 BOOL LockOwnedByCurrentThread() const;
316 PTR_Module GetModule() const;
317 mdMethodDef GetMethodDef() const;
318 ReJITID GetVersionId() const;
319 PTR_COR_ILMETHOD GetIL() const;
320 DWORD GetJitFlags() const;
321 const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
322 ILCodeVersion::RejitFlags GetRejitState() const;
323 PTR_ILCodeVersionNode GetNextILVersionNode() const;
324 #ifndef DACCESS_COMPILE
325 void SetIL(COR_ILMETHOD* pIL);
326 void SetJitFlags(DWORD flags);
327 void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
328 void SetRejitState(ILCodeVersion::RejitFlags newState);
329 void SetNextILVersionNode(ILCodeVersionNode* pNextVersionNode);
333 PTR_Module m_pModule;
334 mdMethodDef m_methodDef;
336 PTR_ILCodeVersionNode m_pNextILVersionNode;
337 Volatile<ILCodeVersion::RejitFlags> m_rejitState;
338 VolatilePtr<COR_ILMETHOD, PTR_COR_ILMETHOD> m_pIL;
339 Volatile<DWORD> m_jitFlags;
340 InstrumentedILOffsetMapping m_instrumentedILMap;
343 class ILCodeVersionCollection
345 friend class ILCodeVersionIterator;
348 ILCodeVersionCollection(PTR_Module pModule, mdMethodDef methodDef);
349 ILCodeVersionIterator Begin();
350 ILCodeVersionIterator End();
353 PTR_Module m_pModule;
354 mdMethodDef m_methodDef;
357 class ILCodeVersionIterator : public Enumerator<const ILCodeVersion, ILCodeVersionIterator>
359 friend class Enumerator<const ILCodeVersion, ILCodeVersionIterator>;
362 ILCodeVersionIterator();
363 ILCodeVersionIterator(const ILCodeVersionIterator & iter);
364 ILCodeVersionIterator(ILCodeVersionCollection* pCollection);
365 CHECK Check() const { CHECK_OK; }
368 const ILCodeVersion & Get() const;
371 bool Equal(const ILCodeVersionIterator &i) const;
373 CHECK DoCheck() const { CHECK_OK; }
383 IterationStage m_stage;
385 PTR_ILCodeVersionNode m_pLinkedListCur;
386 ILCodeVersionCollection* m_pCollection;
389 class MethodDescVersioningState
392 // The size of the code used to jump stamp the prolog
393 #ifdef FEATURE_JUMPSTAMP
394 static const size_t JumpStubSize =
395 #if defined(_X86_) || defined(_AMD64_)
398 #error "Need to define size of jump-stamp for this platform"
400 #endif // FEATURE_JUMPSTAMP
402 MethodDescVersioningState(PTR_MethodDesc pMethodDesc);
403 PTR_MethodDesc GetMethodDesc() const;
404 NativeCodeVersionId AllocateVersionId();
405 PTR_NativeCodeVersionNode GetFirstVersionNode() const;
407 #ifndef DACCESS_COMPILE
408 #ifdef FEATURE_JUMPSTAMP
409 HRESULT SyncJumpStamp(NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
410 HRESULT UpdateJumpTarget(BOOL fEESuspended, PCODE pRejittedCode);
411 HRESULT UndoJumpStampNativeCode(BOOL fEESuspended);
412 HRESULT JumpStampNativeCode(PCODE pCode = NULL);
413 #endif // FEATURE_JUMPSTAMP
414 void LinkNativeCodeVersionNode(NativeCodeVersionNode* pNativeCodeVersionNode);
415 #endif // DACCESS_COMPILE
417 #ifdef FEATURE_JUMPSTAMP
420 // There is no jump stamp in place on this method (Either because
421 // there is no code at all, or there is code that hasn't been
422 // overwritten with a jump)
425 // The method code has the jump stamp written in, and it points to the Prestub
426 JumpStampToPrestub = 0x1,
428 // The method code has the jump stamp written in, and it points to the currently
429 // active code version
430 JumpStampToActiveVersion = 0x2,
433 JumpStampFlags GetJumpStampState();
434 void SetJumpStampState(JumpStampFlags newState);
435 #endif // FEATURE_JUMPSTAMP
437 //read-write data for the default native code version
438 BOOL IsDefaultVersionActiveChild() const;
439 #ifndef DACCESS_COMPILE
440 void SetDefaultVersionActiveChildFlag(BOOL isActive);
444 #if !defined(DACCESS_COMPILE) && defined(FEATURE_JUMPSTAMP)
445 INDEBUG(BOOL CodeIsSaved();)
446 HRESULT UpdateJumpStampHelper(BYTE* pbCode, INT64 i64OldValue, INT64 i64NewValue, BOOL fContentionPossible);
448 PTR_MethodDesc m_pMethodDesc;
450 enum MethodDescVersioningStateFlags
453 IsDefaultVersionActiveChildFlag = 0x4
456 NativeCodeVersionId m_nextId;
457 PTR_NativeCodeVersionNode m_pFirstVersionNode;
460 // The originally JITted code that was overwritten with the jmp stamp.
461 #ifdef FEATURE_JUMPSTAMP
462 BYTE m_rgSavedCode[JumpStubSize];
466 class MethodDescVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_MethodDescVersioningState>>
469 typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::element_t element_t;
470 typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::count_t count_t;
472 typedef const PTR_MethodDesc key_t;
474 static key_t GetKey(element_t e)
476 LIMITED_METHOD_CONTRACT;
477 return e->GetMethodDesc();
479 static BOOL Equals(key_t k1, key_t k2)
481 LIMITED_METHOD_CONTRACT;
484 static count_t Hash(key_t k)
486 LIMITED_METHOD_CONTRACT;
487 return (count_t)(size_t)dac_cast<TADDR>(k);
490 static element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_MethodDescVersioningState>(nullptr); }
491 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
494 typedef SHash<MethodDescVersioningStateHashTraits> MethodDescVersioningStateHash;
496 class ILCodeVersioningState
499 ILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef);
500 ILCodeVersion GetActiveVersion() const;
501 PTR_ILCodeVersionNode GetFirstVersionNode() const;
502 #ifndef DACCESS_COMPILE
503 void SetActiveVersion(ILCodeVersion ilActiveCodeVersion);
504 void LinkILCodeVersionNode(ILCodeVersionNode* pILCodeVersionNode);
511 Key(PTR_Module pModule, mdMethodDef methodDef);
513 bool operator==(const Key & rhs) const;
515 PTR_Module m_pModule;
516 mdMethodDef m_methodDef;
522 ILCodeVersion m_activeVersion;
523 PTR_ILCodeVersionNode m_pFirstVersionNode;
524 PTR_Module m_pModule;
525 mdMethodDef m_methodDef;
528 class ILCodeVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_ILCodeVersioningState>>
531 typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::element_t element_t;
532 typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::count_t count_t;
534 typedef const ILCodeVersioningState::Key key_t;
536 static key_t GetKey(element_t e)
538 LIMITED_METHOD_CONTRACT;
541 static BOOL Equals(key_t k1, key_t k2)
543 LIMITED_METHOD_CONTRACT;
546 static count_t Hash(key_t k)
548 LIMITED_METHOD_CONTRACT;
549 return (count_t)k.Hash();
552 static element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_ILCodeVersioningState>(nullptr); }
553 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
556 typedef SHash<ILCodeVersioningStateHashTraits> ILCodeVersioningStateHash;
559 class CodeVersionManager
561 friend class ILCodeVersion;
562 friend class PublishMethodHolder;
563 friend class PublishMethodTableHolder;
566 CodeVersionManager();
568 void PreInit(BOOL fSharedDomain);
570 class TableLockHolder : public CrstHolder
573 TableLockHolder(CodeVersionManager * pCodeVersionManager);
575 //Using the holder is preferable, but in some cases the holder can't be used
576 #ifndef DACCESS_COMPILE
582 BOOL LockOwnedByCurrentThread() const;
585 DWORD GetNonDefaultILVersionCount();
586 ILCodeVersionCollection GetILCodeVersions(PTR_MethodDesc pMethod);
587 ILCodeVersionCollection GetILCodeVersions(PTR_Module pModule, mdMethodDef methodDef);
588 ILCodeVersion GetActiveILCodeVersion(PTR_MethodDesc pMethod);
589 ILCodeVersion GetActiveILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);
590 ILCodeVersion GetILCodeVersion(PTR_MethodDesc pMethod, ReJITID rejitId);
591 NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pMethod) const;
592 NativeCodeVersion GetNativeCodeVersion(PTR_MethodDesc pMethod, PCODE codeStartAddress) const;
593 PTR_ILCodeVersioningState GetILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef) const;
594 PTR_MethodDescVersioningState GetMethodDescVersioningState(PTR_MethodDesc pMethod) const;
596 #ifndef DACCESS_COMPILE
597 struct CodePublishError
600 mdMethodDef methodDef;
601 MethodDesc* pMethodDesc;
605 HRESULT AddILCodeVersion(Module* pModule, mdMethodDef methodDef, ReJITID rejitId, ILCodeVersion* pILCodeVersion);
606 HRESULT AddNativeCodeVersion(ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion);
607 HRESULT DoJumpStampIfNecessary(MethodDesc* pMD, PCODE pCode);
608 PCODE PublishVersionableCodeIfNecessary(MethodDesc* pMethodDesc, BOOL fCanBackpatchPrestub);
609 HRESULT PublishNativeCodeVersion(MethodDesc* pMethodDesc, NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
610 HRESULT GetOrCreateMethodDescVersioningState(MethodDesc* pMethod, MethodDescVersioningState** ppMethodDescVersioningState);
611 HRESULT GetOrCreateILCodeVersioningState(Module* pModule, mdMethodDef methodDef, ILCodeVersioningState** ppILCodeVersioningState);
612 HRESULT SetActiveILCodeVersions(ILCodeVersion* pActiveVersions, DWORD cActiveVersions, BOOL fEESuspended, CDynArray<CodePublishError> * pPublishErrors);
613 static HRESULT AddCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
614 static HRESULT AddCodePublishError(NativeCodeVersion nativeCodeVersion, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
615 static void OnAppDomainExit(AppDomain* pAppDomain);
620 #ifndef DACCESS_COMPILE
621 static HRESULT EnumerateClosedMethodDescs(MethodDesc* pMD, CDynArray<MethodDesc*> * pClosedMethodDescs, CDynArray<CodePublishError> * pUnsupportedMethodErrors);
622 static HRESULT EnumerateDomainClosedMethodDescs(
623 AppDomain * pAppDomainToSearch,
624 Module* pModuleContainingMethodDef,
625 mdMethodDef methodDef,
626 CDynArray<MethodDesc*> * pClosedMethodDescs,
627 CDynArray<CodePublishError> * pUnsupportedMethodErrors);
628 static HRESULT GetNonVersionableError(MethodDesc* pMD);
629 void ReportCodePublishError(CodePublishError* pErrorRecord);
630 void ReportCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus);
633 //Module,MethodDef -> ILCodeVersioningState
634 ILCodeVersioningStateHash m_ilCodeVersioningStateMap;
636 //closed MethodDesc -> MethodDescVersioningState
637 MethodDescVersioningStateHash m_methodDescVersioningStateMap;
639 CrstExplicitInit m_crstTable;
642 #endif // FEATURE_CODE_VERSIONING
645 // These holders are used by runtime code that is making new code
646 // available for execution, either by publishing jitted code
647 // or restoring NGEN code. It ensures the publishing is synchronized
648 // with rejit requests
650 class PublishMethodHolder
653 #if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
654 PublishMethodHolder(MethodDesc* pMethod, PCODE pCode) { }
656 PublishMethodHolder(MethodDesc* pMethod, PCODE pCode);
657 ~PublishMethodHolder();
661 #if defined(FEATURE_CODE_VERSIONING)
667 class PublishMethodTableHolder
670 #if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
671 PublishMethodTableHolder(MethodTable* pMethodTable) { }
673 PublishMethodTableHolder(MethodTable* pMethodTable);
674 ~PublishMethodTableHolder();
678 #if defined(FEATURE_CODE_VERSIONING) && !defined(DACCESS_COMPILE)
679 MethodTable* m_pMethodTable;
680 CDynArray<CodeVersionManager::CodePublishError> m_errors;
684 #endif // CODE_VERSION_H