summaryrefslogtreecommitdiff
path: root/src/vm/dllimport.h
blob: bbff6fb09d2c502fab45729c5d81fcd1b23e805e (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
// 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: DllImport.h
//

#ifndef __dllimport_h__
#define __dllimport_h__

#include "util.hpp"

class ILStubHashBlob;
class NDirectStubParameters;
struct PInvokeStaticSigInfo;
class LoadLibErrorTracker;

// This structure groups together data that describe the signature for which a marshaling stub is being generated.
struct StubSigDesc
{
public:
    StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo = NULL);
    StubSigDesc(MethodDesc *pMD, Signature sig, Module *m_pModule);

    MethodDesc        *m_pMD;
    Signature          m_sig;
    Module            *m_pModule;
    Module            *m_pLoaderModule;
    mdMethodDef        m_tkMethodDef;
    SigTypeContext     m_typeContext;

#ifdef _DEBUG
    LPCUTF8            m_pDebugName;
    LPCUTF8            m_pDebugClassName;

    void InitDebugNames()
    {
        LIMITED_METHOD_CONTRACT;
    
        if (m_pMD != NULL)
        {
            m_pDebugName = m_pMD->m_pszDebugMethodName;
            m_pDebugClassName = m_pMD->m_pszDebugClassName;
        }
        else
        {
            m_pDebugName = NULL;
            m_pDebugClassName = NULL;
        }
    }
#endif // _DEBUG
};

//=======================================================================
// Collects code and data pertaining to the NDirect interface.
//=======================================================================
class NDirect
{
    friend class NDirectMethodDesc;

public:
    //---------------------------------------------------------
    // Does a class or method have a NAT_L CustomAttribute?
    //
    // S_OK    = yes
    // S_FALSE = no
    // FAILED  = unknown because something failed.
    //---------------------------------------------------------
    static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs);

    static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, NATIVE_LIBRARY_HANDLE hMod);
    static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError);
    static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly, 
                                                   BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags, 
                                                   BOOL throwOnError);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker);
    static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle);
    static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError);

    static VOID NDirectLink(NDirectMethodDesc *pMD);

    // Either MD or signature & module must be given.
    static BOOL MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig = NULL, Module *pModule = NULL);
    static void PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError = TRUE);

    static MethodDesc* CreateCLRToNativeILStub(
                    StubSigDesc*       pSigDesc,
                    CorNativeLinkType  nlType,
                    CorNativeLinkFlags nlFlags,
                    CorPinvokeMap      unmgdCallConv,
                    DWORD              dwStubFlags); // NDirectStubFlags
                    
#ifdef FEATURE_COMINTEROP
    static MethodDesc* CreateFieldAccessILStub(
                    PCCOR_SIGNATURE    szMetaSig,
                    DWORD              cbMetaSigSize,
                    Module*            pModule,
                    mdFieldDef         fd,
                    DWORD              dwStubFlags, // NDirectStubFlags
                    FieldDesc*         pFD);
#endif // FEATURE_COMINTEROP

    static MethodDesc* CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
                             DWORD dwStubFlags,
                             MethodDesc* pMD);

    static MethodDesc*      GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwNGenStubFlags);
    static MethodDesc*      GetStubMethodDesc(MethodDesc *pTargetMD, NDirectStubParameters* pParams, ILStubHashBlob* pHashParams, AllocMemTracker* pamTracker, bool& bILStubCreator, MethodDesc* pLastMD);
    static void             AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD);
    static void             RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams);
    static ILStubHashBlob*  CreateHashBlob(NDirectStubParameters* pParams);
    static PCODE            GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags);
    static PCODE            GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD, DWORD dwStubFlags);

    inline static ILStubCache*     GetILStubCache(NDirectStubParameters* pParams);

private:
    NDirect() {LIMITED_METHOD_CONTRACT;};     // prevent "new"'s on this class

    static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
    static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, LPCWSTR wszLibName);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaEvent(NDirectMethodDesc * pMD, LPCWSTR wszLibName);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaCallback(NDirectMethodDesc * pMD, LPCWSTR wszLibName);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName);
    static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName);
};

