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