Merge pull request #3074 from Dmitry-Me/useElseIfForExclusive
[platform/upstream/coreclr.git] / src / vm / ilmarshalers.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // 
5 // File: ILMarshalers.h
6 // 
7
8 //
9
10
11 #include "common.h"
12 #ifdef FEATURE_COMINTEROP
13 #include "winstring.h"
14 #endif //FEATURE_COMINTEROP
15 #include "stubgen.h"
16 #include "binder.h"
17 #include "marshalnative.h"
18 #include "clrvarargs.h"
19 #ifdef FEATURE_COMINTEROP
20 #include "stdinterfaces.h"
21 #endif
22
23 #define LOCAL_NUM_UNUSED ((DWORD)-1)
24
25 class ILStubMarshalHome
26 {
27 public:
28     typedef enum 
29     {
30         HomeType_Unspecified     = 0,
31         HomeType_ILLocal         = 1,
32         HomeType_ILArgument      = 2,
33         HomeType_ILByrefLocal    = 3,
34         HomeType_ILByrefArgument = 4
35     } MarshalHomeType;
36
37 private:
38     MarshalHomeType     m_homeType;
39     DWORD               m_dwHomeIndex;
40     
41 public:
42     void InitHome(MarshalHomeType homeType, DWORD dwHomeIndex)
43     {
44         LIMITED_METHOD_CONTRACT;
45         m_homeType = homeType;
46         m_dwHomeIndex = dwHomeIndex;
47     }
48         
49     void EmitLoadHome(ILCodeStream* pslILEmit)
50     {
51         CONTRACTL
52         {
53             THROWS;
54             GC_TRIGGERS;
55             MODE_ANY;
56         }
57         CONTRACTL_END;
58
59         switch (m_homeType)
60         {
61             case HomeType_ILLocal:      pslILEmit->EmitLDLOC(m_dwHomeIndex); break;
62             case HomeType_ILArgument:   pslILEmit->EmitLDARG(m_dwHomeIndex); break;
63         
64             default:
65                 UNREACHABLE_MSG("unexpected homeType passed to EmitLoadHome");
66                 break;
67         }
68     }
69
70     void EmitLoadHomeAddr(ILCodeStream* pslILEmit)
71     {
72         CONTRACTL
73         {
74             THROWS;
75             GC_TRIGGERS;
76             MODE_ANY;
77         }
78         CONTRACTL_END;
79         
80         switch (m_homeType)
81         {
82             case HomeType_ILLocal:         pslILEmit->EmitLDLOCA(m_dwHomeIndex); break;
83             case HomeType_ILArgument:      pslILEmit->EmitLDARGA(m_dwHomeIndex); break;
84             case HomeType_ILByrefLocal:    pslILEmit->EmitLDLOC(m_dwHomeIndex);  break;
85             case HomeType_ILByrefArgument: pslILEmit->EmitLDARG(m_dwHomeIndex);  break;
86
87             default:
88                 UNREACHABLE_MSG("unexpected homeType passed to EmitLoadHomeAddr");
89                 break;
90         }
91     }        
92
93     void EmitStoreHome(ILCodeStream* pslILEmit)
94     {
95         CONTRACTL
96         {
97             THROWS;
98             GC_TRIGGERS;
99             MODE_ANY;
100         }
101         CONTRACTL_END;
102         
103         switch (m_homeType)
104         {
105             case HomeType_ILLocal:      pslILEmit->EmitSTLOC(m_dwHomeIndex); break;
106             case HomeType_ILArgument:   pslILEmit->EmitSTARG(m_dwHomeIndex); break;
107
108             default:
109                 UNREACHABLE_MSG("unexpected homeType passed to EmitStoreHome");
110                 break;
111         }
112     }
113
114     void EmitStoreHomeAddr(ILCodeStream* pslILEmit)
115     {
116         CONTRACTL
117         {
118             THROWS;
119             GC_TRIGGERS;
120             MODE_ANY;
121         }
122         CONTRACTL_END;
123         
124         switch (m_homeType)
125         {
126             case HomeType_ILByrefLocal:    pslILEmit->EmitSTLOC(m_dwHomeIndex); break;
127             case HomeType_ILByrefArgument: pslILEmit->EmitSTARG(m_dwHomeIndex); break;
128
129             default:
130                 UNREACHABLE_MSG("unexpected homeType passed to EmitStoreHomeAddr");
131                 break;
132         }
133     }
134
135     void EmitCopyFromByrefArg(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
136     {
137         CONTRACTL
138         {
139             THROWS;
140             GC_TRIGGERS;
141             MODE_ANY;
142         }
143         CONTRACTL_END;
144         
145         CONSISTENCY_CHECK(pManagedType->cbType == 1);
146         if (pManagedType->IsValueClass())
147         {
148             EmitLoadHomeAddr(pslILEmit);    // dest
149             pslILEmit->EmitLDARG(argidx);   // src
150             pslILEmit->EmitCPOBJ(pslILEmit->GetToken(pManagedType->InternalToken));
151         }
152         else
153         {
154             pslILEmit->EmitLDARG(argidx);
155             pslILEmit->EmitLDIND_T(pManagedType);
156             EmitStoreHome(pslILEmit);
157         }
158     }
159
160     void EmitCopyToByrefArg(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
161     {
162         CONTRACTL
163         {
164             THROWS;
165             GC_TRIGGERS;
166             MODE_ANY;
167         }
168         CONTRACTL_END;
169
170         if (pManagedType->IsValueClass())
171         {
172             pslILEmit->EmitLDARG(argidx);   // dest
173             EmitLoadHomeAddr(pslILEmit);    // src
174             pslILEmit->EmitCPOBJ(pslILEmit->GetToken(pManagedType->InternalToken));
175         }
176         else
177         {
178             pslILEmit->EmitLDARG(argidx);
179             EmitLoadHome(pslILEmit);
180             pslILEmit->EmitSTIND_T(pManagedType);
181         }
182     }
183
184     void EmitCopyToByrefArgWithNullCheck(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
185     {
186         CONTRACTL
187         {
188             THROWS;
189             GC_TRIGGERS;
190             MODE_ANY;
191         }
192         CONTRACTL_END;
193
194         ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
195
196         // prevent null-ref exception by an explicit check
197         pslILEmit->EmitLDARG(argidx);
198         pslILEmit->EmitBRFALSE(pNullRefLabel);
199
200         EmitCopyToByrefArg(pslILEmit, pManagedType, argidx);
201
202         pslILEmit->EmitLabel(pNullRefLabel);
203     }
204 };
205         
206
207 class ILMarshaler 
208 {
209 protected:
210
211 #ifdef _DEBUG
212     const static UINT   s_cbStackAllocThreshold = 128;
213 #else
214     const static UINT   s_cbStackAllocThreshold = 2048;
215 #endif // _DEBUG
216
217     OverrideProcArgs*   m_pargs;
218     NDirectStubLinker*  m_pslNDirect;
219     ILCodeStream*       m_pcsMarshal;
220     ILCodeStream*       m_pcsUnmarshal;
221     UINT                m_argidx;
222
223     DWORD               m_dwMarshalFlags;
224
225     ILStubMarshalHome   m_nativeHome;
226     ILStubMarshalHome   m_managedHome;
227
228     DWORD               m_dwMngdMarshalerLocalNum;
229
230 public:
231
232     ILMarshaler() : 
233         m_pslNDirect(NULL)
234     {
235     }
236
237     virtual ~ILMarshaler()
238     {
239         LIMITED_METHOD_CONTRACT;
240     }
241
242     void SetNDirectStubLinker(NDirectStubLinker* pslNDirect)
243     {
244         LIMITED_METHOD_CONTRACT;
245         CONSISTENCY_CHECK(NULL == m_pslNDirect);
246         m_pslNDirect = pslNDirect;
247     }
248
249     void Init(ILCodeStream* pcsMarshal, 
250             ILCodeStream* pcsUnmarshal,
251             UINT argidx,
252             DWORD dwMarshalFlags, 
253             OverrideProcArgs* pargs)
254     {
255         LIMITED_METHOD_CONTRACT;
256         CONSISTENCY_CHECK_MSG(m_pslNDirect != NULL, "please call SetNDirectStubLinker() before EmitMarshalArgument or EmitMarshalReturnValue");
257         m_pcsMarshal = pcsMarshal;
258         m_pcsUnmarshal = pcsUnmarshal;
259         m_pargs = pargs;
260         m_dwMarshalFlags = dwMarshalFlags;
261         m_argidx = argidx;
262         m_dwMngdMarshalerLocalNum = -1;
263     }
264
265 protected:
266     static inline bool IsCLRToNative(DWORD dwMarshalFlags)
267     {
268         LIMITED_METHOD_CONTRACT;
269         return (0 != (dwMarshalFlags & MARSHAL_FLAG_CLR_TO_NATIVE));
270     }
271         
272     static inline bool IsIn(DWORD dwMarshalFlags)
273     {
274         LIMITED_METHOD_CONTRACT;
275         return (0 != (dwMarshalFlags & MARSHAL_FLAG_IN));
276     }
277
278     static inline bool IsOut(DWORD dwMarshalFlags)
279     {
280         LIMITED_METHOD_CONTRACT;
281         return (0 != (dwMarshalFlags & MARSHAL_FLAG_OUT));
282     }
283
284     static inline bool IsByref(DWORD dwMarshalFlags)
285     {
286         LIMITED_METHOD_CONTRACT;
287         return (0 != (dwMarshalFlags & MARSHAL_FLAG_BYREF));
288     }
289
290     static inline bool IsHresultSwap(DWORD dwMarshalFlags)
291     {
292         LIMITED_METHOD_CONTRACT;
293         return (0 != (dwMarshalFlags & MARSHAL_FLAG_HRESULT_SWAP));
294     }
295
296     static inline bool IsRetval(DWORD dwMarshalFlags)
297     {
298         LIMITED_METHOD_CONTRACT;
299         return (0 != (dwMarshalFlags & MARSHAL_FLAG_RETVAL));
300     }
301
302     static inline bool IsHiddenLengthParam(DWORD dwMarshalFlags)
303     {
304         LIMITED_METHOD_CONTRACT;
305         return (0 != (dwMarshalFlags & MARSHAL_FLAG_HIDDENLENPARAM));
306     }
307
308     void EmitLoadManagedValue(ILCodeStream* pslILEmit)
309     {
310         WRAPPER_NO_CONTRACT;
311         m_managedHome.EmitLoadHome(pslILEmit);
312     }
313
314     void EmitLoadNativeValue(ILCodeStream* pslILEmit)
315     {
316         WRAPPER_NO_CONTRACT;
317         m_nativeHome.EmitLoadHome(pslILEmit);
318     }
319
320     void EmitLoadManagedHomeAddr(ILCodeStream* pslILEmit)
321     {
322         WRAPPER_NO_CONTRACT;
323         m_managedHome.EmitLoadHomeAddr(pslILEmit);
324     }
325
326     void EmitLoadNativeHomeAddr(ILCodeStream* pslILEmit)
327     {
328         WRAPPER_NO_CONTRACT;
329         m_nativeHome.EmitLoadHomeAddr(pslILEmit);
330     }
331         
332     void EmitStoreManagedValue(ILCodeStream* pslILEmit)
333     {
334         WRAPPER_NO_CONTRACT;
335         m_managedHome.EmitStoreHome(pslILEmit);
336     }
337
338     void EmitStoreManagedHomeAddr(ILCodeStream* pslILEmit)
339     {
340         WRAPPER_NO_CONTRACT;
341         m_managedHome.EmitStoreHomeAddr(pslILEmit);
342     }
343
344     void EmitStoreNativeValue(ILCodeStream* pslILEmit)
345     {
346         WRAPPER_NO_CONTRACT;
347         m_nativeHome.EmitStoreHome(pslILEmit);
348     }
349
350     void EmitStoreNativeHomeAddr(ILCodeStream* pslILEmit)
351     {
352         WRAPPER_NO_CONTRACT;
353         m_nativeHome.EmitStoreHomeAddr(pslILEmit);
354     }
355
356 public:
357
358     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
359     {
360         LIMITED_METHOD_CONTRACT;
361         return true;
362     }
363
364     virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
365     {
366         LIMITED_METHOD_CONTRACT;
367         return true;
368     }
369
370     // True if marshaling creates data that could need cleanup.
371     bool NeedsMarshalCleanupIndex()
372     {
373         WRAPPER_NO_CONTRACT;
374         return (NeedsClearNative() || NeedsClearCLR());
375     }
376
377     // True if unmarshaling creates data that could need exception cleanup ("rollback").
378     bool NeedsUnmarshalCleanupIndex()
379     {
380         WRAPPER_NO_CONTRACT;
381         return (NeedsClearNative() && !IsCLRToNative(m_dwMarshalFlags));
382     }
383
384     void EmitMarshalArgument(
385                 ILCodeStream*   pcsMarshal, 
386                 ILCodeStream*   pcsUnmarshal, 
387                 UINT            argidx, 
388                 DWORD           dwMarshalFlags,
389                 OverrideProcArgs*  pargs)
390     {
391         STANDARD_VM_CONTRACT;
392
393         Init(pcsMarshal, pcsUnmarshal, argidx, dwMarshalFlags, pargs);
394
395         // We could create the marshaler in the marshal stream right before it's needed (i.e. within the try block),
396         // or in the setup stream (outside of the try block). For managed-to-unmanaged marshaling it does not actually
397         // make much difference except that using setup stream saves us from cleaning up already-marshaled arguments
398         // in case of an exception. For unmanaged-to-managed, we may need to perform cleanup of the incoming arguments
399         // before we were able to marshal them. Therefore this must not happen within the try block so we don't try
400         // to use marshalers that have not been initialized. Potentially leaking unmanaged resources is by-design and
401         // there's not much we can do about it (we cannot do cleanup if we cannot create the marshaler).
402         EmitCreateMngdMarshaler(m_pslNDirect->GetSetupCodeStream());
403
404         if (IsCLRToNative(dwMarshalFlags))
405         {
406             if (IsByref(dwMarshalFlags))
407             {
408                 EmitMarshalArgumentCLRToNativeByref();
409             }
410             else
411             {
412                 EmitMarshalArgumentCLRToNative();
413             }
414         }
415         else
416         {
417             if (IsByref(dwMarshalFlags))
418             {
419                 EmitMarshalArgumentNativeToCLRByref();
420             }
421             else
422             {
423                 EmitMarshalArgumentNativeToCLR();
424             }
425         }
426     }
427
428 #ifdef FEATURE_COMINTEROP
429     void EmitMarshalHiddenLengthArgument(ILCodeStream *pcsMarshal,
430                                          ILCodeStream *pcsUnmarshal,
431                                          MarshalInfo *pArrayInfo,
432                                          UINT arrayIndex,
433                                          DWORD dwMarshalFlags,
434                                          UINT hiddenArgIndex,
435                                          OverrideProcArgs *pargs,
436                                          __out DWORD *pdwHiddenLengthManagedHomeLocal,
437                                          __out DWORD *pdwHiddenLengthNativeHomeLocal)
438     {
439         CONTRACTL
440         {
441             STANDARD_VM_CHECK;
442             PRECONDITION(IsHiddenLengthParam(dwMarshalFlags));
443         }
444         CONTRACTL_END;
445
446         Init(pcsMarshal, pcsUnmarshal, hiddenArgIndex, dwMarshalFlags, pargs);
447         EmitCreateMngdMarshaler(m_pslNDirect->GetSetupCodeStream());
448
449         // Create a local to be the home of the length parameter
450         DWORD dwManagedLocalHome = m_pcsMarshal->NewLocal(GetManagedType());
451         m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwManagedLocalHome);
452         *pdwHiddenLengthManagedHomeLocal = dwManagedLocalHome;
453
454         // managed length = 0
455         m_pcsMarshal->EmitLDC(0);
456         m_pcsMarshal->EmitCONV_T(pArrayInfo->GetHiddenLengthParamElementType());
457         m_pcsMarshal->EmitSTLOC(dwManagedLocalHome);
458
459         // And a local to be the home of the marshaled length
460         LocalDesc nativeArgType(GetNativeType());
461         DWORD dwNativeHomeLocal = m_pcsMarshal->NewLocal(nativeArgType);
462         if (IsByref(dwMarshalFlags))
463         {
464             nativeArgType.MakeByRef();
465         }
466         m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwNativeHomeLocal);
467         *pdwHiddenLengthNativeHomeLocal = dwNativeHomeLocal;
468
469         // Update the native signature to contain the new native parameter
470         m_pcsMarshal->SetStubTargetArgType(&nativeArgType, false);
471
472         if (IsCLRToNative(dwMarshalFlags))
473         {
474             // Load the length of the array into the local
475             if (IsIn(dwMarshalFlags))
476             {
477                 ILCodeLabel *pSkipGetLengthLabel = m_pcsMarshal->NewCodeLabel();
478                 m_pcsMarshal->EmitLDARG(arrayIndex);
479                 m_pcsMarshal->EmitBRFALSE(pSkipGetLengthLabel);
480
481                 m_pcsMarshal->EmitLDARG(arrayIndex);
482
483                 if (IsByref(dwMarshalFlags))
484                 {
485                     // if (*array == null) goto pSkipGetLengthLabel
486                     m_pcsMarshal->EmitLDIND_REF();
487                     m_pcsMarshal->EmitBRFALSE(pSkipGetLengthLabel);
488                     
489                     // array = *array
490                     m_pcsMarshal->EmitLDARG(arrayIndex);
491                     m_pcsMarshal->EmitLDIND_REF();
492                 }
493
494                 m_pcsMarshal->EmitLDLEN();
495                 m_pcsMarshal->EmitCONV_T(pArrayInfo->GetHiddenLengthParamElementType());
496                 m_pcsMarshal->EmitSTLOC(dwManagedLocalHome);
497                 m_pcsMarshal->EmitLabel(pSkipGetLengthLabel);
498             }
499
500             if (IsByref(dwMarshalFlags))
501             {
502                 EmitMarshalArgumentContentsCLRToNativeByref(true);
503             }
504             else
505             {
506                 EmitMarshalArgumentContentsCLRToNative();
507             }
508         }
509         else
510         {
511             // Load the length of the array into the local
512             if (IsIn(dwMarshalFlags))
513             {
514                 m_pcsMarshal->EmitLDARG(hiddenArgIndex);
515                 if (IsByref(dwMarshalFlags))
516                 {
517                     LocalDesc nativeParamType(GetNativeType());
518                     m_pcsMarshal->EmitLDIND_T(&nativeParamType);
519                 }
520                 m_pcsMarshal->EmitSTLOC(dwNativeHomeLocal);
521             }
522
523             if (IsByref(dwMarshalFlags))
524             {
525                 EmitMarshalArgumentContentsNativeToCLRByref(true);
526             }
527             else
528             {
529                 EmitMarshalArgumentContentsNativeToCLR();
530             }
531
532             // We can't copy the final length back to the parameter just yet, since we don't know what
533             // local the array lives in.  Instead, we rely on the hidden length array marshaler to copy
534             // the value into the out parameter for us.
535         }
536     }
537
538 #endif // FEATURE_COMINTEROP
539
540     virtual void EmitSetupArgument(ILCodeStream* pslILEmit)
541     {
542         STANDARD_VM_CONTRACT;
543
544         if (IsCLRToNative(m_dwMarshalFlags))
545         {
546             if (IsNativePassedByRef())
547             {
548                 EmitLoadNativeHomeAddr(pslILEmit);
549             }
550             else
551             {
552                 EmitLoadNativeValue(pslILEmit);
553             }
554         }
555         else
556         {
557             if (IsManagedPassedByRef())
558             {
559                 EmitLoadManagedHomeAddr(pslILEmit);
560             }
561             else
562             {
563                 EmitLoadManagedValue(pslILEmit);
564             }
565         }
566     }
567
568     virtual void EmitMarshalReturnValue(
569                 ILCodeStream* pcsMarshal, 
570                 ILCodeStream* pcsUnmarshal,
571                 ILCodeStream* pcsDispatch,
572                 UINT argidx,
573                 UINT16 wNativeSize,
574                 DWORD dwMarshalFlags,
575                 OverrideProcArgs*  pargs)
576     {
577         STANDARD_VM_CONTRACT;
578
579         Init(pcsMarshal, pcsUnmarshal, argidx, dwMarshalFlags, pargs);
580
581         LocalDesc nativeType = GetNativeType();
582         LocalDesc managedType = GetManagedType();
583         
584         bool byrefNativeReturn = false;
585         CorElementType typ = ELEMENT_TYPE_VOID;
586         UINT32 nativeSize = 0;
587
588         // we need to convert value type return types to primitives as
589         // JIT does not inline P/Invoke calls that return structures
590         if (nativeType.IsValueClass())
591         {
592             if (wNativeSize == VARIABLESIZE)
593             {
594                 // the unmanaged type size is variable
595                 nativeSize = m_pargs->m_pMT->GetNativeSize();
596             }
597             else
598             {
599                 // the unmanaged type size is fixed
600                 nativeSize = wNativeSize;
601             }
602
603 #if !defined(_TARGET_ARM_) && !(defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING))
604             switch (nativeSize)
605             {
606                 case 1: typ = ELEMENT_TYPE_U1; break;
607                 case 2: typ = ELEMENT_TYPE_U2; break;
608                 case 4: typ = ELEMENT_TYPE_U4; break;
609                 case 8: typ = ELEMENT_TYPE_U8; break;
610                 default: byrefNativeReturn = true; break;
611             }
612 #endif
613         }
614
615         if (IsHresultSwap(dwMarshalFlags) || (byrefNativeReturn && IsCLRToNative(dwMarshalFlags)))
616         {
617             LocalDesc extraParamType = nativeType;
618             extraParamType.MakeByRef();
619
620             m_pcsMarshal->SetStubTargetArgType(&extraParamType, false);
621             
622             if (IsHresultSwap(dwMarshalFlags))
623             {
624                 // HRESULT swapping: the original return value is transformed into an extra
625                 // byref parameter and the target is expected to return an HRESULT
626                 m_pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4);    // native method returns an HRESULT
627             }
628             else
629             {
630                 // byref structure return: the original return value is transformed into an
631                 // extra byref parameter and the target is not expected to return anything
632                 //
633                 // note: we do this only for forward calls because [unmanaged calling conv.
634                 // uses byref return] implies [managed calling conv. uses byref return]
635                 m_pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_VOID);
636             }
637         }
638         else
639         {
640             if (typ != ELEMENT_TYPE_VOID)
641             {
642                 // small structure return: the original return value is transformed into
643                 // ELEMENT_TYPE_U1, ELEMENT_TYPE_U2, ELEMENT_TYPE_U4, or ELEMENT_TYPE_U8
644                 m_pcsMarshal->SetStubTargetReturnType(typ);
645             }
646             else
647             {
648                 m_pcsMarshal->SetStubTargetReturnType(&nativeType);
649             }
650         }
651         
652         m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
653         m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
654
655         EmitCreateMngdMarshaler(m_pcsMarshal);
656
657         if (IsCLRToNative(dwMarshalFlags))
658         {
659             if (IsHresultSwap(dwMarshalFlags) || byrefNativeReturn)
660             {
661                 EmitReInitNative(m_pcsMarshal);
662                 EmitLoadNativeHomeAddr(pcsDispatch);    // load up the byref native type as an extra arg
663             }
664             else
665             {
666                 if (typ != ELEMENT_TYPE_VOID)
667                 {
668                     // small structure forward: the returned integer is memcpy'd into native home
669                     // of the structure
670
671                     DWORD dwTempLocalNum = m_pcsUnmarshal->NewLocal(typ);
672                     m_pcsUnmarshal->EmitSTLOC(dwTempLocalNum);
673                             
674                     // cpblk
675                     m_nativeHome.EmitLoadHomeAddr(m_pcsUnmarshal);
676                     m_pcsUnmarshal->EmitLDLOCA(dwTempLocalNum);
677                     m_pcsUnmarshal->EmitLDC(nativeSize);
678                     m_pcsUnmarshal->EmitCPBLK();
679                 }
680                 else
681                 {
682                     EmitStoreNativeValue(m_pcsUnmarshal);
683                 }
684             }
685
686             if (NeedsMarshalCleanupIndex())
687             {
688                 m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx);
689             }
690
691             EmitConvertSpaceAndContentsNativeToCLR(m_pcsUnmarshal);
692
693             EmitCleanupCLRToNative();
694
695             EmitLoadManagedValue(m_pcsUnmarshal);
696         }
697         else
698         {
699             EmitStoreManagedValue(m_pcsUnmarshal);
700
701             if (NeedsMarshalCleanupIndex())
702             {
703                 m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx);
704             }
705
706             if (IsHresultSwap(dwMarshalFlags))
707             {
708                 // we have to skip unmarshaling return value into the HRESULT-swapped argument
709                 // if the argument came as NULL (otherwise we would leak unmanaged resources as
710                 // we have no way of passing them back to the caller)
711                 ILCodeLabel *pSkipConversionLabel = m_pcsUnmarshal->NewCodeLabel();
712
713                 m_pcsUnmarshal->EmitLDARG(argidx);
714                 m_pcsUnmarshal->EmitBRFALSE(pSkipConversionLabel);
715                 EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
716                 m_pcsUnmarshal->EmitLabel(pSkipConversionLabel);
717             }
718             else
719             {
720                 EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
721             }
722
723             if (NeedsUnmarshalCleanupIndex())
724             {
725                 // if an exception is thrown after this point, we will clean up the unmarshaled retval
726                 m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
727             }
728
729             EmitCleanupNativeToCLR();
730
731             if (IsHresultSwap(dwMarshalFlags))
732             {
733                 // we tolerate NULL here mainly for backward compatibility reasons
734                 m_nativeHome.EmitCopyToByrefArgWithNullCheck(m_pcsUnmarshal, &nativeType, argidx);
735                 m_pcsUnmarshal->EmitLDC(S_OK);
736             }
737             else
738             {
739                 if (typ != ELEMENT_TYPE_VOID)
740                 {
741                     // small structure return (reverse): native home of the structure is memcpy'd
742                     // into the integer to be returned from the stub
743
744                     DWORD dwTempLocalNum = m_pcsUnmarshal->NewLocal(typ);
745                             
746                     // cpblk
747                     m_pcsUnmarshal->EmitLDLOCA(dwTempLocalNum);
748                     m_nativeHome.EmitLoadHomeAddr(m_pcsUnmarshal);
749                     m_pcsUnmarshal->EmitLDC(nativeSize);
750                     m_pcsUnmarshal->EmitCPBLK();
751
752                     m_pcsUnmarshal->EmitLDLOC(dwTempLocalNum);
753                 }
754                 else
755                 {
756                     EmitLoadNativeValue(m_pcsUnmarshal);
757                 }
758             }
759
760             // make sure we free (and zero) the return value if an exception is thrown
761             EmitExceptionCleanupNativeToCLR();
762         }
763     }        
764
765
766 protected:
767
768     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
769     {
770         LIMITED_METHOD_CONTRACT;
771     }
772
773     virtual void EmitLoadMngdMarshaler(ILCodeStream* pslILEmit)
774     {
775         CONTRACTL
776         {
777             THROWS;
778             GC_TRIGGERS;
779             MODE_ANY;
780         }
781         CONTRACTL_END;
782
783         CONSISTENCY_CHECK((DWORD)-1 != m_dwMngdMarshalerLocalNum);
784         pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
785     }
786
787     void EmitSetupSigAndDefaultHomesCLRToNative()
788     {
789         CONTRACTL
790         {
791             STANDARD_VM_CHECK;
792             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
793         }
794         CONTRACTL_END;
795
796         LocalDesc nativeArgType = GetNativeType();
797         DWORD     dwNativeHomeLocalNum = m_pcsMarshal->NewLocal(nativeArgType);
798         m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
799
800         m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILArgument, m_argidx);
801         m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwNativeHomeLocalNum);
802     }
803
804     void EmitCleanupCLRToNativeTemp()
805     {
806         STANDARD_VM_CONTRACT;
807
808         if (NeedsClearNative())
809         {
810             CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
811
812             ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
813             ILCodeLabel*  pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
814
815             m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
816                                                  NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
817                                                  NDirectStubLinker::BranchIfNotMarshaled,
818                                                  pSkipClearNativeLabel);
819
820             EmitClearNativeTemp(pcsCleanup);
821             pcsCleanup->EmitLabel(pSkipClearNativeLabel);
822         }
823     }
824
825     void EmitCleanupCLRToNative()
826     {
827         STANDARD_VM_CONTRACT;
828
829         if (NeedsClearNative())
830         {
831             CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
832
833             ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
834             ILCodeLabel*  pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
835
836             m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
837                                                  NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
838                                                  NDirectStubLinker::BranchIfNotMarshaled,
839                                                  pSkipClearNativeLabel);
840
841             EmitClearNative(pcsCleanup);
842             pcsCleanup->EmitLabel(pSkipClearNativeLabel);
843         }
844     }
845
846     virtual void EmitMarshalArgumentCLRToNative()
847     {
848         CONTRACTL
849         {
850             STANDARD_VM_CHECK;
851             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
852         }
853         CONTRACTL_END;
854
855         EmitSetupSigAndDefaultHomesCLRToNative();
856         EmitMarshalArgumentContentsCLRToNative();
857     }
858
859     void EmitMarshalArgumentContentsCLRToNative()
860     {
861         CONTRACTL
862         {
863             STANDARD_VM_CHECK;
864             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
865         }
866         CONTRACTL_END;
867
868         //
869         // marshal
870         //
871         if (IsIn(m_dwMarshalFlags))
872         {
873             EmitConvertSpaceAndContentsCLRToNativeTemp(m_pcsMarshal);
874         }
875         else
876         {
877             EmitConvertSpaceCLRToNativeTemp(m_pcsMarshal);
878         }
879
880         //
881         // unmarshal
882         //
883         if (IsOut(m_dwMarshalFlags))
884         {
885             if (IsIn(m_dwMarshalFlags))
886             {
887                 EmitClearCLRContents(m_pcsUnmarshal);
888             }
889             EmitConvertContentsNativeToCLR(m_pcsUnmarshal);
890         }
891
892         EmitCleanupCLRToNativeTemp();
893    }
894
895     void EmitSetupSigAndDefaultHomesCLRToNativeByref(bool fBlittable = false)
896     {
897         CONTRACTL
898         {
899             STANDARD_VM_CHECK;
900             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
901         }
902         CONTRACTL_END;
903
904         LocalDesc nativeType = GetNativeType();
905         LocalDesc managedType = GetManagedType();
906
907         LocalDesc nativeArgType = nativeType;
908         nativeArgType.MakeByRef();
909         m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
910
911         if (fBlittable)
912         {
913             // we will not work with the actual data but only with a pointer to that data
914             // (the managed and native type had better be the same if it's blittable)
915             _ASSERTE(nativeType.ElementType[0] == managedType.ElementType[0]);
916
917             // native home will keep the containing object pinned
918             nativeType.MakeByRef();
919             nativeType.MakePinned();
920
921             m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILByrefArgument, m_argidx);
922             m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, m_pcsMarshal->NewLocal(nativeType));
923         }
924         else
925         {
926             m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
927             m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
928         }
929     }
930
931     virtual void EmitMarshalArgumentCLRToNativeByref()
932     {
933         CONTRACTL
934         {
935             STANDARD_VM_CHECK;
936             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
937         }
938         CONTRACTL_END;
939
940         EmitSetupSigAndDefaultHomesCLRToNativeByref();
941         EmitMarshalArgumentContentsCLRToNativeByref(false);
942     }
943
944     void EmitMarshalArgumentContentsCLRToNativeByref(bool managedHomeAlreadyInitialized)
945     {
946         CONTRACTL
947         {
948             STANDARD_VM_CHECK;
949             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
950         }
951         CONTRACTL_END;
952
953         LocalDesc managedType = GetManagedType();
954
955         //
956         // marshal
957         //
958         if (IsIn(m_dwMarshalFlags) && ! IsOut(m_dwMarshalFlags))
959         {
960             if (!managedHomeAlreadyInitialized)
961             {
962                 m_managedHome.EmitCopyFromByrefArg(m_pcsMarshal, &managedType, m_argidx);
963             }
964
965             EmitConvertSpaceAndContentsCLRToNativeTemp(m_pcsMarshal);
966         }
967         else if (IsIn(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags)) 
968         {
969             if (!managedHomeAlreadyInitialized)
970             {
971                 m_managedHome.EmitCopyFromByrefArg(m_pcsMarshal, &managedType, m_argidx);
972             }
973
974             EmitConvertSpaceAndContentsCLRToNative(m_pcsMarshal);
975         }
976         else
977         {
978             EmitReInitNative(m_pcsMarshal);
979         }
980
981         //
982         // unmarshal
983         //
984         if (IsOut(m_dwMarshalFlags))
985         {
986             EmitClearCLR(m_pcsUnmarshal);
987
988             EmitConvertSpaceAndContentsNativeToCLR(m_pcsUnmarshal);
989             
990             if (!managedHomeAlreadyInitialized)
991             {
992                 m_managedHome.EmitCopyToByrefArg(m_pcsUnmarshal, &managedType, m_argidx);
993             }
994
995             EmitCleanupCLRToNative();
996         }
997         else
998         {
999             EmitCleanupCLRToNativeTemp();
1000         }
1001         //
1002         // @TODO: ensure ReInitNative is called on [in,out] byref args when an exception occurs 
1003         //
1004     }
1005
1006     void EmitSetupSigAndDefaultHomesNativeToCLR()
1007     {
1008         CONTRACTL
1009         {
1010             STANDARD_VM_CHECK;
1011             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
1012         }
1013         CONTRACTL_END;
1014         
1015         LocalDesc nativeArgType = GetNativeType();
1016         m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
1017
1018         m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(GetManagedType()));
1019         m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILArgument, m_argidx);
1020     }
1021
1022     void EmitCleanupNativeToCLR()
1023     {
1024         STANDARD_VM_CONTRACT;
1025
1026         if (NeedsClearCLR())
1027         {
1028             CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
1029
1030             ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
1031             ILCodeLabel*  pSkipClearCLRLabel = pcsCleanup->NewCodeLabel();
1032
1033             m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
1034                                                  NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
1035                                                  NDirectStubLinker::BranchIfNotMarshaled,
1036                                                  pSkipClearCLRLabel);
1037
1038             EmitClearCLR(pcsCleanup);
1039             pcsCleanup->EmitLabel(pSkipClearCLRLabel);
1040         }
1041     }
1042
1043     // Emits cleanup code that runs only if an exception is thrown during execution of an IL stub (its try
1044     // block to be precise). The goal is to roll back allocations of native resources that may have already
1045     // happened to prevent leaks, and also clear output arguments to prevent passing out invalid data - most
1046     // importantly dangling pointers. The canonical example is an exception thrown during unmarshaling of
1047     // an argument at which point other arguments have already been unmarshaled.
1048     void EmitExceptionCleanupNativeToCLR()
1049     {
1050         STANDARD_VM_CONTRACT;
1051
1052         _ASSERTE(IsRetval(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags));
1053
1054         LocalDesc nativeType = GetNativeType();
1055         ILCodeStream *pcsCleanup = m_pslNDirect->GetExceptionCleanupCodeStream();
1056
1057         if (NeedsClearNative())
1058         {
1059             m_pslNDirect->SetExceptionCleanupNeeded();
1060
1061             ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
1062
1063             // if this is byref in/out and we have not marshaled this argument
1064             // yet, we need to populate the native home with the incoming value
1065             if (IsIn(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags))
1066             {
1067                 ILCodeLabel *pSkipCopyLabel = pcsCleanup->NewCodeLabel();
1068
1069                 CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
1070                 m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
1071                                                      NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
1072                                                      NDirectStubLinker::BranchIfMarshaled,
1073                                                      pSkipCopyLabel);
1074
1075                 pcsCleanup->EmitLDARG(m_argidx);
1076                 pcsCleanup->EmitBRFALSE(pSkipCleanupLabel); // if the argument is NULL, skip cleanup completely
1077
1078                 m_nativeHome.EmitCopyFromByrefArg(pcsCleanup, &nativeType, m_argidx);
1079
1080                 pcsCleanup->EmitLabel(pSkipCopyLabel);
1081             }
1082
1083             // if this is retval or out-only, the native home does not get initialized until we unmarshal it
1084             if (IsRetval(m_dwMarshalFlags) || !IsIn(m_dwMarshalFlags))
1085             {
1086                 CONSISTENCY_CHECK(NeedsUnmarshalCleanupIndex());
1087
1088                 UINT uArgIdx = (IsRetval(m_dwMarshalFlags) ?
1089                     NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL :
1090                     NDirectStubLinker::CLEANUP_INDEX_ARG0_UNMARSHAL + m_argidx);
1091
1092                 m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
1093                                                      uArgIdx,
1094                                                      NDirectStubLinker::BranchIfNotMarshaled,
1095                                                      pSkipCleanupLabel);
1096             }
1097
1098             // we know that native home needs to be cleaned up at this point
1099             if (IsRetval(m_dwMarshalFlags) || (IsOut(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags)))
1100             {
1101                 // we own the buffer - clear everything
1102                 EmitClearNative(pcsCleanup);
1103             }
1104             else
1105             {
1106                 // this is a caller supplied buffer - clear only its contents
1107                 EmitClearNativeContents(pcsCleanup);
1108             }
1109
1110             pcsCleanup->EmitLabel(pSkipCleanupLabel);
1111         }
1112
1113         // if there is an output buffer, zero it out so the caller does not get pointer to already freed data
1114         if (!IsHiddenLengthParam(m_dwMarshalFlags))
1115         {
1116             if (IsRetval(m_dwMarshalFlags) || (IsOut(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags)))
1117             {
1118                 m_pslNDirect->SetExceptionCleanupNeeded();
1119
1120                 EmitReInitNative(pcsCleanup);
1121                 if (IsHresultSwap(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags))
1122                 {
1123                     m_nativeHome.EmitCopyToByrefArgWithNullCheck(pcsCleanup, &nativeType, m_argidx);
1124                 }
1125             }
1126         }
1127     }
1128
1129     virtual void EmitMarshalArgumentNativeToCLR()
1130     {
1131         CONTRACTL
1132         {
1133             STANDARD_VM_CHECK;
1134             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
1135         }
1136         CONTRACTL_END;
1137                     
1138         EmitSetupSigAndDefaultHomesNativeToCLR();
1139         EmitMarshalArgumentContentsNativeToCLR();
1140     }
1141
1142     void EmitMarshalArgumentContentsNativeToCLR()
1143     {
1144         CONTRACTL
1145         {
1146             STANDARD_VM_CHECK;
1147             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
1148         }
1149         CONTRACTL_END;
1150
1151         //
1152         // marshal
1153         //
1154         if (IsIn(m_dwMarshalFlags))
1155         {
1156             EmitConvertSpaceAndContentsNativeToCLR(m_pcsMarshal);
1157         }
1158         else
1159         {
1160             EmitConvertSpaceNativeToCLR(m_pcsMarshal);
1161         }
1162
1163         //
1164         // unmarshal
1165         //
1166         if (IsOut(m_dwMarshalFlags))
1167         {
1168             if (IsIn(m_dwMarshalFlags))
1169             {
1170                 EmitClearNativeContents(m_pcsUnmarshal);
1171             }
1172             EmitConvertContentsCLRToNative(m_pcsUnmarshal);
1173
1174             // make sure we free the argument if an exception is thrown
1175             EmitExceptionCleanupNativeToCLR();
1176         }
1177         EmitCleanupNativeToCLR();
1178     }
1179
1180     void EmitSetupSigAndDefaultHomesNativeToCLRByref(bool fBlittable = false)
1181     {
1182         CONTRACTL
1183         {
1184             STANDARD_VM_CHECK;
1185             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
1186         }
1187         CONTRACTL_END;
1188     
1189         LocalDesc nativeType = GetNativeType();
1190         LocalDesc managedType = GetManagedType();
1191         LocalDesc nativeArgType = nativeType;
1192         nativeArgType.MakeByRef();
1193         m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
1194
1195         if (fBlittable)
1196         {
1197             // we will not work with the actual data but only with a pointer to that data
1198             // (the managed and native type had better be the same if it's blittable)
1199             _ASSERTE(nativeType.ElementType[0] == managedType.ElementType[0]);
1200
1201             managedType.MakeByRef();
1202
1203             m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, m_pcsMarshal->NewLocal(managedType));
1204             m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefArgument, m_argidx);
1205         }
1206         else
1207         {
1208             m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
1209             m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
1210         }
1211     }
1212
1213     virtual void EmitMarshalArgumentNativeToCLRByref()
1214     {
1215         CONTRACTL
1216         {
1217             STANDARD_VM_CHECK;
1218             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
1219         }
1220         CONTRACTL_END;
1221         
1222         EmitSetupSigAndDefaultHomesNativeToCLRByref();
1223         EmitMarshalArgumentContentsNativeToCLRByref(false);
1224     }
1225
1226     void EmitMarshalArgumentContentsNativeToCLRByref(bool nativeHomeAlreadyInitialized)
1227     {
1228         CONTRACTL
1229         {
1230             STANDARD_VM_CHECK;
1231             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
1232         }
1233         CONTRACTL_END;
1234
1235         LocalDesc nativeType = GetNativeType();
1236
1237         //
1238         // marshal
1239         //
1240         if (IsIn(m_dwMarshalFlags))
1241         {
1242             if (!nativeHomeAlreadyInitialized)
1243             {
1244                 m_nativeHome.EmitCopyFromByrefArg(m_pcsMarshal, &nativeType, m_argidx);
1245             }
1246
1247             EmitConvertSpaceAndContentsNativeToCLR(m_pcsMarshal);
1248         }
1249         else
1250         {
1251             // dereference the argument so we throw before calling the managed target - this is the fastest way
1252             // to check for NULL (we can still throw later if the pointer is invalid yet non-NULL but we cannot
1253             // detect this realiably - the memory may get unmapped etc., NULL check is the best we can do here)
1254             m_pcsMarshal->EmitLDARG(m_argidx);
1255             m_pcsMarshal->EmitLDIND_I1();
1256             m_pcsMarshal->EmitPOP();
1257         }
1258         
1259         //
1260         // unmarshal
1261         //
1262         if (IsOut(m_dwMarshalFlags))
1263         {
1264             if (IsIn(m_dwMarshalFlags))
1265             {
1266                 EmitClearNative(m_pcsUnmarshal);
1267                 EmitReInitNative(m_pcsUnmarshal);
1268             }
1269
1270             EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
1271
1272             if (!nativeHomeAlreadyInitialized)
1273             {
1274                 m_nativeHome.EmitCopyToByrefArg(m_pcsUnmarshal, &nativeType, m_argidx);
1275             }
1276
1277             // make sure we free and zero the by-ref argument if an exception is thrown
1278             EmitExceptionCleanupNativeToCLR();
1279         }
1280
1281         EmitCleanupNativeToCLR();
1282     }
1283
1284     virtual LocalDesc GetNativeType() = 0;
1285     virtual LocalDesc GetManagedType() = 0;
1286
1287     //
1288     // Native-to-CLR
1289     //
1290     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
1291     {
1292         LIMITED_METHOD_CONTRACT;
1293     }
1294         
1295     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1296     {
1297         LIMITED_METHOD_CONTRACT;
1298     }
1299
1300     virtual void EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit)
1301     {
1302         WRAPPER_NO_CONTRACT;
1303         EmitConvertSpaceNativeToCLR(pslILEmit);
1304         EmitConvertContentsNativeToCLR(pslILEmit);
1305     }
1306
1307
1308     //
1309     // CLR-to-Native
1310     //
1311     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
1312     {
1313         LIMITED_METHOD_CONTRACT;
1314     }
1315
1316     virtual void EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit)
1317     {
1318         LIMITED_METHOD_CONTRACT;
1319         EmitConvertSpaceCLRToNative(pslILEmit);
1320     }
1321
1322     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1323     {
1324         LIMITED_METHOD_CONTRACT;
1325     }
1326     
1327     virtual void EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
1328     {
1329         STANDARD_VM_CONTRACT;
1330         EmitConvertSpaceCLRToNative(pslILEmit);
1331         EmitConvertContentsCLRToNative(pslILEmit);
1332     }
1333         
1334     virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
1335     {
1336         WRAPPER_NO_CONTRACT;
1337         EmitConvertSpaceAndContentsCLRToNative(pslILEmit);
1338     }
1339
1340     //
1341     // Misc
1342     //
1343     virtual void EmitClearCLRContents(ILCodeStream* pslILEmit)
1344     {
1345         LIMITED_METHOD_CONTRACT;
1346     }
1347
1348     virtual bool NeedsClearNative()
1349     {
1350         LIMITED_METHOD_CONTRACT;
1351         return false;
1352     }
1353
1354     virtual void EmitClearNative(ILCodeStream* pslILEmit)
1355     {
1356         LIMITED_METHOD_CONTRACT;
1357     }
1358
1359     virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit)
1360     {
1361         LIMITED_METHOD_CONTRACT;
1362         EmitClearNative(pslILEmit);
1363     }
1364
1365     virtual void EmitClearNativeContents(ILCodeStream* pslILEmit)
1366     {
1367         LIMITED_METHOD_CONTRACT;
1368     }
1369
1370     virtual bool NeedsClearCLR()
1371     {
1372         LIMITED_METHOD_CONTRACT;
1373         return false;
1374     }
1375
1376     virtual void EmitClearCLR(ILCodeStream* pslILEmit)
1377     {
1378         LIMITED_METHOD_CONTRACT;
1379     }
1380
1381     virtual void EmitReInitNative(ILCodeStream* pslILEmit)
1382     {
1383         STANDARD_VM_CONTRACT;
1384
1385         // Friendly Reminder:
1386         // You should implement your own EmitReInitNative if your native type is a struct,
1387         // as the following instructions apparently won't work on value types and will trigger
1388         // an ASSERT in JIT
1389         _ASSERTE(!GetNativeType().IsValueClass());
1390         
1391         pslILEmit->EmitLDC(0);
1392         pslILEmit->EmitCONV_T(static_cast<CorElementType>(GetNativeType().ElementType[0]));
1393
1394         EmitStoreNativeValue(pslILEmit);
1395     }
1396
1397     virtual bool IsManagedPassedByRef()
1398     {
1399         LIMITED_METHOD_CONTRACT;
1400         return IsByref(m_dwMarshalFlags);
1401     }
1402
1403     virtual bool IsNativePassedByRef()
1404     {
1405         LIMITED_METHOD_CONTRACT;
1406         return IsByref(m_dwMarshalFlags);
1407     }
1408
1409     void EmitInterfaceClearNative(ILCodeStream* pslILEmit);
1410
1411 public:
1412     static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
1413                                                     BOOL               byref,
1414                                                     BOOL               fin,
1415                                                     BOOL               fout,
1416                                                     BOOL               fManagedToNative,
1417                                                     OverrideProcArgs*  pargs,
1418                                                     UINT*              pResID,
1419                                                     UINT               argidx,
1420                                                     UINT               nativeStackOffset)
1421     {
1422         LIMITED_METHOD_CONTRACT;
1423         return HANDLEASNORMAL;
1424     }
1425
1426     static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker*  psl,
1427                                                   BOOL                fManagedToNative,
1428                                                   BOOL                fHresultSwap,
1429                                                   OverrideProcArgs*   pargs,
1430                                                   UINT*               pResID)
1431     {
1432         LIMITED_METHOD_CONTRACT;
1433         return HANDLEASNORMAL;
1434     }
1435 };
1436
1437         
1438 class ILCopyMarshalerBase : public ILMarshaler
1439 {
1440     virtual LocalDesc GetManagedType()
1441     {
1442         WRAPPER_NO_CONTRACT;
1443         return GetNativeType();
1444     }
1445
1446     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1447     {
1448         STANDARD_VM_CONTRACT;
1449
1450         EmitLoadManagedValue(pslILEmit);
1451         EmitStoreNativeValue(pslILEmit);
1452     }
1453
1454     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1455     {
1456         STANDARD_VM_CONTRACT;
1457
1458         EmitLoadNativeValue(pslILEmit);
1459         EmitStoreManagedValue(pslILEmit);
1460     }
1461
1462     //
1463     // It's very unforunate that x86 used ML_COPYPINNEDGCREF for byref args.
1464     // The result is that developers can get away with being lazy about their 
1465     // in/out semantics and often times in/out byref params are marked out-
1466     // only, but because of ML_COPYPINNEDGCREF, they get in/out behavior.  
1467     //
1468     // There are even lazier developers who use byref params to pass arrays.
1469     // Pinning ensures that the native side 'sees' the entire array even when
1470     // only reference to one element was passed.
1471     // 
1472     // This method was changed to pin instead of copy in Dev10 in order
1473     // to match the original ML behavior.
1474     //
1475     virtual void EmitMarshalArgumentCLRToNativeByref()
1476     {
1477         CONTRACTL
1478         {
1479             STANDARD_VM_CHECK;
1480             PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
1481         }
1482         CONTRACTL_END;
1483
1484         EmitSetupSigAndDefaultHomesCLRToNativeByref(true);
1485             
1486         //
1487         // marshal
1488         //
1489         EmitLoadManagedHomeAddr(m_pcsMarshal);
1490         EmitStoreNativeHomeAddr(m_pcsMarshal);
1491         
1492         //
1493         // no unmarshaling is necessary since we directly passed the pinned byref to native,
1494         // the argument is therefore automatically in/out
1495         //
1496     }
1497
1498     //
1499     // Similarly to the other direction, ML used ML_COPYPINNEDGCREF on x86 to
1500     // directly pass the unmanaged pointer as a byref argument to managed code.
1501     // This also makes an observable difference (allows passing NULL, changes
1502     // made to the original value during the call are visible in managed).
1503     //
1504     // This method was changed to pass pointer instead of copy in Dev10 in order
1505     // to match the original ML behavior. Note that in this direction we don't
1506     // need to pin the pointer - if it is pointing to GC heap, it must have been
1507     // pinned on the way to unmanaged.
1508     //
1509     virtual void EmitMarshalArgumentNativeToCLRByref()
1510     {
1511         CONTRACTL
1512         {
1513             STANDARD_VM_CHECK;
1514             PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
1515         }
1516         CONTRACTL_END;
1517
1518         EmitSetupSigAndDefaultHomesNativeToCLRByref(true);
1519             
1520         //
1521         // marshal
1522         //
1523         EmitLoadNativeHomeAddr(m_pcsMarshal);
1524         EmitStoreManagedHomeAddr(m_pcsMarshal);
1525         
1526         //
1527         // no unmarshaling is necessary since we directly passed the pointer to managed
1528         // as a byref, the argument is therefore automatically in/out
1529         //
1530     }
1531 };
1532
1533 template <CorElementType ELEMENT_TYPE, class PROMOTED_ELEMENT>
1534 class ILCopyMarshalerSimple : public ILCopyMarshalerBase
1535 {
1536 public:
1537     enum
1538     {
1539         c_fInOnly               = TRUE,
1540         c_nativeSize            = sizeof(PROMOTED_ELEMENT),
1541         c_CLRSize               = sizeof(PROMOTED_ELEMENT),
1542     };
1543
1544     bool IsSmallValueTypeSpecialCase()
1545     {
1546         //
1547         // Special case for small value types that get
1548         // mapped to MARSHAL_TYPE_GENERIC_8 -- use the 
1549         // valuetype type so the JIT is happy.
1550         //
1551         
1552         return (ELEMENT_TYPE == 
1553 #ifdef _WIN64        
1554                     ELEMENT_TYPE_I8
1555 #else // _WIN64
1556                     ELEMENT_TYPE_I4
1557 #endif // _WIN64
1558                     ) && (NULL != m_pargs->m_pMT);
1559     }
1560     
1561     bool NeedToPromoteTo8Bytes()
1562     {
1563         WRAPPER_NO_CONTRACT;
1564
1565 #if defined(_TARGET_AMD64_)
1566         // If the argument is passed by value, 
1567         if (!IsByref(m_dwMarshalFlags) && !IsRetval(m_dwMarshalFlags))
1568         {
1569             // and it is an I4 or an U4, 
1570             if ( (ELEMENT_TYPE == ELEMENT_TYPE_I4) ||
1571                  (ELEMENT_TYPE == ELEMENT_TYPE_U4) )
1572             {
1573                 // and we are doing a managed-to-unmanaged call,
1574                 if (IsCLRToNative(m_dwMarshalFlags))
1575                 {
1576                     // then we have to promote the native argument type to an I8 or an U8.
1577                     return true;
1578                 }
1579             }
1580         }
1581 #endif // _TARGET_AMD64_
1582
1583         return false;
1584     }
1585
1586     CorElementType GetConversionType(CorElementType type)
1587     {
1588         LIMITED_METHOD_CONTRACT;
1589
1590         // I4 <-> I8; U4 <-> U8
1591         if (type == ELEMENT_TYPE_I4)
1592         {
1593             return ELEMENT_TYPE_I8;
1594         }
1595         else if (type == ELEMENT_TYPE_U4)
1596         {
1597             return ELEMENT_TYPE_U8;
1598         }
1599         else
1600         {
1601             return ELEMENT_TYPE_END;
1602         }
1603     }
1604
1605     void EmitTypePromotion(ILCodeStream* pslILEmit)
1606     {
1607         WRAPPER_NO_CONTRACT;
1608
1609         CorElementType promotedType = GetConversionType(ELEMENT_TYPE);
1610         if (promotedType == ELEMENT_TYPE_I8)
1611         {
1612             pslILEmit->EmitCONV_I8();
1613         }
1614         else if (promotedType == ELEMENT_TYPE_U8)
1615         {
1616             pslILEmit->EmitCONV_U8();
1617         }
1618     }
1619
1620     virtual LocalDesc GetNativeType()
1621     {
1622         WRAPPER_NO_CONTRACT;
1623         
1624         if (NeedToPromoteTo8Bytes())
1625         {
1626             return LocalDesc(GetConversionType(ELEMENT_TYPE));
1627         }
1628         else
1629         {
1630             return GetManagedType();
1631         }
1632     }
1633
1634     virtual LocalDesc GetManagedType()
1635     {
1636         WRAPPER_NO_CONTRACT;
1637
1638         if (IsSmallValueTypeSpecialCase())
1639         {
1640             return LocalDesc(m_pargs->m_pMT);
1641         }
1642         else
1643         {
1644             return LocalDesc(ELEMENT_TYPE);
1645         }
1646     }
1647
1648     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1649     {
1650         STANDARD_VM_CONTRACT;
1651
1652         EmitLoadManagedValue(pslILEmit);
1653         if (NeedToPromoteTo8Bytes())
1654         {
1655             EmitTypePromotion(pslILEmit);
1656         }
1657         EmitStoreNativeValue(pslILEmit);
1658     }
1659
1660     virtual void EmitReInitNative(ILCodeStream* pslILEmit)
1661     {
1662         STANDARD_VM_CONTRACT;
1663
1664         if (IsSmallValueTypeSpecialCase())
1665         {
1666             EmitLoadNativeHomeAddr(pslILEmit);
1667             pslILEmit->EmitINITOBJ(pslILEmit->GetToken(m_pargs->m_pMT));
1668         }
1669         else
1670         {
1671             // ldc.i4.0, conv.i8/u8/r4/r8 is shorter than ldc.i8/r4/r8 0
1672             pslILEmit->EmitLDC(0);
1673             pslILEmit->EmitCONV_T(ELEMENT_TYPE);
1674
1675             EmitStoreNativeValue(pslILEmit);
1676         }
1677     }
1678 };
1679
1680 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I1, INT_PTR>  ILCopyMarshaler1;
1681 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U1, UINT_PTR> ILCopyMarshalerU1;
1682 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I2, INT_PTR>  ILCopyMarshaler2;
1683 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U2, UINT_PTR> ILCopyMarshalerU2;
1684 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I4, INT_PTR>  ILCopyMarshaler4;
1685 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U4, UINT_PTR> ILCopyMarshalerU4;
1686 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I8, INT64>    ILCopyMarshaler8;
1687 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R4, float>    ILFloatMarshaler;
1688 typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R8, double>   ILDoubleMarshaler;
1689
1690 template <BinderClassID CLASS__ID, class PROMOTED_ELEMENT>
1691 class ILCopyMarshalerKnownStruct : public ILCopyMarshalerBase
1692 {
1693 public:
1694     enum
1695     {
1696         c_fInOnly               = TRUE,
1697         c_nativeSize            = sizeof(PROMOTED_ELEMENT),
1698         c_CLRSize               = sizeof(PROMOTED_ELEMENT),
1699     };
1700
1701     virtual void EmitReInitNative(ILCodeStream* pslILEmit)
1702     {
1703         STANDARD_VM_CONTRACT;
1704         
1705         EmitLoadNativeHomeAddr(pslILEmit);
1706         pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID)));
1707     }
1708
1709     virtual LocalDesc GetNativeType()
1710     {
1711         STANDARD_VM_CONTRACT;
1712
1713         return LocalDesc(MscorlibBinder::GetClass(CLASS__ID));
1714     }
1715 };
1716
1717 typedef ILCopyMarshalerKnownStruct<CLASS__DECIMAL, DECIMAL> ILDecimalMarshaler;
1718 typedef ILCopyMarshalerKnownStruct<CLASS__GUID, GUID> ILGuidMarshaler;
1719
1720 class ILBlittableValueClassMarshaler : public ILCopyMarshalerBase
1721 {
1722 public:
1723     enum
1724     {
1725         c_fInOnly               = TRUE,
1726         c_nativeSize            = VARIABLESIZE,
1727         c_CLRSize               = VARIABLESIZE,
1728     };
1729         
1730     virtual void EmitReInitNative(ILCodeStream* pslILEmit)
1731     {
1732         STANDARD_VM_CONTRACT;
1733         
1734         EmitLoadNativeHomeAddr(pslILEmit);
1735         pslILEmit->EmitINITOBJ(pslILEmit->GetToken(m_pargs->m_pMT));
1736     }
1737
1738     virtual LocalDesc GetNativeType()
1739     {
1740         LIMITED_METHOD_CONTRACT;
1741         
1742         return LocalDesc(m_pargs->m_pMT);
1743     }
1744 };
1745
1746
1747 class ILDelegateMarshaler : public ILMarshaler
1748 {
1749 public:
1750     enum
1751     {
1752         c_fInOnly               = TRUE,
1753         c_nativeSize            = sizeof(void *),
1754         c_CLRSize               = sizeof(OBJECTREF),
1755     };
1756
1757 protected:
1758     virtual LocalDesc GetNativeType();
1759     virtual LocalDesc GetManagedType();
1760     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1761     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1762 };
1763
1764 class ILReflectionObjectMarshaler : public ILMarshaler
1765 {
1766 public:
1767     enum
1768     {
1769         c_fInOnly               = TRUE,
1770         c_nativeSize            = sizeof(void *),
1771         c_CLRSize               = sizeof(OBJECTREF),
1772     };
1773
1774 protected:
1775     virtual LocalDesc GetManagedType();
1776     virtual LocalDesc GetNativeType();
1777     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1778     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1779     virtual BinderFieldID GetStructureFieldID() {LIMITED_METHOD_CONTRACT; return (BinderFieldID)0;}
1780     virtual BinderFieldID GetObjectFieldID() = 0;
1781     virtual BinderClassID GetManagedTypeBinderID() = 0;
1782 };
1783
1784 class ILIRuntimeMethodInfoMarshaler : public ILReflectionObjectMarshaler
1785 {
1786 protected:
1787     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__STUBMETHODINFO__HANDLE; }
1788     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__STUBMETHODINFO; }
1789 };
1790
1791 class ILRuntimeModuleMarshaler : public ILReflectionObjectMarshaler
1792 {
1793 protected:
1794     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__MODULE__DATA; }
1795     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__MODULE; }
1796 };
1797
1798 class ILRuntimeAssemblyMarshaler : public ILReflectionObjectMarshaler
1799 {
1800 protected:
1801     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__ASSEMBLY__HANDLE; }
1802     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__ASSEMBLY; }
1803 };
1804
1805 class ILRuntimeTypeHandleMarshaler : public ILReflectionObjectMarshaler
1806 {
1807 protected:
1808     virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__RT_TYPE_HANDLE__M_TYPE; }
1809     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__CLASS__TYPEHANDLE; }
1810     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__RT_TYPE_HANDLE; }
1811 };
1812
1813 class ILRuntimeMethodHandleMarshaler : public ILReflectionObjectMarshaler
1814 {
1815 protected:
1816     virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__METHOD_HANDLE__METHOD; }
1817     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__STUBMETHODINFO__HANDLE; }
1818     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__METHOD_HANDLE; }
1819 };
1820
1821 class ILRuntimeFieldHandleMarshaler : public ILReflectionObjectMarshaler
1822 {
1823 protected:
1824     virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__FIELD_HANDLE__M_FIELD; }
1825     virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__RT_FIELD_INFO__HANDLE; }
1826     virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__FIELD_HANDLE; }
1827 };
1828
1829 class ILBoolMarshaler : public ILMarshaler
1830 {
1831 public:
1832
1833     virtual CorElementType GetNativeBoolElementType() = 0;
1834     virtual int GetNativeTrueValue() = 0;
1835     virtual int GetNativeFalseValue() = 0;
1836
1837 protected:
1838     virtual LocalDesc GetNativeType();
1839     virtual LocalDesc GetManagedType();
1840     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1841     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1842 };
1843
1844 class ILWinBoolMarshaler : public ILBoolMarshaler
1845 {
1846 public:
1847     enum
1848     {
1849         c_fInOnly               = TRUE,
1850         c_nativeSize            = sizeof(BOOL),
1851         c_CLRSize               = sizeof(INT8),
1852     };
1853         
1854 protected:    
1855     virtual CorElementType GetNativeBoolElementType()
1856     {
1857         LIMITED_METHOD_CONTRACT;
1858         return ELEMENT_TYPE_I4;
1859     }
1860
1861     virtual int GetNativeTrueValue()
1862     {
1863         LIMITED_METHOD_CONTRACT;
1864         return 1;
1865     }
1866         
1867     virtual int GetNativeFalseValue()
1868     {
1869         LIMITED_METHOD_CONTRACT;
1870         return 0;
1871     }
1872 };
1873
1874 class ILCBoolMarshaler : public ILBoolMarshaler
1875 {
1876 public:
1877     enum
1878     {
1879         c_fInOnly               = TRUE,
1880         c_nativeSize            = sizeof(BYTE),
1881         c_CLRSize               = sizeof(INT8),
1882     };
1883
1884 protected:
1885     virtual CorElementType GetNativeBoolElementType()
1886     {
1887         LIMITED_METHOD_CONTRACT;
1888         return ELEMENT_TYPE_I1;
1889     }
1890
1891     virtual int GetNativeTrueValue()
1892     {
1893         LIMITED_METHOD_CONTRACT;
1894         return 1;
1895     }
1896                 
1897     virtual int GetNativeFalseValue()
1898     {
1899         LIMITED_METHOD_CONTRACT;
1900         return 0;
1901     }
1902 };
1903
1904 #ifdef FEATURE_COMINTEROP
1905 class ILVtBoolMarshaler : public ILBoolMarshaler
1906 {
1907 public:    
1908     enum
1909     {
1910         c_fInOnly               = TRUE,
1911         c_nativeSize            = sizeof(VARIANT_BOOL),
1912         c_CLRSize               = sizeof(INT8),
1913     };
1914
1915 protected:    
1916     virtual CorElementType GetNativeBoolElementType()
1917     {
1918         LIMITED_METHOD_CONTRACT;
1919         return ELEMENT_TYPE_I2;
1920     }
1921
1922     virtual int GetNativeTrueValue()
1923     {
1924         LIMITED_METHOD_CONTRACT;
1925         return VARIANT_TRUE;
1926     }
1927
1928     virtual int GetNativeFalseValue()
1929     {
1930         LIMITED_METHOD_CONTRACT;
1931         return VARIANT_FALSE;
1932     }
1933 };
1934 #endif // FEATURE_COMINTEROP
1935
1936 class ILWSTRMarshaler : public ILMarshaler
1937 {
1938 public:
1939     enum
1940     {
1941         c_fInOnly               = TRUE,
1942         c_nativeSize            = sizeof(void *),
1943         c_CLRSize               = sizeof(OBJECTREF),
1944     };
1945
1946 #ifdef _DEBUG
1947     bool m_fCoMemoryAllocated;
1948
1949     ILWSTRMarshaler()
1950     {
1951         LIMITED_METHOD_CONTRACT;
1952         m_fCoMemoryAllocated = false;
1953     }
1954 #endif // _DEBUG
1955
1956 protected:
1957     virtual LocalDesc GetNativeType();
1958     virtual LocalDesc GetManagedType();
1959
1960     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
1961     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1962     virtual void EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit);
1963     virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
1964
1965     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
1966     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1967     virtual void EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit);
1968
1969     virtual bool NeedsClearNative();
1970     virtual void EmitClearNative(ILCodeStream* pslILEmit);
1971     virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
1972
1973     static bool CanUsePinnedManagedString(DWORD dwMarshalFlags);
1974     static void EmitCheckManagedStringLength(ILCodeStream* pslILEmit);
1975     static void EmitCheckNativeStringLength(ILCodeStream* pslILEmit);
1976 };
1977
1978 // A marshaler that makes run-time decision based on argument size whether native space will
1979 // be allocated using localloc or on the heap. The ctor argument is a heap free function.
1980 class ILOptimizedAllocMarshaler : public ILMarshaler
1981 {
1982 public:
1983     ILOptimizedAllocMarshaler(BinderMethodID clearNat) :
1984         m_idClearNative(clearNat),
1985         m_dwLocalBuffer((DWORD)-1)
1986     {
1987         LIMITED_METHOD_CONTRACT;
1988     }
1989
1990     virtual LocalDesc GetNativeType();
1991     virtual bool NeedsClearNative();
1992     virtual void EmitClearNative(ILCodeStream* pslILEmit);
1993
1994 protected:
1995     const BinderMethodID m_idClearNative;
1996     DWORD m_dwLocalBuffer;      // localloc'ed temp buffer variable or -1 if not used
1997 };
1998
1999 class ILUTF8BufferMarshaler : public ILOptimizedAllocMarshaler
2000 {
2001 public:
2002         enum
2003         {
2004                 c_fInOnly = FALSE,
2005                 c_nativeSize = sizeof(void *),
2006                 c_CLRSize = sizeof(OBJECTREF),
2007         };
2008
2009         enum
2010         {
2011                 // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2012                 MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
2013         };
2014
2015         ILUTF8BufferMarshaler() :
2016                 ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
2017         {
2018                 LIMITED_METHOD_CONTRACT;
2019         }
2020
2021         virtual LocalDesc GetManagedType();
2022         virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2023         virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2024         virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2025         virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2026 };
2027
2028 class ILWSTRBufferMarshaler : public ILOptimizedAllocMarshaler
2029 {
2030 public:
2031     enum
2032     {
2033         c_fInOnly               = FALSE,
2034         c_nativeSize            = sizeof(void *),
2035         c_CLRSize               = sizeof(OBJECTREF),
2036     };
2037
2038     enum
2039     {
2040         // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2041         MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2
2042     };
2043
2044     ILWSTRBufferMarshaler() :
2045         ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
2046     {
2047         LIMITED_METHOD_CONTRACT;
2048     }
2049
2050     virtual LocalDesc GetManagedType();
2051     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2052     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2053     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2054     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2055 };
2056
2057 class ILCSTRBufferMarshaler : public ILOptimizedAllocMarshaler
2058 {
2059 public:
2060     enum
2061     {
2062         c_fInOnly               = FALSE,
2063         c_nativeSize            = sizeof(void *),
2064         c_CLRSize               = sizeof(OBJECTREF),
2065     };
2066
2067     enum
2068     {
2069         // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2070         MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
2071     };
2072
2073     ILCSTRBufferMarshaler() :
2074         ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
2075     {
2076         LIMITED_METHOD_CONTRACT;
2077     }
2078
2079     virtual LocalDesc GetManagedType();
2080     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2081     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2082     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2083     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2084 };
2085
2086         
2087 class ILHandleRefMarshaler : public ILMarshaler
2088 {
2089     // Managed layout for SRI.HandleRef class
2090     struct HANDLEREF
2091     {
2092         OBJECTREF m_wrapper;
2093         LPVOID    m_handle;
2094     };
2095
2096 public:
2097     enum
2098     {
2099         c_fInOnly               = FALSE,
2100         c_nativeSize            = sizeof(LPVOID),
2101         c_CLRSize               = sizeof(HANDLEREF),
2102     };
2103         
2104     LocalDesc GetManagedType()
2105     {
2106         LIMITED_METHOD_CONTRACT;
2107         return LocalDesc();
2108     }
2109         
2110     LocalDesc GetNativeType()
2111     {
2112         LIMITED_METHOD_CONTRACT;
2113         return LocalDesc();
2114     }
2115
2116     static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
2117                                                     BOOL               byref,
2118                                                     BOOL               fin,
2119                                                     BOOL               fout,
2120                                                     BOOL               fManagedToNative,
2121                                                     OverrideProcArgs*  pargs,
2122                                                     UINT*              pResID,
2123                                                     UINT               argidx,
2124                                                     UINT               nativeStackOffset);
2125
2126     static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker* psl,
2127                                                   BOOL               fManagedToNative,
2128                                                   BOOL               fHresultSwap,
2129                                                   OverrideProcArgs*  pargs,
2130                                                   UINT*              pResID);
2131 };
2132
2133 class ILSafeHandleMarshaler : public ILMarshaler
2134 {
2135 public:
2136     enum
2137     {
2138         c_fInOnly               = FALSE,
2139         c_nativeSize            = sizeof(LPVOID),
2140         c_CLRSize               = sizeof(SAFEHANDLE),
2141     };
2142
2143     virtual LocalDesc GetManagedType();
2144     virtual LocalDesc GetNativeType();
2145
2146     virtual bool NeedsClearNative();
2147     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2148
2149     virtual void EmitMarshalArgumentCLRToNative();
2150
2151     static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
2152                                                     BOOL               byref,
2153                                                     BOOL               fin,
2154                                                     BOOL               fout,
2155                                                     BOOL               fManagedToNative,
2156                                                     OverrideProcArgs*  pargs,
2157                                                     UINT*              pResID,
2158                                                     UINT               argidx,
2159                                                     UINT               nativeStackOffset);
2160         
2161     static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl,
2162                                                   BOOL        fManagedToNative,
2163                                                   BOOL        fHresultSwap,
2164                                                   OverrideProcArgs *pargs,
2165                                                   UINT       *pResID);
2166 };
2167
2168
2169 class ILCriticalHandleMarshaler : public ILMarshaler
2170 {
2171 public:
2172     enum
2173     {
2174         c_fInOnly               = FALSE,
2175         c_nativeSize            = sizeof(LPVOID),
2176         c_CLRSize               = sizeof(CRITICALHANDLE),
2177     };
2178         
2179 public:
2180
2181     LocalDesc GetManagedType()
2182     {
2183         LIMITED_METHOD_CONTRACT;
2184         return LocalDesc();
2185     }
2186     
2187     LocalDesc GetNativeType()
2188     {
2189         LIMITED_METHOD_CONTRACT;
2190         return LocalDesc();
2191     }
2192     
2193     static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
2194                                                     BOOL               byref,
2195                                                     BOOL               fin,
2196                                                     BOOL               fout,
2197                                                     BOOL               fManagedToNative,
2198                                                     OverrideProcArgs*  pargs,
2199                                                     UINT*              pResID,
2200                                                     UINT               argidx,
2201                                                     UINT               nativeStackOffset);
2202
2203     static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl,
2204                                                   BOOL        fManagedToNative,
2205                                                   BOOL        fHresultSwap,
2206                                                   OverrideProcArgs *pargs,
2207                                                   UINT       *pResID);
2208 };
2209
2210
2211 class ILValueClassMarshaler : public ILMarshaler
2212 {
2213 public:
2214     enum
2215     {
2216         c_fInOnly               = TRUE,
2217         c_nativeSize            = VARIABLESIZE,
2218         c_CLRSize               = VARIABLESIZE,
2219     };
2220
2221 protected:
2222     virtual LocalDesc GetNativeType();
2223     virtual LocalDesc GetManagedType();
2224     virtual void EmitReInitNative(ILCodeStream* pslILEmit);
2225     virtual bool NeedsClearNative();
2226     virtual void EmitClearNative(ILCodeStream * pslILEmit);
2227     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2228     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2229 };
2230         
2231 #ifdef FEATURE_COMINTEROP
2232 class ILObjectMarshaler : public ILMarshaler
2233 {
2234 public:
2235     enum
2236     {
2237         c_fInOnly               = TRUE,
2238         c_CLRSize               = sizeof(OBJECTREF),
2239         c_nativeSize            = sizeof(VARIANT),
2240     };
2241
2242 protected:
2243     virtual LocalDesc GetNativeType();
2244     virtual LocalDesc GetManagedType();
2245     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2246     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2247     virtual bool NeedsClearNative();
2248     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2249     virtual void EmitReInitNative(ILCodeStream* pslILEmit);
2250 };
2251 #endif // FEATURE_COMINTEROP
2252
2253 class ILDateMarshaler : public ILMarshaler
2254 {
2255 public:
2256     enum
2257     {
2258         c_fInOnly               = TRUE,
2259         c_nativeSize            = sizeof(DATE),
2260         c_CLRSize               = sizeof(INT64),
2261     };
2262                 
2263 protected:
2264     virtual LocalDesc GetNativeType();
2265     virtual LocalDesc GetManagedType();
2266     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2267     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2268     virtual void EmitReInitNative(ILCodeStream* pslILEmit);
2269 };
2270                 
2271
2272 class ILCurrencyMarshaler : public ILMarshaler
2273 {
2274 public:
2275     enum
2276     {
2277         c_fInOnly               = TRUE,
2278         c_nativeSize            = sizeof(CURRENCY),
2279         c_CLRSize               = sizeof(DECIMAL),
2280     };
2281
2282 protected:    
2283     virtual LocalDesc GetNativeType();
2284     virtual LocalDesc GetManagedType();
2285     virtual void EmitReInitNative(ILCodeStream* pslILEmit);
2286     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2287     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2288 };
2289
2290
2291 #ifdef FEATURE_COMINTEROP
2292 class ILInterfaceMarshaler : public ILMarshaler
2293 {
2294 public:
2295     enum
2296     {
2297         c_fInOnly               = TRUE,
2298         c_nativeSize            = sizeof(void *),
2299         c_CLRSize               = sizeof(OBJECTREF),
2300     };
2301
2302 protected:    
2303     virtual LocalDesc GetNativeType();
2304     virtual LocalDesc GetManagedType();
2305     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2306     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2307     virtual bool NeedsClearNative();
2308     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2309 };
2310 #endif // FEATURE_COMINTEROP
2311
2312
2313 class ILAnsiCharMarshaler : public ILMarshaler
2314 {
2315 public:
2316     enum
2317     {
2318         c_fInOnly               = TRUE,
2319         c_nativeSize            = sizeof(UINT8),
2320         c_CLRSize               = sizeof(UINT16),
2321     };
2322
2323 protected:
2324     virtual LocalDesc GetNativeType();
2325     virtual LocalDesc GetManagedType();
2326     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2327     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2328 };
2329
2330
2331 template <BinderClassID CLASS__ID, class ELEMENT>
2332 class ILValueClassPtrMarshaler : public ILMarshaler
2333 {
2334 public:
2335     enum
2336     {
2337         c_fInOnly               = TRUE,
2338         c_nativeSize            = sizeof(ELEMENT *),
2339         c_CLRSize               = sizeof(ELEMENT),
2340     };
2341
2342 protected:
2343     virtual LocalDesc GetNativeType()
2344     {
2345         LIMITED_METHOD_CONTRACT;
2346
2347         //
2348         // pointer to value class
2349         //
2350         return LocalDesc(ELEMENT_TYPE_I);
2351     }
2352
2353     virtual LocalDesc GetManagedType()
2354     {
2355         STANDARD_VM_CONTRACT;
2356
2357         //
2358         // value class
2359         //
2360         return LocalDesc(MscorlibBinder::GetClass(CLASS__ID));
2361     }
2362
2363     virtual bool NeedsClearNative()
2364     {
2365         LIMITED_METHOD_CONTRACT;
2366         return (IsByref(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags));
2367     }
2368
2369     virtual void EmitClearNative(ILCodeStream* pslILEmit)
2370     {
2371         STANDARD_VM_CONTRACT;
2372
2373         EmitLoadNativeValue(pslILEmit);
2374         // static void CoTaskMemFree(IntPtr ptr)
2375         pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
2376     }
2377
2378     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
2379     {
2380         STANDARD_VM_CONTRACT;
2381
2382         if (NeedsClearNative())
2383         {
2384             pslILEmit->EmitLDC(sizeof(ELEMENT));
2385             pslILEmit->EmitCONV_U();
2386             // static IntPtr CoTaskMemAlloc(UIntPtr cb)
2387             pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMALLOC, 1, 1);
2388             EmitStoreNativeValue(pslILEmit);
2389         }
2390     }
2391
2392     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2393     {
2394         STANDARD_VM_CONTRACT;
2395
2396         if (NeedsClearNative())
2397         {
2398             EmitLoadNativeValue(pslILEmit);     // dest
2399             EmitLoadManagedHomeAddr(pslILEmit); // src
2400             pslILEmit->EmitCPOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID)));
2401         }
2402         else
2403         {
2404             EmitLoadManagedHomeAddr(pslILEmit);
2405             EmitStoreNativeValue(pslILEmit);
2406         }
2407     }
2408
2409     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2410     {
2411         STANDARD_VM_CONTRACT;
2412
2413         int tokType = pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID));
2414         ILCodeLabel *pNullLabel = pslILEmit->NewCodeLabel();
2415         ILCodeLabel *pJoinLabel = pslILEmit->NewCodeLabel();
2416
2417         EmitLoadNativeValue(pslILEmit);
2418         pslILEmit->EmitBRFALSE(pNullLabel);
2419
2420         // the incoming pointer is non-null -> dereference it and copy the struct
2421         EmitLoadManagedHomeAddr(pslILEmit); // dest
2422         EmitLoadNativeValue(pslILEmit);     // src
2423         pslILEmit->EmitCPOBJ(tokType);
2424
2425         pslILEmit->EmitBR(pJoinLabel);
2426
2427         // the incoming pointer is null -> just initobj (i.e. zero) the struct
2428         pslILEmit->EmitLabel(pNullLabel);
2429         
2430         EmitLoadManagedHomeAddr(pslILEmit);
2431         pslILEmit->EmitINITOBJ(tokType);
2432
2433         pslILEmit->EmitLabel(pJoinLabel);
2434     }
2435 };
2436
2437 typedef ILValueClassPtrMarshaler<CLASS__GUID, GUID> ILGuidPtrMarshaler;
2438 typedef ILValueClassPtrMarshaler<CLASS__DECIMAL, DECIMAL> ILDecimalPtrMarshaler;
2439         
2440 #ifdef FEATURE_COMINTEROP        
2441 class ILOleColorMarshaler : public ILMarshaler
2442 {
2443 public:
2444     enum
2445     {
2446         c_fInOnly               = TRUE,
2447         c_nativeSize            = sizeof(OLE_COLOR),
2448         c_CLRSize               = sizeof(SYSTEMCOLOR),
2449     };
2450
2451 protected:
2452     virtual LocalDesc GetNativeType();
2453     virtual LocalDesc GetManagedType();
2454     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2455     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2456 };
2457
2458 class ILVBByValStrWMarshaler : public ILMarshaler
2459 {
2460 public:
2461     enum
2462     {
2463         c_fInOnly               = FALSE,
2464         c_nativeSize            = sizeof(BSTR),
2465         c_CLRSize               = sizeof(OBJECTREF*),
2466     };
2467
2468     enum
2469     {
2470         // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2471         MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2 + sizeof(DWORD)
2472     };
2473
2474
2475     ILVBByValStrWMarshaler() : 
2476         m_dwCCHLocal(-1)
2477        ,m_dwLocalBuffer(-1)
2478     {
2479         LIMITED_METHOD_CONTRACT;
2480     }
2481
2482     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2483     virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2484
2485 protected:
2486     virtual LocalDesc GetNativeType();
2487     virtual LocalDesc GetManagedType();
2488     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2489     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2490     virtual bool NeedsClearNative();
2491     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2492     virtual bool IsNativePassedByRef();
2493         
2494     DWORD m_dwCCHLocal;
2495     DWORD m_dwLocalBuffer;
2496 };
2497
2498 class ILVBByValStrMarshaler : public ILMarshaler
2499 {
2500 public:
2501     enum
2502     {
2503         c_fInOnly               = FALSE,
2504         c_nativeSize            = sizeof(LPSTR),
2505         c_CLRSize               = sizeof(OBJECTREF *),
2506     };
2507
2508     ILVBByValStrMarshaler() :
2509         m_dwCCHLocal(-1)
2510     {
2511         LIMITED_METHOD_CONTRACT;
2512     }
2513
2514     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2515     virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2516
2517 protected:
2518     virtual LocalDesc GetNativeType();
2519     virtual LocalDesc GetManagedType();
2520     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2521     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2522     virtual bool NeedsClearNative();
2523     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2524     virtual bool IsNativePassedByRef();
2525
2526     DWORD m_dwCCHLocal;
2527 };
2528
2529 class ILHSTRINGMarshaler : public ILMarshaler
2530 {
2531 public:
2532     enum
2533     {
2534         c_fInOnly               = FALSE,
2535         c_nativeSize            = sizeof(HSTRING),
2536         c_CLRSize               = sizeof(OBJECTREF),
2537     };
2538
2539 protected:
2540     virtual LocalDesc GetNativeType();
2541     virtual LocalDesc GetManagedType();
2542
2543     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2544     void EmitConvertCLRToHSTRINGReference(ILCodeStream* pslILEmit);
2545     void EmitConvertCLRToHSTRING(ILCodeStream* pslILEmit);
2546
2547     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2548
2549     virtual bool NeedsClearNative();
2550     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2551 };
2552 #endif // FEATURE_COMINTEROP
2553
2554
2555 class ILCUTF8Marshaler : public ILOptimizedAllocMarshaler
2556 {
2557 public:
2558         enum
2559         {
2560                 c_fInOnly = TRUE,
2561                 c_nativeSize = sizeof(void *),
2562                 c_CLRSize = sizeof(OBJECTREF),
2563         };
2564
2565         enum
2566         {
2567                 // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2568                 MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
2569         };
2570
2571         ILCUTF8Marshaler() :
2572                 ILOptimizedAllocMarshaler(METHOD__CSTRMARSHALER__CLEAR_NATIVE)
2573         {
2574                 LIMITED_METHOD_CONTRACT;
2575         }
2576
2577 protected:
2578         virtual LocalDesc GetManagedType();
2579         virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2580         virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2581 };
2582
2583
2584
2585 class ILCSTRMarshaler : public ILOptimizedAllocMarshaler
2586 {
2587 public:
2588     enum
2589     {
2590         c_fInOnly               = TRUE,
2591         c_nativeSize            = sizeof(void *),
2592         c_CLRSize               = sizeof(OBJECTREF),
2593     };
2594
2595     enum
2596     {
2597         // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2598         MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
2599     };
2600
2601     ILCSTRMarshaler() :
2602         ILOptimizedAllocMarshaler(METHOD__CSTRMARSHALER__CLEAR_NATIVE)
2603     {
2604         LIMITED_METHOD_CONTRACT;
2605     }
2606
2607 protected:    
2608     virtual LocalDesc GetManagedType();
2609     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2610     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2611 };
2612
2613 #ifdef FEATURE_COMINTEROP
2614 class ILBSTRMarshaler : public ILOptimizedAllocMarshaler
2615 {
2616 public:
2617     enum
2618     {
2619         c_fInOnly               = TRUE,
2620         c_nativeSize            = sizeof(void *),
2621         c_CLRSize               = sizeof(OBJECTREF),
2622     };
2623
2624     enum
2625     {
2626         // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2627         MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2 + 4
2628     };
2629
2630     ILBSTRMarshaler() :
2631         ILOptimizedAllocMarshaler(METHOD__BSTRMARSHALER__CLEAR_NATIVE)
2632     {
2633         LIMITED_METHOD_CONTRACT;
2634     }
2635
2636 protected:    
2637     virtual LocalDesc GetManagedType();
2638     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2639     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2640 };
2641
2642
2643 class ILAnsiBSTRMarshaler : public ILMarshaler
2644 {
2645 public:
2646     enum
2647     {
2648         c_fInOnly               = TRUE,
2649         c_nativeSize            = sizeof(void *),
2650         c_CLRSize               = sizeof(OBJECTREF),
2651     };
2652
2653 protected:    
2654     virtual LocalDesc GetNativeType();
2655     virtual LocalDesc GetManagedType();
2656     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2657     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2658     virtual bool NeedsClearNative();
2659     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2660 };
2661 #endif // FEATURE_COMINTEROP
2662
2663 class ILLayoutClassPtrMarshalerBase : public ILMarshaler
2664 {
2665 public:
2666     enum
2667     {
2668         c_nativeSize            = sizeof(void *),
2669         c_CLRSize               = sizeof(OBJECTREF),
2670     };
2671
2672 protected:    
2673     virtual LocalDesc GetNativeType();
2674     virtual LocalDesc GetManagedType();
2675     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2676     virtual void EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit);
2677     virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
2678     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2679     virtual bool NeedsClearNative();
2680     virtual void EmitClearNative(ILCodeStream* pslILEmit);
2681     virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2682 };
2683
2684 class ILLayoutClassPtrMarshaler : public ILLayoutClassPtrMarshalerBase
2685 {
2686 public:
2687     enum
2688     {
2689         c_fInOnly               = FALSE,
2690     };
2691         
2692 protected:    
2693     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2694     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2695     virtual void EmitClearNativeContents(ILCodeStream * pslILEmit);
2696 };
2697
2698 class ILBlittablePtrMarshaler : public ILLayoutClassPtrMarshalerBase
2699 {
2700 public:
2701     enum
2702     {
2703         c_fInOnly               = FALSE,
2704     };
2705             
2706 protected:    
2707     virtual void EmitMarshalArgumentCLRToNative();
2708     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2709     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2710 };
2711
2712
2713 #ifndef FEATURE_CORECLR
2714 class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler
2715 {
2716 public:
2717     enum
2718     {
2719         c_fInOnly               = TRUE,
2720         c_nativeSize            = VARIABLESIZE,
2721         c_CLRSize               = sizeof(OBJECTREF),
2722     };
2723
2724     LocalDesc GetManagedType()
2725     {
2726         LIMITED_METHOD_CONTRACT;
2727         return LocalDesc();
2728     }
2729
2730     LocalDesc GetNativeType()
2731     {
2732         LIMITED_METHOD_CONTRACT;
2733         return LocalDesc();
2734     }
2735
2736     static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
2737                                             BOOL               byref,
2738                                             BOOL               fin,
2739                                             BOOL               fout,
2740                                             BOOL               fManagedToNative,
2741                                             OverrideProcArgs*  pargs,
2742                                             UINT*              pResID,
2743                                             UINT               argidx,
2744                                             UINT               nativeStackOffset);
2745
2746
2747 };
2748 #endif // !FEATURE_CORECLR
2749
2750
2751 class ILArgIteratorMarshaler : public ILMarshaler
2752 {
2753 public:
2754     enum
2755     {
2756         c_fInOnly               = TRUE,
2757         c_nativeSize            = sizeof(va_list),
2758         c_CLRSize               = sizeof(VARARGS),
2759     };
2760
2761 protected:
2762     virtual LocalDesc GetNativeType();
2763     virtual LocalDesc GetManagedType();
2764     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2765     virtual void EmitMarshalArgumentCLRToNative();
2766     virtual void EmitMarshalArgumentNativeToCLR();
2767 };
2768         
2769 class ILArrayWithOffsetMarshaler : public ILMarshaler
2770 {
2771 public:
2772     enum
2773     {
2774         c_fInOnly               = FALSE,
2775         c_nativeSize            = sizeof(LPVOID),
2776         c_CLRSize               = sizeof(ArrayWithOffsetData),
2777     };
2778
2779     ILArrayWithOffsetMarshaler() : 
2780         m_dwCountLocalNum(-1),
2781         m_dwOffsetLocalNum(-1),
2782         m_dwPinnedLocalNum(-1)
2783     {
2784         LIMITED_METHOD_CONTRACT;
2785     }
2786
2787 protected:
2788     virtual LocalDesc GetNativeType();
2789     virtual LocalDesc GetManagedType();
2790     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2791
2792     virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
2793     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2794     virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2795
2796         
2797     DWORD m_dwCountLocalNum;
2798     DWORD m_dwOffsetLocalNum;
2799     DWORD m_dwPinnedLocalNum;
2800 };
2801
2802 class ILAsAnyMarshalerBase : public ILMarshaler
2803 {
2804 public:
2805     enum
2806     {
2807         c_nativeSize            = sizeof(void *),
2808         c_CLRSize               = sizeof(OBJECTREF),
2809     };
2810
2811     ILAsAnyMarshalerBase() :
2812         m_dwMarshalerLocalNum(-1)
2813     {
2814         LIMITED_METHOD_CONTRACT;
2815     }
2816
2817 protected:
2818     static const BYTE ML_IN  = 0x10;
2819     static const BYTE ML_OUT = 0x20;
2820
2821     virtual bool IsAnsi() = 0;
2822     virtual LocalDesc GetNativeType();
2823     virtual LocalDesc GetManagedType();
2824     virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2825     virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2826     virtual void EmitMarshalArgumentCLRToNative();
2827     virtual bool NeedsClearNative();
2828     virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2829
2830     DWORD m_dwMarshalerLocalNum;
2831 };
2832
2833 class ILAsAnyWMarshaler : public ILAsAnyMarshalerBase
2834 {
2835 public:
2836     enum
2837     {
2838         c_fInOnly               = FALSE,
2839     };
2840
2841 protected:
2842     virtual bool IsAnsi() 
2843     {
2844         return false;
2845     }
2846 };
2847
2848 class ILAsAnyAMarshaler : public ILAsAnyMarshalerBase
2849 {
2850 public:
2851     enum
2852     {
2853         c_fInOnly               = FALSE,
2854     };
2855
2856 protected:
2857     virtual bool IsAnsi() 
2858     {
2859         return true;
2860     }
2861 };
2862
2863
2864 class ILMngdMarshaler : public ILMarshaler
2865 {
2866 public:
2867     enum
2868     {
2869         c_nativeSize            = sizeof(void *),
2870         c_CLRSize               = sizeof(OBJECTREF),
2871     };
2872
2873     ILMngdMarshaler(BinderMethodID space2Man, 
2874                     BinderMethodID contents2Man, 
2875                     BinderMethodID space2Nat, 
2876                     BinderMethodID contents2Nat, 
2877                     BinderMethodID clearNat, 
2878                     BinderMethodID clearNatContents,
2879                     BinderMethodID clearMan) :
2880         m_idConvertSpaceToManaged(space2Man),
2881         m_idConvertContentsToManaged(contents2Man),
2882         m_idConvertSpaceToNative(space2Nat),
2883         m_idConvertContentsToNative(contents2Nat),
2884         m_idClearNative(clearNat),
2885         m_idClearNativeContents(clearNatContents),
2886         m_idClearManaged(clearMan)
2887     {
2888         LIMITED_METHOD_CONTRACT;
2889     }
2890     
2891 protected:    
2892     virtual LocalDesc GetNativeType();
2893     virtual LocalDesc GetManagedType();
2894
2895     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit) = 0;
2896
2897     virtual void EmitCallMngdMarshalerMethod(ILCodeStream* pslILEmit, MethodDesc *pMD);
2898
2899     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
2900     {
2901         WRAPPER_NO_CONTRACT;
2902         EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToManagedMethod());
2903     }
2904     
2905     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2906     {
2907         WRAPPER_NO_CONTRACT;
2908         EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToManagedMethod());
2909     }
2910     
2911     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
2912     {
2913         WRAPPER_NO_CONTRACT;
2914         EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToNativeMethod());
2915     }
2916     
2917     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2918     {
2919         WRAPPER_NO_CONTRACT;
2920         EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToNativeMethod());
2921     }
2922
2923     virtual bool NeedsClearNative()
2924     {
2925         LIMITED_METHOD_CONTRACT;
2926
2927         if (NULL != GetClearNativeMethod())
2928         {
2929             return true;
2930         }
2931             
2932         return false;
2933     }
2934     
2935     virtual void EmitClearNative(ILCodeStream* pslILEmit)
2936     {
2937         WRAPPER_NO_CONTRACT;
2938         EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeMethod());
2939     }
2940     
2941     virtual void EmitClearNativeContents(ILCodeStream* pslILEmit)
2942     {
2943         WRAPPER_NO_CONTRACT;
2944         EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeContentsMethod());
2945     }
2946
2947     
2948     virtual bool NeedsClearCLR()
2949     {
2950         LIMITED_METHOD_CONTRACT;
2951
2952         if (NULL != GetClearManagedMethod())
2953         {
2954             return true;
2955         }
2956             
2957         return false;
2958     }
2959
2960     virtual void EmitClearCLR(ILCodeStream* pslILEmit)
2961     {
2962         WRAPPER_NO_CONTRACT;
2963         EmitCallMngdMarshalerMethod(pslILEmit, GetClearManagedMethod());
2964     }
2965
2966     virtual MethodDesc *GetConvertSpaceToManagedMethod()    { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToManaged    == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToManaged));    }
2967     virtual MethodDesc *GetConvertContentsToManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToManaged)); }
2968     virtual MethodDesc *GetConvertSpaceToNativeMethod()     { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToNative     == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToNative));     }
2969     virtual MethodDesc *GetConvertContentsToNativeMethod()  { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToNative  == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToNative));  }
2970     virtual MethodDesc *GetClearNativeMethod()              { WRAPPER_NO_CONTRACT; return (m_idClearNative              == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNative));              }
2971     virtual MethodDesc *GetClearNativeContentsMethod()      { WRAPPER_NO_CONTRACT; return (m_idClearNativeContents      == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNativeContents));      }
2972     virtual MethodDesc *GetClearManagedMethod()             { WRAPPER_NO_CONTRACT; return (m_idClearManaged             == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearManaged));             }
2973
2974     const BinderMethodID m_idConvertSpaceToManaged;
2975     const BinderMethodID m_idConvertContentsToManaged;
2976     const BinderMethodID m_idConvertSpaceToNative;
2977     const BinderMethodID m_idConvertContentsToNative;
2978     const BinderMethodID m_idClearNative;
2979     const BinderMethodID m_idClearNativeContents;
2980     const BinderMethodID m_idClearManaged;
2981 };
2982
2983 class ILNativeArrayMarshaler : public ILMngdMarshaler
2984 {
2985 public:    
2986     enum
2987     {
2988         c_fInOnly               = FALSE,
2989     };
2990
2991     ILNativeArrayMarshaler() : 
2992         ILMngdMarshaler(
2993             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
2994             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
2995             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
2996             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
2997             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE,
2998             METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
2999             METHOD__NIL
3000             )
3001     {
3002         LIMITED_METHOD_CONTRACT;
3003         m_dwSavedSizeArg = LOCAL_NUM_UNUSED;
3004     }
3005
3006     virtual void EmitMarshalArgumentCLRToNative();
3007     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
3008     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
3009     virtual void EmitClearNative(ILCodeStream* pslILEmit);    
3010     virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
3011     virtual void EmitMarshalArgumentNativeToCLRByref();
3012     virtual void EmitMarshalArgumentCLRToNativeByref();
3013     
3014 protected:
3015     
3016     bool UsePinnedArraySpecialCase();
3017     
3018     BOOL CheckSizeParamIndexArg(const CREATE_MARSHALER_CARRAY_OPERANDS &mops, CorElementType *pElementType);
3019     
3020     // Calculate element count and load it on evaluation stack
3021     void EmitLoadElementCount(ILCodeStream* pslILEmit);    
3022
3023     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3024
3025     void EmitLoadNativeSize(ILCodeStream* pslILEmit);
3026     void EmitNewSavedSizeArgLocal();
3027     
3028 private :
3029     DWORD m_dwSavedSizeArg;                 
3030 };
3031
3032 class MngdNativeArrayMarshaler
3033 {
3034 public:
3035     static FCDECL3(void, CreateMarshaler,           MngdNativeArrayMarshaler* pThis, MethodTable* pMT, UINT32 dwFlags);
3036     static FCDECL3(void, ConvertSpaceToNative,      MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3037     static FCDECL3(void, ConvertContentsToNative,   MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3038     static FCDECL4(void, ConvertSpaceToManaged,     MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
3039     static FCDECL3(void, ConvertContentsToManaged,  MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3040     static FCDECL3(void, ClearNative,               MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3041     static FCDECL3(void, ClearNativeContents,       MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3042
3043     static void DoClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3044         
3045     enum
3046     {
3047         FLAG_NATIVE_DATA_VALID = 0x40000000
3048     };
3049
3050     MethodTable*            m_pElementMT;
3051     TypeHandle              m_Array;
3052     BOOL                    m_NativeDataValid;
3053     BOOL                    m_BestFitMap;
3054     BOOL                    m_ThrowOnUnmappableChar;
3055     VARTYPE                 m_vt;
3056 };
3057
3058
3059 #ifdef FEATURE_COMINTEROP
3060 class ILSafeArrayMarshaler : public ILMngdMarshaler
3061 {
3062 public:    
3063     enum
3064     {
3065         c_fInOnly               = FALSE,
3066     };
3067
3068     ILSafeArrayMarshaler() : 
3069         ILMngdMarshaler(
3070             METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
3071             METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3072             METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
3073             METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3074             METHOD__MNGD_SAFE_ARRAY_MARSHALER__CLEAR_NATIVE,
3075             METHOD__NIL,
3076             METHOD__NIL
3077             ), 
3078         m_dwOriginalManagedLocalNum(-1)
3079     {
3080         LIMITED_METHOD_CONTRACT;
3081     }
3082     
3083 protected:
3084
3085     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3086     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3087     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3088
3089     virtual void EmitReInitNative(ILCodeStream* pslILEmit)
3090     {
3091         CONTRACTL
3092         {
3093             THROWS;
3094             GC_TRIGGERS;
3095             MODE_ANY;
3096         }
3097         CONTRACTL_END;
3098         if (NeedsCheckForStatic() && pslILEmit->GetStreamType() != ILStubLinker::kExceptionCleanup)
3099         {
3100             // Keep the original value in native home as we are not going to allocate a new
3101             // one. If we cleared it here, we wouldn't be able to ConvertContentsToNative.
3102             // Always perform the real re-init in the ExceptionCleanup stream so the caller
3103             // doesn't get back garbage.
3104         }
3105         else
3106         {
3107             ILMngdMarshaler::EmitReInitNative(pslILEmit);
3108         }
3109     }
3110
3111     bool NeedsCheckForStatic()
3112     {
3113         WRAPPER_NO_CONTRACT;
3114         return IsByref(m_dwMarshalFlags) && !IsCLRToNative(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags);
3115     }
3116
3117     DWORD m_dwOriginalManagedLocalNum;
3118 };
3119
3120 class MngdSafeArrayMarshaler
3121 {
3122 public:
3123     static FCDECL4(void, CreateMarshaler,           MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags);
3124     static FCDECL3(void, ConvertSpaceToNative,      MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3125     static FCDECL4(void, ConvertContentsToNative,   MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, Object* pOriginalManagedUNSAFE);
3126     static FCDECL3(void, ConvertSpaceToManaged,     MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3127     static FCDECL3(void, ConvertContentsToManaged,  MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3128     static FCDECL3(void, ClearNative,               MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3129
3130     enum StaticCheckStateFlags
3131     {
3132         SCSF_CheckForStatic = 1,
3133         SCSF_IsStatic = 2,
3134         SCSF_NativeDataValid = 4
3135     };
3136
3137     MethodTable*    m_pElementMT;
3138     int             m_iRank;
3139     VARTYPE         m_vt;
3140     BYTE            m_fStatic;     // StaticCheckStateFlags
3141     BYTE            m_nolowerbounds;
3142 };
3143
3144 class ILHiddenLengthArrayMarshaler : public ILMngdMarshaler
3145 {
3146     friend class MngdHiddenLengthArrayMarshaler;
3147
3148 public:
3149     enum
3150     {
3151         c_nativeSize            = sizeof(LPVOID),
3152         c_CLRSize               = sizeof(OBJECTREF),
3153         c_fInOnly               = FALSE,
3154     };
3155
3156     ILHiddenLengthArrayMarshaler() :
3157         ILMngdMarshaler(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
3158                         METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3159                         METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
3160                         METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3161                         METHOD__WIN32NATIVE__COTASKMEMFREE,
3162                         METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
3163                         METHOD__NIL)
3164     {
3165         LIMITED_METHOD_CONTRACT;
3166         m_dwMngdMarshalerLocalNum = -1;
3167     }
3168
3169 protected:
3170     virtual LocalDesc GetNativeType();
3171     virtual LocalDesc GetManagedType();
3172
3173     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3174     virtual void EmitMarshalArgumentCLRToNative();
3175     virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
3176     virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
3177     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3178     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3179     virtual void EmitClearNative(ILCodeStream* pslILEmit);    
3180     virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
3181
3182 private:
3183     bool CanUsePinnedArray();
3184     void EmitLoadNativeArrayLength(ILCodeStream *pslILEmit);
3185
3186     virtual MethodDesc *GetConvertContentsToManagedMethod();
3187     virtual MethodDesc *GetConvertContentsToNativeMethod();
3188     virtual MethodDesc *GetClearNativeContentsMethod();
3189
3190     MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3191 };
3192
3193 class MngdHiddenLengthArrayMarshaler
3194 {
3195 public:
3196     static FCDECL4(void, CreateMarshaler,           MngdHiddenLengthArrayMarshaler* pThis, MethodTable* pMT, SIZE_T cbElement, UINT16 vt);
3197     static FCDECL3(void, ConvertSpaceToNative,      MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3198     static FCDECL3(void, ConvertContentsToNative,   MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3199     static FCDECL4(void, ConvertSpaceToManaged,     MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
3200     static FCDECL3(void, ConvertContentsToManaged,  MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3201     static FCDECL3(void, ClearNativeContents,       MngdHiddenLengthArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3202
3203
3204 private:
3205     SIZE_T GetArraySize(SIZE_T elements);
3206     void DoClearNativeContents(void** pNativeHome, INT32 cElements);
3207
3208 private:
3209     MethodTable                         *m_pElementMT;
3210     SIZE_T                               m_cbElementSize;
3211     VARTYPE                              m_vt;
3212 };
3213 #endif // FEATURE_COMINTEROP
3214
3215
3216 class ILReferenceCustomMarshaler : public ILMngdMarshaler
3217 {
3218 public:    
3219     enum
3220     {
3221         c_fInOnly               = FALSE,
3222     };
3223
3224     ILReferenceCustomMarshaler() : 
3225         ILMngdMarshaler(
3226             METHOD__NIL,
3227             METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3228             METHOD__NIL,
3229             METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3230             METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_NATIVE,
3231             METHOD__NIL,
3232             METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_MANAGED
3233             )
3234     {
3235         LIMITED_METHOD_CONTRACT;
3236     }
3237         
3238 protected:
3239     virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3240 };
3241
3242 class MngdRefCustomMarshaler
3243 {
3244 public:
3245     static FCDECL2(void, CreateMarshaler,           MngdRefCustomMarshaler* pThis, void* pCMHelper);
3246     static FCDECL3(void, ConvertContentsToNative,   MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3247     static FCDECL3(void, ConvertContentsToManaged,  MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3248     static FCDECL3(void, ClearNative,               MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3249     static FCDECL3(void, ClearManaged,              MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3250
3251     static void DoClearNativeContents(MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3252
3253     CustomMarshalerHelper*  m_pCMHelper;
3254 };
3255
3256
3257 #ifdef FEATURE_COMINTEROP
3258 class ILUriMarshaler : public ILMarshaler
3259 {
3260 public:
3261     enum
3262     {
3263         c_fInOnly               = TRUE,
3264         c_nativeSize            = sizeof(LPVOID),
3265         c_CLRSize               = sizeof(OBJECTREF),
3266     };
3267
3268     static void EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3269     static void EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3270
3271 protected:
3272     virtual LocalDesc GetNativeType();
3273     virtual LocalDesc GetManagedType();
3274
3275     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);    
3276     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3277
3278     virtual bool NeedsClearNative();
3279     void EmitClearNative(ILCodeStream* pslILEmit);
3280 };
3281
3282 class ILNCCEventArgsMarshaler : public ILMarshaler
3283 {
3284 public:
3285     enum
3286     {
3287         c_fInOnly               = TRUE,
3288         c_nativeSize            = sizeof(LPVOID),
3289         c_CLRSize               = sizeof(OBJECTREF),
3290     };
3291
3292     static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3293     static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3294
3295 protected:
3296     virtual LocalDesc GetNativeType();
3297     virtual LocalDesc GetManagedType();
3298
3299     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);    
3300     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3301
3302     virtual bool NeedsClearNative();
3303     void EmitClearNative(ILCodeStream* pslILEmit);
3304 };
3305
3306 class ILPCEventArgsMarshaler : public ILMarshaler
3307 {
3308 public:
3309     enum
3310     {
3311         c_fInOnly               = TRUE,
3312         c_nativeSize            = sizeof(LPVOID),
3313         c_CLRSize               = sizeof(OBJECTREF),
3314     };
3315
3316     static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3317     static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3318
3319 protected:
3320     virtual LocalDesc GetNativeType();
3321     virtual LocalDesc GetManagedType();
3322
3323     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);    
3324     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3325
3326     virtual bool NeedsClearNative();
3327     void EmitClearNative(ILCodeStream* pslILEmit);
3328 };
3329
3330 class ILDateTimeMarshaler : public ILMarshaler
3331 {
3332 public:
3333     enum
3334     {
3335         c_fInOnly               = FALSE,
3336         c_nativeSize            = sizeof(INT64),  // = sizeof(Windows::Foundation::DateTime)
3337         c_CLRSize               = VARIABLESIZE,
3338     };
3339
3340 protected:
3341     virtual LocalDesc GetNativeType();
3342     virtual LocalDesc GetManagedType();
3343
3344     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);    
3345     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3346
3347     virtual bool NeedsClearNative();
3348     virtual void EmitReInitNative(ILCodeStream* pslILEmit);
3349 };
3350
3351 class ILNullableMarshaler : public ILMarshaler
3352 {
3353 public:
3354     enum
3355     {
3356         c_fInOnly               = FALSE,
3357         c_nativeSize            = sizeof(LPVOID),
3358         c_CLRSize               = VARIABLESIZE,
3359     };
3360                 
3361 protected:
3362     virtual LocalDesc GetNativeType();
3363     virtual LocalDesc GetManagedType();
3364     virtual bool NeedsClearNative();
3365     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3366     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);    
3367     virtual void EmitClearNative(ILCodeStream* pslILEmit);    
3368
3369 private:
3370     MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3371 };
3372
3373 class ILSystemTypeMarshaler : public ILMarshaler
3374 {
3375 public:
3376     enum
3377     {
3378         c_fInOnly           = FALSE, 
3379         c_nativeSize        = sizeof(TypeNameNative),
3380         c_CLRSize           = sizeof(OBJECTREF)
3381     };
3382
3383 protected:
3384     virtual LocalDesc GetNativeType();
3385     virtual LocalDesc GetManagedType();
3386
3387     virtual void EmitConvertContentsCLRToNative(ILCodeStream * pslILEmit);
3388     virtual void EmitConvertContentsNativeToCLR(ILCodeStream * pslILEmit);
3389
3390     virtual bool NeedsClearNative();
3391     virtual void EmitClearNative(ILCodeStream * pslILEmit);
3392     virtual void EmitReInitNative(ILCodeStream * pslILEmit);
3393 };
3394
3395 class ILHResultExceptionMarshaler : public ILMarshaler
3396 {
3397 public:
3398     enum
3399     {
3400         c_fInOnly               = FALSE,
3401         c_nativeSize            = sizeof(INT32),  // = sizeof(Windows::Foundation::HResult)
3402         c_CLRSize               = sizeof(OBJECTREF),
3403     };
3404
3405 protected:
3406     virtual LocalDesc GetNativeType();
3407     virtual LocalDesc GetManagedType();
3408
3409     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);    
3410     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3411
3412     virtual bool NeedsClearNative();
3413 };
3414
3415 class ILKeyValuePairMarshaler : public ILMarshaler
3416 {
3417 public:
3418     enum
3419     {
3420         c_fInOnly               = FALSE,
3421         c_nativeSize            = sizeof(LPVOID),
3422         c_CLRSize               = VARIABLESIZE,
3423     };
3424                 
3425 protected:
3426     virtual LocalDesc GetNativeType();
3427     virtual LocalDesc GetManagedType();
3428     virtual bool NeedsClearNative();
3429     virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3430     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3431     virtual void EmitClearNative(ILCodeStream* pslILEmit);
3432
3433 private:
3434     MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3435 };
3436
3437 #endif // FEATURE_COMINTEROP