//----------------------------------------------------------------
// Flags passed to CreateNDirectStub that control stub generation
//----------------------------------------------------------------
enum NDirectStubFlags
{
    NDIRECTSTUB_FL_CONVSIGASVARARG          = 0x00000001,
    NDIRECTSTUB_FL_BESTFIT                  = 0x00000002,
    NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR    = 0x00000004,
    NDIRECTSTUB_FL_NGENEDSTUB               = 0x00000008,
    NDIRECTSTUB_FL_DELEGATE                 = 0x00000010,
    NDIRECTSTUB_FL_DOHRESULTSWAPPING        = 0x00000020,
    NDIRECTSTUB_FL_REVERSE_INTEROP          = 0x00000040,
#ifdef FEATURE_COMINTEROP
    NDIRECTSTUB_FL_COM                      = 0x00000080,
#endif // FEATURE_COMINTEROP
    NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING   = 0x00000100,
    NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL     = 0x00000200,
    // unused                               = 0x00000400,
    NDIRECTSTUB_FL_UNMANAGED_CALLI          = 0x00000800,
    NDIRECTSTUB_FL_TRIGGERCCTOR             = 0x00001000,
#ifdef FEATURE_COMINTEROP
    NDIRECTSTUB_FL_FIELDGETTER              = 0x00002000, // COM->CLR field getter
    NDIRECTSTUB_FL_FIELDSETTER              = 0x00004000, // COM->CLR field setter
    NDIRECTSTUB_FL_WINRT                    = 0x00008000,
    NDIRECTSTUB_FL_WINRTDELEGATE            = 0x00010000,
    NDIRECTSTUB_FL_WINRTSHAREDGENERIC       = 0x00020000, // stub for methods on shared generic interfaces (only used in the forward direction)
    NDIRECTSTUB_FL_WINRTCTOR                = 0x00080000,
    NDIRECTSTUB_FL_WINRTCOMPOSITION         = 0x00100000, // set along with WINRTCTOR
    NDIRECTSTUB_FL_WINRTSTATIC              = 0x00200000,

    NDIRECTSTUB_FL_WINRTHASREDIRECTION      = 0x00800000, // the stub may tail-call to a static stub in mscorlib, not shareable
#endif // FEATURE_COMINTEROP

    // internal flags -- these won't ever show up in an NDirectStubHashBlob
    NDIRECTSTUB_FL_FOR_NUMPARAMBYTES        = 0x10000000,   // do just enough to return the right value from Marshal.NumParamBytes

#ifdef FEATURE_COMINTEROP    
    NDIRECTSTUB_FL_COMLATEBOUND             = 0x20000000,   // we use a generic stub for late bound calls
    NDIRECTSTUB_FL_COMEVENTCALL             = 0x40000000,   // we use a generic stub for event calls
#endif // FEATURE_COMINTEROP

    // Note: The upper half of the range is reserved for ILStubTypes enum
    NDIRECTSTUB_FL_MASK                     = 0x7FFFFFFF,
    NDIRECTSTUB_FL_INVALID                  = 0x80000000,
};

enum ILStubTypes
{
    ILSTUB_INVALID                       = 0x80000000,
#ifdef FEATURE_ARRAYSTUB_AS_IL
    ILSTUB_ARRAYOP_GET                   = 0x80000001,
    ILSTUB_ARRAYOP_SET                   = 0x80000002,
    ILSTUB_ARRAYOP_ADDRESS               = 0x80000004,
#endif
#ifdef FEATURE_MULTICASTSTUB_AS_IL
    ILSTUB_MULTICASTDELEGATE_INVOKE      = 0x80000010,
#endif
#ifdef FEATURE_INSTANTIATINGSTUB_AS_IL
    ILSTUB_UNBOXINGILSTUB                = 0x80000020,
    ILSTUB_INSTANTIATINGSTUB             = 0x80000040,
#endif
    ILSTUB_WRAPPERDELEGATE_INVOKE        = 0x80000080,
};

#ifdef FEATURE_COMINTEROP
#define COM_ONLY(x) (x)
#else // FEATURE_COMINTEROP
#define COM_ONLY(x) false
#endif // FEATURE_COMINTEROP

