summaryrefslogtreecommitdiff
path: root/src/vm/ilmarshalers.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/ilmarshalers.h')
-rw-r--r--src/vm/ilmarshalers.h3443
1 files changed, 3443 insertions, 0 deletions
diff --git a/src/vm/ilmarshalers.h b/src/vm/ilmarshalers.h
new file mode 100644
index 0000000000..5337b081c6
--- /dev/null
+++ b/src/vm/ilmarshalers.h
@@ -0,0 +1,3443 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: ILMarshalers.h
+//
+
+//
+
+
+#include "common.h"
+#ifdef FEATURE_COMINTEROP
+#include "winstring.h"
+#endif //FEATURE_COMINTEROP
+#include "stubgen.h"
+#include "binder.h"
+#include "marshalnative.h"
+#include "clrvarargs.h"
+#ifdef FEATURE_COMINTEROP
+#include "stdinterfaces.h"
+#endif
+
+#define LOCAL_NUM_UNUSED ((DWORD)-1)
+
+class ILStubMarshalHome
+{
+public:
+ typedef enum
+ {
+ HomeType_Unspecified = 0,
+ HomeType_ILLocal = 1,
+ HomeType_ILArgument = 2,
+ HomeType_ILByrefLocal = 3,
+ HomeType_ILByrefArgument = 4
+ } MarshalHomeType;
+
+private:
+ MarshalHomeType m_homeType;
+ DWORD m_dwHomeIndex;
+
+public:
+ void InitHome(MarshalHomeType homeType, DWORD dwHomeIndex)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_homeType = homeType;
+ m_dwHomeIndex = dwHomeIndex;
+ }
+
+ void EmitLoadHome(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ switch (m_homeType)
+ {
+ case HomeType_ILLocal: pslILEmit->EmitLDLOC(m_dwHomeIndex); break;
+ case HomeType_ILArgument: pslILEmit->EmitLDARG(m_dwHomeIndex); break;
+
+ default:
+ UNREACHABLE_MSG("unexpected homeType passed to EmitLoadHome");
+ break;
+ }
+ }
+
+ void EmitLoadHomeAddr(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ switch (m_homeType)
+ {
+ case HomeType_ILLocal: pslILEmit->EmitLDLOCA(m_dwHomeIndex); break;
+ case HomeType_ILArgument: pslILEmit->EmitLDARGA(m_dwHomeIndex); break;
+ case HomeType_ILByrefLocal: pslILEmit->EmitLDLOC(m_dwHomeIndex); break;
+ case HomeType_ILByrefArgument: pslILEmit->EmitLDARG(m_dwHomeIndex); break;
+
+ default:
+ UNREACHABLE_MSG("unexpected homeType passed to EmitLoadHomeAddr");
+ break;
+ }
+ }
+
+ void EmitStoreHome(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ switch (m_homeType)
+ {
+ case HomeType_ILLocal: pslILEmit->EmitSTLOC(m_dwHomeIndex); break;
+ case HomeType_ILArgument: pslILEmit->EmitSTARG(m_dwHomeIndex); break;
+
+ default:
+ UNREACHABLE_MSG("unexpected homeType passed to EmitStoreHome");
+ break;
+ }
+ }
+
+ void EmitStoreHomeAddr(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ switch (m_homeType)
+ {
+ case HomeType_ILByrefLocal: pslILEmit->EmitSTLOC(m_dwHomeIndex); break;
+ case HomeType_ILByrefArgument: pslILEmit->EmitSTARG(m_dwHomeIndex); break;
+
+ default:
+ UNREACHABLE_MSG("unexpected homeType passed to EmitStoreHomeAddr");
+ break;
+ }
+ }
+
+ void EmitCopyFromByrefArg(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ CONSISTENCY_CHECK(pManagedType->cbType == 1);
+ if (pManagedType->IsValueClass())
+ {
+ EmitLoadHomeAddr(pslILEmit); // dest
+ pslILEmit->EmitLDARG(argidx); // src
+ pslILEmit->EmitCPOBJ(pslILEmit->GetToken(pManagedType->InternalToken));
+ }
+ else
+ {
+ pslILEmit->EmitLDARG(argidx);
+ pslILEmit->EmitLDIND_T(pManagedType);
+ EmitStoreHome(pslILEmit);
+ }
+ }
+
+ void EmitCopyToByrefArg(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (pManagedType->IsValueClass())
+ {
+ pslILEmit->EmitLDARG(argidx); // dest
+ EmitLoadHomeAddr(pslILEmit); // src
+ pslILEmit->EmitCPOBJ(pslILEmit->GetToken(pManagedType->InternalToken));
+ }
+ else
+ {
+ pslILEmit->EmitLDARG(argidx);
+ EmitLoadHome(pslILEmit);
+ pslILEmit->EmitSTIND_T(pManagedType);
+ }
+ }
+
+ void EmitCopyToByrefArgWithNullCheck(ILCodeStream* pslILEmit, LocalDesc* pManagedType, DWORD argidx)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ // prevent null-ref exception by an explicit check
+ pslILEmit->EmitLDARG(argidx);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitCopyToByrefArg(pslILEmit, pManagedType, argidx);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+ }
+};
+
+
+class ILMarshaler
+{
+protected:
+
+#ifdef _DEBUG
+ const static UINT s_cbStackAllocThreshold = 128;
+#else
+ const static UINT s_cbStackAllocThreshold = 2048;
+#endif // _DEBUG
+
+ OverrideProcArgs* m_pargs;
+ NDirectStubLinker* m_pslNDirect;
+ ILCodeStream* m_pcsMarshal;
+ ILCodeStream* m_pcsUnmarshal;
+ UINT m_argidx;
+
+ DWORD m_dwMarshalFlags;
+
+ ILStubMarshalHome m_nativeHome;
+ ILStubMarshalHome m_managedHome;
+
+ DWORD m_dwMngdMarshalerLocalNum;
+
+public:
+
+ ILMarshaler() :
+ m_pslNDirect(NULL)
+ {
+ }
+
+ virtual ~ILMarshaler()
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ void SetNDirectStubLinker(NDirectStubLinker* pslNDirect)
+ {
+ LIMITED_METHOD_CONTRACT;
+ CONSISTENCY_CHECK(NULL == m_pslNDirect);
+ m_pslNDirect = pslNDirect;
+ }
+
+ void Init(ILCodeStream* pcsMarshal,
+ ILCodeStream* pcsUnmarshal,
+ UINT argidx,
+ DWORD dwMarshalFlags,
+ OverrideProcArgs* pargs)
+ {
+ LIMITED_METHOD_CONTRACT;
+ CONSISTENCY_CHECK_MSG(m_pslNDirect != NULL, "please call SetNDirectStubLinker() before EmitMarshalArgument or EmitMarshalReturnValue");
+ m_pcsMarshal = pcsMarshal;
+ m_pcsUnmarshal = pcsUnmarshal;
+ m_pargs = pargs;
+ m_dwMarshalFlags = dwMarshalFlags;
+ m_argidx = argidx;
+ m_dwMngdMarshalerLocalNum = -1;
+ }
+
+protected:
+ static inline bool IsCLRToNative(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_CLR_TO_NATIVE));
+ }
+
+ static inline bool IsIn(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_IN));
+ }
+
+ static inline bool IsOut(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_OUT));
+ }
+
+ static inline bool IsByref(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_BYREF));
+ }
+
+ static inline bool IsHresultSwap(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_HRESULT_SWAP));
+ }
+
+ static inline bool IsRetval(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_RETVAL));
+ }
+
+ static inline bool IsHiddenLengthParam(DWORD dwMarshalFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (0 != (dwMarshalFlags & MARSHAL_FLAG_HIDDENLENPARAM));
+ }
+
+ void EmitLoadManagedValue(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_managedHome.EmitLoadHome(pslILEmit);
+ }
+
+ void EmitLoadNativeValue(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_nativeHome.EmitLoadHome(pslILEmit);
+ }
+
+ void EmitLoadManagedHomeAddr(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_managedHome.EmitLoadHomeAddr(pslILEmit);
+ }
+
+ void EmitLoadNativeHomeAddr(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_nativeHome.EmitLoadHomeAddr(pslILEmit);
+ }
+
+ void EmitStoreManagedValue(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_managedHome.EmitStoreHome(pslILEmit);
+ }
+
+ void EmitStoreManagedHomeAddr(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_managedHome.EmitStoreHomeAddr(pslILEmit);
+ }
+
+ void EmitStoreNativeValue(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_nativeHome.EmitStoreHome(pslILEmit);
+ }
+
+ void EmitStoreNativeHomeAddr(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_nativeHome.EmitStoreHomeAddr(pslILEmit);
+ }
+
+public:
+
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return true;
+ }
+
+ virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return true;
+ }
+
+ // True if marshaling creates data that could need cleanup.
+ bool NeedsMarshalCleanupIndex()
+ {
+ WRAPPER_NO_CONTRACT;
+ return (NeedsClearNative() || NeedsClearCLR());
+ }
+
+ // True if unmarshaling creates data that could need exception cleanup ("rollback").
+ bool NeedsUnmarshalCleanupIndex()
+ {
+ WRAPPER_NO_CONTRACT;
+ return (NeedsClearNative() && !IsCLRToNative(m_dwMarshalFlags));
+ }
+
+ void EmitMarshalArgument(
+ ILCodeStream* pcsMarshal,
+ ILCodeStream* pcsUnmarshal,
+ UINT argidx,
+ DWORD dwMarshalFlags,
+ OverrideProcArgs* pargs)
+ {
+ STANDARD_VM_CONTRACT;
+
+ Init(pcsMarshal, pcsUnmarshal, argidx, dwMarshalFlags, pargs);
+
+ // We could create the marshaler in the marshal stream right before it's needed (i.e. within the try block),
+ // or in the setup stream (outside of the try block). For managed-to-unmanaged marshaling it does not actually
+ // make much difference except that using setup stream saves us from cleaning up already-marshaled arguments
+ // in case of an exception. For unmanaged-to-managed, we may need to perform cleanup of the incoming arguments
+ // before we were able to marshal them. Therefore this must not happen within the try block so we don't try
+ // to use marshalers that have not been initialized. Potentially leaking unmanaged resources is by-design and
+ // there's not much we can do about it (we cannot do cleanup if we cannot create the marshaler).
+ EmitCreateMngdMarshaler(m_pslNDirect->GetSetupCodeStream());
+
+ if (IsCLRToNative(dwMarshalFlags))
+ {
+ if (IsByref(dwMarshalFlags))
+ {
+ EmitMarshalArgumentCLRToNativeByref();
+ }
+ else
+ {
+ EmitMarshalArgumentCLRToNative();
+ }
+ }
+ else
+ {
+ if (IsByref(dwMarshalFlags))
+ {
+ EmitMarshalArgumentNativeToCLRByref();
+ }
+ else
+ {
+ EmitMarshalArgumentNativeToCLR();
+ }
+ }
+ }
+
+#ifdef FEATURE_COMINTEROP
+ void EmitMarshalHiddenLengthArgument(ILCodeStream *pcsMarshal,
+ ILCodeStream *pcsUnmarshal,
+ MarshalInfo *pArrayInfo,
+ UINT arrayIndex,
+ DWORD dwMarshalFlags,
+ UINT hiddenArgIndex,
+ OverrideProcArgs *pargs,
+ __out DWORD *pdwHiddenLengthManagedHomeLocal,
+ __out DWORD *pdwHiddenLengthNativeHomeLocal)
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsHiddenLengthParam(dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ Init(pcsMarshal, pcsUnmarshal, hiddenArgIndex, dwMarshalFlags, pargs);
+ EmitCreateMngdMarshaler(m_pslNDirect->GetSetupCodeStream());
+
+ // Create a local to be the home of the length parameter
+ DWORD dwManagedLocalHome = m_pcsMarshal->NewLocal(GetManagedType());
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwManagedLocalHome);
+ *pdwHiddenLengthManagedHomeLocal = dwManagedLocalHome;
+
+ // managed length = 0
+ m_pcsMarshal->EmitLDC(0);
+ m_pcsMarshal->EmitCONV_T(pArrayInfo->GetHiddenLengthParamElementType());
+ m_pcsMarshal->EmitSTLOC(dwManagedLocalHome);
+
+ // And a local to be the home of the marshaled length
+ LocalDesc nativeArgType(GetNativeType());
+ DWORD dwNativeHomeLocal = m_pcsMarshal->NewLocal(nativeArgType);
+ if (IsByref(dwMarshalFlags))
+ {
+ nativeArgType.MakeByRef();
+ }
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwNativeHomeLocal);
+ *pdwHiddenLengthNativeHomeLocal = dwNativeHomeLocal;
+
+ // Update the native signature to contain the new native parameter
+ m_pcsMarshal->SetStubTargetArgType(&nativeArgType, false);
+
+ if (IsCLRToNative(dwMarshalFlags))
+ {
+ // Load the length of the array into the local
+ if (IsIn(dwMarshalFlags))
+ {
+ ILCodeLabel *pSkipGetLengthLabel = m_pcsMarshal->NewCodeLabel();
+ m_pcsMarshal->EmitLDARG(arrayIndex);
+ m_pcsMarshal->EmitBRFALSE(pSkipGetLengthLabel);
+
+ m_pcsMarshal->EmitLDARG(arrayIndex);
+
+ if (IsByref(dwMarshalFlags))
+ {
+ // if (*array == null) goto pSkipGetLengthLabel
+ m_pcsMarshal->EmitLDIND_REF();
+ m_pcsMarshal->EmitBRFALSE(pSkipGetLengthLabel);
+
+ // array = *array
+ m_pcsMarshal->EmitLDARG(arrayIndex);
+ m_pcsMarshal->EmitLDIND_REF();
+ }
+
+ m_pcsMarshal->EmitLDLEN();
+ m_pcsMarshal->EmitCONV_T(pArrayInfo->GetHiddenLengthParamElementType());
+ m_pcsMarshal->EmitSTLOC(dwManagedLocalHome);
+ m_pcsMarshal->EmitLabel(pSkipGetLengthLabel);
+ }
+
+ if (IsByref(dwMarshalFlags))
+ {
+ EmitMarshalArgumentContentsCLRToNativeByref(true);
+ }
+ else
+ {
+ EmitMarshalArgumentContentsCLRToNative();
+ }
+ }
+ else
+ {
+ // Load the length of the array into the local
+ if (IsIn(dwMarshalFlags))
+ {
+ m_pcsMarshal->EmitLDARG(hiddenArgIndex);
+ if (IsByref(dwMarshalFlags))
+ {
+ LocalDesc nativeParamType(GetNativeType());
+ m_pcsMarshal->EmitLDIND_T(&nativeParamType);
+ }
+ m_pcsMarshal->EmitSTLOC(dwNativeHomeLocal);
+ }
+
+ if (IsByref(dwMarshalFlags))
+ {
+ EmitMarshalArgumentContentsNativeToCLRByref(true);
+ }
+ else
+ {
+ EmitMarshalArgumentContentsNativeToCLR();
+ }
+
+ // We can't copy the final length back to the parameter just yet, since we don't know what
+ // local the array lives in. Instead, we rely on the hidden length array marshaler to copy
+ // the value into the out parameter for us.
+ }
+ }
+
+#endif // FEATURE_COMINTEROP
+
+ virtual void EmitSetupArgument(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ if (IsNativePassedByRef())
+ {
+ EmitLoadNativeHomeAddr(pslILEmit);
+ }
+ else
+ {
+ EmitLoadNativeValue(pslILEmit);
+ }
+ }
+ else
+ {
+ if (IsManagedPassedByRef())
+ {
+ EmitLoadManagedHomeAddr(pslILEmit);
+ }
+ else
+ {
+ EmitLoadManagedValue(pslILEmit);
+ }
+ }
+ }
+
+ virtual void EmitMarshalReturnValue(
+ ILCodeStream* pcsMarshal,
+ ILCodeStream* pcsUnmarshal,
+ ILCodeStream* pcsDispatch,
+ UINT argidx,
+ UINT16 wNativeSize,
+ DWORD dwMarshalFlags,
+ OverrideProcArgs* pargs)
+ {
+ STANDARD_VM_CONTRACT;
+
+ Init(pcsMarshal, pcsUnmarshal, argidx, dwMarshalFlags, pargs);
+
+ LocalDesc nativeType = GetNativeType();
+ LocalDesc managedType = GetManagedType();
+
+ bool byrefNativeReturn = false;
+ CorElementType typ = ELEMENT_TYPE_VOID;
+ UINT32 nativeSize = 0;
+
+ // we need to convert value type return types to primitives as
+ // JIT does not inline P/Invoke calls that return structures
+ if (nativeType.IsValueClass())
+ {
+ if (wNativeSize == VARIABLESIZE)
+ {
+ // the unmanaged type size is variable
+ nativeSize = m_pargs->m_pMT->GetNativeSize();
+ }
+ else
+ {
+ // the unmanaged type size is fixed
+ nativeSize = wNativeSize;
+ }
+
+#if defined(_TARGET_X86_) || (defined(_TARGET_AMD64_) && defined(_WIN64) && !defined(FEATURE_CORECLR))
+ // JIT32 and JIT64 (which is only used on the Windows Desktop CLR) has a problem generating
+ // code for the pinvoke ILStubs which do a return using a struct type. Therefore, we
+ // change the signature of calli to return void and make the return buffer as first argument.
+
+ // for X86 and AMD64-Windows we bash the return type from struct to U1, U2, U4 or U8
+ // and use byrefNativeReturn for all other structs.
+ switch (nativeSize)
+ {
+ case 1: typ = ELEMENT_TYPE_U1; break;
+ case 2: typ = ELEMENT_TYPE_U2; break;
+ case 4: typ = ELEMENT_TYPE_U4; break;
+ case 8: typ = ELEMENT_TYPE_U8; break;
+ default: byrefNativeReturn = true; break;
+ }
+#endif
+ }
+
+ if (IsHresultSwap(dwMarshalFlags) || (byrefNativeReturn && IsCLRToNative(dwMarshalFlags)))
+ {
+ LocalDesc extraParamType = nativeType;
+ extraParamType.MakeByRef();
+
+ m_pcsMarshal->SetStubTargetArgType(&extraParamType, false);
+
+ if (IsHresultSwap(dwMarshalFlags))
+ {
+ // HRESULT swapping: the original return value is transformed into an extra
+ // byref parameter and the target is expected to return an HRESULT
+ m_pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4); // native method returns an HRESULT
+ }
+ else
+ {
+ // byref structure return: the original return value is transformed into an
+ // extra byref parameter and the target is not expected to return anything
+ //
+ // note: we do this only for forward calls because [unmanaged calling conv.
+ // uses byref return] implies [managed calling conv. uses byref return]
+ m_pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_VOID);
+ }
+ }
+ else
+ {
+ if (typ != ELEMENT_TYPE_VOID)
+ {
+ // small structure return: the original return value is transformed into
+ // ELEMENT_TYPE_U1, ELEMENT_TYPE_U2, ELEMENT_TYPE_U4, or ELEMENT_TYPE_U8
+ m_pcsMarshal->SetStubTargetReturnType(typ);
+ }
+ else
+ {
+ m_pcsMarshal->SetStubTargetReturnType(&nativeType);
+ }
+ }
+
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
+
+ EmitCreateMngdMarshaler(m_pcsMarshal);
+
+ if (IsCLRToNative(dwMarshalFlags))
+ {
+ if (IsHresultSwap(dwMarshalFlags) || byrefNativeReturn)
+ {
+ EmitReInitNative(m_pcsMarshal);
+ EmitLoadNativeHomeAddr(pcsDispatch); // load up the byref native type as an extra arg
+ }
+ else
+ {
+ if (typ != ELEMENT_TYPE_VOID)
+ {
+ // small structure forward: the returned integer is memcpy'd into native home
+ // of the structure
+
+ DWORD dwTempLocalNum = m_pcsUnmarshal->NewLocal(typ);
+ m_pcsUnmarshal->EmitSTLOC(dwTempLocalNum);
+
+ // cpblk
+ m_nativeHome.EmitLoadHomeAddr(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitLDLOCA(dwTempLocalNum);
+ m_pcsUnmarshal->EmitLDC(nativeSize);
+ m_pcsUnmarshal->EmitCPBLK();
+ }
+ else
+ {
+ EmitStoreNativeValue(m_pcsUnmarshal);
+ }
+ }
+
+ if (NeedsMarshalCleanupIndex())
+ {
+ m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx);
+ }
+
+ EmitConvertSpaceAndContentsNativeToCLR(m_pcsUnmarshal);
+
+ EmitCleanupCLRToNative();
+
+ EmitLoadManagedValue(m_pcsUnmarshal);
+ }
+ else
+ {
+ EmitStoreManagedValue(m_pcsUnmarshal);
+
+ if (NeedsMarshalCleanupIndex())
+ {
+ m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx);
+ }
+
+ if (IsHresultSwap(dwMarshalFlags))
+ {
+ // we have to skip unmarshaling return value into the HRESULT-swapped argument
+ // if the argument came as NULL (otherwise we would leak unmanaged resources as
+ // we have no way of passing them back to the caller)
+ ILCodeLabel *pSkipConversionLabel = m_pcsUnmarshal->NewCodeLabel();
+
+ m_pcsUnmarshal->EmitLDARG(argidx);
+ m_pcsUnmarshal->EmitBRFALSE(pSkipConversionLabel);
+ EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitLabel(pSkipConversionLabel);
+ }
+ else
+ {
+ EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
+ }
+
+ if (NeedsUnmarshalCleanupIndex())
+ {
+ // if an exception is thrown after this point, we will clean up the unmarshaled retval
+ m_pslNDirect->EmitSetArgMarshalIndex(m_pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
+ }
+
+ EmitCleanupNativeToCLR();
+
+ if (IsHresultSwap(dwMarshalFlags))
+ {
+ // we tolerate NULL here mainly for backward compatibility reasons
+ m_nativeHome.EmitCopyToByrefArgWithNullCheck(m_pcsUnmarshal, &nativeType, argidx);
+ m_pcsUnmarshal->EmitLDC(S_OK);
+ }
+ else
+ {
+ if (typ != ELEMENT_TYPE_VOID)
+ {
+ // small structure return (reverse): native home of the structure is memcpy'd
+ // into the integer to be returned from the stub
+
+ DWORD dwTempLocalNum = m_pcsUnmarshal->NewLocal(typ);
+
+ // cpblk
+ m_pcsUnmarshal->EmitLDLOCA(dwTempLocalNum);
+ m_nativeHome.EmitLoadHomeAddr(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitLDC(nativeSize);
+ m_pcsUnmarshal->EmitCPBLK();
+
+ m_pcsUnmarshal->EmitLDLOC(dwTempLocalNum);
+ }
+ else
+ {
+ EmitLoadNativeValue(m_pcsUnmarshal);
+ }
+ }
+
+ // make sure we free (and zero) the return value if an exception is thrown
+ EmitExceptionCleanupNativeToCLR();
+ }
+ }
+
+
+protected:
+
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitLoadMngdMarshaler(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ CONSISTENCY_CHECK((DWORD)-1 != m_dwMngdMarshalerLocalNum);
+ pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
+ }
+
+ void EmitSetupSigAndDefaultHomesCLRToNative()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc nativeArgType = GetNativeType();
+ DWORD dwNativeHomeLocalNum = m_pcsMarshal->NewLocal(nativeArgType);
+ m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
+
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILArgument, m_argidx);
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, dwNativeHomeLocalNum);
+ }
+
+ void EmitCleanupCLRToNativeTemp()
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (NeedsClearNative())
+ {
+ CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
+
+ ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
+ ILCodeLabel* pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
+
+ m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pSkipClearNativeLabel);
+
+ EmitClearNativeTemp(pcsCleanup);
+ pcsCleanup->EmitLabel(pSkipClearNativeLabel);
+ }
+ }
+
+ void EmitCleanupCLRToNative()
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (NeedsClearNative())
+ {
+ CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
+
+ ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
+ ILCodeLabel* pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
+
+ m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pSkipClearNativeLabel);
+
+ EmitClearNative(pcsCleanup);
+ pcsCleanup->EmitLabel(pSkipClearNativeLabel);
+ }
+ }
+
+ virtual void EmitMarshalArgumentCLRToNative()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+ EmitMarshalArgumentContentsCLRToNative();
+ }
+
+ void EmitMarshalArgumentContentsCLRToNative()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ //
+ // marshal
+ //
+ if (IsIn(m_dwMarshalFlags))
+ {
+ EmitConvertSpaceAndContentsCLRToNativeTemp(m_pcsMarshal);
+ }
+ else
+ {
+ EmitConvertSpaceCLRToNativeTemp(m_pcsMarshal);
+ }
+
+ //
+ // unmarshal
+ //
+ if (IsOut(m_dwMarshalFlags))
+ {
+ if (IsIn(m_dwMarshalFlags))
+ {
+ EmitClearCLRContents(m_pcsUnmarshal);
+ }
+ EmitConvertContentsNativeToCLR(m_pcsUnmarshal);
+ }
+
+ EmitCleanupCLRToNativeTemp();
+ }
+
+ void EmitSetupSigAndDefaultHomesCLRToNativeByref(bool fBlittable = false)
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc nativeType = GetNativeType();
+ LocalDesc managedType = GetManagedType();
+
+ LocalDesc nativeArgType = nativeType;
+ nativeArgType.MakeByRef();
+ m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
+
+ if (fBlittable)
+ {
+ // we will not work with the actual data but only with a pointer to that data
+ // (the managed and native type had better be the same if it's blittable)
+ _ASSERTE(nativeType.ElementType[0] == managedType.ElementType[0]);
+
+ // native home will keep the containing object pinned
+ nativeType.MakeByRef();
+ nativeType.MakePinned();
+
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILByrefArgument, m_argidx);
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, m_pcsMarshal->NewLocal(nativeType));
+ }
+ else
+ {
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
+ }
+ }
+
+ virtual void EmitMarshalArgumentCLRToNativeByref()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNativeByref();
+ EmitMarshalArgumentContentsCLRToNativeByref(false);
+ }
+
+ void EmitMarshalArgumentContentsCLRToNativeByref(bool managedHomeAlreadyInitialized)
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc managedType = GetManagedType();
+
+ //
+ // marshal
+ //
+ if (IsIn(m_dwMarshalFlags) && ! IsOut(m_dwMarshalFlags))
+ {
+ if (!managedHomeAlreadyInitialized)
+ {
+ m_managedHome.EmitCopyFromByrefArg(m_pcsMarshal, &managedType, m_argidx);
+ }
+
+ EmitConvertSpaceAndContentsCLRToNativeTemp(m_pcsMarshal);
+ }
+ else if (IsIn(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags))
+ {
+ if (!managedHomeAlreadyInitialized)
+ {
+ m_managedHome.EmitCopyFromByrefArg(m_pcsMarshal, &managedType, m_argidx);
+ }
+
+ EmitConvertSpaceAndContentsCLRToNative(m_pcsMarshal);
+ }
+ else
+ {
+ EmitReInitNative(m_pcsMarshal);
+ }
+
+ //
+ // unmarshal
+ //
+ if (IsOut(m_dwMarshalFlags))
+ {
+ EmitClearCLR(m_pcsUnmarshal);
+
+ EmitConvertSpaceAndContentsNativeToCLR(m_pcsUnmarshal);
+
+ if (!managedHomeAlreadyInitialized)
+ {
+ m_managedHome.EmitCopyToByrefArg(m_pcsUnmarshal, &managedType, m_argidx);
+ }
+
+ EmitCleanupCLRToNative();
+ }
+ else
+ {
+ EmitCleanupCLRToNativeTemp();
+ }
+ //
+ // @TODO: ensure ReInitNative is called on [in,out] byref args when an exception occurs
+ //
+ }
+
+ void EmitSetupSigAndDefaultHomesNativeToCLR()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc nativeArgType = GetNativeType();
+ m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
+
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(GetManagedType()));
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILArgument, m_argidx);
+ }
+
+ void EmitCleanupNativeToCLR()
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (NeedsClearCLR())
+ {
+ CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
+
+ ILCodeStream* pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
+ ILCodeLabel* pSkipClearCLRLabel = pcsCleanup->NewCodeLabel();
+
+ m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pSkipClearCLRLabel);
+
+ EmitClearCLR(pcsCleanup);
+ pcsCleanup->EmitLabel(pSkipClearCLRLabel);
+ }
+ }
+
+ // Emits cleanup code that runs only if an exception is thrown during execution of an IL stub (its try
+ // block to be precise). The goal is to roll back allocations of native resources that may have already
+ // happened to prevent leaks, and also clear output arguments to prevent passing out invalid data - most
+ // importantly dangling pointers. The canonical example is an exception thrown during unmarshaling of
+ // an argument at which point other arguments have already been unmarshaled.
+ void EmitExceptionCleanupNativeToCLR()
+ {
+ STANDARD_VM_CONTRACT;
+
+ _ASSERTE(IsRetval(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags));
+
+ LocalDesc nativeType = GetNativeType();
+ ILCodeStream *pcsCleanup = m_pslNDirect->GetExceptionCleanupCodeStream();
+
+ if (NeedsClearNative())
+ {
+ m_pslNDirect->SetExceptionCleanupNeeded();
+
+ ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
+
+ // if this is byref in/out and we have not marshaled this argument
+ // yet, we need to populate the native home with the incoming value
+ if (IsIn(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pSkipCopyLabel = pcsCleanup->NewCodeLabel();
+
+ CONSISTENCY_CHECK(NeedsMarshalCleanupIndex());
+ m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_argidx,
+ NDirectStubLinker::BranchIfMarshaled,
+ pSkipCopyLabel);
+
+ pcsCleanup->EmitLDARG(m_argidx);
+ pcsCleanup->EmitBRFALSE(pSkipCleanupLabel); // if the argument is NULL, skip cleanup completely
+
+ m_nativeHome.EmitCopyFromByrefArg(pcsCleanup, &nativeType, m_argidx);
+
+ pcsCleanup->EmitLabel(pSkipCopyLabel);
+ }
+
+ // if this is retval or out-only, the native home does not get initialized until we unmarshal it
+ if (IsRetval(m_dwMarshalFlags) || !IsIn(m_dwMarshalFlags))
+ {
+ CONSISTENCY_CHECK(NeedsUnmarshalCleanupIndex());
+
+ UINT uArgIdx = (IsRetval(m_dwMarshalFlags) ?
+ NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL :
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_UNMARSHAL + m_argidx);
+
+ m_pslNDirect->EmitCheckForArgCleanup(pcsCleanup,
+ uArgIdx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pSkipCleanupLabel);
+ }
+
+ // we know that native home needs to be cleaned up at this point
+ if (IsRetval(m_dwMarshalFlags) || (IsOut(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags)))
+ {
+ // we own the buffer - clear everything
+ EmitClearNative(pcsCleanup);
+ }
+ else
+ {
+ // this is a caller supplied buffer - clear only its contents
+ EmitClearNativeContents(pcsCleanup);
+ }
+
+ pcsCleanup->EmitLabel(pSkipCleanupLabel);
+ }
+
+ // if there is an output buffer, zero it out so the caller does not get pointer to already freed data
+ if (!IsHiddenLengthParam(m_dwMarshalFlags))
+ {
+ if (IsRetval(m_dwMarshalFlags) || (IsOut(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags)))
+ {
+ m_pslNDirect->SetExceptionCleanupNeeded();
+
+ EmitReInitNative(pcsCleanup);
+ if (IsHresultSwap(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags))
+ {
+ m_nativeHome.EmitCopyToByrefArgWithNullCheck(pcsCleanup, &nativeType, m_argidx);
+ }
+ }
+ }
+ }
+
+ virtual void EmitMarshalArgumentNativeToCLR()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesNativeToCLR();
+ EmitMarshalArgumentContentsNativeToCLR();
+ }
+
+ void EmitMarshalArgumentContentsNativeToCLR()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ //
+ // marshal
+ //
+ if (IsIn(m_dwMarshalFlags))
+ {
+ EmitConvertSpaceAndContentsNativeToCLR(m_pcsMarshal);
+ }
+ else
+ {
+ EmitConvertSpaceNativeToCLR(m_pcsMarshal);
+ }
+
+ //
+ // unmarshal
+ //
+ if (IsOut(m_dwMarshalFlags))
+ {
+ if (IsIn(m_dwMarshalFlags))
+ {
+ EmitClearNativeContents(m_pcsUnmarshal);
+ }
+ EmitConvertContentsCLRToNative(m_pcsUnmarshal);
+
+ // make sure we free the argument if an exception is thrown
+ EmitExceptionCleanupNativeToCLR();
+ }
+ EmitCleanupNativeToCLR();
+ }
+
+ void EmitSetupSigAndDefaultHomesNativeToCLRByref(bool fBlittable = false)
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc nativeType = GetNativeType();
+ LocalDesc managedType = GetManagedType();
+ LocalDesc nativeArgType = nativeType;
+ nativeArgType.MakeByRef();
+ m_pcsMarshal->SetStubTargetArgType(&nativeArgType);
+
+ if (fBlittable)
+ {
+ // we will not work with the actual data but only with a pointer to that data
+ // (the managed and native type had better be the same if it's blittable)
+ _ASSERTE(nativeType.ElementType[0] == managedType.ElementType[0]);
+
+ managedType.MakeByRef();
+
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, m_pcsMarshal->NewLocal(managedType));
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefArgument, m_argidx);
+ }
+ else
+ {
+ m_managedHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(managedType));
+ m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILLocal, m_pcsMarshal->NewLocal(nativeType));
+ }
+ }
+
+ virtual void EmitMarshalArgumentNativeToCLRByref()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesNativeToCLRByref();
+ EmitMarshalArgumentContentsNativeToCLRByref(false);
+ }
+
+ void EmitMarshalArgumentContentsNativeToCLRByref(bool nativeHomeAlreadyInitialized)
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ LocalDesc nativeType = GetNativeType();
+
+ //
+ // marshal
+ //
+ if (IsIn(m_dwMarshalFlags))
+ {
+ if (!nativeHomeAlreadyInitialized)
+ {
+ m_nativeHome.EmitCopyFromByrefArg(m_pcsMarshal, &nativeType, m_argidx);
+ }
+
+ EmitConvertSpaceAndContentsNativeToCLR(m_pcsMarshal);
+ }
+ else
+ {
+ // dereference the argument so we throw before calling the managed target - this is the fastest way
+ // to check for NULL (we can still throw later if the pointer is invalid yet non-NULL but we cannot
+ // detect this realiably - the memory may get unmapped etc., NULL check is the best we can do here)
+ m_pcsMarshal->EmitLDARG(m_argidx);
+ m_pcsMarshal->EmitLDIND_I1();
+ m_pcsMarshal->EmitPOP();
+ }
+
+ //
+ // unmarshal
+ //
+ if (IsOut(m_dwMarshalFlags))
+ {
+ if (IsIn(m_dwMarshalFlags))
+ {
+ EmitClearNative(m_pcsUnmarshal);
+ EmitReInitNative(m_pcsUnmarshal);
+ }
+
+ EmitConvertSpaceAndContentsCLRToNative(m_pcsUnmarshal);
+
+ if (!nativeHomeAlreadyInitialized)
+ {
+ m_nativeHome.EmitCopyToByrefArg(m_pcsUnmarshal, &nativeType, m_argidx);
+ }
+
+ // make sure we free and zero the by-ref argument if an exception is thrown
+ EmitExceptionCleanupNativeToCLR();
+ }
+
+ EmitCleanupNativeToCLR();
+ }
+
+ virtual LocalDesc GetNativeType() = 0;
+ virtual LocalDesc GetManagedType() = 0;
+
+ //
+ // Native-to-CLR
+ //
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitConvertSpaceNativeToCLR(pslILEmit);
+ EmitConvertContentsNativeToCLR(pslILEmit);
+ }
+
+
+ //
+ // CLR-to-Native
+ //
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ EmitConvertSpaceCLRToNative(pslILEmit);
+ }
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+ EmitConvertSpaceCLRToNative(pslILEmit);
+ EmitConvertContentsCLRToNative(pslILEmit);
+ }
+
+ virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitConvertSpaceAndContentsCLRToNative(pslILEmit);
+ }
+
+ //
+ // Misc
+ //
+ virtual void EmitClearCLRContents(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual bool NeedsClearNative()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return false;
+ }
+
+ virtual void EmitClearNative(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ EmitClearNative(pslILEmit);
+ }
+
+ virtual void EmitClearNativeContents(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual bool NeedsClearCLR()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return false;
+ }
+
+ virtual void EmitClearCLR(ILCodeStream* pslILEmit)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ // Friendly Reminder:
+ // You should implement your own EmitReInitNative if your native type is a struct,
+ // as the following instructions apparently won't work on value types and will trigger
+ // an ASSERT in JIT
+ _ASSERTE(!GetNativeType().IsValueClass());
+
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCONV_T(static_cast<CorElementType>(GetNativeType().ElementType[0]));
+
+ EmitStoreNativeValue(pslILEmit);
+ }
+
+ virtual bool IsManagedPassedByRef()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return IsByref(m_dwMarshalFlags);
+ }
+
+ virtual bool IsNativePassedByRef()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return IsByref(m_dwMarshalFlags);
+ }
+
+ void EmitInterfaceClearNative(ILCodeStream* pslILEmit);
+
+public:
+ static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return HANDLEASNORMAL;
+ }
+
+ static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker* psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs* pargs,
+ UINT* pResID)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return HANDLEASNORMAL;
+ }
+};
+
+
+class ILCopyMarshalerBase : public ILMarshaler
+{
+ virtual LocalDesc GetManagedType()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetNativeType();
+ }
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitStoreNativeValue(pslILEmit);
+ }
+
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ EmitStoreManagedValue(pslILEmit);
+ }
+
+ //
+ // It's very unforunate that x86 used ML_COPYPINNEDGCREF for byref args.
+ // The result is that developers can get away with being lazy about their
+ // in/out semantics and often times in/out byref params are marked out-
+ // only, but because of ML_COPYPINNEDGCREF, they get in/out behavior.
+ //
+ // There are even lazier developers who use byref params to pass arrays.
+ // Pinning ensures that the native side 'sees' the entire array even when
+ // only reference to one element was passed.
+ //
+ // This method was changed to pin instead of copy in Dev10 in order
+ // to match the original ML behavior.
+ //
+ virtual void EmitMarshalArgumentCLRToNativeByref()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNativeByref(true);
+
+ //
+ // marshal
+ //
+ EmitLoadManagedHomeAddr(m_pcsMarshal);
+ EmitStoreNativeHomeAddr(m_pcsMarshal);
+
+ //
+ // no unmarshaling is necessary since we directly passed the pinned byref to native,
+ // the argument is therefore automatically in/out
+ //
+ }
+
+ //
+ // Similarly to the other direction, ML used ML_COPYPINNEDGCREF on x86 to
+ // directly pass the unmanaged pointer as a byref argument to managed code.
+ // This also makes an observable difference (allows passing NULL, changes
+ // made to the original value during the call are visible in managed).
+ //
+ // This method was changed to pass pointer instead of copy in Dev10 in order
+ // to match the original ML behavior. Note that in this direction we don't
+ // need to pin the pointer - if it is pointing to GC heap, it must have been
+ // pinned on the way to unmanaged.
+ //
+ virtual void EmitMarshalArgumentNativeToCLRByref()
+ {
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesNativeToCLRByref(true);
+
+ //
+ // marshal
+ //
+ EmitLoadNativeHomeAddr(m_pcsMarshal);
+ EmitStoreManagedHomeAddr(m_pcsMarshal);
+
+ //
+ // no unmarshaling is necessary since we directly passed the pointer to managed
+ // as a byref, the argument is therefore automatically in/out
+ //
+ }
+};
+
+template <CorElementType ELEMENT_TYPE, class PROMOTED_ELEMENT>
+class ILCopyMarshalerSimple : public ILCopyMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(PROMOTED_ELEMENT),
+ c_CLRSize = sizeof(PROMOTED_ELEMENT),
+ };
+
+ bool IsSmallValueTypeSpecialCase()
+ {
+ //
+ // Special case for small value types that get
+ // mapped to MARSHAL_TYPE_GENERIC_8 -- use the
+ // valuetype type so the JIT is happy.
+ //
+
+ return (ELEMENT_TYPE ==
+#ifdef _WIN64
+ ELEMENT_TYPE_I8
+#else // _WIN64
+ ELEMENT_TYPE_I4
+#endif // _WIN64
+ ) && (NULL != m_pargs->m_pMT);
+ }
+
+ bool NeedToPromoteTo8Bytes()
+ {
+ WRAPPER_NO_CONTRACT;
+
+#if defined(_TARGET_AMD64_)
+ // If the argument is passed by value,
+ if (!IsByref(m_dwMarshalFlags) && !IsRetval(m_dwMarshalFlags))
+ {
+ // and it is an I4 or an U4,
+ if ( (ELEMENT_TYPE == ELEMENT_TYPE_I4) ||
+ (ELEMENT_TYPE == ELEMENT_TYPE_U4) )
+ {
+ // and we are doing a managed-to-unmanaged call,
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ // then we have to promote the native argument type to an I8 or an U8.
+ return true;
+ }
+ }
+ }
+#endif // _TARGET_AMD64_
+
+ return false;
+ }
+
+ CorElementType GetConversionType(CorElementType type)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // I4 <-> I8; U4 <-> U8
+ if (type == ELEMENT_TYPE_I4)
+ {
+ return ELEMENT_TYPE_I8;
+ }
+ else if (type == ELEMENT_TYPE_U4)
+ {
+ return ELEMENT_TYPE_U8;
+ }
+ else
+ {
+ return ELEMENT_TYPE_END;
+ }
+ }
+
+ void EmitTypePromotion(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ CorElementType promotedType = GetConversionType(ELEMENT_TYPE);
+ if (promotedType == ELEMENT_TYPE_I8)
+ {
+ pslILEmit->EmitCONV_I8();
+ }
+ else if (promotedType == ELEMENT_TYPE_U8)
+ {
+ pslILEmit->EmitCONV_U8();
+ }
+ }
+
+ virtual LocalDesc GetNativeType()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (NeedToPromoteTo8Bytes())
+ {
+ return LocalDesc(GetConversionType(ELEMENT_TYPE));
+ }
+ else
+ {
+ return GetManagedType();
+ }
+ }
+
+ virtual LocalDesc GetManagedType()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (IsSmallValueTypeSpecialCase())
+ {
+ return LocalDesc(m_pargs->m_pMT);
+ }
+ else
+ {
+ return LocalDesc(ELEMENT_TYPE);
+ }
+ }
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ if (NeedToPromoteTo8Bytes())
+ {
+ EmitTypePromotion(pslILEmit);
+ }
+ EmitStoreNativeValue(pslILEmit);
+ }
+
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (IsSmallValueTypeSpecialCase())
+ {
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(m_pargs->m_pMT));
+ }
+ else
+ {
+ // ldc.i4.0, conv.i8/u8/r4/r8 is shorter than ldc.i8/r4/r8 0
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCONV_T(ELEMENT_TYPE);
+
+ EmitStoreNativeValue(pslILEmit);
+ }
+ }
+};
+
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I1, INT_PTR> ILCopyMarshaler1;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U1, UINT_PTR> ILCopyMarshalerU1;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I2, INT_PTR> ILCopyMarshaler2;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U2, UINT_PTR> ILCopyMarshalerU2;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I4, INT_PTR> ILCopyMarshaler4;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_U4, UINT_PTR> ILCopyMarshalerU4;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_I8, INT64> ILCopyMarshaler8;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R4, float> ILFloatMarshaler;
+typedef ILCopyMarshalerSimple<ELEMENT_TYPE_R8, double> ILDoubleMarshaler;
+
+template <BinderClassID CLASS__ID, class PROMOTED_ELEMENT>
+class ILCopyMarshalerKnownStruct : public ILCopyMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(PROMOTED_ELEMENT),
+ c_CLRSize = sizeof(PROMOTED_ELEMENT),
+ };
+
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID)));
+ }
+
+ virtual LocalDesc GetNativeType()
+ {
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__ID));
+ }
+};
+
+typedef ILCopyMarshalerKnownStruct<CLASS__DECIMAL, DECIMAL> ILDecimalMarshaler;
+typedef ILCopyMarshalerKnownStruct<CLASS__GUID, GUID> ILGuidMarshaler;
+
+class ILBlittableValueClassMarshaler : public ILCopyMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = VARIABLESIZE,
+ c_CLRSize = VARIABLESIZE,
+ };
+
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(m_pargs->m_pMT));
+ }
+
+ virtual LocalDesc GetNativeType()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(m_pargs->m_pMT);
+ }
+};
+
+
+class ILDelegateMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+class ILReflectionObjectMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetManagedType();
+ virtual LocalDesc GetNativeType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual BinderFieldID GetStructureFieldID() {LIMITED_METHOD_CONTRACT; return (BinderFieldID)0;}
+ virtual BinderFieldID GetObjectFieldID() = 0;
+ virtual BinderClassID GetManagedTypeBinderID() = 0;
+};
+
+class ILIRuntimeMethodInfoMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__STUBMETHODINFO__HANDLE; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__STUBMETHODINFO; }
+};
+
+class ILRuntimeModuleMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__MODULE__DATA; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__MODULE; }
+};
+
+class ILRuntimeAssemblyMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__ASSEMBLY__HANDLE; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__ASSEMBLY; }
+};
+
+class ILRuntimeTypeHandleMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__RT_TYPE_HANDLE__M_TYPE; }
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__CLASS__TYPEHANDLE; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__RT_TYPE_HANDLE; }
+};
+
+class ILRuntimeMethodHandleMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__METHOD_HANDLE__METHOD; }
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__STUBMETHODINFO__HANDLE; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__METHOD_HANDLE; }
+};
+
+class ILRuntimeFieldHandleMarshaler : public ILReflectionObjectMarshaler
+{
+protected:
+ virtual BinderFieldID GetStructureFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__FIELD_HANDLE__M_FIELD; }
+ virtual BinderFieldID GetObjectFieldID() { LIMITED_METHOD_CONTRACT; return FIELD__RT_FIELD_INFO__HANDLE; }
+ virtual BinderClassID GetManagedTypeBinderID() { LIMITED_METHOD_CONTRACT; return CLASS__FIELD_HANDLE; }
+};
+
+class ILBoolMarshaler : public ILMarshaler
+{
+public:
+
+ virtual CorElementType GetNativeBoolElementType() = 0;
+ virtual int GetNativeTrueValue() = 0;
+ virtual int GetNativeFalseValue() = 0;
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+class ILWinBoolMarshaler : public ILBoolMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(BOOL),
+ c_CLRSize = sizeof(INT8),
+ };
+
+protected:
+ virtual CorElementType GetNativeBoolElementType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ELEMENT_TYPE_I4;
+ }
+
+ virtual int GetNativeTrueValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return 1;
+ }
+
+ virtual int GetNativeFalseValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return 0;
+ }
+};
+
+class ILCBoolMarshaler : public ILBoolMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(BYTE),
+ c_CLRSize = sizeof(INT8),
+ };
+
+protected:
+ virtual CorElementType GetNativeBoolElementType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ELEMENT_TYPE_I1;
+ }
+
+ virtual int GetNativeTrueValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return 1;
+ }
+
+ virtual int GetNativeFalseValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return 0;
+ }
+};
+
+#ifdef FEATURE_COMINTEROP
+class ILVtBoolMarshaler : public ILBoolMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(VARIANT_BOOL),
+ c_CLRSize = sizeof(INT8),
+ };
+
+protected:
+ virtual CorElementType GetNativeBoolElementType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ELEMENT_TYPE_I2;
+ }
+
+ virtual int GetNativeTrueValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return VARIANT_TRUE;
+ }
+
+ virtual int GetNativeFalseValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return VARIANT_FALSE;
+ }
+};
+#endif // FEATURE_COMINTEROP
+
+class ILWSTRMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+#ifdef _DEBUG
+ bool m_fCoMemoryAllocated;
+
+ ILWSTRMarshaler()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_fCoMemoryAllocated = false;
+ }
+#endif // _DEBUG
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
+
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
+
+ static bool CanUsePinnedManagedString(DWORD dwMarshalFlags);
+ static void EmitCheckManagedStringLength(ILCodeStream* pslILEmit);
+ static void EmitCheckNativeStringLength(ILCodeStream* pslILEmit);
+};
+
+// A marshaler that makes run-time decision based on argument size whether native space will
+// be allocated using localloc or on the heap. The ctor argument is a heap free function.
+class ILOptimizedAllocMarshaler : public ILMarshaler
+{
+public:
+ ILOptimizedAllocMarshaler(BinderMethodID clearNat) :
+ m_idClearNative(clearNat),
+ m_dwLocalBuffer((DWORD)-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual LocalDesc GetNativeType();
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+
+protected:
+ const BinderMethodID m_idClearNative;
+ DWORD m_dwLocalBuffer; // localloc'ed temp buffer variable or -1 if not used
+};
+
+class ILUTF8BufferMarshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
+ };
+
+ ILUTF8BufferMarshaler() :
+ ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+class ILWSTRBufferMarshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2
+ };
+
+ ILWSTRBufferMarshaler() :
+ ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+class ILCSTRBufferMarshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
+ };
+
+ ILCSTRBufferMarshaler() :
+ ILOptimizedAllocMarshaler(METHOD__WIN32NATIVE__COTASKMEMFREE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+class ILHandleRefMarshaler : public ILMarshaler
+{
+ // Managed layout for SRI.HandleRef class
+ struct HANDLEREF
+ {
+ OBJECTREF m_wrapper;
+ LPVOID m_handle;
+ };
+
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(HANDLEREF),
+ };
+
+ LocalDesc GetManagedType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ LocalDesc GetNativeType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset);
+
+ static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker* psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs* pargs,
+ UINT* pResID);
+};
+
+class ILSafeHandleMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(SAFEHANDLE),
+ };
+
+ virtual LocalDesc GetManagedType();
+ virtual LocalDesc GetNativeType();
+
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+
+ virtual void EmitMarshalArgumentCLRToNative();
+
+ static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset);
+
+ static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs *pargs,
+ UINT *pResID);
+};
+
+
+class ILCriticalHandleMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(CRITICALHANDLE),
+ };
+
+public:
+
+ LocalDesc GetManagedType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ LocalDesc GetNativeType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset);
+
+ static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs *pargs,
+ UINT *pResID);
+};
+
+
+class ILValueClassMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = VARIABLESIZE,
+ c_CLRSize = VARIABLESIZE,
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream * pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+#ifdef FEATURE_COMINTEROP
+class ILObjectMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_CLRSize = sizeof(OBJECTREF),
+ c_nativeSize = sizeof(VARIANT),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit);
+};
+#endif // FEATURE_COMINTEROP
+
+class ILDateMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(DATE),
+ c_CLRSize = sizeof(INT64),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit);
+};
+
+
+class ILCurrencyMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(CURRENCY),
+ c_CLRSize = sizeof(DECIMAL),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+#ifdef FEATURE_COMINTEROP
+class ILInterfaceMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+};
+#endif // FEATURE_COMINTEROP
+
+
+class ILAnsiCharMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(UINT8),
+ c_CLRSize = sizeof(UINT16),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+template <BinderClassID CLASS__ID, class ELEMENT>
+class ILValueClassPtrMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(ELEMENT *),
+ c_CLRSize = sizeof(ELEMENT),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ //
+ // pointer to value class
+ //
+ return LocalDesc(ELEMENT_TYPE_I);
+ }
+
+ virtual LocalDesc GetManagedType()
+ {
+ STANDARD_VM_CONTRACT;
+
+ //
+ // value class
+ //
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__ID));
+ }
+
+ virtual bool NeedsClearNative()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (IsByref(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags));
+ }
+
+ virtual void EmitClearNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ // static void CoTaskMemFree(IntPtr ptr)
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
+ }
+
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (NeedsClearNative())
+ {
+ pslILEmit->EmitLDC(sizeof(ELEMENT));
+ pslILEmit->EmitCONV_U();
+ // static IntPtr CoTaskMemAlloc(UIntPtr cb)
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMALLOC, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+ }
+ }
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ if (NeedsClearNative())
+ {
+ EmitLoadNativeValue(pslILEmit); // dest
+ EmitLoadManagedHomeAddr(pslILEmit); // src
+ pslILEmit->EmitCPOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID)));
+ }
+ else
+ {
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitStoreNativeValue(pslILEmit);
+ }
+ }
+
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ STANDARD_VM_CONTRACT;
+
+ int tokType = pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__ID));
+ ILCodeLabel *pNullLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel *pJoinLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullLabel);
+
+ // the incoming pointer is non-null -> dereference it and copy the struct
+ EmitLoadManagedHomeAddr(pslILEmit); // dest
+ EmitLoadNativeValue(pslILEmit); // src
+ pslILEmit->EmitCPOBJ(tokType);
+
+ pslILEmit->EmitBR(pJoinLabel);
+
+ // the incoming pointer is null -> just initobj (i.e. zero) the struct
+ pslILEmit->EmitLabel(pNullLabel);
+
+ EmitLoadManagedHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(tokType);
+
+ pslILEmit->EmitLabel(pJoinLabel);
+ }
+};
+
+typedef ILValueClassPtrMarshaler<CLASS__GUID, GUID> ILGuidPtrMarshaler;
+typedef ILValueClassPtrMarshaler<CLASS__DECIMAL, DECIMAL> ILDecimalPtrMarshaler;
+
+#ifdef FEATURE_COMINTEROP
+class ILOleColorMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(OLE_COLOR),
+ c_CLRSize = sizeof(SYSTEMCOLOR),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+class ILVBByValStrWMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(BSTR),
+ c_CLRSize = sizeof(OBJECTREF*),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2 + sizeof(DWORD)
+ };
+
+
+ ILVBByValStrWMarshaler() :
+ m_dwCCHLocal(-1)
+ ,m_dwLocalBuffer(-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+ virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual bool IsNativePassedByRef();
+
+ DWORD m_dwCCHLocal;
+ DWORD m_dwLocalBuffer;
+};
+
+class ILVBByValStrMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPSTR),
+ c_CLRSize = sizeof(OBJECTREF *),
+ };
+
+ ILVBByValStrMarshaler() :
+ m_dwCCHLocal(-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+ virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual bool IsNativePassedByRef();
+
+ DWORD m_dwCCHLocal;
+};
+
+class ILHSTRINGMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(HSTRING),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ void EmitConvertCLRToHSTRINGReference(ILCodeStream* pslILEmit);
+ void EmitConvertCLRToHSTRING(ILCodeStream* pslILEmit);
+
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+};
+#endif // FEATURE_COMINTEROP
+
+
+class ILCUTF8Marshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
+ };
+
+ ILCUTF8Marshaler() :
+ ILOptimizedAllocMarshaler(METHOD__CSTRMARSHALER__CLEAR_NATIVE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+
+class ILCSTRMarshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = MAX_PATH_FNAME + 1
+ };
+
+ ILCSTRMarshaler() :
+ ILOptimizedAllocMarshaler(METHOD__CSTRMARSHALER__CLEAR_NATIVE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+#ifdef FEATURE_COMINTEROP
+class ILBSTRMarshaler : public ILOptimizedAllocMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ enum
+ {
+ // If required buffer length > MAX_LOCAL_BUFFER_LENGTH, don't optimize by allocating memory on stack
+ MAX_LOCAL_BUFFER_LENGTH = (MAX_PATH_FNAME + 1) * 2 + 4
+ };
+
+ ILBSTRMarshaler() :
+ ILOptimizedAllocMarshaler(METHOD__BSTRMARSHALER__CLEAR_NATIVE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+class ILAnsiBSTRMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+};
+#endif // FEATURE_COMINTEROP
+
+class ILLayoutClassPtrMarshalerBase : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
+};
+
+class ILLayoutClassPtrMarshaler : public ILLayoutClassPtrMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+protected:
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeContents(ILCodeStream * pslILEmit);
+};
+
+class ILBlittablePtrMarshaler : public ILLayoutClassPtrMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+protected:
+ virtual void EmitMarshalArgumentCLRToNative();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+};
+
+
+#ifndef FEATURE_CORECLR
+class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = VARIABLESIZE,
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ LocalDesc GetManagedType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ LocalDesc GetNativeType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc();
+ }
+
+ static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset);
+
+
+};
+#endif // !FEATURE_CORECLR
+
+
+class ILArgIteratorMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(va_list),
+ c_CLRSize = sizeof(VARARGS),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+ virtual void EmitMarshalArgumentCLRToNative();
+ virtual void EmitMarshalArgumentNativeToCLR();
+};
+
+class ILArrayWithOffsetMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(ArrayWithOffsetData),
+ };
+
+ ILArrayWithOffsetMarshaler() :
+ m_dwCountLocalNum(-1),
+ m_dwOffsetLocalNum(-1),
+ m_dwPinnedLocalNum(-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+
+ virtual void EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
+
+
+ DWORD m_dwCountLocalNum;
+ DWORD m_dwOffsetLocalNum;
+ DWORD m_dwPinnedLocalNum;
+};
+
+class ILAsAnyMarshalerBase : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ ILAsAnyMarshalerBase() :
+ m_dwMarshalerLocalNum(-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ static const BYTE ML_IN = 0x10;
+ static const BYTE ML_OUT = 0x20;
+
+ virtual bool IsAnsi() = 0;
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual bool SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+ virtual bool SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID);
+ virtual void EmitMarshalArgumentCLRToNative();
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNativeTemp(ILCodeStream* pslILEmit);
+
+ DWORD m_dwMarshalerLocalNum;
+};
+
+class ILAsAnyWMarshaler : public ILAsAnyMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+protected:
+ virtual bool IsAnsi()
+ {
+ return false;
+ }
+};
+
+class ILAsAnyAMarshaler : public ILAsAnyMarshalerBase
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+protected:
+ virtual bool IsAnsi()
+ {
+ return true;
+ }
+};
+
+
+class ILMngdMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_nativeSize = sizeof(void *),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ ILMngdMarshaler(BinderMethodID space2Man,
+ BinderMethodID contents2Man,
+ BinderMethodID space2Nat,
+ BinderMethodID contents2Nat,
+ BinderMethodID clearNat,
+ BinderMethodID clearNatContents,
+ BinderMethodID clearMan) :
+ m_idConvertSpaceToManaged(space2Man),
+ m_idConvertContentsToManaged(contents2Man),
+ m_idConvertSpaceToNative(space2Nat),
+ m_idConvertContentsToNative(contents2Nat),
+ m_idClearNative(clearNat),
+ m_idClearNativeContents(clearNatContents),
+ m_idClearManaged(clearMan)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit) = 0;
+
+ virtual void EmitCallMngdMarshalerMethod(ILCodeStream* pslILEmit, MethodDesc *pMD);
+
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToManagedMethod());
+ }
+
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToManagedMethod());
+ }
+
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetConvertSpaceToNativeMethod());
+ }
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetConvertContentsToNativeMethod());
+ }
+
+ virtual bool NeedsClearNative()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ if (NULL != GetClearNativeMethod())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void EmitClearNative(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeMethod());
+ }
+
+ virtual void EmitClearNativeContents(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetClearNativeContentsMethod());
+ }
+
+
+ virtual bool NeedsClearCLR()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ if (NULL != GetClearManagedMethod())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void EmitClearCLR(ILCodeStream* pslILEmit)
+ {
+ WRAPPER_NO_CONTRACT;
+ EmitCallMngdMarshalerMethod(pslILEmit, GetClearManagedMethod());
+ }
+
+ virtual MethodDesc *GetConvertSpaceToManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToManaged)); }
+ virtual MethodDesc *GetConvertContentsToManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToManaged)); }
+ virtual MethodDesc *GetConvertSpaceToNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertSpaceToNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertSpaceToNative)); }
+ virtual MethodDesc *GetConvertContentsToNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idConvertContentsToNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idConvertContentsToNative)); }
+ virtual MethodDesc *GetClearNativeMethod() { WRAPPER_NO_CONTRACT; return (m_idClearNative == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNative)); }
+ virtual MethodDesc *GetClearNativeContentsMethod() { WRAPPER_NO_CONTRACT; return (m_idClearNativeContents == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearNativeContents)); }
+ virtual MethodDesc *GetClearManagedMethod() { WRAPPER_NO_CONTRACT; return (m_idClearManaged == METHOD__NIL ? NULL : MscorlibBinder::GetMethod(m_idClearManaged)); }
+
+ const BinderMethodID m_idConvertSpaceToManaged;
+ const BinderMethodID m_idConvertContentsToManaged;
+ const BinderMethodID m_idConvertSpaceToNative;
+ const BinderMethodID m_idConvertContentsToNative;
+ const BinderMethodID m_idClearNative;
+ const BinderMethodID m_idClearNativeContents;
+ const BinderMethodID m_idClearManaged;
+};
+
+class ILNativeArrayMarshaler : public ILMngdMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+ ILNativeArrayMarshaler() :
+ ILMngdMarshaler(
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE,
+ METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
+ METHOD__NIL
+ )
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_dwSavedSizeArg = LOCAL_NUM_UNUSED;
+ }
+
+ virtual void EmitMarshalArgumentCLRToNative();
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
+ virtual void EmitMarshalArgumentNativeToCLRByref();
+ virtual void EmitMarshalArgumentCLRToNativeByref();
+
+protected:
+
+ bool UsePinnedArraySpecialCase();
+
+ BOOL CheckSizeParamIndexArg(const CREATE_MARSHALER_CARRAY_OPERANDS &mops, CorElementType *pElementType);
+
+ // Calculate element count and load it on evaluation stack
+ void EmitLoadElementCount(ILCodeStream* pslILEmit);
+
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
+
+ void EmitLoadNativeSize(ILCodeStream* pslILEmit);
+ void EmitNewSavedSizeArgLocal();
+
+private :
+ DWORD m_dwSavedSizeArg;
+};
+
+class MngdNativeArrayMarshaler
+{
+public:
+ static FCDECL3(void, CreateMarshaler, MngdNativeArrayMarshaler* pThis, MethodTable* pMT, UINT32 dwFlags);
+ static FCDECL3(void, ConvertSpaceToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ConvertContentsToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL4(void, ConvertSpaceToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
+ static FCDECL3(void, ConvertContentsToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ClearNative, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
+ static FCDECL3(void, ClearNativeContents, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
+
+ static void DoClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
+
+ enum
+ {
+ FLAG_NATIVE_DATA_VALID = 0x40000000
+ };
+
+ MethodTable* m_pElementMT;
+ TypeHandle m_Array;
+ BOOL m_NativeDataValid;
+ BOOL m_BestFitMap;
+ BOOL m_ThrowOnUnmappableChar;
+ VARTYPE m_vt;
+};
+
+
+#ifdef FEATURE_COMINTEROP
+class ILSafeArrayMarshaler : public ILMngdMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+ ILSafeArrayMarshaler() :
+ ILMngdMarshaler(
+ METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
+ METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
+ METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
+ METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
+ METHOD__MNGD_SAFE_ARRAY_MARSHALER__CLEAR_NATIVE,
+ METHOD__NIL,
+ METHOD__NIL
+ ),
+ m_dwOriginalManagedLocalNum(-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ if (NeedsCheckForStatic() && pslILEmit->GetStreamType() != ILStubLinker::kExceptionCleanup)
+ {
+ // Keep the original value in native home as we are not going to allocate a new
+ // one. If we cleared it here, we wouldn't be able to ConvertContentsToNative.
+ // Always perform the real re-init in the ExceptionCleanup stream so the caller
+ // doesn't get back garbage.
+ }
+ else
+ {
+ ILMngdMarshaler::EmitReInitNative(pslILEmit);
+ }
+ }
+
+ bool NeedsCheckForStatic()
+ {
+ WRAPPER_NO_CONTRACT;
+ return IsByref(m_dwMarshalFlags) && !IsCLRToNative(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags);
+ }
+
+ DWORD m_dwOriginalManagedLocalNum;
+};
+
+class MngdSafeArrayMarshaler
+{
+public:
+ static FCDECL4(void, CreateMarshaler, MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags);
+ static FCDECL3(void, ConvertSpaceToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL4(void, ConvertContentsToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, Object* pOriginalManagedUNSAFE);
+ static FCDECL3(void, ConvertSpaceToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ConvertContentsToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ClearNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+
+ enum StaticCheckStateFlags
+ {
+ SCSF_CheckForStatic = 1,
+ SCSF_IsStatic = 2,
+ SCSF_NativeDataValid = 4
+ };
+
+ MethodTable* m_pElementMT;
+ int m_iRank;
+ VARTYPE m_vt;
+ BYTE m_fStatic; // StaticCheckStateFlags
+ BYTE m_nolowerbounds;
+};
+
+class ILHiddenLengthArrayMarshaler : public ILMngdMarshaler
+{
+ friend class MngdHiddenLengthArrayMarshaler;
+
+public:
+ enum
+ {
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(OBJECTREF),
+ c_fInOnly = FALSE,
+ };
+
+ ILHiddenLengthArrayMarshaler() :
+ ILMngdMarshaler(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_MANAGED,
+ METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
+ METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_SPACE_TO_NATIVE,
+ METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
+ METHOD__WIN32NATIVE__COTASKMEMFREE,
+ METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS,
+ METHOD__NIL)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_dwMngdMarshalerLocalNum = -1;
+ }
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
+ virtual void EmitMarshalArgumentCLRToNative();
+ virtual void EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+ virtual void EmitClearNativeContents(ILCodeStream* pslILEmit);
+
+private:
+ bool CanUsePinnedArray();
+ void EmitLoadNativeArrayLength(ILCodeStream *pslILEmit);
+
+ virtual MethodDesc *GetConvertContentsToManagedMethod();
+ virtual MethodDesc *GetConvertContentsToNativeMethod();
+ virtual MethodDesc *GetClearNativeContentsMethod();
+
+ MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
+};
+
+class MngdHiddenLengthArrayMarshaler
+{
+public:
+ static FCDECL4(void, CreateMarshaler, MngdHiddenLengthArrayMarshaler* pThis, MethodTable* pMT, SIZE_T cbElement, UINT16 vt);
+ static FCDECL3(void, ConvertSpaceToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ConvertContentsToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL4(void, ConvertSpaceToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements);
+ static FCDECL3(void, ConvertContentsToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ClearNativeContents, MngdHiddenLengthArrayMarshaler* pThis, void** pNativeHome, INT32 cElements);
+
+
+private:
+ SIZE_T GetArraySize(SIZE_T elements);
+ void DoClearNativeContents(void** pNativeHome, INT32 cElements);
+
+private:
+ MethodTable *m_pElementMT;
+ SIZE_T m_cbElementSize;
+ VARTYPE m_vt;
+};
+#endif // FEATURE_COMINTEROP
+
+
+class ILReferenceCustomMarshaler : public ILMngdMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ };
+
+ ILReferenceCustomMarshaler() :
+ ILMngdMarshaler(
+ METHOD__NIL,
+ METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_MANAGED,
+ METHOD__NIL,
+ METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_NATIVE,
+ METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_NATIVE,
+ METHOD__NIL,
+ METHOD__MNGD_REF_CUSTOM_MARSHALER__CLEAR_MANAGED
+ )
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+protected:
+ virtual void EmitCreateMngdMarshaler(ILCodeStream* pslILEmit);
+};
+
+class MngdRefCustomMarshaler
+{
+public:
+ static FCDECL2(void, CreateMarshaler, MngdRefCustomMarshaler* pThis, void* pCMHelper);
+ static FCDECL3(void, ConvertContentsToNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ConvertContentsToManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ClearNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+ static FCDECL3(void, ClearManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+
+ static void DoClearNativeContents(MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome);
+
+ CustomMarshalerHelper* m_pCMHelper;
+};
+
+
+#ifdef FEATURE_COMINTEROP
+class ILUriMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ static void EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+ static void EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ void EmitClearNative(ILCodeStream* pslILEmit);
+};
+
+class ILNCCEventArgsMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+ static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ void EmitClearNative(ILCodeStream* pslILEmit);
+};
+
+class ILPCEventArgsMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = TRUE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+ static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+ static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ void EmitClearNative(ILCodeStream* pslILEmit);
+};
+
+class ILDateTimeMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(INT64), // = sizeof(Windows::Foundation::DateTime)
+ c_CLRSize = VARIABLESIZE,
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+ virtual void EmitReInitNative(ILCodeStream* pslILEmit);
+};
+
+class ILNullableMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = VARIABLESIZE,
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual bool NeedsClearNative();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+
+private:
+ MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
+};
+
+class ILSystemTypeMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(TypeNameNative),
+ c_CLRSize = sizeof(OBJECTREF)
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream * pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream * pslILEmit);
+
+ virtual bool NeedsClearNative();
+ virtual void EmitClearNative(ILCodeStream * pslILEmit);
+ virtual void EmitReInitNative(ILCodeStream * pslILEmit);
+};
+
+class ILHResultExceptionMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(INT32), // = sizeof(Windows::Foundation::HResult)
+ c_CLRSize = sizeof(OBJECTREF),
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+
+ virtual bool NeedsClearNative();
+};
+
+class ILKeyValuePairMarshaler : public ILMarshaler
+{
+public:
+ enum
+ {
+ c_fInOnly = FALSE,
+ c_nativeSize = sizeof(LPVOID),
+ c_CLRSize = VARIABLESIZE,
+ };
+
+protected:
+ virtual LocalDesc GetNativeType();
+ virtual LocalDesc GetManagedType();
+ virtual bool NeedsClearNative();
+ virtual void EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit);
+ virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
+ virtual void EmitClearNative(ILCodeStream* pslILEmit);
+
+private:
+ MethodDesc *GetExactMarshalerMethod(MethodDesc *pGenericMD);
+};
+
+#endif // FEATURE_COMINTEROP