summaryrefslogtreecommitdiff
path: root/src/vm/codeversion.h
blob: 898796f18333b808ca007772941b869f1ac8d214 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: CodeVersion.h
//
// ===========================================================================


#ifndef CODE_VERSION_H
#define CODE_VERSION_H

class NativeCodeVersion;
class ILCodeVersion;
typedef DWORD NativeCodeVersionId;

#ifdef FEATURE_CODE_VERSIONING
class NativeCodeVersionNode;
typedef DPTR(class NativeCodeVersionNode) PTR_NativeCodeVersionNode;
class NativeCodeVersionCollection;
class NativeCodeVersionIterator;
class ILCodeVersionNode;
typedef DPTR(class ILCodeVersionNode) PTR_ILCodeVersionNode;
class ILCodeVersionCollection;
class ILCodeVersionIterator;
class MethodDescVersioningState;
typedef DPTR(class MethodDescVersioningState) PTR_MethodDescVersioningState;

class ILCodeVersioningState;
typedef DPTR(class ILCodeVersioningState) PTR_ILCodeVersioningState;
class CodeVersionManager;
typedef DPTR(class CodeVersionManager) PTR_CodeVersionManager;

// This HRESULT is only used as a private implementation detail. Corerror.xml has a comment in it
//  reserving this value for our use but it doesn't appear in the public headers.
#define CORPROF_E_RUNTIME_SUSPEND_REQUIRED _HRESULT_TYPEDEF_(0x80131381L)

#endif

#ifdef HAVE_GCCOVER
class GCCoverageInfo;
typedef DPTR(class GCCoverageInfo) PTR_GCCoverageInfo;
#endif

class NativeCodeVersion
{
#ifdef FEATURE_CODE_VERSIONING
    friend class MethodDescVersioningState;
    friend class ILCodeVersion;
#endif

public:
    NativeCodeVersion();
    NativeCodeVersion(const NativeCodeVersion & rhs);
#ifdef FEATURE_CODE_VERSIONING
    NativeCodeVersion(PTR_NativeCodeVersionNode pVersionNode);
#endif
    explicit NativeCodeVersion(PTR_MethodDesc pMethod);

    BOOL IsNull() const;
    PTR_MethodDesc GetMethodDesc() const;
    NativeCodeVersionId GetVersionId() const;
    BOOL IsDefaultVersion() const;
    PCODE GetNativeCode() const;

#ifdef FEATURE_CODE_VERSIONING
    ILCodeVersion GetILCodeVersion() const;
    ReJITID GetILCodeVersionId() const;
#endif

#ifndef DACCESS_COMPILE
    BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected = NULL);
#endif

    enum OptimizationTier
    {
        OptimizationTier0,
        OptimizationTier1,
        OptimizationTierOptimized, // may do less optimizations than tier 1
    };
#ifdef FEATURE_TIERED_COMPILATION
    OptimizationTier GetOptimizationTier() const;
#ifndef DACCESS_COMPILE
    void SetOptimizationTier(OptimizationTier tier);
#endif
#endif // FEATURE_TIERED_COMPILATION

#ifdef HAVE_GCCOVER
    PTR_GCCoverageInfo GetGCCoverageInfo() const;
    void SetGCCoverageInfo(PTR_GCCoverageInfo gcCover);
#endif

    bool operator==(const NativeCodeVersion & rhs) const;
    bool operator!=(const NativeCodeVersion & rhs) const;

#if defined(DACCESS_COMPILE) && defined(FEATURE_CODE_VERSIONING)
    // The DAC is privy to the backing node abstraction
    PTR_NativeCodeVersionNode AsNode() const;
#endif

private:

#ifndef FEATURE_CODE_VERSIONING
    PTR_MethodDesc m_pMethodDesc;
#else // FEATURE_CODE_VERSIONING

#ifndef DACCESS_COMPILE
    NativeCodeVersionNode* AsNode() const;
    NativeCodeVersionNode* AsNode();
    void SetActiveChildFlag(BOOL isActive);
    MethodDescVersioningState* GetMethodDescVersioningState();
#endif

    BOOL IsActiveChildVersion() const;
    PTR_MethodDescVersioningState GetMethodDescVersioningState() const;

    enum StorageKind
    {
        Unknown,
        Explicit,
        Synthetic
    };

    StorageKind m_storageKind;
    union
    {
        PTR_NativeCodeVersionNode m_pVersionNode;
        struct
        {
            PTR_MethodDesc m_pMethodDesc;
        } m_synthetic;
    };
