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);
67 #ifdef FEATURE_TIERED_COMPILATION
73 OptimizationTier GetOptimizationTier() const;
74 #ifndef DACCESS_COMPILE
75 void SetOptimizationTier(OptimizationTier tier);
77 #endif // FEATURE_TIERED_COMPILATION
78 bool operator==(const NativeCodeVersion & rhs) const;
79 bool operator!=(const NativeCodeVersion & rhs) const;
80 #if defined(DACCESS_COMPILE) && defined(FEATURE_CODE_VERSIONING)
81 // The DAC is privy to the backing node abstraction
82 PTR_NativeCodeVersionNode AsNode() const;
87 #ifndef FEATURE_CODE_VERSIONING
88 MethodDesc* m_pMethodDesc;
89 #else // FEATURE_CODE_VERSIONING
91 #ifndef DACCESS_COMPILE
92 NativeCodeVersionNode* AsNode() const;
93 NativeCodeVersionNode* AsNode();
94 void SetActiveChildFlag(BOOL isActive);
95 MethodDescVersioningState* GetMethodDescVersioningState();
98 BOOL IsActiveChildVersion() const;
99 PTR_MethodDescVersioningState GetMethodDescVersioningState() const;
108 StorageKind m_storageKind;
111 PTR_NativeCodeVersionNode m_pVersionNode;
112 struct SyntheticStorage
114 PTR_MethodDesc m_pMethodDesc;
117 #endif // FEATURE_CODE_VERSIONING
122 #ifdef FEATURE_CODE_VERSIONING
128 friend class NativeCodeVersionIterator;
132 ILCodeVersion(const ILCodeVersion & ilCodeVersion);
133 ILCodeVersion(PTR_ILCodeVersionNode pILCodeVersionNode);
134 ILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);
136 bool operator==(const ILCodeVersion & rhs) const;
137 bool operator!=(const ILCodeVersion & rhs) const;
139 BOOL IsDefaultVersion() const;
140 PTR_Module GetModule() const;
141 mdMethodDef GetMethodDef() const;
142 ReJITID GetVersionId() const;
143 NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pClosedMethodDesc) const;
144 NativeCodeVersion GetActiveNativeCodeVersion(PTR_MethodDesc pClosedMethodDesc) const;
145 PTR_COR_ILMETHOD GetIL() const;
146 PTR_COR_ILMETHOD GetILNoThrow() const;
147 DWORD GetJitFlags() const;
148 const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
150 #ifndef DACCESS_COMPILE
151 void SetIL(COR_ILMETHOD* pIL);
152 void SetJitFlags(DWORD flags);
153 void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
154 HRESULT AddNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion);
155 HRESULT GetOrCreateActiveNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion);
156 HRESULT SetActiveNativeCodeVersion(NativeCodeVersion activeNativeCodeVersion, BOOL fEESuspended);
157 #endif //DACCESS_COMPILE
161 // The profiler has requested a ReJit, so we've allocated stuff, but we haven't
162 // called back to the profiler to get any info or indicate that the ReJit has
163 // started. (This Info can be 'reused' for a new ReJit if the
164 // profiler calls RequestRejit again before we transition to the next state.)
165 kStateRequested = 0x00000000,
167 // The CLR has initiated the call to the profiler's GetReJITParameters() callback
168 // but it hasn't completed yet. At this point we have to assume the profiler has
169 // commited to a specific IL body, even if the CLR doesn't know what it is yet.
170 // If the profiler calls RequestRejit we need to allocate a new ILCodeVersion
171 // and call GetReJITParameters() again.
172 kStateGettingReJITParameters = 0x00000001,
174 // We have asked the profiler about this method via ICorProfilerFunctionControl,
175 // and have thus stored the IL and codegen flags the profiler specified.
176 kStateActive = 0x00000002,
178 kStateMask = 0x0000000F,
181 RejitFlags GetRejitState() const;
182 #ifndef DACCESS_COMPILE
183 void SetRejitState(RejitFlags newState);
186 #ifdef DACCESS_COMPILE
187 // The DAC is privy to the backing node abstraction
188 PTR_ILCodeVersionNode AsNode() const;
193 #ifndef DACCESS_COMPILE
194 PTR_ILCodeVersionNode AsNode();
195 PTR_ILCodeVersionNode AsNode() const;
205 StorageKind m_storageKind;
208 PTR_ILCodeVersionNode m_pVersionNode;
209 struct SyntheticStorage
211 PTR_Module m_pModule;
212 mdMethodDef m_methodDef;
218 class NativeCodeVersionNode
220 friend NativeCodeVersionIterator;
221 friend MethodDescVersioningState;
222 friend ILCodeVersionNode;
224 #ifndef DACCESS_COMPILE
225 NativeCodeVersionNode(NativeCodeVersionId id, MethodDesc* pMethod, ReJITID parentId);
228 BOOL LockOwnedByCurrentThread() const;
230 PTR_MethodDesc GetMethodDesc() const;
231 NativeCodeVersionId GetVersionId() const;
232 PCODE GetNativeCode() const;
233 ReJITID GetILVersionId() const;
234 ILCodeVersion GetILCodeVersion() const;
235 BOOL IsActiveChildVersion() const;
236 #ifndef DACCESS_COMPILE
237 BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected);
238 void SetActiveChildFlag(BOOL isActive);
240 #ifdef FEATURE_TIERED_COMPILATION
241 NativeCodeVersion::OptimizationTier GetOptimizationTier() const;
242 #ifndef DACCESS_COMPILE
243 void SetOptimizationTier(NativeCodeVersion::OptimizationTier tier);
248 //union - could save a little memory?
251 PTR_MethodDesc m_pMethodDesc;
255 PTR_NativeCodeVersionNode m_pNextMethodDescSibling;
256 NativeCodeVersionId m_id;
257 #ifdef FEATURE_TIERED_COMPILATION
258 Volatile<NativeCodeVersion::OptimizationTier> m_optTier;
261 enum NativeCodeVersionNodeFlags
263 IsActiveChildFlag = 1
268 class NativeCodeVersionCollection
270 friend class NativeCodeVersionIterator;
272 NativeCodeVersionCollection(PTR_MethodDesc pMethodDescFilter, ILCodeVersion ilCodeFilter);
273 NativeCodeVersionIterator Begin();
274 NativeCodeVersionIterator End();
277 PTR_MethodDesc m_pMethodDescFilter;
278 ILCodeVersion m_ilCodeFilter;
281 class NativeCodeVersionIterator : public Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>
283 friend class Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>;
286 NativeCodeVersionIterator(NativeCodeVersionCollection* pCollection);
287 CHECK Check() const { CHECK_OK; }
290 const NativeCodeVersion & Get() const;
293 bool Equal(const NativeCodeVersionIterator &i) const;
295 CHECK DoCheck() const { CHECK_OK; }
305 IterationStage m_stage;
306 NativeCodeVersionCollection* m_pCollection;
307 PTR_NativeCodeVersionNode m_pLinkedListCur;
308 NativeCodeVersion m_cur;
311 class ILCodeVersionNode
315 #ifndef DACCESS_COMPILE
316 ILCodeVersionNode(Module* pModule, mdMethodDef methodDef, ReJITID id);
319 BOOL LockOwnedByCurrentThread() const;
321 PTR_Module GetModule() const;
322 mdMethodDef GetMethodDef() const;
323 ReJITID GetVersionId() const;
324 PTR_COR_ILMETHOD GetIL() const;
325 DWORD GetJitFlags() const;
326 const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
327 ILCodeVersion::RejitFlags GetRejitState() const;
328 PTR_ILCodeVersionNode GetNextILVersionNode() const;
329 #ifndef DACCESS_COMPILE
330 void SetIL(COR_ILMETHOD* pIL);
331 void SetJitFlags(DWORD flags);
332 void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
333 void SetRejitState(ILCodeVersion::RejitFlags newState);
334 void SetNextILVersionNode(ILCodeVersionNode* pNextVersionNode);
338 PTR_Module m_pModule;
339 mdMethodDef m_methodDef;
341 PTR_ILCodeVersionNode m_pNextILVersionNode;
342 Volatile<ILCodeVersion::RejitFlags> m_rejitState;
343 VolatilePtr<COR_ILMETHOD> m_pIL;
344 Volatile<DWORD> m_jitFlags;
345 InstrumentedILOffsetMapping m_instrumentedILMap;
348 class ILCodeVersionCollection
350 friend class ILCodeVersionIterator;
353 ILCodeVersionCollection(PTR_Module pModule, mdMethodDef methodDef);
354 ILCodeVersionIterator Begin();
355 ILCodeVersionIterator End();
358 PTR_Module m_pModule;
359 mdMethodDef m_methodDef;
362 class ILCodeVersionIterator : public Enumerator<const ILCodeVersion, ILCodeVersionIterator>
364 friend class Enumerator<const ILCodeVersion, ILCodeVersionIterator>;
367 ILCodeVersionIterator();
368 ILCodeVersionIterator(const ILCodeVersionIterator & iter);
369 ILCodeVersionIterator(ILCodeVersionCollection* pCollection);
370 CHECK Check() const { CHECK_OK; }
373 const ILCodeVersion & Get() const;
376 bool Equal(const ILCodeVersionIterator &i) const;
378 CHECK DoCheck() const { CHECK_OK; }
388 IterationStage m_stage;
390 PTR_ILCodeVersionNode m_pLinkedListCur;
391 ILCodeVersionCollection* m_pCollection;
394 class MethodDescVersioningState
397 // The size of the code used to jump stamp the prolog
398 #ifdef FEATURE_JUMPSTAMP
399 static const size_t JumpStubSize =
400 #if defined(_X86_) || defined(_AMD64_)
403 #error "Need to define size of jump-stamp for this platform"
405 #endif // FEATURE_JUMPSTAMP
407 MethodDescVersioningState(PTR_MethodDesc pMethodDesc);
408 PTR_MethodDesc GetMethodDesc() const;
409 NativeCodeVersionId AllocateVersionId();
410 PTR_NativeCodeVersionNode GetFirstVersionNode() const;
412 #ifndef DACCESS_COMPILE
413 #ifdef FEATURE_JUMPSTAMP
414 HRESULT SyncJumpStamp(NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
415 HRESULT UpdateJumpTarget(BOOL fEESuspended, PCODE pRejittedCode);
416 HRESULT UndoJumpStampNativeCode(BOOL fEESuspended);
417 HRESULT JumpStampNativeCode(PCODE pCode = NULL);
418 #endif // FEATURE_JUMPSTAMP
419 void LinkNativeCodeVersionNode(NativeCodeVersionNode* pNativeCodeVersionNode);
420 #endif // DACCESS_COMPILE
422 #ifdef FEATURE_JUMPSTAMP
425 // There is no jump stamp in place on this method (Either because
426 // there is no code at all, or there is code that hasn't been
427 // overwritten with a jump)
430 // The method code has the jump stamp written in, and it points to the Prestub
431 JumpStampToPrestub = 0x1,
433 // The method code has the jump stamp written in, and it points to the currently
434 // active code version
435 JumpStampToActiveVersion = 0x2,
438 JumpStampFlags GetJumpStampState();
439 void SetJumpStampState(JumpStampFlags newState);
440 #endif // FEATURE_JUMPSTAMP
442 //read-write data for the default native code version
443 BOOL IsDefaultVersionActiveChild() const;
444 #ifndef DACCESS_COMPILE
445 void SetDefaultVersionActiveChildFlag(BOOL isActive);
449 #if !defined(DACCESS_COMPILE) && defined(FEATURE_JUMPSTAMP)
450 INDEBUG(BOOL CodeIsSaved();)
451 HRESULT UpdateJumpStampHelper(BYTE* pbCode, INT64 i64OldValue, INT64 i64NewValue, BOOL fContentionPossible);
453 PTR_MethodDesc m_pMethodDesc;
455 enum MethodDescVersioningStateFlags
458 IsDefaultVersionActiveChildFlag = 0x4
461 NativeCodeVersionId m_nextId;
462 PTR_NativeCodeVersionNode m_pFirstVersionNode;
465 // The originally JITted code that was overwritten with the jmp stamp.
466 #ifdef FEATURE_JUMPSTAMP
467 BYTE m_rgSavedCode[JumpStubSize];
471 class MethodDescVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_MethodDescVersioningState>>
474 typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::element_t element_t;
475 typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::count_t count_t;
477 typedef const PTR_MethodDesc key_t;
479 static key_t GetKey(element_t e)
481 LIMITED_METHOD_CONTRACT;
482 return e->GetMethodDesc();
484 static BOOL Equals(key_t k1, key_t k2)
486 LIMITED_METHOD_CONTRACT;
489 static count_t Hash(key_t k)
491 LIMITED_METHOD_CONTRACT;
492 return (count_t)(size_t)dac_cast<TADDR>(k);
495 static const element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_MethodDescVersioningState>(nullptr); }
496 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
499 typedef SHash<MethodDescVersioningStateHashTraits> MethodDescVersioningStateHash;
501 class ILCodeVersioningState
504 ILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef);
505 ILCodeVersion GetActiveVersion() const;
506 PTR_ILCodeVersionNode GetFirstVersionNode() const;
507 #ifndef DACCESS_COMPILE
508 void SetActiveVersion(ILCodeVersion ilActiveCodeVersion);
509 void LinkILCodeVersionNode(ILCodeVersionNode* pILCodeVersionNode);
516 Key(PTR_Module pModule, mdMethodDef methodDef);
518 bool operator==(const Key & rhs) const;
520 PTR_Module m_pModule;
521 mdMethodDef m_methodDef;
527 ILCodeVersion m_activeVersion;
528 PTR_ILCodeVersionNode m_pFirstVersionNode;
529 PTR_Module m_pModule;
530 mdMethodDef m_methodDef;
533 class ILCodeVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_ILCodeVersioningState>>
536 typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::element_t element_t;
537 typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::count_t count_t;
539 typedef const ILCodeVersioningState::Key key_t;
541 static key_t GetKey(element_t e)
543 LIMITED_METHOD_CONTRACT;
546 static BOOL Equals(key_t k1, key_t k2)
548 LIMITED_METHOD_CONTRACT;
551 static count_t Hash(key_t k)
553 LIMITED_METHOD_CONTRACT;
554 return (count_t)k.Hash();
557 static const element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_ILCodeVersioningState>(nullptr); }
558 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
561 typedef SHash<ILCodeVersioningStateHashTraits> ILCodeVersioningStateHash;
564 class CodeVersionManager
566 friend class ILCodeVersion;
567 friend class PublishMethodHolder;
568 friend class PublishMethodTableHolder;
571 CodeVersionManager();
573 void PreInit(BOOL fSharedDomain);
575 class TableLockHolder : public CrstHolder
578 TableLockHolder(CodeVersionManager * pCodeVersionManager);
580 //Using the holder is preferable, but in some cases the holder can't be used
581 #ifndef DACCESS_COMPILE
587 BOOL LockOwnedByCurrentThread() const;
590 DWORD GetNonDefaultILVersionCount();
591 ILCodeVersionCollection GetILCodeVersions(PTR_MethodDesc pMethod);
592 ILCodeVersionCollection GetILCodeVersions(PTR_Module pModule, mdMethodDef methodDef);
593 ILCodeVersion GetActiveILCodeVersion(PTR_MethodDesc pMethod);
594 ILCodeVersion GetActiveILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);
595 ILCodeVersion GetILCodeVersion(PTR_MethodDesc pMethod, ReJITID rejitId);
596 NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pMethod) const;
597 NativeCodeVersion GetNativeCodeVersion(PTR_MethodDesc pMethod, PCODE codeStartAddress) const;
598 PTR_ILCodeVersioningState GetILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef) const;
599 PTR_MethodDescVersioningState GetMethodDescVersioningState(PTR_MethodDesc pMethod) const;
601 #ifndef DACCESS_COMPILE
602 struct CodePublishError
605 mdMethodDef methodDef;
606 MethodDesc* pMethodDesc;
610 HRESULT AddILCodeVersion(Module* pModule, mdMethodDef methodDef, ReJITID rejitId, ILCodeVersion* pILCodeVersion);
611 HRESULT AddNativeCodeVersion(ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion);
612 HRESULT DoJumpStampIfNecessary(MethodDesc* pMD, PCODE pCode);
613 PCODE PublishVersionableCodeIfNecessary(MethodDesc* pMethodDesc, BOOL fCanBackpatchPrestub);
614 HRESULT PublishNativeCodeVersion(MethodDesc* pMethodDesc, NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
615 HRESULT GetOrCreateMethodDescVersioningState(MethodDesc* pMethod, MethodDescVersioningState** ppMethodDescVersioningState);
616 HRESULT GetOrCreateILCodeVersioningState(Module* pModule, mdMethodDef methodDef, ILCodeVersioningState** ppILCodeVersioningState);
617 HRESULT SetActiveILCodeVersions(ILCodeVersion* pActiveVersions, DWORD cActiveVersions, BOOL fEESuspended, CDynArray<CodePublishError> * pPublishErrors);
618 static HRESULT AddCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
619 static HRESULT AddCodePublishError(NativeCodeVersion nativeCodeVersion, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
620 static void OnAppDomainExit(AppDomain* pAppDomain);
625 #ifndef DACCESS_COMPILE
626 static HRESULT EnumerateClosedMethodDescs(MethodDesc* pMD, CDynArray<MethodDesc*> * pClosedMethodDescs, CDynArray<CodePublishError> * pUnsupportedMethodErrors);
627 static HRESULT EnumerateDomainClosedMethodDescs(
628 AppDomain * pAppDomainToSearch,
629 Module* pModuleContainingMethodDef,
630 mdMethodDef methodDef,
631 CDynArray<MethodDesc*> * pClosedMethodDescs,
632 CDynArray<CodePublishError> * pUnsupportedMethodErrors);
633 static HRESULT GetNonVersionableError(MethodDesc* pMD);
634 void ReportCodePublishError(CodePublishError* pErrorRecord);
635 void ReportCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus);
638 //Module,MethodDef -> ILCodeVersioningState
639 ILCodeVersioningStateHash m_ilCodeVersioningStateMap;
641 //closed MethodDesc -> MethodDescVersioningState
642 MethodDescVersioningStateHash m_methodDescVersioningStateMap;
644 CrstExplicitInit m_crstTable;
647 #endif // FEATURE_CODE_VERSIONING
650 // These holders are used by runtime code that is making new code
651 // available for execution, either by publishing jitted code
652 // or restoring NGEN code. It ensures the publishing is synchronized
653 // with rejit requests
655 class PublishMethodHolder
658 #if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
659 PublishMethodHolder(MethodDesc* pMethod, PCODE pCode) { }
661 PublishMethodHolder(MethodDesc* pMethod, PCODE pCode);
662 ~PublishMethodHolder();
666 #if defined(FEATURE_CODE_VERSIONING)
672 class PublishMethodTableHolder
675 #if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
676 PublishMethodTableHolder(MethodTable* pMethodTable) { }
678 PublishMethodTableHolder(MethodTable* pMethodTable);
679 ~PublishMethodTableHolder();
683 #if defined(FEATURE_CODE_VERSIONING) && !defined(DACCESS_COMPILE)
684 MethodTable* m_pMethodTable;
685 CDynArray<CodeVersionManager::CodePublishError> m_errors;
689 #endif // CODE_VERSION_H