inline bool SF_IsVarArgStub            (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)); }
inline bool SF_IsBestFit               (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_BESTFIT)); }
inline bool SF_IsThrowOnUnmappableChar (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR)); }
inline bool SF_IsNGENedStub            (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)); }
inline bool SF_IsDelegateStub          (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DELEGATE)); }
inline bool SF_IsHRESULTSwapping       (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DOHRESULTSWAPPING)); }
inline bool SF_IsReverseStub           (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)); }
inline bool SF_IsNGENedStubForProfiling(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING)); }
inline bool SF_IsDebuggableStub        (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL)); }
inline bool SF_IsCALLIStub             (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)); }
inline bool SF_IsStubWithCctorTrigger  (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_TRIGGERCCTOR)); }
inline bool SF_IsForNumParamBytes      (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FOR_NUMPARAMBYTES)); }

#ifdef FEATURE_ARRAYSTUB_AS_IL
inline bool SF_IsArrayOpStub           (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return ((dwStubFlags == ILSTUB_ARRAYOP_GET) || 
                                                                                              (dwStubFlags == ILSTUB_ARRAYOP_SET) ||
                                                                                              (dwStubFlags == ILSTUB_ARRAYOP_ADDRESS)); }
#endif

#ifdef FEATURE_MULTICASTSTUB_AS_IL
inline bool SF_IsMulticastDelegateStub  (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_MULTICASTDELEGATE_INVOKE); }
#endif

inline bool SF_IsWrapperDelegateStub    (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_WRAPPERDELEGATE_INVOKE); }
#ifdef FEATURE_INSTANTIATINGSTUB_AS_IL
inline bool SF_IsUnboxingILStub         (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_UNBOXINGILSTUB); }
inline bool SF_IsInstantiatingStub      (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_INSTANTIATINGSTUB); }
#endif

inline bool SF_IsCOMStub               (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COM)); }
inline bool SF_IsWinRTStub             (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRT)); }
inline bool SF_IsCOMLateBoundStub      (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMLATEBOUND)); }
inline bool SF_IsCOMEventCallStub      (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMEVENTCALL)); }
inline bool SF_IsFieldGetterStub       (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDGETTER)); }
inline bool SF_IsFieldSetterStub       (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDSETTER)); }
inline bool SF_IsWinRTDelegateStub     (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTDELEGATE)); }
inline bool SF_IsWinRTCtorStub         (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCTOR)); }
inline bool SF_IsWinRTCompositionStub  (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCOMPOSITION)); }
inline bool SF_IsWinRTStaticStub       (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSTATIC)); }
inline bool SF_IsWinRTSharedGenericStub(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSHAREDGENERIC)); }
inline bool SF_IsWinRTHasRedirection   (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTHASREDIRECTION)); }

inline bool SF_IsSharedStub(DWORD dwStubFlags)
{
    WRAPPER_NO_CONTRACT;

    if (SF_IsWinRTHasRedirection(dwStubFlags))
    {
        // tail-call to a target-specific mscorlib routine is burned into the stub
        return false;
    }

    return !SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags);
}

inline bool SF_IsForwardStub             (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return !SF_IsReverseStub(dwStubFlags); }

inline bool SF_IsForwardPInvokeStub      (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
inline bool SF_IsReversePInvokeStub      (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }

inline bool SF_IsForwardCOMStub          (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
inline bool SF_IsReverseCOMStub          (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }

inline bool SF_IsForwardDelegateStub     (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
inline bool SF_IsReverseDelegateStub     (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }

#undef COM_ONLY

inline void SF_ConsistencyCheck(DWORD dwStubFlags)
{
    LIMITED_METHOD_CONTRACT;

    // Late bound and event calls imply COM
    CONSISTENCY_CHECK(!(SF_IsCOMLateBoundStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags)));
    CONSISTENCY_CHECK(!(SF_IsCOMEventCallStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags)));

    // Field accessors imply reverse COM
    CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags)));
    CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags)));

    // Field accessors are always HRESULT swapping
    CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags)));
    CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags)));

    // Delegate stubs are not COM
    CONSISTENCY_CHECK(!(SF_IsDelegateStub(dwStubFlags) && SF_IsCOMStub(dwStubFlags)));
}