#endif // FEATURE_CODE_VERSIONING
};



#ifdef FEATURE_CODE_VERSIONING



class ILCodeVersion
{
    friend class NativeCodeVersionIterator;

public:
    ILCodeVersion();
    ILCodeVersion(const ILCodeVersion & ilCodeVersion);
    ILCodeVersion(PTR_ILCodeVersionNode pILCodeVersionNode);
    ILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);

    bool operator==(const ILCodeVersion & rhs) const;
    bool operator!=(const ILCodeVersion & rhs) const;
    BOOL HasDefaultIL() const;
    BOOL IsNull() const;
    BOOL IsDefaultVersion() const;
    PTR_Module GetModule() const;
    mdMethodDef GetMethodDef() const;
    ReJITID GetVersionId() const;
    NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pClosedMethodDesc) const;
    NativeCodeVersion GetActiveNativeCodeVersion(PTR_MethodDesc pClosedMethodDesc) const;
    PTR_COR_ILMETHOD GetIL() const;
    PTR_COR_ILMETHOD GetILNoThrow() const;
    DWORD GetJitFlags() const;
    const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;

#ifndef DACCESS_COMPILE
    void SetIL(COR_ILMETHOD* pIL);
    void SetJitFlags(DWORD flags);
    void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
    HRESULT AddNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion);
    HRESULT GetOrCreateActiveNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion);
    HRESULT SetActiveNativeCodeVersion(NativeCodeVersion activeNativeCodeVersion, BOOL fEESuspended);
#endif //DACCESS_COMPILE

    enum RejitFlags
    {
        // The profiler has requested a ReJit, so we've allocated stuff, but we haven't
        // called back to the profiler to get any info or indicate that the ReJit has
        // started. (This Info can be 'reused' for a new ReJit if the
        // profiler calls RequestRejit again before we transition to the next state.)
        kStateRequested = 0x00000000,

        // The CLR has initiated the call to the profiler's GetReJITParameters() callback
        // but it hasn't completed yet. At this point we have to assume the profiler has
        // commited to a specific IL body, even if the CLR doesn't know what it is yet.
        // If the profiler calls RequestRejit we need to allocate a new ILCodeVersion
        // and call GetReJITParameters() again.
        kStateGettingReJITParameters = 0x00000001,

        // We have asked the profiler about this method via ICorProfilerFunctionControl,
        // and have thus stored the IL and codegen flags the profiler specified.
        kStateActive = 0x00000002,

        kStateMask = 0x0000000F,

        // Indicates that the method being ReJITted is an inliner of the actual 
        // ReJIT request and we should not issue the GetReJITParameters for this 
        // method.
        kSuppressParams = 0x80000000
    };

    RejitFlags GetRejitState() const;
    BOOL GetEnableReJITCallback() const;
#ifndef DACCESS_COMPILE
    void SetRejitState(RejitFlags newState);
    void SetEnableReJITCallback(BOOL state);
#endif

#ifdef DACCESS_COMPILE
    // The DAC is privy to the backing node abstraction
    PTR_ILCodeVersionNode AsNode() const;
#endif

private:

#ifndef DACCESS_COMPILE
    PTR_ILCodeVersionNode AsNode();
    PTR_ILCodeVersionNode AsNode() const;
#endif

    enum StorageKind
    {
        Unknown,
        Explicit,
        Synthetic
    };

    StorageKind m_storageKind;
    union
    {
        PTR_ILCodeVersionNode m_pVersionNode;
        struct
        {
            PTR_Module m_pModule;
            mdMethodDef m_methodDef;
        } m_synthetic;
    };
};


class NativeCodeVersionNode
{
    friend NativeCodeVersionIterator;
    friend MethodDescVersioningState;
    friend ILCodeVersionNode;

public:
#ifndef DACCESS_COMPILE
    NativeCodeVersionNode(NativeCodeVersionId id, MethodDesc* pMethod, ReJITID parentId, NativeCodeVersion::OptimizationTier optimizationTier);
#endif

#ifdef DEBUG
    BOOL LockOwnedByCurrentThread() const;
#endif

