summaryrefslogtreecommitdiff
path: root/src/vm/compile.h
blob: 5b932d5e070b7d6cd0cb17785e1b1730f0963119 (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
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
// 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: compile.h
//
// Interfaces and support for zap compiler and zap files
// 

// ===========================================================================


/*

The preloader is used to serialize internal EE data structures in the
zapped image.  The object model looks like the following:

                    +--------------------+
                    |                    |
                    |    ZapperModule    |
                    |                    |
                    +--------------------+
                              |
                              *    
                     ICorCompileDataStore           Zapper
                    
           =====================================================      
                    
                     ICorCompilePreloader           EE
                              * 
                              | 
                    +--------------------+
                    |                    |
                    |    CEEPreloader    |
                    |                    |
                    +--------------------+                    
                              |
                              *    
                     DataImage::IDataStore                    
                    
                                                 
                    +--------------------+
                    |                    |
                    |     DataImage      |
                    |                    |
                    +--------------------+
                    
ZapperModule - Created by the zapper for each module.  It implements the
               ICorCompileDataStore interface that the preloader uses to
               allocate space for the EE data structures.  Currently it
               allocates space in a single PE section (though the DataImage
               has logic to further subdivide the space into subsections).
  
CEEPreloader - Created by ZapperModule in order to serialize EE
               data structures.  It implements two interfaces.  
               ICorCompilePreloader is used by ZapperModule to inquire
               about the offsets of various EE data structures inside
               the preloader section.  DataImage::IDataStore is used
               by DataImage to manage the PE section memory, and the
               implementation in the CEEPreloader mostly forwards the calls
               to the zapper (ICorCompileDataStore).

DataImage    - Created by CEEPreloader to keep track of memory used by
               EE data structures.  Even though it uses only one PE
               section, it allows the EE to allocate memory in multiple
               subsections.  This is accomplished by splitting the work into
               three phases (there are comments in dataimage.h that explain
               this in detail).
               

The CEEPreloader is created when ZapperModule::Preload calls
m_zapper->m_pEECompileInfo->PreloadModule.  PreloadModule creates
the CEEPreloader and then calls its Preload method, which explicitely
loads all the EE objects into memory (Module::ExpandAll), and then
allocates space for them in the preloader section (Module::Save).

Each EE data structure that needs to be serialized implements a Save
method.  A Save method is required to:
1) Store all of its data (including strings and other buffers that it
   uses) in the preloader section.  This is accomplished by calling on
   one of the DataImage storage methods (such as DataImage::StoreStructure).
2) Call the Save method on the objects that it owns.  The interesting
   part of the hierarchy looks like:
   
   Module::Save
     MethodTable::Save (in profile order)
       EEClass::Save
         MethodDescChunk::Save (method desc chunks can be split into hot 
                                and cold based on profile info)
           MethodDesc::Save
           
Note that while the architecture requires the data structures in the
preloader sections to look like their EE counterparts, it is possible
to work around that limitation by constructing multiple submappings of
these data structures.  Sometimes the submappings require a change to the actual
data (i.e. each method desc has information that tells you how far it is
from the MethodDescChunk, and that needs to change when reordering method
descs).  In such cases you create new copies of that memory and construct
a regular copying map for each of the new updated copies (DataImage::StoreStructure),
and a pointer update map for each of the original EE data structures 
(DataImage::StoreStructureUsingSurrogate).  See MethodDescChunk::Save for
an example on how to do this.

Fixups:  once everything has been layout out in memory, the ZapperModule
calls CEEPreloader::Link to generate fixups for the data.  CEEPreloader::Link
calls Module::Fixup, which results in a data structure walk very similar to
that of Module::Save.  Each data structure calls one of the FixupPointerField
methods on the DataImage, which in turn forwards the call to
CEEPreloader::AddFixup, which forwards it to the zapper 
(ZapperModule::AddFixup).
   
*/

#ifndef COMPILE_H_
#define COMPILE_H_

#ifdef FEATURE_NATIVE_IMAGE_GENERATION

struct ZapperLoaderModuleTableKey {
    ZapperLoaderModuleTableKey(Module *pDefinitionModule, 
        mdToken token, 
        Instantiation classInst,
        Instantiation methodInst)
        : m_inst(classInst, methodInst)
    { WRAPPER_NO_CONTRACT;
      this->m_pDefinitionModule = pDefinitionModule;
      this->m_token = token;  }
    
    Module *m_pDefinitionModule;
    mdToken m_token;
    SigTypeContext m_inst;
} ;

struct ZapperLoaderModuleTableEntry {
    ZapperLoaderModuleTableEntry(): key(0,0,Instantiation(),Instantiation()) { WRAPPER_NO_CONTRACT; this->result = 0; }
    ZapperLoaderModuleTableEntry(const ZapperLoaderModuleTableKey &_key,Module *_result) 
        : key(_key)
    { this->result = _result; }
    
    ZapperLoaderModuleTableKey key;
    Module *result;
} ;

class ZapperLoaderModuleTableTraits : public NoRemoveSHashTraits<DefaultSHashTraits<ZapperLoaderModuleTableEntry> >
{
    
public:
    typedef const ZapperLoaderModuleTableKey *key_t;
    static const ZapperLoaderModuleTableKey * GetKey(const ZapperLoaderModuleTableEntry &e) { return &e.key; }
    static count_t Hash(const ZapperLoaderModuleTableKey * k) 
    { 
        LIMITED_METHOD_CONTRACT;
        
        DWORD dwHash = 5381;
        
        dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)k->m_pDefinitionModule;
        dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)k->m_token;
        dwHash = ((dwHash << 5) + dwHash) ^ EEInstantiationHashTableHelper:: Hash(&k->m_inst);
        return dwHash;
    }
    
    static BOOL Equals(const ZapperLoaderModuleTableKey *e1, const ZapperLoaderModuleTableKey *e2)
    {
        WRAPPER_NO_CONTRACT;
        return e1->m_pDefinitionModule == e2->m_pDefinitionModule && 
            e1->m_token == e2->m_token && 
            SigTypeContext::Equal(&e1->m_inst, &e2->m_inst);
    }
    static const ZapperLoaderModuleTableEntry Null() 
    { return ZapperLoaderModuleTableEntry(); }
    
    static bool IsNull(const ZapperLoaderModuleTableEntry &e) 
    { LIMITED_METHOD_CONTRACT; return e.key.m_pDefinitionModule == 0 && e.key.m_token == 0 && e.key.m_inst.IsEmpty(); }
    
};