enum ETW_IL_STUB_FLAGS
{
    ETW_IL_STUB_FLAGS_REVERSE_INTEROP       = 0x00000001,
    ETW_IL_STUB_FLAGS_COM_INTEROP           = 0x00000002,    
    ETW_IL_STUB_FLAGS_NGENED_STUB           = 0x00000004,
    ETW_IL_STUB_FLAGS_DELEGATE              = 0x00000008,    
    ETW_IL_STUB_FLAGS_VARARG                = 0x00000010,
    ETW_IL_STUB_FLAGS_UNMANAGED_CALLI       = 0x00000020
};

//---------------------------------------------------------
// PInvoke has three flavors: DllImport M->U, Delegate M->U and Delegate U->M
// Each flavor uses rougly the same mechanism to marshal and place the call and so
// each flavor supports roughly the same switches. Those switches which can be 
// statically determined via CAs (DllImport, UnmanagedFunctionPointer, 
// BestFitMappingAttribute, etc) or via MetaSig are parsed and unified by this 
// class. There are two flavors of constructor, one for NDirectMethodDescs and one
// for Delegates. 
//---------------------------------------------------------
struct PInvokeStaticSigInfo
{
public:
    enum ThrowOnError { THROW_ON_ERROR = TRUE, NO_THROW_ON_ERROR = FALSE };

public:     
    PInvokeStaticSigInfo() { LIMITED_METHOD_CONTRACT; }

    PInvokeStaticSigInfo(Signature sig, Module* pModule, ThrowOnError throwOnError = THROW_ON_ERROR);
    
    PInvokeStaticSigInfo(MethodDesc* pMdDelegate, ThrowOnError throwOnError = THROW_ON_ERROR);
    
    PInvokeStaticSigInfo(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError = THROW_ON_ERROR);

public:     
    void ReportErrors();
    
private:
    void InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg);
    void DllImportInit(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName);
    void PreInit(Module* pModule, MethodTable *pClass);
    void PreInit(MethodDesc* pMD);
    void SetError(WORD error) { if (!m_error) m_error = error; }
    void BestGuessNDirectDefaults(MethodDesc* pMD);

public:     
    DWORD GetStubFlags() 
    { 
        WRAPPER_NO_CONTRACT;
        return (GetThrowOnUnmappableChar() ? NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR : 0) | 
               (GetBestFitMapping() ? NDIRECTSTUB_FL_BESTFIT : 0) | 
               (IsDelegateInterop() ? NDIRECTSTUB_FL_DELEGATE : 0);
    }
    Module* GetModule() { LIMITED_METHOD_CONTRACT; return m_pModule; }
    BOOL IsStatic() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_STATIC; }
    void SetIsStatic (BOOL isStatic) 
    { 
        LIMITED_METHOD_CONTRACT; 
        if (isStatic) 
            m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_STATIC; 
        else 
            m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_STATIC; 
    }
    BOOL GetThrowOnUnmappableChar() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; }
    void SetThrowOnUnmappableChar (BOOL throwOnUnmappableChar) 
    { 
        LIMITED_METHOD_CONTRACT; 
        if (throwOnUnmappableChar) 
            m_wFlags |= PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; 
        else 
            m_wFlags &= ~PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; 
    }
    BOOL GetBestFitMapping() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_BEST_FIT; }
    void SetBestFitMapping (BOOL bestFit) 
    { 
        LIMITED_METHOD_CONTRACT; 
        if (bestFit) 
            m_wFlags |= PINVOKE_STATIC_SIGINFO_BEST_FIT; 
        else 
            m_wFlags &= ~PINVOKE_STATIC_SIGINFO_BEST_FIT; 
    }
    BOOL IsDelegateInterop() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; } 
    void SetIsDelegateInterop (BOOL delegateInterop) 
    { 
        LIMITED_METHOD_CONTRACT; 
        if (delegateInterop) 
            m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; 
        else 
            m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; 
    }
    CorPinvokeMap GetCallConv() { LIMITED_METHOD_CONTRACT; return m_callConv; }
    Signature GetSignature() { LIMITED_METHOD_CONTRACT; return m_sig; }
    