    PTR_MethodDesc GetMethodDesc() const;
    NativeCodeVersionId GetVersionId() const;
    PCODE GetNativeCode() const;
    ReJITID GetILVersionId() const;
    ILCodeVersion GetILCodeVersion() const;
    BOOL IsActiveChildVersion() const;
#ifndef DACCESS_COMPILE
    BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected);
    void SetActiveChildFlag(BOOL isActive);
#endif

#ifdef FEATURE_TIERED_COMPILATION
    NativeCodeVersion::OptimizationTier GetOptimizationTier() const;
#ifndef DACCESS_COMPILE
    void SetOptimizationTier(NativeCodeVersion::OptimizationTier tier);
#endif
#endif // FEATURE_TIERED_COMPILATION

#ifdef HAVE_GCCOVER
    PTR_GCCoverageInfo GetGCCoverageInfo() const;
    void SetGCCoverageInfo(PTR_GCCoverageInfo gcCover);
#endif

private:
    //union - could save a little memory?
    //{
    PCODE m_pNativeCode;
    PTR_MethodDesc m_pMethodDesc;
    //};

    ReJITID m_parentId;
    PTR_NativeCodeVersionNode m_pNextMethodDescSibling;
    NativeCodeVersionId m_id;
#ifdef FEATURE_TIERED_COMPILATION
    NativeCodeVersion::OptimizationTier m_optTier;
#endif
#ifdef HAVE_GCCOVER
    PTR_GCCoverageInfo m_gcCover;
#endif

    enum NativeCodeVersionNodeFlags
    {
        IsActiveChildFlag = 1
    };
    DWORD m_flags;
};

class NativeCodeVersionCollection
{
    friend class NativeCodeVersionIterator;
public:
    NativeCodeVersionCollection(PTR_MethodDesc pMethodDescFilter, ILCodeVersion ilCodeFilter);
    NativeCodeVersionIterator Begin();
    NativeCodeVersionIterator End();

private:
    PTR_MethodDesc m_pMethodDescFilter;
    ILCodeVersion m_ilCodeFilter;
};

class NativeCodeVersionIterator : public Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>
{
    friend class Enumerator<const NativeCodeVersion, NativeCodeVersionIterator>;

public:
    NativeCodeVersionIterator(NativeCodeVersionCollection* pCollection);
    CHECK Check() const { CHECK_OK; }

protected:
    const NativeCodeVersion & Get() const;
    void First();
    void Next();
    bool Equal(const NativeCodeVersionIterator &i) const;

    CHECK DoCheck() const { CHECK_OK; }

private:
    enum IterationStage
    {
        Initial,
        ImplicitCodeVersion,
        LinkedList,
        End
    };
    IterationStage m_stage;
    NativeCodeVersionCollection* m_pCollection;
    PTR_NativeCodeVersionNode m_pLinkedListCur;
    NativeCodeVersion m_cur;
};

class ILCodeVersionNode
{
public:
    ILCodeVersionNode();
#ifndef DACCESS_COMPILE
    ILCodeVersionNode(Module* pModule, mdMethodDef methodDef, ReJITID id);
#endif
#ifdef DEBUG
    BOOL LockOwnedByCurrentThread() const;
#endif //DEBUG
    PTR_Module GetModule() const;
    mdMethodDef GetMethodDef() const;
    ReJITID GetVersionId() const;
    PTR_COR_ILMETHOD GetIL() const;
    DWORD GetJitFlags() const;
    const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
    ILCodeVersion::RejitFlags GetRejitState() const;
    BOOL GetEnableReJITCallback() const;
    PTR_ILCodeVersionNode GetNextILVersionNode() const;
#ifndef DACCESS_COMPILE
    void SetIL(COR_ILMETHOD* pIL);
    void SetJitFlags(DWORD flags);
    void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap);
    void SetRejitState(ILCodeVersion::RejitFlags newState);
    void SetEnableReJITCallback(BOOL state);
    void SetNextILVersionNode(ILCodeVersionNode* pNextVersionNode);
#endif

private:
    PTR_Module m_pModule;
    mdMethodDef m_methodDef;
    ReJITID m_rejitId;
    PTR_ILCodeVersionNode m_pNextILVersionNode;
    Volatile<ILCodeVersion::RejitFlags> m_rejitState;
    VolatilePtr<COR_ILMETHOD, PTR_COR_ILMETHOD> m_pIL;
    Volatile<DWORD> m_jitFlags;
    InstrumentedILOffsetMapping m_instrumentedILMap;
};