typedef  SHash<ZapperLoaderModuleTableTraits> ZapperLoaderModuleTable;

class CEECompileInfo : public ICorCompileInfo
{
  public:
    virtual ~CEECompileInfo()
    {
        WRAPPER_NO_CONTRACT;
    }
    
    HRESULT Startup(     BOOL                     fForceDebug, 
                         BOOL                     fForceProfiling,
                         BOOL                     fForceInstrument);

    HRESULT CreateDomain(ICorCompilationDomain **ppDomain,
                         IMetaDataAssemblyEmit    *pEmitter,
                         BOOL                     fForceDebug,
                         BOOL                     fForceProfiling,
                         BOOL                     fForceInstrument,
                         BOOL                     fForceFulltrustDomain);

    HRESULT MakeCrossDomainCallback(
                                    ICorCompilationDomain*  pDomain,
                                    CROSS_DOMAIN_CALLBACK   pfnCallback,
                                    LPVOID                  pArgs);
   
    HRESULT DestroyDomain(ICorCompilationDomain   *pDomain);

    HRESULT LoadAssemblyByPath(LPCWSTR                  wzPath,
                               BOOL                     fExplicitBindToNativeImage,
                               CORINFO_ASSEMBLY_HANDLE *pHandle);


#ifdef FEATURE_COMINTEROP
    HRESULT LoadTypeRefWinRT(IMDInternalImport       *pAssemblyImport,
                                     mdTypeRef               ref,
                                     CORINFO_ASSEMBLY_HANDLE *pHandle);
#endif

    BOOL IsInCurrentVersionBubble(CORINFO_MODULE_HANDLE hModule);

    HRESULT LoadAssemblyModule(CORINFO_ASSEMBLY_HANDLE assembly,
                               mdFile                  file,
                               CORINFO_MODULE_HANDLE   *pHandle);