private:
    Module* m_pModule;
    Signature m_sig;
    CorPinvokeMap m_callConv;
    WORD m_error;

    enum 
    {
        PINVOKE_STATIC_SIGINFO_IS_STATIC = 0x0001,
        PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR = 0x0002,
        PINVOKE_STATIC_SIGINFO_BEST_FIT = 0x0004,

        COR_NATIVE_LINK_TYPE_MASK = 0x0038,  // 0000 0000 0011 1000  <--- These 3 1's make the link type mask
        
        COR_NATIVE_LINK_FLAGS_MASK = 0x00C0, //0000 0000 1100 0000  <---- These 2 bits make up the link flags

        PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP = 0x0100,
        
    };
    #define COR_NATIVE_LINK_TYPE_SHIFT 3 // Keep in synch with above mask
    #define COR_NATIVE_LINK_FLAGS_SHIFT 6  // Keep in synch with above mask
    WORD m_wFlags;

  public:
    CorNativeLinkType GetCharSet() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkType)((m_wFlags & COR_NATIVE_LINK_TYPE_MASK) >> COR_NATIVE_LINK_TYPE_SHIFT); }
    CorNativeLinkFlags GetLinkFlags() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkFlags)((m_wFlags & COR_NATIVE_LINK_FLAGS_MASK) >> COR_NATIVE_LINK_FLAGS_SHIFT); }
    void SetCharSet(CorNativeLinkType linktype) 
    { 
        LIMITED_METHOD_CONTRACT; 
        _ASSERTE( linktype == (linktype & (COR_NATIVE_LINK_TYPE_MASK >> COR_NATIVE_LINK_TYPE_SHIFT))); 
        // Clear out the old value first
        m_wFlags &= (~COR_NATIVE_LINK_TYPE_MASK);
        // Then set the given value
        m_wFlags |= (linktype << COR_NATIVE_LINK_TYPE_SHIFT); 
    }
    void SetLinkFlags(CorNativeLinkFlags linkflags) 
    { 
        LIMITED_METHOD_CONTRACT; 
        _ASSERTE( linkflags == (linkflags & (COR_NATIVE_LINK_FLAGS_MASK >> COR_NATIVE_LINK_FLAGS_SHIFT)));
        // Clear out the old value first
        m_wFlags &= (~COR_NATIVE_LINK_FLAGS_MASK);
        // Then set the given value
        m_wFlags |= (linkflags << COR_NATIVE_LINK_FLAGS_SHIFT);
    }
};


#include "stubgen.h"

class NDirectStubLinker : public ILStubLinker
{
public:
    NDirectStubLinker(
                DWORD dwStubFlags, 
                Module* pModule,
                const Signature &signature,
                SigTypeContext *pTypeContext,
                MethodDesc* pTargetMD,
                int  iLCIDParamIdx,
                BOOL fTargetHasThis,
                BOOL fStubHasThis);

    void    SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg);

    void    Begin(DWORD dwStubFlags);
    void    End(DWORD dwStubFlags);
    void    DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD);
    void    EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal);
    void    LoadCleanupWorkList(ILCodeStream* pcsEmit);
#ifdef PROFILING_SUPPORTED
    DWORD   EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags);
    void    EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum);
#endif
#ifdef VERIFY_HEAP
    void    EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags);
    void    EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags);
#endif // VERIFY_HEAP
    void    EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags);
    void    GenerateInteropParamException(ILCodeStream* pcsEmit);
    void    NeedsCleanupList();

#ifdef FEATURE_COMINTEROP
    DWORD   GetTargetInterfacePointerLocalNum();
    DWORD   GetTargetEntryPointLocalNum();
    void    EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags);