class ILCodeVersionCollection
{
    friend class ILCodeVersionIterator;

public:
    ILCodeVersionCollection(PTR_Module pModule, mdMethodDef methodDef);
    ILCodeVersionIterator Begin();
    ILCodeVersionIterator End();

private:
    PTR_Module m_pModule;
    mdMethodDef m_methodDef;
};

class ILCodeVersionIterator : public Enumerator<const ILCodeVersion, ILCodeVersionIterator>
{
    friend class Enumerator<const ILCodeVersion, ILCodeVersionIterator>;

public:
    ILCodeVersionIterator();
    ILCodeVersionIterator(const ILCodeVersionIterator & iter);
    ILCodeVersionIterator(ILCodeVersionCollection* pCollection);
    CHECK Check() const { CHECK_OK; }

protected:
    const ILCodeVersion & Get() const;
    void First();
    void Next();
    bool Equal(const ILCodeVersionIterator &i) const;

    CHECK DoCheck() const { CHECK_OK; }

private:
    enum IterationStage
    {
        Initial,
        ImplicitCodeVersion,
        LinkedList,
        End
    };
    IterationStage m_stage;
    ILCodeVersion m_cur;
    PTR_ILCodeVersionNode m_pLinkedListCur;
    ILCodeVersionCollection* m_pCollection;
};

class MethodDescVersioningState
{
public:
    // The size of the code used to jump stamp the prolog
#ifdef FEATURE_JUMPSTAMP
    static const size_t JumpStubSize =
#if defined(_X86_) || defined(_AMD64_)
        5;
#else
#error "Need to define size of jump-stamp for this platform"
#endif
#endif // FEATURE_JUMPSTAMP

    MethodDescVersioningState(PTR_MethodDesc pMethodDesc);
    PTR_MethodDesc GetMethodDesc() const;
    NativeCodeVersionId AllocateVersionId();
    PTR_NativeCodeVersionNode GetFirstVersionNode() const;

#ifndef DACCESS_COMPILE
#ifdef FEATURE_JUMPSTAMP
    HRESULT SyncJumpStamp(NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
    HRESULT UpdateJumpTarget(BOOL fEESuspended, PCODE pRejittedCode);
    HRESULT UndoJumpStampNativeCode(BOOL fEESuspended);
    HRESULT JumpStampNativeCode(PCODE pCode = NULL);
#endif // FEATURE_JUMPSTAMP
    void LinkNativeCodeVersionNode(NativeCodeVersionNode* pNativeCodeVersionNode);
#endif // DACCESS_COMPILE

#ifdef FEATURE_JUMPSTAMP
    enum JumpStampFlags
    {
        // There is no jump stamp in place on this method (Either because
        // there is no code at all, or there is code that hasn't been
        // overwritten with a jump)
        JumpStampNone = 0x0,

        // The method code has the jump stamp written in, and it points to the Prestub
        JumpStampToPrestub = 0x1,

        // The method code has the jump stamp written in, and it points to the currently
        // active code version
        JumpStampToActiveVersion = 0x2,
    };

    JumpStampFlags GetJumpStampState();
    void SetJumpStampState(JumpStampFlags newState);
#endif // FEATURE_JUMPSTAMP

    //read-write data for the default native code version
    BOOL IsDefaultVersionActiveChild() const;
#ifndef DACCESS_COMPILE
    void SetDefaultVersionActiveChildFlag(BOOL isActive);
#endif

private:
#if !defined(DACCESS_COMPILE) && defined(FEATURE_JUMPSTAMP)
    INDEBUG(BOOL CodeIsSaved();)
    HRESULT UpdateJumpStampHelper(BYTE* pbCode, INT64 i64OldValue, INT64 i64NewValue, BOOL fContentionPossible);
#endif
    PTR_MethodDesc m_pMethodDesc;

    enum MethodDescVersioningStateFlags
    {
        JumpStampMask = 0x3,
        IsDefaultVersionActiveChildFlag = 0x4
    };
    BYTE m_flags;
    NativeCodeVersionId m_nextId;
    PTR_NativeCodeVersionNode m_pFirstVersionNode;


    // The originally JITted code that was overwritten with the jmp stamp.
#ifdef FEATURE_JUMPSTAMP
    BYTE m_rgSavedCode[JumpStubSize];
#endif
};

class MethodDescVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_MethodDescVersioningState>>
{
public:
    typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::element_t element_t;
    typedef typename DefaultSHashTraits<PTR_MethodDescVersioningState>::count_t count_t;