    BOOL CheckAssemblyZap(
        CORINFO_ASSEMBLY_HANDLE assembly, 
      __out_ecount_opt(*cAssemblyManifestModulePath) 
        LPWSTR                  assemblyManifestModulePath, 
        LPDWORD                 cAssemblyManifestModulePath);

    HRESULT SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE     assembly,
                                 CORINFO_MODULE_HANDLE       module);

    IMDInternalImport * GetAssemblyMetaDataImport(CORINFO_ASSEMBLY_HANDLE scope);

    IMDInternalImport * GetModuleMetaDataImport(CORINFO_MODULE_HANDLE scope);

    CORINFO_MODULE_HANDLE GetAssemblyModule(CORINFO_ASSEMBLY_HANDLE module);

    CORINFO_ASSEMBLY_HANDLE GetModuleAssembly(CORINFO_MODULE_HANDLE module);

    PEDecoder * GetModuleDecoder(CORINFO_MODULE_HANDLE scope);

    void GetModuleFileName(CORINFO_MODULE_HANDLE module,
                           SString               &result);

    void EncodeModuleAsIndexes( CORINFO_MODULE_HANDLE   fromHandle,
                                CORINFO_MODULE_HANDLE   handle,
                                DWORD                   *pAssemblyIndex,
                                DWORD                   *pModuleIndex,
                                IMetaDataAssemblyEmit   *pAssemblyEmit); 

    void EncodeClass(  CORINFO_MODULE_HANDLE   referencingModule,
                       CORINFO_CLASS_HANDLE    classHandle,
                       SigBuilder              *pSigBuilder,
                       LPVOID                  encodeContext,
                       ENCODEMODULE_CALLBACK   pfnEncodeModule);

    void EncodeMethod( CORINFO_MODULE_HANDLE   referencingModule,
                       CORINFO_METHOD_HANDLE   methHnd,
                       SigBuilder              *pSigBuilder,
                       LPVOID                  encodeContext,
                       ENCODEMODULE_CALLBACK   pfnEncodeModule,
                       CORINFO_RESOLVED_TOKEN  *pResolvedToken,
                       CORINFO_RESOLVED_TOKEN  *pConstrainedResolvedToken,
                       BOOL                    fEncodeUsingResolvedTokenSpecStreams);

    virtual mdToken TryEncodeMethodAsToken(CORINFO_METHOD_HANDLE handle, 
                                           CORINFO_RESOLVED_TOKEN * pResolvedToken,
                                           CORINFO_MODULE_HANDLE * referencingModule);

    virtual DWORD TryEncodeMethodSlot(CORINFO_METHOD_HANDLE handle);

    void EncodeField(  CORINFO_MODULE_HANDLE   referencingModule,
                       CORINFO_FIELD_HANDLE    handle,
                       SigBuilder              *pSigBuilder,
                       LPVOID                  encodeContext,
                       ENCODEMODULE_CALLBACK   pfnEncodeModule,
                       CORINFO_RESOLVED_TOKEN  *pResolvedToken,
                       BOOL                    fEncodeUsingResolvedTokenSpecStreams);

    // Encode generic dictionary signature
    virtual void EncodeGenericSignature(
            LPVOID signature,
            BOOL fMethod,
            SigBuilder * pSigBuilder,
            LPVOID encodeContext,
            ENCODEMODULE_CALLBACK pfnEncodeModule);


    BOOL IsEmptyString(mdString token,
                       CORINFO_MODULE_HANDLE module);

    BOOL IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle);

    BOOL IsCachingOfInliningHintsEnabled()
    {
        return m_fCachingOfInliningHintsEnabled;
    }

    void DisableCachingOfInliningHints()
    {
        m_fCachingOfInliningHintsEnabled = FALSE;
    }

    HRESULT GetTypeDef(   CORINFO_CLASS_HANDLE    classHandle,
                          mdTypeDef               *token);
    HRESULT GetMethodDef( CORINFO_METHOD_HANDLE   methodHandle,
                          mdMethodDef             *token);
    HRESULT GetFieldDef(  CORINFO_FIELD_HANDLE    fieldHandle,
                          mdFieldDef              *token);

    void SetAssemblyHardBindList(__in_ecount( cHardBindList )
                                 LPWSTR *pHardBindList,
                                 DWORD cHardBindList);

    CORINFO_MODULE_HANDLE GetLoaderModuleForMscorlib();
    CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableType(CORINFO_CLASS_HANDLE classHandle);
    CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableMethod(CORINFO_METHOD_HANDLE methodHandle);
    CORINFO_MODULE_HANDLE GetLoaderModuleForEmbeddableField(CORINFO_FIELD_HANDLE fieldHandle);

    ICorCompilePreloader * PreloadModule(CORINFO_MODULE_HANDLE   moduleHandle,
                                    ICorCompileDataStore    *pData,
                                    CorProfileData          *profileData);

    
    HRESULT GetLoadHint(CORINFO_ASSEMBLY_HANDLE   hAssembly,
                        CORINFO_ASSEMBLY_HANDLE hAssemblyDependency,
                        LoadHintEnum           *loadHint,
                        LoadHintEnum           *defaultLoadHint);

    HRESULT GetAssemblyVersionInfo(CORINFO_ASSEMBLY_HANDLE Handle, 
                                    CORCOMPILE_VERSION_INFO *pInfo);

    void GetAssemblyCodeBase(CORINFO_ASSEMBLY_HANDLE hAssembly,
                             SString                &result);

    void GetCallRefMap(CORINFO_METHOD_HANDLE hMethod, 
                       GCRefMapBuilder * pBuilder);

    void CompressDebugInfo(
                                    IN ICorDebugInfo::OffsetMapping * pOffsetMapping,
                                    IN ULONG            iOffsetMapping,
                                    IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo,
                                    IN ULONG            iNativeVarInfo,
                                    IN OUT SBuffer    * pDebugInfoBuffer);

    HRESULT SetVerboseLevel(
                                    IN  VerboseLevel        level);

    HRESULT GetBaseJitFlags(
            IN  CORINFO_METHOD_HANDLE    hMethod,
            OUT CORJIT_FLAGS            *pFlags);