#endif // FEATURE_COMINTEROP
    DWORD   GetCleanupWorkListLocalNum();
    DWORD   GetThreadLocalNum();
    DWORD   GetReturnValueLocalNum();
    void    SetCleanupNeeded();
    void    SetExceptionCleanupNeeded();
    BOOL    IsCleanupWorkListSetup();
    void    GetCleanupFinallyOffsets(ILStubEHClause * pClause);
    void    AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
    void    AdjustTargetStackDeltaForExtraParam();

    void    SetInteropParamExceptionInfo(UINT resID, UINT paramIdx);
    bool    HasInteropParamExceptionInfo();
    bool    TargetHasThis()
    {
        return m_targetHasThis == TRUE;
    }

    void ClearCode();

    enum
    {
        CLEANUP_INDEX_ARG0_MARSHAL     = 0x00000000,  // cleanup index of the first argument (marshal and retval unmarshal stream)
        CLEANUP_INDEX_RETVAL_UNMARSHAL = 0x3fffffff,  // cleanup index of the return value (retval unmarshal stream)
        CLEANUP_INDEX_ARG0_UNMARSHAL   = 0x40000000,  // cleanup index of the first argument (unmarshal stream)
        CLEANUP_INDEX_ALL_DONE         = 0x7ffffffe   // everything was successfully marshaled and unmarshaled, no exception thrown
    };

    enum ArgCleanupBranchKind
    {
        BranchIfMarshaled,
        BranchIfNotMarshaled
    };

    void    EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx);
    void    EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel);

    int     GetLCIDParamIdx();

    ILCodeStream* GetSetupCodeStream();
    ILCodeStream* GetMarshalCodeStream();
    ILCodeStream* GetUnmarshalCodeStream();
    ILCodeStream* GetReturnUnmarshalCodeStream();
    ILCodeStream* GetDispatchCodeStream();
    ILCodeStream* GetCleanupCodeStream();
    ILCodeStream* GetExceptionCleanupCodeStream();

protected:
    BOOL            IsCleanupNeeded();
    BOOL            IsExceptionCleanupNeeded();
    void            InitCleanupCode();
    void            InitExceptionCleanupCode();



    ILCodeStream*   m_pcsSetup;
    ILCodeStream*   m_pcsMarshal;
    ILCodeStream*   m_pcsDispatch;
    ILCodeStream*   m_pcsRetUnmarshal;
    ILCodeStream*   m_pcsUnmarshal;
    ILCodeStream*   m_pcsExceptionCleanup;
    ILCodeStream*   m_pcsCleanup;


    ILCodeLabel*        m_pCleanupTryBeginLabel;
    ILCodeLabel*        m_pCleanupTryEndLabel;
    ILCodeLabel*        m_pCleanupFinallyBeginLabel;
    ILCodeLabel*        m_pCleanupFinallyEndLabel;
    ILCodeLabel*        m_pSkipExceptionCleanupLabel;

#ifdef FEATURE_COMINTEROP
    DWORD               m_dwTargetInterfacePointerLocalNum;
    DWORD               m_dwTargetEntryPointLocalNum;
    DWORD               m_dwWinRTFactoryObjectLocalNum;
#endif // FEATURE_COMINTEROP

    BOOL                m_fHasCleanupCode;
    BOOL                m_fHasExceptionCleanupCode;
    BOOL                m_fCleanupWorkListIsSetup;
    BOOL                m_targetHasThis;
    DWORD               m_dwThreadLocalNum;                 // managed-to-native only
    DWORD               m_dwArgMarshalIndexLocalNum;
    DWORD               m_dwCleanupWorkListLocalNum;
    DWORD               m_dwRetValLocalNum;
    

    UINT                m_ErrorResID;
    UINT                m_ErrorParamIdx;
    int                 m_iLCIDParamIdx;

    DWORD               m_dwStubFlags;
};

// This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget);
BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget);
DWORD STDMETHODCALLTYPE FalseGetLastError();

class NDirectStubParameters
{
public:

    NDirectStubParameters(Signature          sig,
                          SigTypeContext*    pTypeContext,
                          Module*            pModule,
                          Module*            pLoaderModule,
                          CorNativeLinkType  nlType,
                          CorNativeLinkFlags nlFlags,
                          CorPinvokeMap      unmgdCallConv,
                          DWORD              dwStubFlags,  // NDirectStubFlags
                          int                nParamTokens,
                          mdParamDef*        pParamTokenArray,
                          int                iLCIDArg
                          ) :
        m_sig(sig),
        m_pTypeContext(pTypeContext),
        m_pModule(pModule),
        m_pLoaderModule(pLoaderModule),
        m_pParamTokenArray(pParamTokenArray),
        m_unmgdCallConv(unmgdCallConv),
        m_nlType(nlType),
        m_nlFlags(nlFlags),
        m_dwStubFlags(dwStubFlags),
        m_iLCIDArg(iLCIDArg),
        m_nParamTokens(nParamTokens)
    {
        LIMITED_METHOD_CONTRACT;
    }

