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
25class ILStubMarshalHome
26{
27public:
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
37private:
38 MarshalHomeType m_homeType;
39 DWORD m_dwHomeIndex;
40
41public:
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
207class ILMarshaler
208{
209protected:
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
230public:
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
265protected:
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
356public:
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
775protected:
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
1420public:
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
1447class 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
1542template <CorElementType ELEMENT_TYPE, class PROMOTED_ELEMENT>
1543class ILCopyMarshalerSimple : public ILCopyMarshalerBase
1544{
1545public:
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
1689typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I1, INT_PTR> ILCopyMarshaler1;
1690typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U1, UINT_PTR> ILCopyMarshalerU1;
1691typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I2, INT_PTR> ILCopyMarshaler2;
1692typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U2, UINT_PTR> ILCopyMarshalerU2;
1693typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I4, INT_PTR> ILCopyMarshaler4;
1694typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U4, UINT_PTR> ILCopyMarshalerU4;
1695typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I8, INT64> ILCopyMarshaler8;
1696typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R4, float> ILFloatMarshaler;
1697typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R8, double> ILDoubleMarshaler;
1698
1699template <BinderClassID CLASS__ID, class PROMOTED_ELEMENT>
1700class ILCopyMarshalerKnownStruct : public ILCopyMarshalerBase
1701{
1702public:
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
1726typedef ILCopyMarshalerKnownStruct<CLASS__DECIMAL, DECIMAL> ILDecimalMarshaler;
1727typedef ILCopyMarshalerKnownStruct<CLASS__GUID, GUID> ILGuidMarshaler;
1728
1729class ILBlittableValueClassMarshaler : public ILCopyMarshalerBase
1730{
1731public:
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
1756class ILDelegateMarshaler : public ILMarshaler
1757{
1758public:
1759 enum
1760 {
1761 c_fInOnly = TRUE,
1762 c_nativeSize = sizeof(void *),
1763 c_CLRSize = sizeof(OBJECTREF),
1764 };
1765
1766protected:
1767 virtual LocalDesc GetNativeType();
1768 virtual LocalDesc GetManagedType();
1769 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1770 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1771};
1772
1773class ILReflectionObjectMarshaler : public ILMarshaler
1774{
1775public:
1776 enum
1777 {
1778 c_fInOnly = TRUE,
1779 c_nativeSize = sizeof(void *),
1780 c_CLRSize = sizeof(OBJECTREF),
1781 };
1782
1783protected:
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
1793class ILIRuntimeMethodInfoMarshaler : public ILReflectionObjectMarshaler
1794{
1795protected:
1796 virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__STUBMETHODINFO__HANDLE; }
1797 virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__STUBMETHODINFO; }
1798};
1799
1800class ILRuntimeModuleMarshaler : public ILReflectionObjectMarshaler
1801{
1802protected:
1803 virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__MODULE__DATA; }
1804 virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__MODULE; }
1805};
1806
1807class ILRuntimeAssemblyMarshaler : public ILReflectionObjectMarshaler
1808{
1809protected:
1810 virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__ASSEMBLY__HANDLE; }
1811 virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__ASSEMBLY; }
1812};
1813
1814class ILRuntimeTypeHandleMarshaler : public ILReflectionObjectMarshaler
1815{
1816protected:
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
1822class ILRuntimeMethodHandleMarshaler : public ILReflectionObjectMarshaler
1823{
1824protected:
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
1830class ILRuntimeFieldHandleMarshaler : public ILReflectionObjectMarshaler
1831{
1832protected:
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
1838class ILBoolMarshaler : public ILMarshaler
1839{
1840public:
1841
1842 virtual CorElementType GetNativeBoolElementType() = 0;
1843 virtual int GetNativeTrueValue() = 0;
1844 virtual int GetNativeFalseValue() = 0;
1845
1846protected:
1847 virtual LocalDesc GetNativeType();
1848 virtual LocalDesc GetManagedType();
1849 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
1850 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
1851};
1852
1853class ILWinBoolMarshaler : public ILBoolMarshaler
1854{
1855public:
1856 enum
1857 {
1858 c_fInOnly = TRUE,
1859 c_nativeSize = sizeof(BOOL),
1860 c_CLRSize = sizeof(INT8),
1861 };
1862
1863protected:
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
1883class ILCBoolMarshaler : public ILBoolMarshaler
1884{
1885public:
1886 enum
1887 {
1888 c_fInOnly = TRUE,
1889 c_nativeSize = sizeof(BYTE),
1890 c_CLRSize = sizeof(INT8),
1891 };
1892
1893protected:
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
1914class ILVtBoolMarshaler : public ILBoolMarshaler
1915{
1916public:
1917 enum
1918 {
1919 c_fInOnly = TRUE,
1920 c_nativeSize = sizeof(VARIANT_BOOL),
1921 c_CLRSize = sizeof(INT8),
1922 };
1923
1924protected:
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
1945class ILWSTRMarshaler : public ILMarshaler
1946{
1947public:
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
1965protected:
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.
1989class ILOptimizedAllocMarshaler : public ILMarshaler
1990{
1991public:
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
2003protected:
2004 const BinderMethodID m_idClearNative;
2005 DWORD m_dwLocalBuffer; // localloc'ed temp buffer variable or -1 if not used
2006};
2007
2008class ILUTF8BufferMarshaler : public ILOptimizedAllocMarshaler
2009{
2010public:
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
2037class ILWSTRBufferMarshaler : public ILOptimizedAllocMarshaler
2038{
2039public:
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
2066class ILCSTRBufferMarshaler : public ILOptimizedAllocMarshaler
2067{
2068public:
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
2096class 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
2105public:
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
2142class ILSafeHandleMarshaler : public ILMarshaler
2143{
2144public:
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
2178class ILCriticalHandleMarshaler : public ILMarshaler
2179{
2180public:
2181 enum
2182 {
2183 c_fInOnly = FALSE,
2184 c_nativeSize = sizeof(LPVOID),
2185 c_CLRSize = sizeof(CRITICALHANDLE),
2186 };
2187
2188public:
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
2220class ILValueClassMarshaler : public ILMarshaler
2221{
2222public:
2223 enum
2224 {
2225 c_fInOnly = TRUE,
2226 c_nativeSize = VARIABLESIZE,
2227 c_CLRSize = VARIABLESIZE,
2228 };
2229
2230protected:
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
2241class ILObjectMarshaler : public ILMarshaler
2242{
2243public:
2244 enum
2245 {
2246 c_fInOnly = TRUE,
2247 c_CLRSize = sizeof(OBJECTREF),
2248 c_nativeSize = sizeof(VARIANT),
2249 };
2250
2251protected:
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
2262class ILDateMarshaler : public ILMarshaler
2263{
2264public:
2265 enum
2266 {
2267 c_fInOnly = TRUE,
2268 c_nativeSize = sizeof(DATE),
2269 c_CLRSize = sizeof(INT64),
2270 };
2271
2272protected:
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
2281class ILCurrencyMarshaler : public ILMarshaler
2282{
2283public:
2284 enum
2285 {
2286 c_fInOnly = TRUE,
2287 c_nativeSize = sizeof(CURRENCY),
2288 c_CLRSize = sizeof(DECIMAL),
2289 };
2290
2291protected:
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
2301class ILInterfaceMarshaler : public ILMarshaler
2302{
2303public:
2304 enum
2305 {
2306 c_fInOnly = TRUE,
2307 c_nativeSize = sizeof(void *),
2308 c_CLRSize = sizeof(OBJECTREF),
2309 };
2310
2311protected:
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
2322class ILAnsiCharMarshaler : public ILMarshaler
2323{
2324public:
2325 enum
2326 {
2327 c_fInOnly = TRUE,
2328 c_nativeSize = sizeof(UINT8),
2329 c_CLRSize = sizeof(UINT16),
2330 };
2331
2332protected:
2333 virtual LocalDesc GetNativeType();
2334 virtual LocalDesc GetManagedType();
2335 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2336 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2337};
2338
2339
2340template <BinderClassID CLASS__ID, class ELEMENT>
2341class ILValueClassPtrMarshaler : public ILMarshaler
2342{
2343public:
2344 enum
2345 {
2346 c_fInOnly = TRUE,
2347 c_nativeSize = sizeof(ELEMENT *),
2348 c_CLRSize = sizeof(ELEMENT),
2349 };
2350
2351protected:
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
2446typedef ILValueClassPtrMarshaler<CLASS__GUID, GUID> ILGuidPtrMarshaler;
2447typedef ILValueClassPtrMarshaler<CLASS__DECIMAL, DECIMAL> ILDecimalPtrMarshaler;
2448
2449#ifdef FEATURE_COMINTEROP
2450class ILOleColorMarshaler : public ILMarshaler
2451{
2452public:
2453 enum
2454 {
2455 c_fInOnly = TRUE,
2456 c_nativeSize = sizeof(OLE_COLOR),
2457 c_CLRSize = sizeof(SYSTEMCOLOR),
2458 };
2459
2460protected:
2461 virtual LocalDesc GetNativeType();
2462 virtual LocalDesc GetManagedType();
2463 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2464 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2465};
2466
2467class ILVBByValStrWMarshaler : public ILMarshaler
2468{
2469public:
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
2494protected:
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
2507class ILVBByValStrMarshaler : public ILMarshaler
2508{
2509public:
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
2526protected:
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
2538class ILHSTRINGMarshaler : public ILMarshaler
2539{
2540public:
2541 enum
2542 {
2543 c_fInOnly = FALSE,
2544 c_nativeSize = sizeof(HSTRING),
2545 c_CLRSize = sizeof(OBJECTREF),
2546 };
2547
2548protected:
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
2564class ILCUTF8Marshaler : public ILOptimizedAllocMarshaler
2565{
2566public:
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
2586protected:
2587 virtual LocalDesc GetManagedType();
2588 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2589 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2590};
2591
2592
2593
2594class ILCSTRMarshaler : public ILOptimizedAllocMarshaler
2595{
2596public:
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
2616protected:
2617 virtual LocalDesc GetManagedType();
2618 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2619 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2620};
2621
2622class ILBSTRMarshaler : public ILOptimizedAllocMarshaler
2623{
2624public:
2625 enum
2626 {
2627 c_fInOnly = TRUE,
2628 c_nativeSize = sizeof(void *),
2629 c_CLRSize = sizeof(OBJECTREF),
2630 };
2631
2632 enum
2633 {
2634 // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
2635 MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2 + 4
2636 };
2637
2638 ILBSTRMarshaler() :
2639 ILOptimizedAllocMarshaler(METHOD__BSTRMARSHALER__CLEAR_NATIVE)
2640 {
2641 LIMITED_METHOD_CONTRACT;
2642 }
2643
2644protected:
2645 virtual LocalDesc GetManagedType();
2646 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2647 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2648};
2649
2650class ILAnsiBSTRMarshaler : public ILMarshaler
2651{
2652public:
2653 enum
2654 {
2655 c_fInOnly = TRUE,
2656 c_nativeSize = sizeof(void *),
2657 c_CLRSize = sizeof(OBJECTREF),
2658 };
2659
2660protected:
2661 virtual LocalDesc GetNativeType();
2662 virtual LocalDesc GetManagedType();
2663 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2664 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2665 virtual bool NeedsClearNative();
2666 virtual void EmitClearNative(ILCodeStream* pslILEmit);
2667};
2668
2669class ILLayoutClassPtrMarshalerBase : public ILMarshaler
2670{
2671public:
2672 enum
2673 {
2674 c_nativeSize = sizeof(void *),
2675 c_CLRSize = sizeof(OBJECTREF),
2676 };
2677
2678protected:
2679 virtual LocalDesc GetNativeType();
2680 virtual LocalDesc GetManagedType();
2681 virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2682 virtual void EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit);
2683 virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
2684 virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2685 virtual bool NeedsClearNative();
2686 virtual void EmitClearNative(ILCodeStream* pslILEmit);
2687 virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2688};
2689
2690class ILLayoutClassPtrMarshaler : public ILLayoutClassPtrMarshalerBase
2691{
2692public:
2693 enum
2694 {
2695 c_fInOnly = FALSE,
2696 };
2697
2698protected:
2699 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2700 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2701 virtual void EmitClearNativeContents(ILCodeStream * pslILEmit);
2702};
2703
2704class ILBlittablePtrMarshaler : public ILLayoutClassPtrMarshalerBase
2705{
2706public:
2707 enum
2708 {
2709 c_fInOnly = FALSE,
2710 };
2711
2712protected:
2713 virtual void EmitMarshalArgumentCLRToNative();
2714 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
2715 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2716};
2717
2718
2719
2720
2721class ILArgIteratorMarshaler : public ILMarshaler
2722{
2723public:
2724 enum
2725 {
2726 c_fInOnly = TRUE,
2727 c_nativeSize = sizeof(va_list),
2728 c_CLRSize = sizeof(VARARGS),
2729 };
2730
2731protected:
2732 virtual LocalDesc GetNativeType();
2733 virtual LocalDesc GetManagedType();
2734 virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2735 virtual void EmitMarshalArgumentCLRToNative();
2736 virtual void EmitMarshalArgumentNativeToCLR();
2737};
2738
2739class ILArrayWithOffsetMarshaler : public ILMarshaler
2740{
2741public:
2742 enum
2743 {
2744 c_fInOnly = FALSE,
2745 c_nativeSize = sizeof(LPVOID),
2746 c_CLRSize = sizeof(ArrayWithOffsetData),
2747 };
2748
2749 ILArrayWithOffsetMarshaler() :
2750 m_dwCountLocalNum(-1),
2751 m_dwOffsetLocalNum(-1),
2752 m_dwPinnedLocalNum(-1)
2753 {
2754 LIMITED_METHOD_CONTRACT;
2755 }
2756
2757protected:
2758 virtual LocalDesc GetNativeType();
2759 virtual LocalDesc GetManagedType();
2760 virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2761
2762 virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
2763 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
2764 virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2765
2766
2767 DWORD m_dwCountLocalNum;
2768 DWORD m_dwOffsetLocalNum;
2769 DWORD m_dwPinnedLocalNum;
2770};
2771
2772class ILAsAnyMarshalerBase : public ILMarshaler
2773{
2774public:
2775 enum
2776 {
2777 c_nativeSize = sizeof(void *),
2778 c_CLRSize = sizeof(OBJECTREF),
2779 };
2780
2781 ILAsAnyMarshalerBase() :
2782 m_dwMarshalerLocalNum(-1)
2783 {
2784 LIMITED_METHOD_CONTRACT;
2785 }
2786
2787protected:
2788 static const BYTE ML_IN = 0x10;
2789 static const BYTE ML_OUT = 0x20;
2790
2791 virtual bool IsAnsi() = 0;
2792 virtual LocalDesc GetNativeType();
2793 virtual LocalDesc GetManagedType();
2794 virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2795 virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
2796 virtual void EmitMarshalArgumentCLRToNative();
2797 virtual bool NeedsClearNative();
2798 virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
2799
2800 DWORD m_dwMarshalerLocalNum;
2801};
2802
2803class ILAsAnyWMarshaler : public ILAsAnyMarshalerBase
2804{
2805public:
2806 enum
2807 {
2808 c_fInOnly = FALSE,
2809 };
2810
2811protected:
2812 virtual bool IsAnsi()
2813 {
2814 return false;
2815 }
2816};
2817
2818class ILAsAnyAMarshaler : public ILAsAnyMarshalerBase
2819{
2820public:
2821 enum
2822 {
2823 c_fInOnly = FALSE,
2824 };
2825
2826protected:
2827 virtual bool IsAnsi()
2828 {
2829 return true;
2830 }
2831};
2832
2833
2834class ILMngdMarshaler : public ILMarshaler
2835{
2836public:
2837 enum
2838 {
2839 c_nativeSize = sizeof(void *),
2840 c_CLRSize = sizeof(OBJECTREF),
2841 };
2842
2843 ILMngdMarshaler(BinderMethodID space2Man,
2844 BinderMethodID contents2Man,
2845 BinderMethodID space2Nat,
2846 BinderMethodID contents2Nat,
2847 BinderMethodID clearNat,
2848 BinderMethodID clearNatContents,
2849 BinderMethodID clearMan) :
2850 m_idConvertSpaceToManaged(space2Man),
2851 m_idConvertContentsToManaged(contents2Man),
2852 m_idConvertSpaceToNative(space2Nat),
2853 m_idConvertContentsToNative(contents2Nat),
2854 m_idClearNative(clearNat),
2855 m_idClearNativeContents(clearNatContents),
2856 m_idClearManaged(clearMan)
2857 {
2858 LIMITED_METHOD_CONTRACT;
2859 }
2860
2861protected:
2862 virtual LocalDesc GetNativeType();
2863 virtual LocalDesc GetManagedType();
2864
2865 virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit) = 0;
2866
2867 virtual void EmitCallMngdMarshalerMethod(ILCodeStream* pslILEmit, MethodDesc *pMD);
2868
2869 virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
2870 {
2871 WRAPPER_NO_CONTRACT;
2872 EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToManagedMethod());
2873 }
2874
2875 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2876 {
2877 WRAPPER_NO_CONTRACT;
2878 EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToManagedMethod());
2879 }
2880
2881 virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
2882 {
2883 WRAPPER_NO_CONTRACT;
2884 EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToNativeMethod());
2885 }
2886
2887 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2888 {
2889 WRAPPER_NO_CONTRACT;
2890 EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToNativeMethod());
2891 }
2892
2893 virtual bool NeedsClearNative()
2894 {
2895 LIMITED_METHOD_CONTRACT;
2896
2897 if (NULL != GetClearNativeMethod())
2898 {
2899 return true;
2900 }
2901
2902 return false;
2903 }
2904
2905 virtual void EmitClearNative(ILCodeStream* pslILEmit)
2906 {
2907 WRAPPER_NO_CONTRACT;
2908 EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeMethod());
2909 }
2910
2911 virtual void EmitClearNativeContents(ILCodeStream* pslILEmit)
2912 {
2913 WRAPPER_NO_CONTRACT;
2914 EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeContentsMethod());
2915 }
2916
2917
2918 virtual bool NeedsClearCLR()
2919 {
2920 LIMITED_METHOD_CONTRACT;
2921
2922 if (NULL != GetClearManagedMethod())
2923 {
2924 return true;
2925 }
2926
2927 return false;
2928 }
2929
2930 virtual void EmitClearCLR(ILCodeStream* pslILEmit)
2931 {
2932 WRAPPER_NO_CONTRACT;
2933 EmitCallMngdMarshalerMethod(pslILEmit, GetClearManagedMethod());
2934 }
2935
2936 virtual MethodDesc *GetConvertSpaceToManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToManaged)); }
2937 virtual MethodDesc *GetConvertContentsToManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToManaged)); }
2938 virtual MethodDesc *GetConvertSpaceToNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToNative)); }
2939 virtual MethodDesc *GetConvertContentsToNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToNative)); }
2940 virtual MethodDesc *GetClearNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idClearNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNative)); }
2941 virtual MethodDesc *GetClearNativeContentsMethod() { WRAPPER_NO_CONTRACT; return (m_idClearNativeContents == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNativeContents)); }
2942 virtual MethodDesc *GetClearManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idClearManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearManaged)); }
2943
2944 const BinderMethodID m_idConvertSpaceToManaged;
2945 const BinderMethodID m_idConvertContentsToManaged;
2946 const BinderMethodID m_idConvertSpaceToNative;
2947 const BinderMethodID m_idConvertContentsToNative;
2948 const BinderMethodID m_idClearNative;
2949 const BinderMethodID m_idClearNativeContents;
2950 const BinderMethodID m_idClearManaged;
2951};
2952
2953class ILNativeArrayMarshaler : public ILMngdMarshaler
2954{
2955public:
2956 enum
2957 {
2958 c_fInOnly = FALSE,
2959 };
2960
2961 ILNativeArrayMarshaler() :
2962 ILMngdMarshaler(
2963 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
2964 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
2965 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
2966 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
2967 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE,
2968 METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
2969 METHOD__NIL
2970 )
2971 {
2972 LIMITED_METHOD_CONTRACT;
2973 m_dwSavedSizeArg = LOCAL_NUM_UNUSED;
2974 }
2975
2976 virtual void EmitMarshalArgumentCLRToNative();
2977 virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
2978 virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
2979 virtual void EmitClearNative(ILCodeStream* pslILEmit);
2980 virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
2981 virtual void EmitMarshalArgumentNativeToCLRByref();
2982 virtual void EmitMarshalArgumentCLRToNativeByref();
2983
2984protected:
2985
2986 bool UsePinnedArraySpecialCase();
2987
2988 BOOL CheckSizeParamIndexArg(const CREATE_MARSHALER_CARRAY_OPERANDS &mops, CorElementType *pElementType);
2989
2990 // Calculate element count and load it on evaluation stack
2991 void EmitLoadElementCount(ILCodeStream* pslILEmit);
2992
2993 virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
2994
2995 void EmitLoadNativeSize(ILCodeStream* pslILEmit);
2996 void EmitNewSavedSizeArgLocal();
2997
2998private :
2999 DWORD m_dwSavedSizeArg;
3000};
3001
3002class MngdNativeArrayMarshaler
3003{
3004public:
3005 static FCDECL3(void, CreateMarshaler, MngdNativeArrayMarshaler* pThis, MethodTable* pMT, UINT32 dwFlags);
3006 static FCDECL3(void, ConvertSpaceToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3007 static FCDECL3(void, ConvertContentsToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3008 static FCDECL4(void, ConvertSpaceToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
3009 static FCDECL3(void, ConvertContentsToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3010 static FCDECL3(void, ClearNative, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3011 static FCDECL3(void, ClearNativeContents, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3012
3013 static void DoClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3014
3015 enum
3016 {
3017 FLAG_NATIVE_DATA_VALID = 0x40000000
3018 };
3019
3020 MethodTable* m_pElementMT;
3021 TypeHandle m_Array;
3022 BOOL m_NativeDataValid;
3023 BOOL m_BestFitMap;
3024 BOOL m_ThrowOnUnmappableChar;
3025 VARTYPE m_vt;
3026};
3027
3028
3029#ifdef FEATURE_COMINTEROP
3030class ILSafeArrayMarshaler : public ILMngdMarshaler
3031{
3032public:
3033 enum
3034 {
3035 c_fInOnly = FALSE,
3036 };
3037
3038 ILSafeArrayMarshaler() :
3039 ILMngdMarshaler(
3040 METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
3041 METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3042 METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
3043 METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3044 METHOD__MNGD_SAFE_ARRAY_MARSHALER__CLEAR_NATIVE,
3045 METHOD__NIL,
3046 METHOD__NIL
3047 ),
3048 m_dwOriginalManagedLocalNum(-1)
3049 {
3050 LIMITED_METHOD_CONTRACT;
3051 }
3052
3053protected:
3054
3055 virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3056 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3057 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3058
3059 virtual void EmitReInitNative(ILCodeStream* pslILEmit)
3060 {
3061 CONTRACTL
3062 {
3063 THROWS;
3064 GC_TRIGGERS;
3065 MODE_ANY;
3066 }
3067 CONTRACTL_END;
3068 if (NeedsCheckForStatic() && pslILEmit->GetStreamType() != ILStubLinker::kExceptionCleanup)
3069 {
3070 // Keep the original value in native home as we are not going to allocate a new
3071 // one. If we cleared it here, we wouldn't be able to ConvertContentsToNative.
3072 // Always perform the real re-init in the ExceptionCleanup stream so the caller
3073 // doesn't get back garbage.
3074 }
3075 else
3076 {
3077 ILMngdMarshaler::EmitReInitNative(pslILEmit);
3078 }
3079 }
3080
3081 bool NeedsCheckForStatic()
3082 {
3083 WRAPPER_NO_CONTRACT;
3084 return IsByref(m_dwMarshalFlags) && !IsCLRToNative(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags);
3085 }
3086
3087 DWORD m_dwOriginalManagedLocalNum;
3088};
3089
3090class MngdSafeArrayMarshaler
3091{
3092public:
3093 static FCDECL4(void, CreateMarshaler, MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags);
3094 static FCDECL3(void, ConvertSpaceToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3095 static FCDECL4(void, ConvertContentsToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, Object* pOriginalManagedUNSAFE);
3096 static FCDECL3(void, ConvertSpaceToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3097 static FCDECL3(void, ConvertContentsToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3098 static FCDECL3(void, ClearNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3099
3100 enum StaticCheckStateFlags
3101 {
3102 SCSF_CheckForStatic = 1,
3103 SCSF_IsStatic = 2,
3104 SCSF_NativeDataValid = 4
3105 };
3106
3107 MethodTable* m_pElementMT;
3108 int m_iRank;
3109 VARTYPE m_vt;
3110 BYTE m_fStatic; // StaticCheckStateFlags
3111 BYTE m_nolowerbounds;
3112};
3113
3114class ILHiddenLengthArrayMarshaler : public ILMngdMarshaler
3115{
3116 friend class MngdHiddenLengthArrayMarshaler;
3117
3118public:
3119 enum
3120 {
3121 c_nativeSize = sizeof(LPVOID),
3122 c_CLRSize = sizeof(OBJECTREF),
3123 c_fInOnly = FALSE,
3124 };
3125
3126 ILHiddenLengthArrayMarshaler() :
3127 ILMngdMarshaler(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
3128 METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3129 METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
3130 METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3131 METHOD__WIN32NATIVE__COTASKMEMFREE,
3132 METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
3133 METHOD__NIL)
3134 {
3135 LIMITED_METHOD_CONTRACT;
3136 m_dwMngdMarshalerLocalNum = -1;
3137 }
3138
3139protected:
3140 virtual LocalDesc GetNativeType();
3141 virtual LocalDesc GetManagedType();
3142
3143 virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3144 virtual void EmitMarshalArgumentCLRToNative();
3145 virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
3146 virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
3147 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3148 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3149 virtual void EmitClearNative(ILCodeStream* pslILEmit);
3150 virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
3151
3152private:
3153 bool CanUsePinnedArray();
3154 void EmitLoadNativeArrayLength(ILCodeStream *pslILEmit);
3155
3156 virtual MethodDesc *GetConvertContentsToManagedMethod();
3157 virtual MethodDesc *GetConvertContentsToNativeMethod();
3158 virtual MethodDesc *GetClearNativeContentsMethod();
3159
3160 MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3161};
3162
3163class MngdHiddenLengthArrayMarshaler
3164{
3165public:
3166 static FCDECL4(void, CreateMarshaler, MngdHiddenLengthArrayMarshaler* pThis, MethodTable* pMT, SIZE_T cbElement, UINT16 vt);
3167 static FCDECL3(void, ConvertSpaceToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3168 static FCDECL3(void, ConvertContentsToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3169 static FCDECL4(void, ConvertSpaceToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
3170 static FCDECL3(void, ConvertContentsToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3171 static FCDECL3(void, ClearNativeContents, MngdHiddenLengthArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
3172
3173
3174private:
3175 SIZE_T GetArraySize(SIZE_T elements);
3176 void DoClearNativeContents(void** pNativeHome, INT32 cElements);
3177
3178private:
3179 MethodTable *m_pElementMT;
3180 SIZE_T m_cbElementSize;
3181 VARTYPE m_vt;
3182};
3183#endif // FEATURE_COMINTEROP
3184
3185
3186class ILReferenceCustomMarshaler : public ILMngdMarshaler
3187{
3188public:
3189 enum
3190 {
3191 c_fInOnly = FALSE,
3192 };
3193
3194 ILReferenceCustomMarshaler() :
3195 ILMngdMarshaler(
3196 METHOD__NIL,
3197 METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
3198 METHOD__NIL,
3199 METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
3200 METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_NATIVE,
3201 METHOD__NIL,
3202 METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_MANAGED
3203 )
3204 {
3205 LIMITED_METHOD_CONTRACT;
3206 }
3207
3208protected:
3209 virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
3210};
3211
3212class MngdRefCustomMarshaler
3213{
3214public:
3215 static FCDECL2(void, CreateMarshaler, MngdRefCustomMarshaler* pThis, void* pCMHelper);
3216 static FCDECL3(void, ConvertContentsToNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3217 static FCDECL3(void, ConvertContentsToManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3218 static FCDECL3(void, ClearNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3219 static FCDECL3(void, ClearManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3220
3221 static void DoClearNativeContents(MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
3222
3223 CustomMarshalerHelper* m_pCMHelper;
3224};
3225
3226
3227#ifdef FEATURE_COMINTEROP
3228class ILUriMarshaler : public ILMarshaler
3229{
3230public:
3231 enum
3232 {
3233 c_fInOnly = TRUE,
3234 c_nativeSize = sizeof(LPVOID),
3235 c_CLRSize = sizeof(OBJECTREF),
3236 };
3237
3238 static void EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3239 static void EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3240
3241protected:
3242 virtual LocalDesc GetNativeType();
3243 virtual LocalDesc GetManagedType();
3244
3245 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3246 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3247
3248 virtual bool NeedsClearNative();
3249 void EmitClearNative(ILCodeStream* pslILEmit);
3250};
3251
3252class ILNCCEventArgsMarshaler : public ILMarshaler
3253{
3254public:
3255 enum
3256 {
3257 c_fInOnly = TRUE,
3258 c_nativeSize = sizeof(LPVOID),
3259 c_CLRSize = sizeof(OBJECTREF),
3260 };
3261
3262 static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3263 static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3264
3265protected:
3266 virtual LocalDesc GetNativeType();
3267 virtual LocalDesc GetManagedType();
3268
3269 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3270 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3271
3272 virtual bool NeedsClearNative();
3273 void EmitClearNative(ILCodeStream* pslILEmit);
3274};
3275
3276class ILPCEventArgsMarshaler : public ILMarshaler
3277{
3278public:
3279 enum
3280 {
3281 c_fInOnly = TRUE,
3282 c_nativeSize = sizeof(LPVOID),
3283 c_CLRSize = sizeof(OBJECTREF),
3284 };
3285
3286 static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3287 static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
3288
3289protected:
3290 virtual LocalDesc GetNativeType();
3291 virtual LocalDesc GetManagedType();
3292
3293 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3294 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3295
3296 virtual bool NeedsClearNative();
3297 void EmitClearNative(ILCodeStream* pslILEmit);
3298};
3299
3300class ILDateTimeMarshaler : public ILMarshaler
3301{
3302public:
3303 enum
3304 {
3305 c_fInOnly = FALSE,
3306 c_nativeSize = sizeof(INT64), // = sizeof(Windows::Foundation::DateTime)
3307 c_CLRSize = VARIABLESIZE,
3308 };
3309
3310protected:
3311 virtual LocalDesc GetNativeType();
3312 virtual LocalDesc GetManagedType();
3313
3314 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3315 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3316
3317 virtual bool NeedsClearNative();
3318 virtual void EmitReInitNative(ILCodeStream* pslILEmit);
3319};
3320
3321class ILNullableMarshaler : public ILMarshaler
3322{
3323public:
3324 enum
3325 {
3326 c_fInOnly = FALSE,
3327 c_nativeSize = sizeof(LPVOID),
3328 c_CLRSize = VARIABLESIZE,
3329 };
3330
3331protected:
3332 virtual LocalDesc GetNativeType();
3333 virtual LocalDesc GetManagedType();
3334 virtual bool NeedsClearNative();
3335 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3336 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3337 virtual void EmitClearNative(ILCodeStream* pslILEmit);
3338
3339private:
3340 MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3341};
3342
3343class ILSystemTypeMarshaler : public ILMarshaler
3344{
3345public:
3346 enum
3347 {
3348 c_fInOnly = FALSE,
3349 c_nativeSize = sizeof(TypeNameNative),
3350 c_CLRSize = sizeof(OBJECTREF)
3351 };
3352
3353protected:
3354 virtual LocalDesc GetNativeType();
3355 virtual LocalDesc GetManagedType();
3356
3357 virtual void EmitConvertContentsCLRToNative(ILCodeStream * pslILEmit);
3358 virtual void EmitConvertContentsNativeToCLR(ILCodeStream * pslILEmit);
3359
3360 virtual bool NeedsClearNative();
3361 virtual void EmitClearNative(ILCodeStream * pslILEmit);
3362 virtual void EmitReInitNative(ILCodeStream * pslILEmit);
3363};
3364
3365class ILHResultExceptionMarshaler : public ILMarshaler
3366{
3367public:
3368 enum
3369 {
3370 c_fInOnly = FALSE,
3371 c_nativeSize = sizeof(INT32), // = sizeof(Windows::Foundation::HResult)
3372 c_CLRSize = sizeof(OBJECTREF),
3373 };
3374
3375protected:
3376 virtual LocalDesc GetNativeType();
3377 virtual LocalDesc GetManagedType();
3378
3379 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3380 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3381
3382 virtual bool NeedsClearNative();
3383};
3384
3385class ILKeyValuePairMarshaler : public ILMarshaler
3386{
3387public:
3388 enum
3389 {
3390 c_fInOnly = FALSE,
3391 c_nativeSize = sizeof(LPVOID),
3392 c_CLRSize = VARIABLESIZE,
3393 };
3394
3395protected:
3396 virtual LocalDesc GetNativeType();
3397 virtual LocalDesc GetManagedType();
3398 virtual bool NeedsClearNative();
3399 virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
3400 virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
3401 virtual void EmitClearNative(ILCodeStream* pslILEmit);
3402
3403private:
3404 MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
3405};
3406
3407#endif // FEATURE_COMINTEROP
3408