#ifdef _WIN64
    SIZE_T  getPersonalityValue();
#endif

    void* GetStubSize(void *pStubAddress, DWORD *pSizeToCopy);

    HRESULT GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize);

    BOOL GetIsGeneratingNgenPDB();
    void SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB);

#ifdef FEATURE_READYTORUN_COMPILER
    CORCOMPILE_FIXUP_BLOB_KIND GetFieldBaseOffset(
            CORINFO_CLASS_HANDLE classHnd, 
            DWORD * pBaseOffset);

    BOOL NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd);
    void EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder);

    BOOL AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle);

    int GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token);

    int GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle);
#endif

    BOOL HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName);

    //--------------------------------------------------------------------
    // ZapperLoaderModules and the ZapperLoaderModuleTable
    //
    // When NGEN'ing we want to adjust the
    // places where some items (i.e. generic instantiations) are placed, in order to get some of them
    // placed into the module we are compiling.  However, the
    // results of ComputeLoaderModule must be stable for the duration
    // of an entire instance of the VM, i.e. for the duration of a compilation 
    // process.  Thus each time we place an item into a non-standard LoaderModule we record 
    // that fact.

    Module *LookupZapperLoaderModule(const ZapperLoaderModuleTableKey *pKey)
    {
        WRAPPER_NO_CONTRACT;
        const ZapperLoaderModuleTableEntry *pEntry = m_ZapperLoaderModuleTable.LookupPtr(pKey);
        if (pEntry)
            return pEntry->result;
        return NULL;
    }

    void RecordZapperLoaderModule(const ZapperLoaderModuleTableKey *pKey,
                                  Module *pZapperLoaderModuleTable)
    {
        CONTRACTL
        {
            THROWS;
            GC_NOTRIGGER;
            SO_TOLERANT;
            MODE_ANY;
        }
        CONTRACTL_END;
        ZapperLoaderModuleTableEntry entry(*pKey, pZapperLoaderModuleTable);
        m_ZapperLoaderModuleTable.Add(entry);
    }

    ZapperLoaderModuleTable m_ZapperLoaderModuleTable;
    
private:
    BOOL m_fCachingOfInliningHintsEnabled;
    BOOL m_fGeneratingNgenPDB;
};

extern CEECompileInfo *g_pCEECompileInfo;

BOOL IsNgenPDBCompilationProcess();

//
// See comment at top of file for an explanation on the preloader
// architecture.
//