    typedef const PTR_MethodDesc key_t;

    static key_t GetKey(element_t e)
    {
        LIMITED_METHOD_CONTRACT;
        return e->GetMethodDesc();
    }
    static BOOL Equals(key_t k1, key_t k2)
    {
        LIMITED_METHOD_CONTRACT;
        return k1 == k2;
    }
    static count_t Hash(key_t k)
    {
        LIMITED_METHOD_CONTRACT;
        return (count_t)(size_t)dac_cast<TADDR>(k);
    }

    static element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_MethodDescVersioningState>(nullptr); }
    static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
};

typedef SHash<MethodDescVersioningStateHashTraits> MethodDescVersioningStateHash;

class ILCodeVersioningState
{
public:
    ILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef);
    ILCodeVersion GetActiveVersion() const;
    PTR_ILCodeVersionNode GetFirstVersionNode() const;
#ifndef DACCESS_COMPILE
    void SetActiveVersion(ILCodeVersion ilActiveCodeVersion);
    void LinkILCodeVersionNode(ILCodeVersionNode* pILCodeVersionNode);
#endif

    struct Key
    {
    public:
        Key();
        Key(PTR_Module pModule, mdMethodDef methodDef);
        size_t Hash() const;
        bool operator==(const Key & rhs) const;
    private:
        PTR_Module m_pModule;
        mdMethodDef m_methodDef;
    };

    Key GetKey() const;

private:
    ILCodeVersion m_activeVersion;
    PTR_ILCodeVersionNode m_pFirstVersionNode;
    PTR_Module m_pModule;
    mdMethodDef m_methodDef;
};

class ILCodeVersioningStateHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<PTR_ILCodeVersioningState>>
{
public:
    typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::element_t element_t;
    typedef typename DefaultSHashTraits<PTR_ILCodeVersioningState>::count_t count_t;

    typedef const ILCodeVersioningState::Key key_t;

    static key_t GetKey(element_t e)
    {
        LIMITED_METHOD_CONTRACT;
        return e->GetKey();
    }
    static BOOL Equals(key_t k1, key_t k2)
    {
        LIMITED_METHOD_CONTRACT;
        return k1 == k2;
    }
    static count_t Hash(key_t k)
    {
        LIMITED_METHOD_CONTRACT;
        return (count_t)k.Hash();
    }

    static element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_ILCodeVersioningState>(nullptr); }
    static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
};

typedef SHash<ILCodeVersioningStateHashTraits> ILCodeVersioningStateHash;

class CodeVersionManager
{
    friend class ILCodeVersion;
    friend class PublishMethodHolder;
    friend class PublishMethodTableHolder;

public:
    CodeVersionManager();

    void PreInit();

    class TableLockHolder : public CrstHolder
    {
    public:
        TableLockHolder(CodeVersionManager * pCodeVersionManager);
    };
    //Using the holder is preferable, but in some cases the holder can't be used
#ifndef DACCESS_COMPILE
    void EnterLock();
    void LeaveLock();
#endif

#ifdef DEBUG
    BOOL LockOwnedByCurrentThread() const;
#endif

    DWORD GetNonDefaultILVersionCount();
    ILCodeVersionCollection GetILCodeVersions(PTR_MethodDesc pMethod);
    ILCodeVersionCollection GetILCodeVersions(PTR_Module pModule, mdMethodDef methodDef);
    ILCodeVersion GetActiveILCodeVersion(PTR_MethodDesc pMethod);
    ILCodeVersion GetActiveILCodeVersion(PTR_Module pModule, mdMethodDef methodDef);
    ILCodeVersion GetILCodeVersion(PTR_MethodDesc pMethod, ReJITID rejitId);
    NativeCodeVersionCollection GetNativeCodeVersions(PTR_MethodDesc pMethod) const;
    NativeCodeVersion GetNativeCodeVersion(PTR_MethodDesc pMethod, PCODE codeStartAddress) const;
    PTR_ILCodeVersioningState GetILCodeVersioningState(PTR_Module pModule, mdMethodDef methodDef) const;
    PTR_MethodDescVersioningState GetMethodDescVersioningState(PTR_MethodDesc pMethod) const;

#ifndef DACCESS_COMPILE
    struct CodePublishError
    {
        Module* pModule;
        mdMethodDef methodDef;
        MethodDesc* pMethodDesc;
        HRESULT hrStatus;
    };