    Signature           m_sig;
    SigTypeContext*     m_pTypeContext;
    Module*             m_pModule;
    Module*             m_pLoaderModule;
    mdParamDef*         m_pParamTokenArray;
    CorPinvokeMap       m_unmgdCallConv;
    CorNativeLinkType   m_nlType;
    CorNativeLinkFlags  m_nlFlags;
    DWORD               m_dwStubFlags;
    int                 m_iLCIDArg;
    int                 m_nParamTokens;
};

PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD);

MethodDesc *GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags);
PCODE JitILStub(MethodDesc* pStubMD);
MethodDesc *RestoreNGENedStub(MethodDesc* pStubMD);
PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags = 0, MethodDesc **ppStubMD = NULL);

#ifdef FEATURE_COMINTEROP
// Resolve and return the predefined IL stub method
HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD);
#endif // FEATURE_COMINTEROP

// 
// Limit length of string field in IL stub ETW events so that the whole
// IL stub ETW events won't exceed 64KB
//
#define ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE      (1024)
#define ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE (1024*32)

class SString;

//
// Truncates a SString by first converting it to unicode and truncate it 
// if it is larger than size. "..." will be appened if it is truncated.
//
void TruncateUnicodeString(SString &string, COUNT_T bufSize);

//=======================================================================
// ILStubCreatorHelper
// The class is used as a helper class in CreateInteropILStub. It mainly
// puts two methods NDirect::GetStubMethodDesc and NDirect::RemoveILStubCacheEntry
// into a holder. See CreateInteropILStub for more information
//=======================================================================
class ILStubCreatorHelper
{
public:
    ILStubCreatorHelper(MethodDesc *pTargetMD,
                        NDirectStubParameters* pParams
                        ) :
        m_pTargetMD(pTargetMD),
        m_pParams(pParams),
        m_pStubMD(NULL),
        m_bILStubCreator(false)
    {
        STANDARD_VM_CONTRACT;
        m_pHashParams = NDirect::CreateHashBlob(m_pParams);
    }

    ~ILStubCreatorHelper()
    {
        CONTRACTL
        {
            THROWS;
            GC_TRIGGERS;
            MODE_ANY;
        }
        CONTRACTL_END;

        RemoveILStubCacheEntry();
    }

    inline void GetStubMethodDesc()
    {
        WRAPPER_NO_CONTRACT;

        m_pStubMD = NDirect::GetStubMethodDesc(m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD);
    }

    inline void RemoveILStubCacheEntry()
    {
        WRAPPER_NO_CONTRACT;
        
        if (m_bILStubCreator)
        {
            NDirect::RemoveILStubCacheEntry(m_pParams, m_pHashParams);
            m_bILStubCreator = false;
        }
    }

    inline MethodDesc* GetStubMD()
    {
        LIMITED_METHOD_CONTRACT;
        return m_pStubMD;
    }

    inline void SuppressRelease()
    {
        WRAPPER_NO_CONTRACT;
        m_bILStubCreator = false;
        m_amTracker.SuppressRelease();
    }

    DEBUG_NOINLINE static void HolderEnter(ILStubCreatorHelper *pThis)
    {
        WRAPPER_NO_CONTRACT;
        ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
        pThis->GetStubMethodDesc();
    }

    DEBUG_NOINLINE static void HolderLeave(ILStubCreatorHelper *pThis)
    {
        WRAPPER_NO_CONTRACT;
        ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
        pThis->RemoveILStubCacheEntry();
    }

private:
    MethodDesc*                      m_pTargetMD;
    NDirectStubParameters*           m_pParams;
    NewArrayHolder<ILStubHashBlob>   m_pHashParams;
    AllocMemTracker*                 m_pAmTracker;
    MethodDesc*                      m_pStubMD;
    AllocMemTracker                  m_amTracker;
    bool                             m_bILStubCreator;     // Only the creator can remove the ILStub from the Cache
};  //ILStubCreatorHelper

typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder;

#endif // __dllimport_h__