class CEEPreloader : public ICorCompilePreloader
{
  private:
    DataImage              *m_image;
    ICorCompileDataStore   *m_pData;

    class MethodSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodDesc *> >
    {
    public:
        typedef MethodDesc *key_t;
        static MethodDesc * GetKey(MethodDesc *md) { return md; }
        static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; }
        static BOOL Equals(MethodDesc *md1, MethodDesc *md2)
        {
            return md1 == md2;
        }
    };

    class TypeSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<TypeHandle> >
    {
    public:
        typedef TypeHandle key_t;
        static const TypeHandle Null() { return TypeHandle(); }
        static bool IsNull(const TypeHandle &th) { return !!th.IsNull(); }
        static TypeHandle GetKey(TypeHandle th) { return th; }
        static count_t Hash(TypeHandle th) { return (count_t) th.AsTAddr(); }
        static BOOL Equals(TypeHandle th1, TypeHandle th2) { return th1 == th2; }
    };

    // Cached results of instantiations triage
    SHash<TypeSetTraits>    m_acceptedTypes;
    SHash<MethodSetTraits>  m_acceptedMethods;
    SHash<TypeSetTraits>    m_rejectedTypes;
    SHash<MethodSetTraits>  m_rejectedMethods;

#ifdef FEATURE_FULL_NGEN
    // Tentatively accepted instantiations
    InlineSArray<TypeHandle, 20>    m_speculativeTypes;
    BOOL                            m_fSpeculativeTriage;
    BOOL                            m_fDictionariesPopulated;
#endif

    struct CompileMethodEntry
    {
        MethodDesc * pMD;
#ifndef FEATURE_FULL_NGEN // Unreferenced methods
        bool fReferenced; // true when this method was referenced by other code
        bool fScheduled;  // true when this method was scheduled for compilation
#endif
    };

    class CompileMethodSetTraits : public NoRemoveSHashTraits< DefaultSHashTraits<CompileMethodEntry> >
    {
    public:
        typedef MethodDesc *key_t;
        static MethodDesc * GetKey(CompileMethodEntry e) { return e.pMD; }
        static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; }
        static BOOL Equals(MethodDesc *md1, MethodDesc *md2)
        {
            return md1 == md2;
        }
        static const CompileMethodEntry Null() { CompileMethodEntry e; e.pMD = NULL; return e; }
        static bool IsNull(const CompileMethodEntry &e) { return e.pMD == NULL; }
    };

    SHash<CompileMethodSetTraits> m_compileMethodsHash;

    // Array of methods that we need to compile.
    SArray<MethodDesc*> m_uncompiledMethods;

    int m_methodCompileLimit;

    void AppendUncompiledMethod(MethodDesc *pMD)
    {
        STANDARD_VM_CONTRACT;
        if (m_methodCompileLimit > 0)
        {
            m_uncompiledMethods.Append(pMD);
            m_methodCompileLimit--;
        }
    }

    struct DuplicateMethodEntry
    {
        MethodDesc * pMD;
        MethodDesc * pDuplicateMD;
    };

    class DuplicateMethodTraits : public NoRemoveSHashTraits< DefaultSHashTraits<DuplicateMethodEntry> >
    {
    public:
        typedef MethodDesc *key_t;
        static MethodDesc * GetKey(DuplicateMethodEntry e) { return e.pMD; }
        static count_t Hash(MethodDesc *md) { return (count_t) (UINT_PTR) md; }
        static BOOL Equals(MethodDesc *md1, MethodDesc *md2)
        {
            return md1 == md2;
        }
        static const DuplicateMethodEntry Null() { DuplicateMethodEntry e; e.pMD = NULL; return e; }
        static bool IsNull(const DuplicateMethodEntry &e) { return e.pMD == NULL; }
    };

    SHash<DuplicateMethodTraits> m_duplicateMethodsHash;

    MethodDesc * CompileMethodStubIfNeeded(
            MethodDesc *pMD,
            MethodDesc *pStubMD,
            ICorCompilePreloader::CORCOMPILE_CompileStubCallback pfnCallback,
            LPVOID pCallbackContext);

  public:
    CEEPreloader(Module *pModule,
                 ICorCompileDataStore *pData);
    virtual ~CEEPreloader();

    void Preload(CorProfileData * profileData);
    DataImage * GetDataImage() { LIMITED_METHOD_CONTRACT; return m_image; }
    ICorCompileDataStore * GetDataStore() { LIMITED_METHOD_CONTRACT; return m_pData; }

    //
    // ICorCompilerPreloader
    //

    DWORD MapMethodEntryPoint(CORINFO_METHOD_HANDLE handle);
    DWORD MapClassHandle(CORINFO_CLASS_HANDLE handle);
    DWORD MapMethodHandle(CORINFO_METHOD_HANDLE handle);
    DWORD MapFieldHandle(CORINFO_FIELD_HANDLE handle);
    DWORD MapAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE handle);
    DWORD MapGenericHandle(CORINFO_GENERIC_HANDLE handle);    
    DWORD MapModuleIDHandle(CORINFO_MODULE_HANDLE handle);

    void AddMethodToTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle);
    void AddTypeToTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle);
    BOOL IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle);
    BOOL IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle);

    void MethodReferencedByCompiledCode(CORINFO_METHOD_HANDLE handle);

    BOOL IsUncompiledMethod(CORINFO_METHOD_HANDLE handle);