    HRESULT AddILCodeVersion(Module* pModule, mdMethodDef methodDef, ReJITID rejitId, ILCodeVersion* pILCodeVersion);
    HRESULT AddNativeCodeVersion(ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion);
    HRESULT DoJumpStampIfNecessary(MethodDesc* pMD, PCODE pCode);
    PCODE PublishVersionableCodeIfNecessary(MethodDesc* pMethodDesc, BOOL fCanBackpatchPrestub);
    HRESULT PublishNativeCodeVersion(MethodDesc* pMethodDesc, NativeCodeVersion nativeCodeVersion, BOOL fEESuspended);
    HRESULT GetOrCreateMethodDescVersioningState(MethodDesc* pMethod, MethodDescVersioningState** ppMethodDescVersioningState);
    HRESULT GetOrCreateILCodeVersioningState(Module* pModule, mdMethodDef methodDef, ILCodeVersioningState** ppILCodeVersioningState);
    HRESULT SetActiveILCodeVersions(ILCodeVersion* pActiveVersions, DWORD cActiveVersions, BOOL fEESuspended, CDynArray<CodePublishError> * pPublishErrors);
    static HRESULT AddCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
    static HRESULT AddCodePublishError(NativeCodeVersion nativeCodeVersion, HRESULT hrStatus, CDynArray<CodePublishError> * pErrors);
    static void OnAppDomainExit(AppDomain* pAppDomain);
#endif

    static bool IsMethodSupported(PTR_MethodDesc pMethodDesc);

private:

#ifndef DACCESS_COMPILE
    static HRESULT EnumerateClosedMethodDescs(MethodDesc* pMD, CDynArray<MethodDesc*> * pClosedMethodDescs, CDynArray<CodePublishError> * pUnsupportedMethodErrors);
    static HRESULT EnumerateDomainClosedMethodDescs(
        AppDomain * pAppDomainToSearch,
        Module* pModuleContainingMethodDef,
        mdMethodDef methodDef,
        CDynArray<MethodDesc*> * pClosedMethodDescs,
        CDynArray<CodePublishError> * pUnsupportedMethodErrors);
    static HRESULT GetNonVersionableError(MethodDesc* pMD);
    void ReportCodePublishError(CodePublishError* pErrorRecord);
    void ReportCodePublishError(Module* pModule, mdMethodDef methodDef, MethodDesc* pMD, HRESULT hrStatus);
#endif

    //Module,MethodDef -> ILCodeVersioningState
    ILCodeVersioningStateHash m_ilCodeVersioningStateMap;

    //closed MethodDesc -> MethodDescVersioningState
    MethodDescVersioningStateHash m_methodDescVersioningStateMap;

    CrstExplicitInit m_crstTable;
};

#endif // FEATURE_CODE_VERSIONING

//
// These holders are used by runtime code that is making new code
// available for execution, either by publishing jitted code
// or restoring NGEN code. It ensures the publishing is synchronized
// with rejit requests
//
class PublishMethodHolder
{
public:
#if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
    PublishMethodHolder(MethodDesc* pMethod, PCODE pCode) { }
#else
    PublishMethodHolder(MethodDesc* pMethod, PCODE pCode);
    ~PublishMethodHolder();
#endif

private:
#if defined(FEATURE_CODE_VERSIONING)
    MethodDesc * m_pMD;
    HRESULT m_hr;
#endif
};

class PublishMethodTableHolder
{
public:
#if !defined(FEATURE_CODE_VERSIONING) || defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
    PublishMethodTableHolder(MethodTable* pMethodTable) { }
#else
    PublishMethodTableHolder(MethodTable* pMethodTable);
    ~PublishMethodTableHolder();
#endif

private:
#if defined(FEATURE_CODE_VERSIONING) && !defined(DACCESS_COMPILE)
    MethodTable* m_pMethodTable;
    CDynArray<CodeVersionManager::CodePublishError> m_errors;
#endif
};

#endif // CODE_VERSION_H