private:
    void AddToUncompiledMethods(MethodDesc *pMethod, BOOL fForStubs);

    void ApplyTypeDependencyProductionsForType(TypeHandle t);
    void ApplyTypeDependencyForSZArrayHelper(MethodTable * pInterfaceMT, TypeHandle elemTypeHnd);

    friend class Module;
    void TriageTypeForZap(TypeHandle th, BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE);
    void TriageMethodForZap(MethodDesc* pMethod, BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE);

    void ExpandTypeDependencies(TypeHandle th);
    void ExpandMethodDependencies(MethodDesc * pMD);

    void TriageTypeSpecsFromSoftBoundModule(Module * pSoftBoundModule);
    void TriageTypeFromSoftBoundModule(TypeHandle th, Module * pSoftBoundModule);
    void TriageSpeculativeType(TypeHandle th);
    void TriageSpeculativeInstantiations();

    // Returns TRUE if new types or methods have been added by the triage
    BOOL TriageForZap(BOOL fAcceptIfNotSure, BOOL fExpandDependencies = TRUE);

public:
    CORINFO_METHOD_HANDLE NextUncompiledMethod();

    void PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod);

    void GenerateMethodStubs(
            CORINFO_METHOD_HANDLE hMethod,
            bool                  fNgenProfileImage,
            CORCOMPILE_CompileStubCallback pfnCallback,
            LPVOID                pCallbackContext);

    bool IsDynamicMethod(CORINFO_METHOD_HANDLE hMethod);
    void SetMethodProfilingFlags(CORINFO_METHOD_HANDLE hMethod, DWORD flags);

    bool CanSkipMethodPreparation (
            CORINFO_METHOD_HANDLE   callerHnd,      /* IN  */
            CORINFO_METHOD_HANDLE   calleeHnd,      /* IN  */
            CorInfoIndirectCallReason *pReason = NULL,
            CORINFO_ACCESS_FLAGS    accessFlags = CORINFO_ACCESS_ANY);

    BOOL CanEmbedClassID     (CORINFO_CLASS_HANDLE    typeHandle);
    BOOL CanEmbedModuleID    (CORINFO_MODULE_HANDLE   moduleHandle);    
    BOOL CanEmbedModuleHandle(CORINFO_MODULE_HANDLE   moduleHandle);
    BOOL CanEmbedClassHandle (CORINFO_CLASS_HANDLE    typeHandle);
    BOOL CanEmbedMethodHandle(CORINFO_METHOD_HANDLE   methodHandle, 
                              CORINFO_METHOD_HANDLE   contextHandle);
    BOOL CanEmbedFieldHandle (CORINFO_FIELD_HANDLE    fieldHandle);

    BOOL CanPrerestoreEmbedClassHandle (CORINFO_CLASS_HANDLE  classHnd);
    BOOL CanPrerestoreEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHnd);

    BOOL CanEmbedFunctionEntryPoint(CORINFO_METHOD_HANDLE   methodHandle,
                                    CORINFO_METHOD_HANDLE   contextHandle,
                                    CORINFO_ACCESS_FLAGS    accessFlags = CORINFO_ACCESS_ANY);

    BOOL DoesMethodNeedRestoringBeforePrestubIsRun(CORINFO_METHOD_HANDLE   methodHandle);

    BOOL CanSkipDependencyActivation(CORINFO_METHOD_HANDLE   context,
                                     CORINFO_MODULE_HANDLE   moduleFrom,
                                     CORINFO_MODULE_HANDLE   moduleTo);

    CORINFO_MODULE_HANDLE GetPreferredZapModuleForClassHandle(CORINFO_CLASS_HANDLE classHnd);

    void NoteDeduplicatedCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod);

    CORINFO_METHOD_HANDLE LookupMethodDef(mdMethodDef token);
    bool GetMethodInfo(mdMethodDef token, CORINFO_METHOD_HANDLE ftnHnd, CORINFO_METHOD_INFO * methInfo);

    CorCompileILRegion GetILRegion(mdMethodDef token);

    CORINFO_METHOD_HANDLE FindMethodForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry);

    void ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee);
    
    void Link();
    void FixupRVAs();

    void SetRVAsForFields(IMetaDataEmit * pEmit);

    void GetRVAFieldData(mdFieldDef fd, PVOID * ppData, DWORD * pcbSize, DWORD * pcbAlignment);

    ULONG Release();

#ifdef FEATURE_READYTORUN_COMPILER
    void GetSerializedInlineTrackingMap(SBuffer* pBuffer);
#endif

    void Error(mdToken token, Exception * pException);
};


struct RefCache
{
    RefCache(Module *pModule)
    {
        CONTRACTL
        {
            NOTHROW;
            GC_NOTRIGGER;
            FORBID_FAULT;
        }
        CONTRACTL_END


        m_pModule = pModule;

        {
            // HashMap::Init can throw due to OOM. Our ctor can't. Since this whole
            // thing is for use inside CEECompileInfo methods, it doesn't make sense to
            // use an exception model. Thus we probably have to move the hashmap init
            // calls out of the ctor so can catch these exceptions and translate them to
            // hresults.
            // 
            CONTRACT_VIOLATION(ThrowsViolation|FaultViolation);

            m_sAssemblyRefMap.Init(FALSE,NULL);
        }
    }

    Module *m_pModule;

    HashMap m_sAssemblyRefMap;
};

struct AssemblySpecDefRefMapEntry {
    AssemblySpec * m_pDef;
    AssemblySpec * m_pRef;
};

class AssemblySpecDefRefMapTraits : public NoRemoveSHashTraits<DefaultSHashTraits<AssemblySpecDefRefMapEntry> >
{
public:
    typedef const AssemblySpec *key_t;
    static const AssemblySpec * GetKey(const AssemblySpecDefRefMapEntry &e) { return e.m_pDef; }

    static count_t Hash(const AssemblySpec * k)
    {
        return const_cast<AssemblySpec *>(k)->Hash();
    }

    static BOOL Equals(const AssemblySpec * lhs, const AssemblySpec * rhs)
    {
        return const_cast<AssemblySpec *>(lhs)->CompareEx(const_cast<AssemblySpec *>(rhs), AssemblySpec::ASC_DefinitionEquality);
    }

    static const AssemblySpecDefRefMapEntry Null() { AssemblySpecDefRefMapEntry e; e.m_pDef = NULL; return e; }
    static bool IsNull(const AssemblySpecDefRefMapEntry &e) { return e.m_pDef == NULL; }

    void OnDestructPerEntryCleanupAction(const AssemblySpecDefRefMapEntry& e)
    {
        WRAPPER_NO_CONTRACT;
        delete e.m_pDef;
        delete e.m_pRef;
    }
    static const bool s_DestructPerEntryCleanupAction = true;
};

typedef SHash<AssemblySpecDefRefMapTraits> AssemblySpecMapDefRefMapTable;

class CompilationDomain : public AppDomain, 
                          public ICorCompilationDomain
{

 public:
    BOOL                    m_fForceDebug; 
    BOOL                    m_fForceProfiling;
    BOOL                    m_fForceInstrument;

    // TODO:  During ngen, we need to determine whether we can call NeedsRestore
    // before the preloader has been initialized.  This is accomplished via this
    // method.  This code needs to be cleaned up.  See bug #284709 for background.
    BOOL canCallNeedsRestore() { return  (m_pTargetImage != NULL); };

    // DDB 175659: Make sure that canCallNeedsRestore() returns FALSE during compilation 
    // domain shutdown.
    void setCannotCallNeedsRestore() { m_pTargetImage = NULL; }
    
  private:

    Assembly                *m_pTargetAssembly;     // Assembly being compiled
    Module                  *m_pTargetModule;       // Module currently being compiled. Needed for multi-module assemblies
    DataImage               *m_pTargetImage;        // Data image
    CEEPreloader            *m_pTargetPreloader;

    ReleaseHolder<IMetaDataAssemblyEmit>    m_pEmit;

    NewHolder<AssemblySpecHash>             m_pDependencyRefSpecs;

    AssemblySpecMapDefRefMapTable           m_dependencyDefRefMap;

    CORCOMPILE_DEPENDENCY   *m_pDependencies;
    USHORT                   m_cDependenciesCount, m_cDependenciesAlloc;

    CQuickArray<RefCache*> m_rRefCaches;

    HRESULT AddDependencyEntry(PEAssembly *pFile, mdAssemblyRef ref,mdAssemblyRef def);
    void ReleaseDependencyEmitter();


  public:

#ifndef DACCESS_COMPILE
    CompilationDomain(BOOL fForceDebug = FALSE, 
                      BOOL fForceProfiling = FALSE,
                      BOOL fForceInstrument = FALSE);
    ~CompilationDomain();
#endif

    void Init();

    HRESULT AddDependency(AssemblySpec *pRefSpec, PEAssembly *pFile);

    AssemblySpec* FindAssemblyRefSpecForDefSpec(
        AssemblySpec* pDefSpec);

    PEAssembly *BindAssemblySpec(
        AssemblySpec *pSpec,
        BOOL fThrowOnFileNotFound,
        BOOL fRaisePrebindEvents,
        StackCrawlMark *pCallerStackMark = NULL,
        BOOL fUseHostBinderIfAvailable = TRUE) DAC_EMPTY_RET(NULL);

    BOOL CanEagerBindToZapFile(Module *targetModule, BOOL limitToHardBindList = TRUE);



    // Returns NULL on out-of-memory
    RefCache *GetRefCache(Module *pModule)
    {
        CONTRACTL
        {
            NOTHROW;
            GC_NOTRIGGER;
            INJECT_FAULT(return NULL;);
        }
        CONTRACTL_END

        unsigned uSize = (unsigned) m_rRefCaches.Size();
        for (unsigned i = 0; i < uSize; i++)
            if (m_rRefCaches[i]->m_pModule == pModule)
                return m_rRefCaches[i];

        // Add a new cache entry
        HRESULT hr;
        
        if (FAILED(hr = m_rRefCaches.ReSizeNoThrow(uSize + 1)))
        {
            _ASSERTE(hr == E_OUTOFMEMORY);
            return NULL;
        }
        
        m_rRefCaches[uSize] = new (nothrow) RefCache(pModule);
        return m_rRefCaches[uSize];
    }

    void SetTarget(Assembly * pAssembly, Module *pModule);
    
    void SetTargetImage(DataImage * pImage, CEEPreloader * pPreloader);
    DataImage * GetTargetImage() { LIMITED_METHOD_CONTRACT; return m_pTargetImage; }

    Assembly * GetTargetAssembly()
        { LIMITED_METHOD_CONTRACT; return m_pTargetAssembly; }
    Module * GetTargetModule()
        { LIMITED_METHOD_CONTRACT; return m_pTargetModule; }

    // ICorCompilationDomain

    HRESULT SetContextInfo(LPCWSTR exePath, BOOL isExe) DAC_EMPTY_RET(E_FAIL);
    HRESULT GetDependencies(CORCOMPILE_DEPENDENCY **ppDependencies,
                            DWORD *cDependencies) DAC_EMPTY_RET(E_FAIL);

#ifdef CROSSGEN_COMPILE
    HRESULT SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths) DAC_EMPTY_RET(E_FAIL);
#endif

    void SetDependencyEmitter(IMetaDataAssemblyEmit *pEmitter);
};

#endif // FEATURE_NATIVE_IMAGE_GENERATION

#endif // COMPILE_H_