summaryrefslogtreecommitdiff
path: root/src/vm/ilmarshalers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/ilmarshalers.cpp')
-rw-r--r--src/vm/ilmarshalers.cpp6379
1 files changed, 6379 insertions, 0 deletions
diff --git a/src/vm/ilmarshalers.cpp b/src/vm/ilmarshalers.cpp
new file mode 100644
index 0000000000..114fbe3ccb
--- /dev/null
+++ b/src/vm/ilmarshalers.cpp
@@ -0,0 +1,6379 @@
+// 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.cpp
+//
+
+//
+
+
+#include "common.h"
+#include "dllimport.h"
+#include "mlinfo.h"
+#include "ilmarshalers.h"
+#include "olevariant.h"
+#include "comdatetime.h"
+#include "fieldmarshaler.h"
+
+LocalDesc ILReflectionObjectMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(GetManagedTypeBinderID()));
+}
+
+LocalDesc ILReflectionObjectMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+void ILReflectionObjectMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ int tokObject__m_handle = pslILEmit->GetToken(MscorlibBinder::GetField(GetObjectFieldID()));
+ int tokStruct__m_object = 0;
+ BinderFieldID structField = GetStructureFieldID();
+
+ // This marshaler can generate code for marshaling an object containing a handle, and for
+ // marshaling a struct referring to an object containing a handle.
+ if (structField != 0)
+ {
+ tokStruct__m_object = pslILEmit->GetToken(MscorlibBinder::GetField(structField));
+ }
+
+ ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ if (tokStruct__m_object != 0)
+ {
+ EmitLoadManagedHomeAddr(pslILEmit);
+ pslILEmit->EmitLDFLD(tokStruct__m_object);
+ }
+ else
+ {
+ EmitLoadManagedValue(pslILEmit);
+ }
+ pslILEmit->EmitBRFALSE(pNullLabel);
+
+ if (tokStruct__m_object != 0)
+ {
+ EmitLoadManagedHomeAddr(pslILEmit);
+ pslILEmit->EmitLDFLD(tokStruct__m_object);
+ }
+ else
+ {
+ EmitLoadManagedValue(pslILEmit);
+ }
+
+ pslILEmit->EmitLDFLD(tokObject__m_handle);
+ EmitStoreNativeValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullLabel);
+
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ // keep the object alive across the call-out to native
+ if (tokStruct__m_object != 0)
+ {
+ EmitLoadManagedHomeAddr(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitLDFLD(tokStruct__m_object);
+ }
+ else
+ {
+ EmitLoadManagedValue(m_pcsUnmarshal);
+ }
+ m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
+ }
+}
+
+void ILReflectionObjectMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ COMPlusThrow(kTypeLoadException, IDS_EE_COM_UNSUPPORTED_SIG);
+}
+
+LocalDesc ILDelegateMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILDelegateMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+void ILDelegateMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__MARSHAL__GET_FUNCTION_POINTER_FOR_DELEGATE, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullLabel);
+
+ //
+ // @TODO: is there a better way to do this?
+ //
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ // keep the delegate ref alive across the call-out to native
+ EmitLoadManagedValue(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
+ }
+}
+
+void ILDelegateMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullLabel);
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
+ pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1); // Type System.Type.GetTypeFromHandle(RuntimeTypeHandle handle)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER, 2, 1); // Delegate System.Marshal.GetDelegateForFunctionPointer(IntPtr p, Type t)
+ EmitStoreManagedValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullLabel);
+}
+
+
+LocalDesc ILBoolMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(GetNativeBoolElementType());
+}
+
+LocalDesc ILBoolMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_BOOLEAN);
+}
+
+void ILBoolMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pLoadFalseLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
+
+
+ int trueValue = GetNativeTrueValue();
+ int falseValue = GetNativeFalseValue();
+
+ EmitLoadManagedValue(pslILEmit);
+
+ if (falseValue == 0 && trueValue == 1)
+ {
+ // this can be done without jumps
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCEQ();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCEQ();
+ }
+ else
+ {
+ pslILEmit->EmitBRFALSE(pLoadFalseLabel);
+ pslILEmit->EmitLDC(trueValue);
+ pslILEmit->EmitBR(pDoneLabel);
+#ifdef _DEBUG
+ pslILEmit->EmitPOP(); // keep the simple stack level calculator happy
+#endif // _DEBUG
+ pslILEmit->EmitLabel(pLoadFalseLabel);
+ pslILEmit->EmitLDC(falseValue);
+ pslILEmit->EmitLabel(pDoneLabel);
+ }
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILBoolMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ int falseValue = GetNativeFalseValue();
+
+ EmitLoadNativeValue(pslILEmit);
+
+ pslILEmit->EmitLDC(falseValue);
+ pslILEmit->EmitCEQ();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCEQ();
+
+ EmitStoreManagedValue(pslILEmit);
+}
+
+
+LocalDesc ILWSTRMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ //
+ // pointer to value class
+ //
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILWSTRMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ //
+ // value class
+ //
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+void ILWSTRMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ LIMITED_METHOD_CONTRACT;
+ UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
+}
+
+void ILWSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ LIMITED_METHOD_CONTRACT;
+ UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
+}
+
+void ILWSTRMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ LIMITED_METHOD_CONTRACT;
+ UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
+}
+
+void ILWSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ LIMITED_METHOD_CONTRACT;
+ UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
+}
+
+bool ILWSTRMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // will evaluate to true iff there is something CoTaskMemAlloc'ed that we need to free
+ bool needsClear = (IsByref(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags)) || IsRetval(m_dwMarshalFlags);
+
+ // m_fCoMemoryAllocated => needsClear
+ // (if we allocated the memory, we will free it; for byref [out] and retval we free memory allocated by the callee)
+ _ASSERTE(!m_fCoMemoryAllocated || needsClear);
+
+ return needsClear;
+}
+
+void ILWSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ // static void CoTaskMemFree(IntPtr ptr)
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
+}
+
+void ILWSTRMarshaler::EmitClearNativeTemp(ILCodeStream* pslILEmit)
+{
+ LIMITED_METHOD_CONTRACT;
+ UNREACHABLE_MSG("The string is either pinned or a copy is stack-allocated, NeedsClearNative should have returned false");
+}
+
+bool ILWSTRMarshaler::CanUsePinnedManagedString(DWORD dwMarshalFlags)
+{
+ LIMITED_METHOD_CONTRACT;
+ return IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && !IsOut(dwMarshalFlags);
+}
+
+//
+// input stack: 0: managed string
+// output stack: 0: (string_length+1) * sizeof(WCHAR)
+//
+void ILWSTRMarshaler::EmitCheckManagedStringLength(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitADD(); // (length+1) * sizeof(WCHAR)
+}
+
+void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ INDEBUG(m_fCoMemoryAllocated = true);
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ DWORD dwLengthLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitCheckManagedStringLength(pslILEmit);
+
+ // cb
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwLengthLocalNum);
+
+ // cb
+
+ // static IntPtr AllocCoTaskMem(int cb)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ // src, dst
+
+ pslILEmit->EmitLDLOC(dwLengthLocalNum); // length
+
+ // static void System.String.InternalCopy(String src, IntPtr dest,int len)
+ pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (CanUsePinnedManagedString(m_dwMarshalFlags))
+ {
+ LocalDesc locDesc = GetManagedType();
+ locDesc.MakePinned();
+ DWORD dwPinnedLocal = pslILEmit->NewLocal(locDesc);
+ int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__STRING__M_FIRST_CHAR));
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitSTLOC(dwPinnedLocal);
+ pslILEmit->EmitLDLOC(dwPinnedLocal);
+ pslILEmit->EmitLDFLDA(fieldDef);
+ EmitStoreNativeValue(pslILEmit);
+
+ if (g_pConfig->InteropLogArguments())
+ {
+ m_pslNDirect->EmitLogNativeArgument(pslILEmit, dwPinnedLocal);
+ }
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+
+ }
+ else
+ {
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ DWORD dwLengthLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitCheckManagedStringLength(pslILEmit);
+
+ // cb
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwLengthLocalNum);
+
+ // cb
+
+ pslILEmit->EmitLOCALLOC(); // @TODO: add a non-localloc path for large strings
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ // src, dst
+
+ pslILEmit->EmitLDLOC(dwLengthLocalNum); // length
+
+ // static void System.String.InternalCopy(String src, IntPtr dest,int len)
+ pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
+ pslILEmit->EmitLabel(pNullRefLabel);
+ }
+}
+
+//
+// input stack: 0: native string
+// output stack: 0: num chars, no null
+//
+void ILWSTRMarshaler::EmitCheckNativeStringLength(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+}
+
+void ILWSTRMarshaler::EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pIsNullLabelByref = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pIsNullLabelByref);
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitDUP();
+ EmitCheckNativeStringLength(pslILEmit);
+ pslILEmit->EmitPOP(); // pop num chars
+
+ pslILEmit->EmitNEWOBJ(METHOD__STRING__CTOR_CHARPTR, 1);
+ EmitStoreManagedValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pIsNullLabelByref);
+}
+
+
+LocalDesc ILOptimizedAllocMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+bool ILOptimizedAllocMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILOptimizedAllocMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel *pOptimize = NULL;
+
+ if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
+ {
+ pOptimize = pslILEmit->NewCodeLabel();
+
+ // if (m_dwLocalBuffer) goto Optimize
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBRTRUE(pOptimize);
+ }
+
+ EmitLoadNativeValue(pslILEmit);
+ // static void m_idClearNative(IntPtr ptr)
+ pslILEmit->EmitCALL(m_idClearNative, 1, 0);
+
+ // Optimize:
+ if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
+ {
+ pslILEmit->EmitLabel(pOptimize);
+ }
+}
+
+LocalDesc ILUTF8BufferMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
+}
+
+void ILUTF8BufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ // int System.Text.StringBuilder.get_Capacity()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
+ pslILEmit->EmitDUP();
+
+ // static void StubHelpers.CheckStringLength(int length)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+
+ // Max number of bytes for UTF8 string in BMP plane is ( StringBuilder.Capacity + 1 ) * 3 + 1
+ // first +1 if the high surrogate is '?' and second +1 for null byte.
+
+ // stack: capacity_in_bytes
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+
+ // stack: capacity
+ pslILEmit->EmitLDC(3);
+ pslILEmit->EmitMUL();
+
+ // stack: offset_of_null
+ DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
+
+ // make space for '\0'
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+
+ // stack: alloc_size_in_bytes
+ ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
+ if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel();
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pNoOptimize);
+
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBR(pAllocRejoin);
+
+ pslILEmit->EmitLabel(pNoOptimize);
+ }
+
+ // static IntPtr AllocCoTaskMem(int cb)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+
+ pslILEmit->EmitLabel(pAllocRejoin);
+
+ // stack: native_addr
+
+ pslILEmit->EmitDUP();
+ EmitStoreNativeValue(pslILEmit);
+
+ pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
+
+ // stack: native_addr offset_of_null
+ pslILEmit->EmitADD();
+
+ // stack: addr_of_null0
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I1();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILUTF8BufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ DWORD dwUtf8MarshalFlags =
+ (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
+ (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
+
+ // setup to call UTF8BufferMarshaler.ConvertToNative
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDC(dwUtf8MarshalFlags);
+
+ //ConvertToNative(StringBuilder sb,IntPtr pNativeBuffer, int flags)
+ pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_NATIVE, 3, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILUTF8BufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
+ {
+ EmitLoadNativeValue(pslILEmit);
+ // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
+ }
+ else
+ {
+ // don't touch the native buffer in the native->CLR out-only case
+ pslILEmit->EmitLDC(0);
+ }
+ // Convert to UTF8 and then call
+ // System.Text.StringBuilder..ctor(int capacity)
+ pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
+ EmitStoreManagedValue(pslILEmit);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILUTF8BufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ //void UTF8BufferMarshaler.ConvertToManaged(StringBuilder sb, IntPtr pNative)
+ pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_MANAGED, 2, 0);
+}
+
+
+LocalDesc ILWSTRBufferMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
+}
+
+void ILWSTRBufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ // int System.Text.StringBuilder.get_Capacity()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
+ pslILEmit->EmitDUP();
+
+ // static void StubHelpers.CheckStringLength(int length)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+
+ // stack: capacity
+
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitMUL();
+
+ // stack: capacity_in_bytes
+
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitADD();
+
+ // stack: offset_of_secret_null
+
+ DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
+
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitADD();
+
+ // stack: alloc_size_in_bytes
+ ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
+ if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel();
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pNoOptimize);
+
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBR(pAllocRejoin);
+
+ pslILEmit->EmitLabel(pNoOptimize);
+ }
+
+ // static IntPtr AllocCoTaskMem(int cb)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+
+ pslILEmit->EmitLabel(pAllocRejoin);
+
+ // stack: native_addr
+
+ pslILEmit->EmitDUP();
+ EmitStoreNativeValue(pslILEmit);
+
+ pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
+
+ // stack: offset_of_secret_null native_addr
+
+ pslILEmit->EmitADD();
+
+ // stack: addr_of_secret_null
+
+ pslILEmit->EmitLDC(0);
+
+ // stack: addr_of_secret_null 0
+
+ pslILEmit->EmitSTIND_I2();
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILWSTRBufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwTempNumBytesLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitDUP();
+
+ // stack: StringBuilder StringBuilder
+
+ // int System.Text.StringBuilder.get_Length()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_LENGTH, 1, 1);
+
+ // stack: StringBuilder length
+
+ // if (!fConvertSpaceJustCalled)
+ {
+ // we don't need to double-check the length because the length
+ // must be smaller than the capacity and the capacity was already
+ // checked by EmitConvertSpaceCLRToNative
+
+ pslILEmit->EmitDUP();
+ // static void StubHelpers.CheckStringLength(int length)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+ }
+
+ // stack: StringBuilder length
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitADD();
+
+ // stack: StringBuilder cb
+
+ pslILEmit->EmitSTLOC(dwTempNumBytesLocal);
+
+ // stack: StringBuilder
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDLOC(dwTempNumBytesLocal);
+
+ // stack: stringbuilder native_buffer cb
+
+ // void System.Text.StringBuilder.InternalCopy(IntPtr dest,int len)
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__INTERNAL_COPY, 3, 0);
+
+ //
+ // null-terminate the native string
+ //
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDLOC(dwTempNumBytesLocal);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I2();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILWSTRBufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
+ {
+ EmitLoadNativeValue(pslILEmit);
+ // static int System.String.wcslen(char *ptr)
+ pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
+ }
+ else
+ {
+ // don't touch the native buffer in the native->CLR out-only case
+ pslILEmit->EmitLDC(0);
+ }
+
+ // System.Text.StringBuilder..ctor(int capacity)
+ pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
+ EmitStoreManagedValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILWSTRBufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ pslILEmit->EmitDUP();
+ // static int System.String.wcslen(char *ptr)
+ pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
+
+ // void System.Text.StringBuilder.ReplaceBuffer(char* newBuffer, int newLength);
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__REPLACE_BUFFER_INTERNAL, 3, 0);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+LocalDesc ILCSTRBufferMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
+}
+
+void ILCSTRBufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ // int System.Text.StringBuilder.get_Capacity()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
+ pslILEmit->EmitDUP();
+
+ // static void StubHelpers.CheckStringLength(int length)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+
+ // stack: capacity
+
+ pslILEmit->EmitLDSFLD(pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
+ pslILEmit->EmitMUL();
+
+ // stack: capacity_in_bytes
+
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+
+ // stack: offset_of_secret_null
+
+ DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
+
+ pslILEmit->EmitLDC(3);
+ pslILEmit->EmitADD();
+
+ // stack: alloc_size_in_bytes
+ ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
+ if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel();
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pNoOptimize);
+
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBR(pAllocRejoin);
+
+ pslILEmit->EmitLabel(pNoOptimize);
+ }
+
+ // static IntPtr AllocCoTaskMem(int cb)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+
+ pslILEmit->EmitLabel(pAllocRejoin);
+
+ // stack: native_addr
+
+ pslILEmit->EmitDUP();
+ EmitStoreNativeValue(pslILEmit);
+
+ pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
+
+ // stack: native_addr offset_of_secret_null
+
+ pslILEmit->EmitADD();
+
+ // stack: addr_of_secret_null0
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I1();
+
+ // stack: addr_of_secret_null0
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I1();
+
+ // stack: addr_of_secret_null0
+
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I1();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILCSTRBufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ DWORD dwNumBytesLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ DWORD dwSrcLocal = pslILEmit->NewLocal(ELEMENT_TYPE_OBJECT);
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ // int System.Text.StringBuilder.get_Length()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_LENGTH, 1, 1);
+ // static void StubHelpers.CheckStringLength(int length)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+
+ EmitLoadManagedValue(pslILEmit);
+ // String System.Text.StringBuilder.ToString()
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__TO_STRING, 1, 1);
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
+ pslILEmit->EmitLDLOCA(dwNumBytesLocalNum);
+
+ // static byte[] DoAnsiConversion(string str, bool fBestFit, bool fThrowOnUnmappableChar, out int cbLength)
+ pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__DO_ANSI_CONVERSION, 4, 1);
+ pslILEmit->EmitSTLOC(dwSrcLocal);
+ EmitLoadNativeValue(pslILEmit); // pDest
+ pslILEmit->EmitLDC(0); // destIndex
+ pslILEmit->EmitLDLOC(dwSrcLocal); // src[]
+ pslILEmit->EmitLDC(0); // srcIndex
+ pslILEmit->EmitLDLOC(dwNumBytesLocalNum); // len
+
+ // static void Memcpy(byte* pDest, int destIndex, byte[] src, int srcIndex, int len)
+ pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY_PTRBYTE_ARRBYTE, 5, 0);
+
+ // null terminate the string
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDLOC(dwNumBytesLocalNum);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTIND_I1();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILCSTRBufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
+ {
+ EmitLoadNativeValue(pslILEmit);
+ // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
+ }
+ else
+ {
+ // don't touch the native buffer in the native->CLR out-only case
+ pslILEmit->EmitLDC(0);
+ }
+
+ // System.Text.StringBuilder..ctor(int capacity)
+ pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
+ EmitStoreManagedValue(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILCSTRBufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ pslILEmit->EmitDUP();
+ // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
+
+ // void System.Text.StringBuilder.ReplaceBuffer(sbyte* newBuffer, int newLength);
+ pslILEmit->EmitCALL(METHOD__STRING_BUILDER__REPLACE_BUFFER_ANSI_INTERNAL, 3, 0);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+
+
+LocalDesc ILValueClassMarshaler::GetNativeType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(TypeHandle(m_pargs->m_pMT).MakeNativeValueType());
+}
+
+LocalDesc ILValueClassMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+void ILValueClassMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(TypeHandle(m_pargs->m_pMT).MakeNativeValueType()));
+}
+
+bool ILValueClassMarshaler::NeedsClearNative()
+{
+ return true;
+}
+
+void ILValueClassMarshaler::EmitClearNative(ILCodeStream * pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ mdToken managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitLDTOKEN(managedVCToken); // pMT
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CLEAR_NATIVE, 2, 0);
+}
+
+
+void ILValueClassMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ mdToken managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
+
+ EmitLoadNativeHomeAddr(pslILEmit); // dst
+ EmitLoadManagedHomeAddr(pslILEmit); // src
+ pslILEmit->EmitLDTOKEN(managedVCToken); // pMT
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1); // Convert RTH to IntPtr
+
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ // this should only be needed in CLR-to-native scenarios for the SafeHandle field marshaler
+ m_pslNDirect->LoadCleanupWorkList(pslILEmit);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+
+ pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CONVERT_TO_NATIVE, 4, 0); // void ConvertToNative(IntPtr dst, IntPtr src, IntPtr pMT, ref CleanupWorkList pCleanupWorkList)
+}
+
+void ILValueClassMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ mdToken managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
+
+ EmitLoadManagedHomeAddr(pslILEmit); // dst
+ EmitLoadNativeHomeAddr(pslILEmit); // src
+ pslILEmit->EmitLDTOKEN(managedVCToken); // pMT
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CONVERT_TO_MANAGED, 3, 0); // void ConvertToManaged(IntPtr dst, IntPtr src, IntPtr pMT)
+}
+
+
+#ifdef FEATURE_COMINTEROP
+LocalDesc ILObjectMarshaler::GetNativeType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__NATIVEVARIANT)));
+}
+
+LocalDesc ILObjectMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_OBJECT);
+}
+
+void ILObjectMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
+ {
+ // Keep the VARIANT as it is - the stubhelper will do a VT_BYREF check on it.
+ }
+ else
+ {
+ // V_VT(pDest) = VT_EMPTY
+ EmitReInitNative(pslILEmit);
+ }
+
+ EmitLoadManagedValue(pslILEmit); // load src
+ EmitLoadNativeHomeAddr(pslILEmit); // load dst
+ pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CONVERT_TO_NATIVE, 2, 0); // void ConvertToNative(object objSrc, IntPtr pDstVariant)
+}
+
+void ILObjectMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CONVERT_TO_MANAGED, 1, 1); // object ConvertToManaged(IntPtr pSrcVariant);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+bool ILObjectMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILObjectMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
+ {
+ // We don't want to clear variants passed from native by-ref here as we
+ // want to be able to detect the VT_BYREF case during backpropagation.
+
+ // @TODO: We shouldn't be skipping the call if pslILEmit is ILStubLinker::kExceptionCleanup
+ // because we always want to do real cleanup in this stream.
+ }
+ else
+ {
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CLEAR_NATIVE, 1, 0);
+ }
+}
+
+void ILObjectMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ CONSISTENCY_CHECK(offsetof(VARIANT, vt) == 0);
+ }
+ CONTRACTL_END;
+
+ if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
+ {
+ // We don't want to clear variants passed from native by-ref here as we
+ // want to be able to detect the VT_BYREF case during backpropagation.
+ }
+ else
+ {
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitLDC(VT_EMPTY);
+ pslILEmit->EmitSTIND_I2();
+ }
+}
+#endif // FEATURE_COMINTEROP
+
+LocalDesc ILDateMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_R8);
+}
+
+LocalDesc ILDateMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__DATE_TIME));
+}
+
+void ILDateMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ // double ConvertToNative(INT64 managedDate)
+ pslILEmit->EmitCALL(METHOD__DATEMARSHALER__CONVERT_TO_NATIVE, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILDateMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // will call DateTime constructor on managed home
+ EmitLoadManagedHomeAddr(pslILEmit);
+
+ EmitLoadNativeValue(pslILEmit);
+ // long ConvertToNative(double nativeData)
+ pslILEmit->EmitCALL(METHOD__DATEMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+
+ pslILEmit->EmitCALL(METHOD__DATE_TIME__LONG_CTOR, 2, 0);
+}
+
+void ILDateMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // ldc.i4.0, conv.r8 is shorter than ldc.r8 0.0
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCONV_R8();
+ EmitStoreNativeValue(pslILEmit);
+}
+
+LocalDesc ILCurrencyMarshaler::GetNativeType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY)));
+}
+
+LocalDesc ILCurrencyMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)));
+}
+
+
+void ILCurrencyMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY))));
+}
+
+void ILCurrencyMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadManagedValue(pslILEmit);
+
+ pslILEmit->EmitCALL(METHOD__CURRENCY__DECIMAL_CTOR, 2, 0);
+}
+
+void ILCurrencyMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ pslILEmit->EmitCALL(METHOD__DECIMAL__CURRENCY_CTOR, 2, 0);
+
+ EmitLoadManagedHomeAddr(pslILEmit);
+
+ // static void System.StubHelpers.DecimalCanonicalizeInternal(ref Decimal dec);
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__DECIMAL_CANONICALIZE_INTERNAL, 1, 0);
+}
+
+
+#ifdef FEATURE_COMINTEROP
+LocalDesc ILInterfaceMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILInterfaceMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_OBJECT);
+}
+
+void ILInterfaceMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ItfMarshalInfo itfInfo;
+ m_pargs->m_pMarshalInfo->GetItfMarshalInfo(&itfInfo);
+
+ EmitLoadManagedValue(pslILEmit);
+
+ if (itfInfo.thNativeItf.GetMethodTable())
+ {
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thNativeItf.GetMethodTable()));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+
+ if (itfInfo.thClass.GetMethodTable())
+ {
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+ pslILEmit->EmitLDC(itfInfo.dwFlags);
+
+ // static IntPtr ConvertToNative(object objSrc, IntPtr itfMT, IntPtr classMT, int flags);
+ pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CONVERT_TO_NATIVE, 4, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+
+ if (IsCLRToNative(m_dwMarshalFlags) &&
+ m_pargs->m_pMarshalInfo->IsWinRTScenario())
+ {
+ // If we are calling from CLR into WinRT and we are passing an interface to WinRT, we need to
+ // keep the object alive across unmanaged call because Jupiter might need to add this
+ // RCW into their live tree and whatever CCWs referenced by this RCW could get collected
+ // before the call to native, for example:
+ //
+ // Button btn = new Button();
+ // btn.OnClick += ...
+ // m_grid.Children.Add(btn)
+ //
+ // In this case, btn could be collected and takes the delegate CCW with it, before Children.add
+ // native method is called, and as a result Jupiter will add the neutered CCW into the tree
+ //
+ // The fix is to extend the lifetime of the argument across the call to native by doing a GC.KeepAlive
+ // keep the delegate ref alive across the call-out to native
+ EmitLoadManagedValue(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
+ }
+}
+
+void ILInterfaceMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ItfMarshalInfo itfInfo;
+ m_pargs->m_pMarshalInfo->GetItfMarshalInfo(&itfInfo);
+
+ // the helper may assign NULL to the home (see below)
+ EmitLoadNativeHomeAddr(pslILEmit);
+
+ if (IsCLRToNative(m_dwMarshalFlags) && m_pargs->m_pMarshalInfo->IsWinRTScenario())
+ {
+ // We are converting an interface pointer to object in a CLR->native stub which means
+ // that the interface pointer has been AddRef'ed for us by the callee. If we end up
+ // wrapping it with a new RCW, we can omit another AddRef/Release pair. Note that if
+ // a new RCW is created the native home will be zeroed out by the helper so the call
+ // to InterfaceMarshaler__ClearNative will become a no-op.
+
+ // Note that we are only doing this for WinRT scenarios to reduce the risk of this change
+ itfInfo.dwFlags |= ItfMarshalInfo::ITF_MARSHAL_SUPPRESS_ADDREF;
+ }
+
+ if (itfInfo.thItf.GetMethodTable())
+ {
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thItf.GetMethodTable()));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+
+ if (itfInfo.thClass.GetMethodTable())
+ {
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+ pslILEmit->EmitLDC(itfInfo.dwFlags);
+
+ // static object ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, int flags);
+ pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CONVERT_TO_MANAGED, 4, 1);
+
+ EmitStoreManagedValue(pslILEmit);
+}
+
+bool ILInterfaceMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILMarshaler::EmitInterfaceClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel *pSkipClearNativeLabel = pslILEmit->NewCodeLabel();
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pSkipClearNativeLabel);
+ EmitLoadNativeValue(pslILEmit);
+ // static void ClearNative(IntPtr pUnk);
+ pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
+ pslILEmit->EmitLabel(pSkipClearNativeLabel);
+}
+
+void ILInterfaceMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+#endif // FEATURE_COMINTEROP
+
+
+LocalDesc ILAnsiCharMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_U1);
+}
+
+LocalDesc ILAnsiCharMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_CHAR);
+}
+
+void ILAnsiCharMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
+ pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__CONVERT_TO_NATIVE, 3, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILAnsiCharMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+#ifdef FEATURE_COMINTEROP
+LocalDesc ILOleColorMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I4);
+}
+
+LocalDesc ILOleColorMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ TypeHandle hndColorType = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
+
+ //
+ // value class
+ //
+ return LocalDesc(hndColorType); // System.Drawing.Color
+}
+
+void ILOleColorMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
+
+ EmitLoadManagedValue(pslILEmit);
+ // int System.Drawing.ColorTranslator.ToOle(System.Drawing.Color c)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILOleColorMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
+
+ EmitLoadNativeValue(pslILEmit);
+ // System.Drawing.Color System.Drawing.ColorTranslator.FromOle(int oleColor)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+bool ILVBByValStrWMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ LIMITED_METHOD_CONTRACT;
+ if (IsCLRToNative(dwMarshalFlags) && IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
+ {
+ return true;
+ }
+
+ *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
+ return false;
+}
+
+bool ILVBByValStrWMarshaler::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ LIMITED_METHOD_CONTRACT;
+ *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
+ return false;
+}
+
+LocalDesc ILVBByValStrWMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I); // BSTR
+}
+
+LocalDesc ILVBByValStrWMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+bool ILVBByValStrWMarshaler::IsNativePassedByRef()
+{
+ LIMITED_METHOD_CONTRACT;
+ return false;
+}
+
+void ILVBByValStrWMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
+ m_dwLocalBuffer = pcsSetup->NewLocal(ELEMENT_TYPE_I);
+ pcsSetup->EmitLoadNullPtr();
+ pcsSetup->EmitSTLOC(m_dwLocalBuffer);
+
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ m_dwCCHLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ DWORD dwNumBytesLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwCCHLocal);
+
+ // cch
+
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitADD(); // (length+1) * sizeof(WCHAR)
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwNumBytesLocal); // len <- doesn't include size of the DWORD preceeding the string
+ pslILEmit->EmitLDC(sizeof(DWORD));
+ pslILEmit->EmitADD(); // (length+1) * sizeof(WCHAR) + sizeof(DWORD)
+
+ // cb
+
+ ILCodeLabel* pNoOptimizeLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel* pAllocRejoinLabel = pslILEmit->NewCodeLabel();
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pNoOptimizeLabel);
+
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitBR(pAllocRejoinLabel);
+
+ pslILEmit->EmitLabel(pNoOptimizeLabel);
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ pslILEmit->EmitLabel(pAllocRejoinLabel);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDLOC(m_dwCCHLocal);
+ pslILEmit->EmitSTIND_I4();
+ pslILEmit->EmitLDC(sizeof(DWORD));
+ pslILEmit->EmitADD();
+ EmitStoreNativeValue(pslILEmit);
+
+ // <emtpy>
+
+ EmitLoadManagedValue(pslILEmit); // src
+ EmitLoadNativeValue(pslILEmit); // dest
+ pslILEmit->EmitLDLOC(dwNumBytesLocal); // len
+
+ // static void System.String.InternalCopy(String src, IntPtr dest,int len)
+ pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILVBByValStrWMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ pslILEmit->EmitLDNULL(); // this
+ EmitLoadNativeValue(pslILEmit); // ptr
+ pslILEmit->EmitLDC(0); // startIndex
+ pslILEmit->EmitLDLOC(m_dwCCHLocal); // length
+
+ // String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
+ // TODO Phase5: Why do we call this weirdo?
+ pslILEmit->EmitCALL(METHOD__STRING__CTORF_CHARPTR_START_LEN, 4, 1);
+
+ EmitStoreManagedValue(pslILEmit);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+
+bool ILVBByValStrWMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILVBByValStrWMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pExitLabel = pslILEmit->NewCodeLabel();
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBRFALSE(pExitLabel);
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
+ pslILEmit->EmitLabel(pExitLabel);
+}
+
+
+bool ILVBByValStrMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ if (IsCLRToNative(dwMarshalFlags) && IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
+ {
+ return true;
+ }
+
+ *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
+ return false;
+}
+
+bool ILVBByValStrMarshaler::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
+ return false;
+}
+
+LocalDesc ILVBByValStrMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I); // BSTR
+}
+
+LocalDesc ILVBByValStrMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+bool ILVBByValStrMarshaler::IsNativePassedByRef()
+{
+ LIMITED_METHOD_CONTRACT;
+ return false;
+}
+
+void ILVBByValStrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ m_dwCCHLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
+ pslILEmit->EmitLDLOCA(m_dwCCHLocal);
+
+ // static IntPtr ConvertToNative(string strManaged, bool fBestFit, bool fThrowOnUnmappableChar, ref int cch)
+ pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CONVERT_TO_NATIVE, 4, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILVBByValStrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit); // pNative
+ pslILEmit->EmitLDLOC(m_dwCCHLocal); // cch
+
+ // static string ConvertToManaged(IntPtr pNative, int cch)
+ pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CONVERT_TO_MANAGED, 2, 1);
+
+ EmitStoreManagedValue(pslILEmit);
+}
+
+bool ILVBByValStrMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILVBByValStrMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit); // pNative
+
+ // static void ClearNative(IntPtr pNative);
+ pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CLEAR_NATIVE, 1, 0);
+}
+
+LocalDesc ILBSTRMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+void ILBSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pRejoinLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadManagedValue(pslILEmit);
+
+ if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pNoOptimizeLabel = pslILEmit->NewCodeLabel();
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitBRFALSE(pNoOptimizeLabel);
+
+ // String.Length
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+
+ // if (length > (MAX_LOCAL_BUFFER_LENGTH - 6) / 2) goto NoOptimize
+ pslILEmit->EmitLDC((MAX_LOCAL_BUFFER_LENGTH - 6) / 2); // number of Unicode characters - terminator - length dword
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pNoOptimizeLabel);
+
+ // LocalBuffer = localloc[(String.Length * 2) + 6]
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitMUL();
+ pslILEmit->EmitLDC(7); // + length (4B) + terminator (2B) + possible trailing byte (1B)
+ pslILEmit->EmitADD();
+
+#ifdef _DEBUG
+ // Save the buffer length
+ DWORD dwTmpAllocSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(dwTmpAllocSize);
+#endif // _DEBUG
+
+ pslILEmit->EmitLOCALLOC();
+
+#ifdef _DEBUG
+ // Pass buffer length in the first DWORD so the helper is able to assert that
+ // the buffer is large enough.
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDLOC(dwTmpAllocSize);
+ pslILEmit->EmitSTIND_I4();
+#endif // _DEBUG
+
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // load string and LocalBuffer
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ pslILEmit->EmitBR(pRejoinLabel);
+
+ pslILEmit->EmitLabel(pNoOptimizeLabel);
+ }
+ pslILEmit->EmitLoadNullPtr();
+
+ pslILEmit->EmitLabel(pRejoinLabel);
+ pslILEmit->EmitCALL(METHOD__BSTRMARSHALER__CONVERT_TO_NATIVE, 2, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__BSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+
+LocalDesc ILAnsiBSTRMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I); // BSTR
+}
+
+LocalDesc ILAnsiBSTRMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+void ILAnsiBSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwAnsiMarshalFlags =
+ (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
+ (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
+
+ pslILEmit->EmitLDC(dwAnsiMarshalFlags);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CONVERT_TO_NATIVE, 2, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILAnsiBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+bool ILAnsiBSTRMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILAnsiBSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CLEAR_NATIVE, 1, 0);
+}
+
+LocalDesc ILHSTRINGMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I); // HSTRING
+}
+
+LocalDesc ILHSTRINGMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+bool ILHSTRINGMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILHSTRINGMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // If we're only going into native code, then we can optimize and create a HSTRING reference over
+ // the pinned System.String. However, if the parameter will remain in native code as an out
+ // value, then we need to create a real HSTRING.
+ if (!IsOut(m_dwMarshalFlags) && !IsRetval(m_dwMarshalFlags))
+ {
+ EmitConvertCLRToHSTRINGReference(pslILEmit);
+ }
+ else
+ {
+ EmitConvertCLRToHSTRING(pslILEmit);
+ }
+}
+
+void ILHSTRINGMarshaler::EmitConvertCLRToHSTRINGReference(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ PRECONDITION(!IsOut(m_dwMarshalFlags));
+ PRECONDITION(!IsRetval(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ //
+ // The general strategy for fast path marshaling a short lived System.String -> HSTRING is:
+ // 1. Pin the System.String
+ // 2. Create an HSTRING Reference over the pinned string
+ // 3. Pass that reference to native code
+ //
+
+ // Local to hold the HSTRING_HEADER of the HSTRING reference
+ MethodTable *pHStringHeaderMT = MscorlibBinder::GetClass(CLASS__HSTRING_HEADER_MANAGED);
+ DWORD dwHStringHeaderLocal = pslILEmit->NewLocal(pHStringHeaderMT);
+
+ // Local to hold the pinned input string
+ LocalDesc pinnedStringDesc = GetManagedType();
+ pinnedStringDesc.MakePinned();
+ DWORD dwPinnedStringLocal = pslILEmit->NewLocal(pinnedStringDesc);
+
+ // pinnedString = managed
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitSTLOC(dwPinnedStringLocal);
+
+ // hstring = HSTRINGMarshaler.ConvertManagedToNativeReference(pinnedString, out HStringHeader)
+ pslILEmit->EmitLDLOC(dwPinnedStringLocal);
+ pslILEmit->EmitLDLOCA(dwHStringHeaderLocal);
+ pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_NATIVE_REFERENCE, 2, 1);
+
+ if (g_pConfig->InteropLogArguments())
+ {
+ m_pslNDirect->EmitLogNativeArgument(pslILEmit, dwPinnedStringLocal);
+ }
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILHSTRINGMarshaler::EmitConvertCLRToHSTRING(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // hstring = HSTRINGMarshaler.ConvertManagedToNative(managed);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_NATIVE, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILHSTRINGMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ //
+ // To convert an HSTRING to a CLR String:
+ // 1. WindowsGetStringRawBuffer() to get the raw string data
+ // 2. WindowsGetStringLen() to get the string length
+ // 3. Construct a System.String from these parameters
+ // 4. Release the HSTRING
+ //
+
+ // string = HSTRINGMarshaler.ConvertNativeToManaged(native);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+
+void ILHSTRINGMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // HStringMarshaler.ClearNative(hstring)
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CLEAR_NATIVE, 1, 0);
+}
+
+#endif // FEATURE_COMINTEROP
+
+LocalDesc ILCUTF8Marshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+void ILCUTF8Marshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwUtf8MarshalFlags =
+ (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
+ (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
+
+ bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags);
+ if (bPassByValueInOnly)
+ {
+ DWORD dwBufSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ ILCodeLabel* pNoOptimize = pslILEmit->NewCodeLabel();
+
+ // if == NULL, goto NoOptimize
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNoOptimize);
+
+ // (String.Length + 1)
+ // Characters would be # of characters + 1 in case left over high surrogate is ?
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+
+ // Max 3 bytes per char.
+ // (String.Length + 1) * 3
+ pslILEmit->EmitLDC(3);
+ pslILEmit->EmitMUL();
+
+ // +1 for the 0x0 that we put in.
+ // ((String.Length + 1) * 3) + 1
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+
+ // BufSize = ( (String.Length+1) * 3) + 1
+ pslILEmit->EmitSTLOC(dwBufSize);
+
+ // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitLDLOC(dwBufSize);
+ pslILEmit->EmitCLT();
+ pslILEmit->EmitBRTRUE(pNoOptimize);
+
+ // LocalBuffer = localloc(BufSize);
+ pslILEmit->EmitLDLOC(dwBufSize);
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // NoOptimize:
+ pslILEmit->EmitLabel(pNoOptimize);
+ }
+
+ // UTF8Marshaler.ConvertToNative(dwUtf8MarshalFlags,pManaged, pLocalBuffer)
+ pslILEmit->EmitLDC(dwUtf8MarshalFlags);
+ EmitLoadManagedValue(pslILEmit);
+
+ if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
+ {
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+
+ pslILEmit->EmitCALL(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE, 3, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILCUTF8Marshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+
+LocalDesc ILCSTRMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_STRING);
+}
+
+void ILCSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwAnsiMarshalFlags =
+ (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
+ (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
+
+ bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags);
+ if (bPassByValueInOnly)
+ {
+ DWORD dwBufSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ // LocalBuffer = 0
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ ILCodeLabel* pNoOptimize = pslILEmit->NewCodeLabel();
+
+ // if == NULL, goto NoOptimize
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNoOptimize);
+
+ // String.Length + 2
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
+ pslILEmit->EmitLDC(2);
+ pslILEmit->EmitADD();
+
+ // (String.Length + 2) * GetMaxDBCSCharByteSize()
+ pslILEmit->EmitLDSFLD(pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
+ pslILEmit->EmitMUL();
+
+ // BufSize = (String.Length + 2) * GetMaxDBCSCharByteSize()
+ pslILEmit->EmitSTLOC(dwBufSize);
+
+ // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
+ pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
+ pslILEmit->EmitLDLOC(dwBufSize);
+ pslILEmit->EmitCLT();
+ pslILEmit->EmitBRTRUE(pNoOptimize);
+
+ // LocalBuffer = localloc(BufSize);
+ pslILEmit->EmitLDLOC(dwBufSize);
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwLocalBuffer);
+
+ // NoOptimize:
+ pslILEmit->EmitLabel(pNoOptimize);
+ }
+
+ // CSTRMarshaler.ConvertToNative pManaged, dwAnsiMarshalFlags, pLocalBuffer
+ pslILEmit->EmitLDC(dwAnsiMarshalFlags);
+ EmitLoadManagedValue(pslILEmit);
+
+ if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
+ {
+ pslILEmit->EmitLDLOC(m_dwLocalBuffer);
+ }
+ else
+ {
+ pslILEmit->EmitLoadNullPtr();
+ }
+
+ pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_TO_NATIVE, 3, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILCSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+LocalDesc ILLayoutClassPtrMarshalerBase::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I); // ptr to struct
+}
+
+LocalDesc ILLayoutClassPtrMarshalerBase::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+ pslILEmit->EmitLDC(uNativeSize);
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+ pslILEmit->EmitDUP(); // for INITBLK
+ EmitStoreNativeValue(pslILEmit);
+
+ // initialize local block we just allocated
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitLDC(uNativeSize);
+ pslILEmit->EmitINITBLK();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+ if (uNativeSize > s_cbStackAllocThreshold)
+ {
+ EmitConvertSpaceCLRToNative(pslILEmit);
+ }
+ else
+ {
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLoadNullPtr();
+ EmitStoreNativeValue(pslILEmit);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ pslILEmit->EmitLDC(uNativeSize);
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitDUP(); // for INITBLK
+ EmitStoreNativeValue(pslILEmit);
+
+ // initialize local block we just allocated
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitLDC(uNativeSize);
+ pslILEmit->EmitINITBLK();
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+ }
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitConvertSpaceCLRToNativeTemp(pslILEmit);
+ EmitConvertContentsCLRToNative(pslILEmit);
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ // static object AllocateInternal(IntPtr typeHandle);
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__ALLOCATE_INTERNAL, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+
+bool ILLayoutClassPtrMarshalerBase::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitClearNativeContents(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILLayoutClassPtrMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+ if (uNativeSize > s_cbStackAllocThreshold)
+ {
+ EmitClearNative(pslILEmit);
+ }
+ else
+ {
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitClearNativeContents(pslILEmit);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+ }
+}
+
+
+
+void ILLayoutClassPtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitLDC(uNativeSize);
+ pslILEmit->EmitINITBLK();
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ if (IsCLRToNative(m_dwMarshalFlags))
+ {
+ m_pslNDirect->LoadCleanupWorkList(pslILEmit);
+ }
+ else
+ {
+ //
+ // The assertion here is as follows:
+ // 1) the only field marshaler that requires the CleanupWorkList is FieldMarshaler_SafeHandle
+ // 2) SafeHandle marshaling is disallowed in the native-to-CLR direction, so we'll never see it..
+ //
+ pslILEmit->EmitLDNULL(); // pass a NULL CleanupWorkList in the native-to-CLR case
+ }
+
+ // static void FmtClassUpdateNativeInternal(object obj, byte* pNative, IntPtr pOptionalCleanupList);
+
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__FMT_CLASS_UPDATE_NATIVE_INTERNAL, 3, 0);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILLayoutClassPtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeValue(pslILEmit);
+
+ // static void FmtClassUpdateCLRInternal(object obj, byte* pNative);
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__FMT_CLASS_UPDATE_CLR_INTERNAL, 2, 0);
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILLayoutClassPtrMarshaler::EmitClearNativeContents(ILCodeStream * pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ int tokManagedType = pslILEmit->GetToken(m_pargs->m_pMT);
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitLDTOKEN(tokManagedType);
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+
+ // static void LayoutDestroyNativeInternal(byte* pNative, IntPtr pMT);
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__LAYOUT_DESTROY_NATIVE_INTERNAL, 2, 0);
+}
+
+
+void ILBlittablePtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+ int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__PINNING_HELPER__M_DATA));
+
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadNativeValue(pslILEmit); // dest
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLDA(fieldDef); // src
+
+ pslILEmit->EmitLDC(uNativeSize); // size
+
+ pslILEmit->EmitCPBLK();
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILBlittablePtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+ UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
+ int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__PINNING_HELPER__M_DATA));
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLDA(fieldDef); // dest
+
+ EmitLoadNativeValue(pslILEmit); // src
+
+ pslILEmit->EmitLDC(uNativeSize); // size
+
+ pslILEmit->EmitCPBLK();
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILBlittablePtrMarshaler::EmitMarshalArgumentCLRToNative()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ //
+ // marshal
+ //
+
+ ILCodeLabel* pSkipAddLabel = m_pcsMarshal->NewCodeLabel();
+ LocalDesc managedTypePinned = GetManagedType();
+ managedTypePinned.MakePinned();
+ DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedTypePinned);
+
+ EmitLoadManagedValue(m_pcsMarshal);
+
+ m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
+ m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
+ m_pcsMarshal->EmitCONV_U();
+ m_pcsMarshal->EmitDUP();
+ m_pcsMarshal->EmitBRFALSE(pSkipAddLabel);
+ m_pcsMarshal->EmitLDC(Object::GetOffsetOfFirstField());
+ m_pcsMarshal->EmitADD();
+ m_pcsMarshal->EmitLabel(pSkipAddLabel);
+
+ if (g_pConfig->InteropLogArguments())
+ {
+ m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
+ }
+
+ EmitStoreNativeValue(m_pcsMarshal);
+}
+
+
+
+
+MarshalerOverrideStatus ILHandleRefMarshaler::ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pcsMarshal = psl->GetMarshalCodeStream();
+ ILCodeStream* pcsDispatch = psl->GetDispatchCodeStream();
+
+ if (fManagedToNative && !byref)
+ {
+ pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I);
+
+
+ // HandleRefs are valuetypes, so pinning is not needed.
+ // The argument address is on the stack and will not move.
+ pcsDispatch->EmitLDARGA(argidx);
+ pcsDispatch->EmitLDC(offsetof(HANDLEREF, m_handle));
+ pcsDispatch->EmitADD();
+ pcsDispatch->EmitLDIND_I();
+ return OVERRIDDEN;
+ }
+ else
+ {
+ *pResID = IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION;
+ return DISALLOWED;
+ }
+}
+
+MarshalerOverrideStatus ILHandleRefMarshaler::ReturnOverride(NDirectStubLinker* psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs* pargs,
+ UINT* pResID)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ *pResID = IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION;
+ return DISALLOWED;
+}
+
+LocalDesc ILSafeHandleMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE));
+}
+
+LocalDesc ILSafeHandleMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+bool ILSafeHandleMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILSafeHandleMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ _ASSERTE(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+
+ // call StubHelpers::SafeHandleRelease
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_RELEASE, 1, 0);
+}
+
+void ILSafeHandleMarshaler::EmitMarshalArgumentCLRToNative()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ // by-value CLR-to-native SafeHandle is always passed in-only regardless of [In], [Out]
+ // marshal and cleanup communicate via an extra local and are both emitted in this method
+
+ // bool <dwHandleAddRefedLocalNum> = false
+ ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
+ DWORD dwHandleAddRefedLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
+
+ pcsSetup->EmitLDC(0);
+ pcsSetup->EmitSTLOC(dwHandleAddRefedLocalNum);
+
+ // <nativeHandle> = StubHelpers::SafeHandleAddRef(<managedSH>, ref <dwHandleAddRefedLocalNum>)
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitLDLOCA(dwHandleAddRefedLocalNum);
+ m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_ADD_REF, 2, 1);
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ // cleanup:
+ // if (<dwHandleAddRefedLocalNum>) StubHelpers.SafeHandleRelease(<managedSH>)
+ ILCodeStream *pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
+ ILCodeLabel *pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
+
+ pcsCleanup->EmitLDLOC(dwHandleAddRefedLocalNum);
+ pcsCleanup->EmitBRFALSE(pSkipClearNativeLabel);
+
+ EmitClearNativeTemp(pcsCleanup);
+ m_pslNDirect->SetCleanupNeeded();
+
+ pcsCleanup->EmitLabel(pSkipClearNativeLabel);
+}
+
+MarshalerOverrideStatus ILSafeHandleMarshaler::ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pslIL = psl->GetMarshalCodeStream();
+ ILCodeStream* pslILDispatch = psl->GetDispatchCodeStream();
+
+ if (fManagedToNative)
+ {
+ if (byref)
+ {
+ pslIL->SetStubTargetArgType(ELEMENT_TYPE_I);
+
+ // The specific SafeHandle subtype we're dealing with here.
+ MethodTable *pHandleType = pargs->m_pMT;
+
+ // Out SafeHandle parameters must not be abstract.
+ if (fout && pHandleType->IsAbstract())
+ {
+ *pResID = IDS_EE_BADMARSHAL_ABSTRACTOUTSAFEHANDLE;
+ return DISALLOWED;
+ }
+
+ // We rely on the SafeHandle having a default constructor.
+ if (!pHandleType->HasDefaultConstructor())
+ {
+ MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
+ COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
+ }
+
+ // Grab the token for the native handle field embedded inside the SafeHandle. We'll be using it to direct access the
+ // native handle later.
+ mdToken tkNativeHandleField = pslIL->GetToken(MscorlibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE));
+
+ // The high level logic (note that the parameter may be in, out or both):
+ // 1) If this is an input parameter we need to AddRef the SafeHandle and schedule a Release cleanup item.
+ // 2) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We
+ // must allocate this before the native call to avoid a failure point when we already have a native resource
+ // allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native
+ // handles need to be tracked and released by a SafeHandle.
+ // 3) Initialize a local IntPtr that will be passed to the native call. If we have an input SafeHandle the value
+ // comes from there otherwise we get it from the new SafeHandle (which is guaranteed to be initialized to an
+ // invalid handle value).
+ // 4) If this is a out parameter we also store the original handle value (that we just computed above) in a local
+ // variable.
+ // 5) After the native call, if this is an output parameter and the handle value we passed to native differs from
+ // the local copy we made then the new handle value is written into the output SafeHandle and that SafeHandle
+ // is propagated back to the caller.
+
+ // Locals:
+ DWORD dwInputHandleLocal = 0; // The input safe handle (in only)
+ DWORD dwOutputHandleLocal = 0; // The output safe handle (out only)
+ DWORD dwOldNativeHandleLocal = 0; // The original native handle value for comparison (out only)
+ DWORD dwNativeHandleLocal; // The input (and possibly updated) native handle value
+
+ if (fin)
+ {
+ LocalDesc locInputHandle(pHandleType);
+ dwInputHandleLocal = pslIL->NewLocal(locInputHandle);
+ }
+ if (fout)
+ {
+ LocalDesc locOutputHandle(pHandleType);
+ dwOutputHandleLocal = pslIL->NewLocal(locOutputHandle);
+
+ dwOldNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+ }
+
+ dwNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+
+ // Call StubHelpers.AddToCleanupList to atomically AddRef incoming SafeHandle and schedule a cleanup work item to
+ // perform Release after the call. The helper also returns the native handle value to us so take the opportunity
+ // to store this in the NativeHandle local we've allocated.
+ if (fin)
+ {
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitLDIND_REF();
+
+ pslIL->EmitSTLOC(dwInputHandleLocal);
+
+ // Release the original input SafeHandle after the call.
+ psl->LoadCleanupWorkList(pslIL);
+ pslIL->EmitLDLOC(dwInputHandleLocal);
+
+ // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
+ pslIL->EmitCALL(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST, 2, 1);
+
+ pslIL->EmitSTLOC(dwNativeHandleLocal);
+
+ }
+
+ // For output parameters we need to allocate a new SafeHandle to hold the result.
+ if (fout)
+ {
+ MethodDesc* pMDCtor = pHandleType->GetDefaultConstructor();
+ pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
+ pslIL->EmitSTLOC(dwOutputHandleLocal);
+
+ // If we didn't provide an input handle then we initialize the NativeHandle local with the (initially invalid)
+ // handle field set up inside the output handle by the constructor.
+ if (!fin)
+ {
+ pslIL->EmitLDLOC(dwOutputHandleLocal);
+ pslIL->EmitLDFLD(tkNativeHandleField);
+ pslIL->EmitSTLOC(dwNativeHandleLocal);
+ }
+
+ // Remember the handle value we start out with so we know whether to back propagate after the native call.
+ pslIL->EmitLDLOC(dwNativeHandleLocal);
+ pslIL->EmitSTLOC(dwOldNativeHandleLocal);
+ }
+
+ // Leave the address of the native handle local as the argument to the native method.
+ pslILDispatch->EmitLDLOCA(dwNativeHandleLocal);
+
+ // On the output side we only backpropagate the native handle into the output SafeHandle and the output SafeHandle
+ // to the caller if the native handle actually changed (otherwise we can end up with two SafeHandles wrapping the
+ // same native handle, which is bad).
+ if (fout)
+ {
+ // We will use cleanup stream to avoid leaking the handle on thread abort.
+ psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx);
+
+ psl->SetCleanupNeeded();
+ ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
+
+ ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
+
+ psl->EmitCheckForArgCleanup(pslCleanupIL,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pDoneLabel);
+
+ // If this is an [in, out] handle check if the native handles have changed. If not we're finished.
+ if (fin)
+ {
+ pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwOldNativeHandleLocal);
+ pslCleanupIL->EmitCEQ();
+ pslCleanupIL->EmitBRTRUE(pDoneLabel);
+ }
+
+ // Propagate the native handle into the output SafeHandle.
+ pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
+ pslCleanupIL->EmitSTFLD(tkNativeHandleField);
+
+ // Propagate the output SafeHandle back to the caller.
+ pslCleanupIL->EmitLDARG(argidx);
+ pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
+ pslCleanupIL->EmitSTIND_REF();
+
+ pslCleanupIL->EmitLabel(pDoneLabel);
+ }
+ }
+ else
+ {
+ // Avoid using the cleanup list in this common case for perf reasons (cleanup list is
+ // unmanaged and destroying it means excessive managed<->native transitions; in addition,
+ // as X86 IL stubs do not use interop frames, there's nothing protecting the cleanup list
+ // and the SafeHandle references must be GC handles which does not help perf either).
+ //
+ // This code path generates calls to StubHelpers.SafeHandleAddRef and SafeHandleRelease.
+ // NICE: Could SafeHandle.DangerousAddRef and DangerousRelease be implemented in managed?
+ return HANDLEASNORMAL;
+ }
+
+ return OVERRIDDEN;
+ }
+ else
+ {
+ *pResID = IDS_EE_BADMARSHAL_SAFEHANDLENATIVETOCOM;
+ return DISALLOWED;
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//
+MarshalerOverrideStatus
+ILSafeHandleMarshaler::ReturnOverride(
+ NDirectStubLinker * psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs * pargs,
+ UINT * pResID)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(psl));
+ PRECONDITION(CheckPointer(pargs));
+ PRECONDITION(CheckPointer(pResID));
+ }
+ CONTRACTL_END;
+
+ ILCodeStream * pslIL = psl->GetMarshalCodeStream();
+ ILCodeStream * pslPostIL = psl->GetReturnUnmarshalCodeStream();
+ ILCodeStream * pslILDispatch = psl->GetDispatchCodeStream();
+
+ if (!fManagedToNative)
+ {
+ *pResID = IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE;
+ return DISALLOWED;
+ }
+
+ // Returned SafeHandle parameters must not be abstract.
+ if (pargs->m_pMT->IsAbstract())
+ {
+ *pResID = IDS_EE_BADMARSHAL_ABSTRACTRETSAFEHANDLE;
+ return DISALLOWED;
+ }
+
+ // 1) create local for new safehandle
+ // 2) prealloc a safehandle
+ // 3) create local to hold returned handle
+ // 4) [byref] add byref IntPtr to native sig
+ // 5) [byref] pass address of local as last arg
+ // 6) store return value in safehandle
+
+ // 1) create local for new safehandle
+ MethodTable * pMT = pargs->m_pMT;
+ LocalDesc locDescReturnHandle(pMT);
+ DWORD dwReturnHandleLocal;
+
+ dwReturnHandleLocal = pslIL->NewLocal(locDescReturnHandle);
+
+ if (!pMT->HasDefaultConstructor())
+ {
+ MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
+ COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
+ }
+
+ // 2) prealloc a safehandle
+ MethodDesc* pMDCtor = pMT->GetDefaultConstructor();
+ pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
+ pslIL->EmitSTLOC(dwReturnHandleLocal);
+
+ mdToken tkNativeHandleField = pslPostIL->GetToken(MscorlibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE));
+
+ // 3) create local to hold returned handle
+ DWORD dwReturnNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+
+ if (fHresultSwap)
+ {
+ // initialize the native handle
+ pslIL->EmitLDLOC(dwReturnHandleLocal);
+ pslIL->EmitLDFLD(tkNativeHandleField);
+ pslIL->EmitSTLOC(dwReturnNativeHandleLocal);
+
+ pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I4); // native method returns an HRESULT
+
+ // 4) [byref] add byref IntPtr to native sig
+ locDescReturnHandle.ElementType[0] = ELEMENT_TYPE_BYREF;
+ locDescReturnHandle.ElementType[1] = ELEMENT_TYPE_I;
+ locDescReturnHandle.cbType = 2;
+ pslIL->SetStubTargetArgType(&locDescReturnHandle, false); // extra arg is a byref IntPtr
+
+ // 5) [byref] pass address of local as last arg
+ pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal);
+
+ // We will use cleanup stream to avoid leaking the handle on thread abort.
+ psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
+
+ psl->SetCleanupNeeded();
+ ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
+ ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
+
+ psl->EmitCheckForArgCleanup(pslCleanupIL,
+ NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pDoneLabel);
+
+ // 6) store return value in safehandle
+ pslCleanupIL->EmitLDLOC(dwReturnHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwReturnNativeHandleLocal);
+ pslCleanupIL->EmitSTFLD(tkNativeHandleField);
+ pslCleanupIL->EmitLabel(pDoneLabel);
+
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ }
+ else
+ {
+ pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I);
+ pslPostIL->EmitSTLOC(dwReturnNativeHandleLocal);
+
+ // 6) store return value in safehandle
+ // The thread abort logic knows that it must not interrupt the stub so we will
+ // always be able to execute this sequence after returning from the call.
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ pslPostIL->EmitLDLOC(dwReturnNativeHandleLocal);
+ pslPostIL->EmitSTFLD(tkNativeHandleField);
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ }
+
+ return OVERRIDDEN;
+} // ILSafeHandleMarshaler::ReturnOverride
+
+
+//---------------------------------------------------------------------------------------
+//
+MarshalerOverrideStatus ILCriticalHandleMarshaler::ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pslIL = psl->GetMarshalCodeStream();
+ ILCodeStream* pslPostIL = psl->GetUnmarshalCodeStream();
+ ILCodeStream* pslILDispatch = psl->GetDispatchCodeStream();
+
+ if (fManagedToNative)
+ {
+ pslIL->SetStubTargetArgType(ELEMENT_TYPE_I);
+
+ // Grab the token for the native handle field embedded inside the CriticalHandle. We'll be using it to direct access
+ // the native handle later.
+ mdToken tkNativeHandleField = pslIL->GetToken(MscorlibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE));
+
+ if (byref)
+ {
+ // The specific CriticalHandle subtype we're dealing with here.
+ MethodTable *pHandleType = pargs->m_pMT;
+
+ // Out CriticalHandle parameters must not be abstract.
+ if (fout && pHandleType->IsAbstract())
+ {
+ *pResID = IDS_EE_BADMARSHAL_ABSTRACTOUTCRITICALHANDLE;
+ return DISALLOWED;
+ }
+
+ // We rely on the CriticalHandle having a default constructor.
+ if (!pHandleType->HasDefaultConstructor())
+ {
+ MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
+ COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
+ }
+
+ // The high level logic (note that the parameter may be in, out or both):
+ // 1) If this is an output parameter we need to preallocate a CriticalHandle to wrap the new native handle value. We
+ // must allocate this before the native call to avoid a failure point when we already have a native resource
+ // allocated. We must allocate a new CriticalHandle even if we have one on input since both input and output native
+ // handles need to be tracked and released by a CriticalHandle.
+ // 2) Initialize a local IntPtr that will be passed to the native call. If we have an input CriticalHandle the value
+ // comes from there otherwise we get it from the new CriticalHandle (which is guaranteed to be initialized to an
+ // invalid handle value).
+ // 3) If this is a out parameter we also store the original handle value (that we just computed above) in a local
+ // variable.
+ // 4) After the native call, if this is an output parameter and the handle value we passed to native differs from
+ // the local copy we made then the new handle value is written into the output CriticalHandle and that
+ // CriticalHandle is propagated back to the caller.
+
+ // Locals:
+ LocalDesc locOutputHandle;
+ DWORD dwOutputHandleLocal = 0; // The output critical handle (out only)
+ DWORD dwOldNativeHandleLocal = 0; // The original native handle value for comparison (out only)
+ DWORD dwNativeHandleLocal; // The input (and possibly updated) native handle value
+
+ if (fout)
+ {
+ locOutputHandle.ElementType[0] = ELEMENT_TYPE_INTERNAL;
+ locOutputHandle.cbType = 1;
+ locOutputHandle.InternalToken = pHandleType;
+
+ dwOutputHandleLocal = pslIL->NewLocal(locOutputHandle);
+
+ dwOldNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+ }
+
+ dwNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+
+
+ // If we have an input CriticalHandle then initialize our NativeHandle local with it.
+ if (fin)
+ {
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitLDIND_REF();
+ pslIL->EmitLDFLD(tkNativeHandleField);
+ pslIL->EmitSTLOC(dwNativeHandleLocal);
+ }
+
+ // For output parameters we need to allocate a new CriticalHandle to hold the result.
+ if (fout)
+ {
+ MethodDesc* pMDCtor = pHandleType->GetDefaultConstructor();
+ pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
+ pslIL->EmitSTLOC(dwOutputHandleLocal);
+
+ // If we didn't provide an input handle then we initialize the NativeHandle local with the (initially invalid)
+ // handle field set up inside the output handle by the constructor.
+ if (!fin)
+ {
+ pslIL->EmitLDLOC(dwOutputHandleLocal);
+ pslIL->EmitLDFLD(tkNativeHandleField);
+ pslIL->EmitSTLOC(dwNativeHandleLocal);
+ }
+
+ // Remember the handle value we start out with so we know whether to back propagate after the native call.
+ pslIL->EmitLDLOC(dwNativeHandleLocal);
+ pslIL->EmitSTLOC(dwOldNativeHandleLocal);
+ }
+
+ // Leave the address of the native handle local as the argument to the native method.
+ pslILDispatch->EmitLDLOCA(dwNativeHandleLocal);
+
+ if (fin)
+ {
+ // prevent the CriticalHandle from being finalized during the call-out to native
+ pslPostIL->EmitLDARG(argidx);
+ pslPostIL->EmitLDIND_REF();
+ pslPostIL->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
+ }
+
+ // On the output side we only backpropagate the native handle into the output CriticalHandle and the output
+ // CriticalHandle to the caller if the native handle actually changed (otherwise we can end up with two
+ // CriticalHandles wrapping the same native handle, which is bad).
+ if (fout)
+ {
+ // We will use cleanup stream to avoid leaking the handle on thread abort.
+ psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx);
+
+ psl->SetCleanupNeeded();
+ ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
+
+ ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
+
+ psl->EmitCheckForArgCleanup(pslCleanupIL,
+ NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pDoneLabel);
+
+ // If this is an [in, out] handle check if the native handles have changed. If not we're finished.
+ if (fin)
+ {
+ pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwOldNativeHandleLocal);
+ pslCleanupIL->EmitCEQ();
+ pslCleanupIL->EmitBRTRUE(pDoneLabel);
+ }
+
+ // Propagate the native handle into the output CriticalHandle.
+ pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
+ pslCleanupIL->EmitSTFLD(tkNativeHandleField);
+
+ // Propagate the output CriticalHandle back to the caller.
+ pslCleanupIL->EmitLDARG(argidx);
+ pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
+ pslCleanupIL->EmitSTIND_REF();
+
+ pslCleanupIL->EmitLabel(pDoneLabel);
+ }
+ }
+ else
+ {
+ pslILDispatch->EmitLDARG(argidx);
+ pslILDispatch->EmitLDFLD(tkNativeHandleField);
+
+ // prevent the CriticalHandle from being finalized during the call-out to native
+ pslPostIL->EmitLDARG(argidx);
+ pslPostIL->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
+ }
+
+ return OVERRIDDEN;
+ }
+ else
+ {
+ *pResID = IDS_EE_BADMARSHAL_CRITICALHANDLENATIVETOCOM;
+ return DISALLOWED;
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//
+MarshalerOverrideStatus
+ILCriticalHandleMarshaler::ReturnOverride(
+ NDirectStubLinker * psl,
+ BOOL fManagedToNative,
+ BOOL fHresultSwap,
+ OverrideProcArgs * pargs,
+ UINT * pResID)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(psl));
+ PRECONDITION(CheckPointer(pargs));
+ PRECONDITION(CheckPointer(pResID));
+ }
+ CONTRACTL_END;
+
+ if (!fManagedToNative)
+ {
+ *pResID = IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE;
+ return DISALLOWED;
+ }
+
+ // Returned CriticalHandle parameters must not be abstract.
+ if (pargs->m_pMT->IsAbstract())
+ {
+ *pResID = IDS_EE_BADMARSHAL_ABSTRACTRETCRITICALHANDLE;
+ return DISALLOWED;
+ }
+
+ ILCodeStream * pslIL = psl->GetMarshalCodeStream();
+ ILCodeStream * pslPostIL = psl->GetReturnUnmarshalCodeStream();
+ ILCodeStream * pslILDispatch = psl->GetDispatchCodeStream();
+
+ // 1) create local for new criticalhandle
+ // 2) prealloc a criticalhandle
+ // 3) create local to hold returned handle
+ // 4) [byref] add byref IntPtr to native sig
+ // 5) [byref] pass address of local as last arg
+ // 6) store return value in criticalhandle
+
+ // 1) create local for new criticalhandle
+ MethodTable * pMT = pargs->m_pMT;
+ LocalDesc locDescReturnHandle(pMT);
+ DWORD dwReturnHandleLocal;
+
+ dwReturnHandleLocal = pslIL->NewLocal(locDescReturnHandle);
+
+ if (!pMT->HasDefaultConstructor())
+ {
+ MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
+ COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
+ }
+
+ // 2) prealloc a criticalhandle
+ MethodDesc * pMDCtor = pMT->GetDefaultConstructor();
+ pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
+ pslIL->EmitSTLOC(dwReturnHandleLocal);
+
+ mdToken tkNativeHandleField = pslPostIL->GetToken(MscorlibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE));
+
+ // 3) create local to hold returned handle
+ DWORD dwReturnNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
+
+ if (fHresultSwap)
+ {
+ // initialize the native handle
+ pslIL->EmitLDLOC(dwReturnHandleLocal);
+ pslIL->EmitLDFLD(tkNativeHandleField);
+ pslIL->EmitSTLOC(dwReturnNativeHandleLocal);
+
+ pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I4); // native method returns an HRESULT
+
+ // 4) [byref] add byref IntPtr to native sig
+ locDescReturnHandle.ElementType[0] = ELEMENT_TYPE_BYREF;
+ locDescReturnHandle.ElementType[1] = ELEMENT_TYPE_I;
+ locDescReturnHandle.cbType = 2;
+ pslIL->SetStubTargetArgType(&locDescReturnHandle, false); // extra arg is a byref IntPtr
+
+ // 5) [byref] pass address of local as last arg
+ pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal);
+
+ // We will use cleanup stream to avoid leaking the handle on thread abort.
+ psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
+
+ psl->SetCleanupNeeded();
+ ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
+ ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
+
+ // 6) store return value in criticalhandle
+ psl->EmitCheckForArgCleanup(pslCleanupIL,
+ NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
+ NDirectStubLinker::BranchIfNotMarshaled,
+ pDoneLabel);
+
+ pslCleanupIL->EmitLDLOC(dwReturnHandleLocal);
+ pslCleanupIL->EmitLDLOC(dwReturnNativeHandleLocal);
+ pslCleanupIL->EmitSTFLD(tkNativeHandleField);
+ pslCleanupIL->EmitLabel(pDoneLabel);
+
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ }
+ else
+ {
+ pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I);
+ pslPostIL->EmitSTLOC(dwReturnNativeHandleLocal);
+
+ // 6) store return value in criticalhandle
+ // The thread abort logic knows that it must not interrupt the stub so we will
+ // always be able to execute this sequence after returning from the call.
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ pslPostIL->EmitLDLOC(dwReturnNativeHandleLocal);
+ pslPostIL->EmitSTFLD(tkNativeHandleField);
+ pslPostIL->EmitLDLOC(dwReturnHandleLocal);
+ }
+
+ return OVERRIDDEN;
+} // ILCriticalHandleMarshaler::ReturnOverride
+
+#ifndef FEATURE_CORECLR
+//---------------------------------------------------------------------------------------
+//
+MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOverride(NDirectStubLinker* psl,
+ BOOL byref,
+ BOOL fin,
+ BOOL fout,
+ BOOL fManagedToNative,
+ OverrideProcArgs* pargs,
+ UINT* pResID,
+ UINT argidx,
+ UINT nativeStackOffset)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pslIL = psl->GetMarshalCodeStream();
+ ILCodeStream* pslILDispatch = psl->GetDispatchCodeStream();
+
+ if (byref)
+ {
+ *pResID = IDS_EE_BADMARSHAL_COPYCTORRESTRICTION;
+ return DISALLOWED;
+ }
+
+ if (fManagedToNative)
+ {
+#ifdef _TARGET_X86_
+ _ASSERTE(nativeStackOffset != (UINT)-1);
+
+ // get a new copy ctor cookie
+ DWORD dwCookieLocalNum = psl->CreateCopyCtorCookie(pslIL);
+
+ // and initialize it with our values
+ pslIL->EmitLDLOCA(dwCookieLocalNum);
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitLDC(nativeStackOffset);
+
+ // SetData takes pointers to managed methods although code:CopyCtorCallStubWorker
+ // currently calls them via reverse P/Invokes
+ if (pargs->mm.m_pCopyCtor)
+ {
+ pslIL->EmitLDFTN(pslIL->GetToken(pargs->mm.m_pCopyCtor));
+ }
+ else
+ {
+ pslIL->EmitLoadNullPtr();
+ }
+
+ if (pargs->mm.m_pDtor)
+ {
+ pslIL->EmitLDFTN(pslIL->GetToken(pargs->mm.m_pDtor));
+ }
+ else
+ {
+ pslIL->EmitLoadNullPtr();
+ }
+
+ // <dwCookieLocalNum>.SetData(<argidx>, <nativeStackOffset>, ctorPtr, dtorPtr)
+ pslIL->EmitCALL(METHOD__COPYCTORSTUBCOOKIE__SET_DATA, 5, 0);
+
+ LocalDesc locDesc(pargs->mm.m_pMT);
+ pslIL->SetStubTargetArgType(&locDesc); // native type is the value type
+
+ pslILDispatch->EmitLDARG(argidx); // we load the argument directly
+ pslILDispatch->EmitLDOBJ(pslILDispatch->GetToken(pargs->mm.m_pMT));
+#else // _TARGET_X86_
+ // On WIN64 platforms, copy-constructed arguments are actually passed by reference.
+ // This is the same calling convention as used by managed code, but to maintain parity,
+ // we mimic the x86 behaviour:
+ //
+ // 1) create new native value type local
+ // 2) run new->CopyCtor(old)
+ // 3) run old->Dtor()
+
+ LocalDesc locDesc(pargs->mm.m_pMT);
+
+ DWORD dwNewValueTypeLocal;
+
+ // Step 1
+ dwNewValueTypeLocal = pslIL->NewLocal(locDesc);
+
+ // Step 2
+ if (pargs->mm.m_pCopyCtor)
+ {
+ pslIL->EmitLDLOCA(dwNewValueTypeLocal);
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pCopyCtor), 2, 0);
+ }
+ else
+ {
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitLDOBJ(pslIL->GetToken(pargs->mm.m_pMT));
+ pslIL->EmitSTLOC(dwNewValueTypeLocal);
+ }
+
+ // Step 3
+ if (pargs->mm.m_pDtor)
+ {
+ pslIL->EmitLDARG(argidx);
+ pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pDtor), 1, 0);
+ }
+
+ pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer
+ pslILDispatch->EmitLDLOCA(dwNewValueTypeLocal);
+#endif // _TARGET_X86_
+
+ return OVERRIDDEN;
+ }
+ else
+ {
+ // nothing to do but pass the value along
+ // note that on x86 the argument comes by-value but is converted to pointer by the UM thunk
+ // so that we don't make copies that would not be accounted for by copy ctors
+ LocalDesc locDesc(pargs->mm.m_pMT);
+ locDesc.MakeCopyConstructedPointer();
+
+ pslIL->SetStubTargetArgType(&locDesc); // native type is a pointer
+ pslILDispatch->EmitLDARG(argidx);
+
+ return OVERRIDDEN;
+ }
+}
+#endif // FEATURE_CORECLR
+
+LocalDesc ILArgIteratorMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I); // va_list
+}
+
+LocalDesc ILArgIteratorMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
+}
+
+bool ILArgIteratorMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (IsByref(dwMarshalFlags))
+ {
+ *pErrorResID = IDS_EE_BADMARSHAL_ARGITERATORRESTRICTION;
+ return false;
+ }
+
+ return true;
+}
+
+void ILArgIteratorMarshaler::EmitMarshalArgumentCLRToNative()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ //
+ // marshal
+ //
+
+ // Allocate enough memory for va_list
+ DWORD dwVaListSizeLocal = m_pcsMarshal->NewLocal(LocalDesc(ELEMENT_TYPE_U4));
+ EmitLoadManagedHomeAddr(m_pcsMarshal);
+ m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__CALC_VA_LIST_SIZE, 1, 1);
+ m_pcsMarshal->EmitSTLOC(dwVaListSizeLocal);
+ m_pcsMarshal->EmitLDLOC(dwVaListSizeLocal);
+ m_pcsMarshal->EmitLOCALLOC();
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ // void MarshalToUnmanagedVaListInternal(cbVaListSize, va_list, VARARGS* data)
+ EmitLoadNativeValue(m_pcsMarshal);
+ m_pcsMarshal->EmitLDLOC(dwVaListSizeLocal);
+ EmitLoadManagedHomeAddr(m_pcsMarshal);
+ m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__MARSHAL_TO_UNMANAGED_VA_LIST_INTERNAL, 3, 0);
+}
+
+void ILArgIteratorMarshaler::EmitMarshalArgumentNativeToCLR()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesNativeToCLR();
+
+ EmitLoadNativeValue(m_pcsMarshal);
+ EmitLoadManagedHomeAddr(m_pcsMarshal);
+
+ // void MarshalToManagedVaList(va_list va, VARARGS *dataout)
+ m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__MARSHAL_TO_MANAGED_VA_LIST_INTERNAL, 2, 0);
+}
+
+
+LocalDesc ILArrayWithOffsetMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILArrayWithOffsetMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__ARRAY_WITH_OFFSET));
+}
+
+bool ILArrayWithOffsetMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
+ {
+ return true;
+ }
+
+ *pErrorResID = IDS_EE_BADMARSHAL_AWORESTRICTION;
+
+ return false;
+}
+
+void ILArrayWithOffsetMarshaler::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwCountLocalNum);
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwOffsetLocalNum);
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwPinnedLocalNum);
+ }
+ CONTRACTL_END;
+
+ int tokArrayWithOffset_m_array = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_ARRAY));
+ int tokArrayWithOffset_m_count = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_COUNT));
+
+ ILCodeLabel* pNonNullLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel* pSlowAllocPathLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
+
+ m_dwCountLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ //
+ // Convert the space
+ //
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
+ pslILEmit->EmitBRTRUE(pNonNullLabel);
+
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitBR(pDoneLabel);
+ pslILEmit->EmitLabel(pNonNullLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_count);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwCountLocalNum);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitLDC(s_cbStackAllocThreshold);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRTRUE(pSlowAllocPathLabel);
+
+ // localloc
+ pslILEmit->EmitLOCALLOC();
+
+ pslILEmit->EmitBR(pDoneLabel);
+ pslILEmit->EmitLabel(pSlowAllocPathLabel);
+
+ // AllocCoTaskMem
+ pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
+
+ pslILEmit->EmitLabel(pDoneLabel);
+ EmitStoreNativeValue(pslILEmit);
+
+ //
+ // Convert the contents
+ //
+
+ int tokArrayWithOffset_m_offset = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_OFFSET));
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ LocalDesc locDescPinned;
+ locDescPinned.cbType = 2;
+ locDescPinned.ElementType[0] = ELEMENT_TYPE_PINNED;
+ locDescPinned.ElementType[1] = ELEMENT_TYPE_OBJECT;
+ m_dwPinnedLocalNum = pslILEmit->NewLocal(locDescPinned);
+ m_dwOffsetLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
+ pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
+
+ EmitLoadNativeValue(pslILEmit); // dest
+
+ pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
+ pslILEmit->EmitCONV_I();
+ pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
+ pslILEmit->EmitCALL(METHOD__ARRAY__GET_DATA_PTR_OFFSET_INTERNAL, 1, 1);
+ pslILEmit->EmitADD(); // TODO Phase5: Use UnsafeAddrOfPinnedArrayElement
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_offset);
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitSTLOC(m_dwOffsetLocalNum);
+ pslILEmit->EmitADD(); // src
+ pslILEmit->EmitLDLOC(m_dwCountLocalNum); // len
+
+ // static void Memcpy(byte* dest, byte* src, int len)
+ pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY, 3, 0);
+
+ pslILEmit->EmitLDNULL();
+ pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILArrayWithOffsetMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwCountLocalNum);
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwOffsetLocalNum);
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwPinnedLocalNum);
+ }
+ CONTRACTL_END;
+
+ int tokArrayWithOffset_m_array = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_ARRAY));
+
+ ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
+ pslILEmit->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
+ pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
+
+ pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
+ pslILEmit->EmitCONV_I();
+ pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
+ pslILEmit->EmitCALL(METHOD__ARRAY__GET_DATA_PTR_OFFSET_INTERNAL, 1, 1);
+ pslILEmit->EmitADD(); // TODO Phase5: Use UnsafeAddrOfPinnedArrayElement
+
+ pslILEmit->EmitLDLOC(m_dwOffsetLocalNum);
+ pslILEmit->EmitADD(); // dest
+
+ EmitLoadNativeValue(pslILEmit); // src
+
+ pslILEmit->EmitLDLOC(m_dwCountLocalNum); // len
+
+ // static void Memcpy(byte* dest, byte* src, int len)
+ pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY, 3, 0);
+
+ pslILEmit->EmitLDNULL();
+ pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
+
+ pslILEmit->EmitLabel(pNullRefLabel);
+}
+
+void ILArrayWithOffsetMarshaler::EmitClearNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitLDLOC(m_dwCountLocalNum);
+ pslILEmit->EmitLDC(s_cbStackAllocThreshold);
+ pslILEmit->EmitCGT_UN();
+ pslILEmit->EmitBRFALSE(pDoneLabel);
+
+ // CoTaskMemFree
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
+
+ pslILEmit->EmitLabel(pDoneLabel);
+}
+
+LocalDesc ILAsAnyMarshalerBase::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILAsAnyMarshalerBase::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_OBJECT);
+}
+
+bool ILAsAnyMarshalerBase::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags))
+ {
+ return true;
+ }
+
+ *pErrorResID = IDS_EE_BADMARSHAL_ASANYRESTRICTION;
+ return false;
+}
+
+bool ILAsAnyMarshalerBase::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
+{
+ LIMITED_METHOD_CONTRACT;
+ *pErrorResID = IDS_EE_BADMARSHAL_ASANYRESTRICTION;
+ return false;
+}
+
+void ILAsAnyMarshalerBase::EmitMarshalArgumentCLRToNative()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwMarshalerLocalNum);
+ }
+ CONTRACTL_END;
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ BYTE inout = (IsIn(m_dwMarshalFlags) ? ML_IN : 0) | (IsOut(m_dwMarshalFlags) ? ML_OUT : 0);
+ BYTE fIsAnsi = IsAnsi() ? 1 : 0;
+ BYTE fBestFit = m_pargs->m_pMarshalInfo->GetBestFitMapping();
+ BYTE fThrow = m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar();
+
+ DWORD dwFlags = 0;
+
+ dwFlags |= inout << 24;
+ dwFlags |= fIsAnsi << 16;
+ dwFlags |= fThrow << 8;
+ dwFlags |= fBestFit << 0;
+
+ //
+ // marshal
+ //
+
+ LocalDesc marshalerType(MscorlibBinder::GetClass(CLASS__ASANY_MARSHALER));
+ m_dwMarshalerLocalNum = m_pcsMarshal->NewLocal(marshalerType);
+ DWORD dwTmpLocalNum = m_pcsMarshal->NewLocal(ELEMENT_TYPE_I);
+
+ m_pcsMarshal->EmitLDC(sizeof(MngdNativeArrayMarshaler));
+ m_pcsMarshal->EmitLOCALLOC();
+ m_pcsMarshal->EmitSTLOC(dwTmpLocalNum);
+
+ // marshaler = new AsAnyMarshaler(local_buffer)
+ m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
+ m_pcsMarshal->EmitINITOBJ(m_pcsMarshal->GetToken(marshalerType.InternalToken));
+
+ m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
+ m_pcsMarshal->EmitLDLOC(dwTmpLocalNum);
+ m_pcsMarshal->EmitCALL(METHOD__ASANY_MARSHALER__CTOR, 2, 0);
+
+ // nativeValue = marshaler.ConvertToNative(managedValue, flags);
+ m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitLDC(dwFlags);
+ m_pcsMarshal->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_NATIVE, 3, 1);
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ //
+ // unmarshal
+ //
+ if (IsOut(m_dwMarshalFlags))
+ {
+ // marshaler.ConvertToManaged(managedValue, nativeValue)
+ m_pcsUnmarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
+ EmitLoadManagedValue(m_pcsUnmarshal);
+ EmitLoadNativeValue(m_pcsUnmarshal);
+ m_pcsUnmarshal->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_MANAGED, 3, 0);
+ }
+
+ //
+ // cleanup
+ //
+ EmitCleanupCLRToNativeTemp();
+}
+
+bool ILAsAnyMarshalerBase::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILAsAnyMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // marshaler.ClearNative(nativeHome)
+ pslILEmit->EmitLDLOCA(m_dwMarshalerLocalNum);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__ASANY_MARSHALER__CLEAR_NATIVE, 2, 0);
+}
+
+// we can get away with putting the GetManagedType and GetNativeType on ILMngdMarshaler because
+// currently it is only used for reference marshaling where this is appropriate. If it became
+// used for something else, we would want to move this down in the inheritence tree..
+LocalDesc ILMngdMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILMngdMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return LocalDesc(ELEMENT_TYPE_OBJECT);
+}
+
+void ILMngdMarshaler::EmitCallMngdMarshalerMethod(ILCodeStream* pslILEmit, MethodDesc *pMD)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (pMD != NULL)
+ {
+ MetaSig sig(pMD);
+ UINT numArgs = sig.NumFixedArgs();
+
+ if (numArgs == 3)
+ {
+ EmitLoadMngdMarshaler(pslILEmit);
+ }
+ else
+ {
+ _ASSERTE(numArgs == 2);
+ }
+
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), numArgs, 0);
+ }
+}
+
+bool ILNativeArrayMarshaler::UsePinnedArraySpecialCase()
+{
+ if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && (NULL == OleVariant::GetMarshalerForVarType(m_pargs->na.m_vt, TRUE)))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void ILNativeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (UsePinnedArraySpecialCase())
+ {
+ return;
+ }
+
+ m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ pslILEmit->EmitLDC(sizeof(MngdNativeArrayMarshaler));
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
+
+ CREATE_MARSHALER_CARRAY_OPERANDS mops;
+ m_pargs->m_pMarshalInfo->GetMops(&mops);
+
+ pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
+
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(mops.methodTable));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+
+ DWORD dwFlags = mops.elementType;
+ dwFlags |= (((DWORD)mops.bestfitmapping) << 16);
+ dwFlags |= (((DWORD)mops.throwonunmappablechar) << 24);
+
+ if (!IsCLRToNative(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
+ {
+ // Unmanaged->managed in/out is the only case where we expect the native buffer to contain valid data.
+ _ASSERTE((dwFlags & MngdNativeArrayMarshaler::FLAG_NATIVE_DATA_VALID) == 0);
+ dwFlags |= MngdNativeArrayMarshaler::FLAG_NATIVE_DATA_VALID;
+ }
+
+ pslILEmit->EmitLDC(dwFlags);
+
+ pslILEmit->EmitCALL(METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CREATE_MARSHALER, 3, 0);
+}
+
+
+void ILNativeArrayMarshaler::EmitMarshalArgumentCLRToNative()
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
+ }
+ CONTRACTL_END;
+
+ if (UsePinnedArraySpecialCase())
+ {
+ //
+ // Replicate ML_PINNEDISOMORPHICARRAY_C2N_EXPRESS behavior -- note that this
+ // gives in/out semantics "for free" even if the app doesn't specify one or
+ // the other. Since there is no enforcement of this, apps blithely depend
+ // on it.
+ //
+
+ // The base offset should only be 0 for System.Array parameters for which
+ // OleVariant::GetMarshalerForVarType(vt) should never return NULL.
+ _ASSERTE(m_pargs->na.m_optionalbaseoffset != 0);
+
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ LocalDesc managedType = GetManagedType();
+ managedType.MakePinned();
+
+ DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedType);
+ ILCodeLabel* pNullRefLabel = m_pcsMarshal->NewCodeLabel();
+
+ m_pcsMarshal->EmitLoadNullPtr();
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitBRFALSE(pNullRefLabel);
+
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
+ m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
+ m_pcsMarshal->EmitCONV_I();
+ m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
+ m_pcsMarshal->EmitADD();
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ if (g_pConfig->InteropLogArguments())
+ {
+ m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
+ }
+
+ m_pcsMarshal->EmitLabel(pNullRefLabel);
+ }
+ else
+ {
+ ILMngdMarshaler::EmitMarshalArgumentCLRToNative();
+ }
+}
+
+//
+// Peek at the SizeParamIndex argument
+// 1) See if the SizeParamIndex argument is being passed by ref
+// 2) Get the element type of SizeParamIndex argument
+//
+BOOL ILNativeArrayMarshaler::CheckSizeParamIndexArg(
+ const CREATE_MARSHALER_CARRAY_OPERANDS &mops,
+ CorElementType *pElementType)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(m_pargs != NULL);
+ PRECONDITION(m_pargs->m_pMarshalInfo != NULL);
+ }
+ CONTRACTL_END;
+
+ MethodDesc *pMD = m_pargs->m_pMarshalInfo->GetMethodDesc();
+ _ASSERT(pMD);
+
+ Module *pModule = m_pargs->m_pMarshalInfo->GetModule();
+ _ASSERT(pModule);
+
+ SigTypeContext emptyTypeContext; // this is an empty type context: ndirect and COM calls are guaranteed to not be generics.
+ MetaSig msig(pMD->GetSignature(),
+ pModule,
+ &emptyTypeContext);
+
+ //
+ // Go to the SizeParamIndex argument
+ // Note that we already have check in place to make sure SizeParamIndex is within range
+ //
+ if (msig.HasExplicitThis())
+ msig.SkipArg();
+
+ for (int i = 0; i < mops.countParamIdx; ++i)
+ msig.SkipArg();
+
+ msig.NextArg();
+
+ SigPointer sigPointer = msig.GetArgProps();
+
+ // Peek into the SizeParamIndex argument
+ CorElementType elementType;
+ IfFailThrow(sigPointer.PeekElemType(&elementType));
+
+ if (elementType != ELEMENT_TYPE_BYREF)
+ {
+ if (elementType == ELEMENT_TYPE_STRING ||
+ elementType == ELEMENT_TYPE_ARRAY ||
+ elementType == ELEMENT_TYPE_FNPTR ||
+ elementType == ELEMENT_TYPE_OBJECT ||
+ elementType == ELEMENT_TYPE_SZARRAY ||
+ elementType == ELEMENT_TYPE_TYPEDBYREF)
+ {
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIZECONTROLBADTYPE);
+ }
+
+ *pElementType = elementType;
+ return FALSE;
+ }
+
+ // Get the real type
+ IfFailThrow(sigPointer.GetElemType(NULL));
+ IfFailThrow(sigPointer.PeekElemType(&elementType));
+
+ // All the integral types are supported
+ switch(elementType)
+ {
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_I:
+ case ELEMENT_TYPE_U:
+ break;
+
+ default :
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIZECONTROLBADTYPE);
+ }
+
+ *pElementType = elementType;
+ return TRUE;
+}
+
+//
+// Calculate the number of elements and load it into stack
+//
+void ILNativeArrayMarshaler::EmitLoadElementCount(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ //
+ // Determine the element count and load into evaluation stack
+ //
+ CREATE_MARSHALER_CARRAY_OPERANDS mops;
+ m_pargs->m_pMarshalInfo->GetMops(&mops);
+
+ if (mops.multiplier != 0)
+ {
+ //
+ // SizeParamIndex arg fix up for LCID
+ //
+ unsigned countParamIdx = mops.countParamIdx;
+ if (!IsCLRToNative(m_dwMarshalFlags))
+ {
+ int lcidParamIdx = m_pslNDirect->GetLCIDParamIdx();
+
+ if (lcidParamIdx >= 0 && (unsigned)lcidParamIdx <= countParamIdx)
+ {
+ // the LCID is injected before the count parameter so the index
+ // has to be incremented to get the unmanaged parameter number
+ countParamIdx++;
+ }
+ }
+
+ //
+ // Load SizeParamIndex argument
+ //
+ pslILEmit->EmitLDARG(countParamIdx);
+
+ //
+ // By-Ref support
+ //
+
+ // Is the SizeParamIndex points to a by-ref parameter?
+ CorElementType sizeParamIndexArgType;
+ if (CheckSizeParamIndexArg(mops, &sizeParamIndexArgType))
+ {
+ // Load the by-ref parameter
+ switch (sizeParamIndexArgType)
+ {
+ case ELEMENT_TYPE_I1:
+ pslILEmit->EmitLDIND_I1();
+ break;
+
+ case ELEMENT_TYPE_U1:
+ pslILEmit->EmitLDIND_U1();
+ break;
+
+ case ELEMENT_TYPE_I2:
+ pslILEmit->EmitLDIND_I2();
+ break;
+
+ case ELEMENT_TYPE_U2:
+ pslILEmit->EmitLDIND_U2();
+ break;
+
+ case ELEMENT_TYPE_I4:
+ pslILEmit->EmitLDIND_I4();
+ break;
+
+ case ELEMENT_TYPE_U4:
+ pslILEmit->EmitLDIND_U4();
+ break;
+
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_I8:
+ pslILEmit->EmitLDIND_I8();
+ break;
+
+ case ELEMENT_TYPE_I:
+ case ELEMENT_TYPE_U:
+ pslILEmit->EmitLDIND_I();
+ break;
+
+ default :
+ // Should not go here because we should've thrown exception
+ _ASSERT(FALSE);
+ }
+
+ }
+
+ pslILEmit->EmitCONV_OVF_I4();
+
+ // multiplier * arg + additive
+ pslILEmit->EmitLDC(mops.multiplier);
+ pslILEmit->EmitMUL_OVF();
+ pslILEmit->EmitLDC(mops.additive);
+ pslILEmit->EmitADD_OVF();
+ }
+ else
+ {
+ pslILEmit->EmitLDC((int)mops.additive);
+ }
+}
+
+void ILNativeArrayMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadMngdMarshaler(pslILEmit);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ //
+ // Reset the element count just in case there is a exception thrown in the code emitted by
+ // EmitLoadElementCount. The best thing we can do here is to avoid a crash.
+ //
+ _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
+ }
+
+ // Dynamically calculate element count using SizeParamIndex argument
+ EmitLoadElementCount(pslILEmit);
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ //
+ // Save the native array size before converting it to managed and load it again
+ //
+ _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
+ pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
+ pslILEmit->EmitLDLOC(m_dwSavedSizeArg);
+ }
+
+ // MngdNativeArrayMarshaler::ConvertSpaceToManaged
+ pslILEmit->EmitCALL(pslILEmit->GetToken(GetConvertSpaceToManagedMethod()), 4, 0);
+}
+
+void ILNativeArrayMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
+
+ //
+ // Save the array size before converting it to native
+ //
+ EmitLoadManagedValue(pslILEmit);
+ ILCodeLabel *pManagedHomeIsNull = pslILEmit->NewCodeLabel();
+ pslILEmit->EmitBRFALSE(pManagedHomeIsNull);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLEN();
+ pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
+ pslILEmit->EmitLabel(pManagedHomeIsNull);
+ }
+
+
+ ILMngdMarshaler::EmitConvertSpaceCLRToNative(pslILEmit);
+}
+
+void ILNativeArrayMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadMngdMarshaler(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadNativeSize(pslILEmit);
+
+ pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeMethod()), 3, 0);
+}
+
+void ILNativeArrayMarshaler::EmitLoadNativeSize(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ _ASSERT(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
+ pslILEmit->EmitLDLOC(m_dwSavedSizeArg);
+ }
+ else
+ {
+ pslILEmit->EmitLDC(0);
+ EmitLoadManagedValue(pslILEmit);
+ ILCodeLabel *pManagedHomeIsNull = pslILEmit->NewCodeLabel();
+ pslILEmit->EmitBRFALSE(pManagedHomeIsNull);
+ pslILEmit->EmitPOP(); // Pop the 0 on the stack
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLEN();
+ pslILEmit->EmitCONV_OVF_I4();
+ pslILEmit->EmitLabel(pManagedHomeIsNull); // Keep the 0 on the stack
+ }
+}
+
+void ILNativeArrayMarshaler::EmitClearNativeContents(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadMngdMarshaler(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadNativeSize(pslILEmit);
+
+ pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeContentsMethod()), 3, 0);
+}
+
+void ILNativeArrayMarshaler::EmitNewSavedSizeArgLocal()
+{
+ STANDARD_VM_CONTRACT;
+
+ _ASSERTE(m_dwSavedSizeArg == LOCAL_NUM_UNUSED);
+ ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
+ m_dwSavedSizeArg = pcsSetup->NewLocal(ELEMENT_TYPE_I4);
+ pcsSetup->EmitLDC(0);
+ pcsSetup->EmitSTLOC(m_dwSavedSizeArg);
+}
+
+void ILNativeArrayMarshaler::EmitMarshalArgumentNativeToCLRByref()
+{
+ STANDARD_VM_CONTRACT;
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ EmitNewSavedSizeArgLocal();
+ }
+
+ ILMngdMarshaler::EmitMarshalArgumentNativeToCLRByref();
+}
+
+void ILNativeArrayMarshaler::EmitMarshalArgumentCLRToNativeByref()
+{
+ STANDARD_VM_CONTRACT;
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ EmitNewSavedSizeArgLocal();
+ }
+
+ ILMngdMarshaler::EmitMarshalArgumentCLRToNativeByref();
+}
+
+
+#ifndef CROSSGEN_COMPILE
+
+FCIMPL3(void, MngdNativeArrayMarshaler::CreateMarshaler, MngdNativeArrayMarshaler* pThis, MethodTable* pMT, UINT32 dwFlags)
+{
+ FCALL_CONTRACT;
+
+ // Don't check whether the input values are negative - passing negative size-controlling
+ // arguments and compensating them with a positive SizeConst has always worked.
+ pThis->m_pElementMT = pMT;
+ pThis->m_vt = (VARTYPE)(dwFlags);
+ pThis->m_NativeDataValid = (BYTE)((dwFlags & FLAG_NATIVE_DATA_VALID) != 0);
+ dwFlags &= ~FLAG_NATIVE_DATA_VALID;
+ pThis->m_BestFitMap = (BYTE)(dwFlags >> 16);
+ pThis->m_ThrowOnUnmappableChar = (BYTE)(dwFlags >> 24);
+ pThis->m_Array = TypeHandle();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdNativeArrayMarshaler::ConvertSpaceToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ BASEARRAYREF arrayRef = (BASEARRAYREF) *pManagedHome;
+
+ if (arrayRef == NULL)
+ {
+ *pNativeHome = NULL;
+ }
+ else
+ {
+ SIZE_T cElements = arrayRef->GetNumComponents();
+ SIZE_T cbElement = OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT);
+
+ if (cbElement == 0)
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+
+ SIZE_T cbArray = cElements;
+ if ( (!SafeMulSIZE_T(&cbArray, cbElement)) || cbArray > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
+
+ *pNativeHome = CoTaskMemAlloc(cbArray);
+ if (*pNativeHome == NULL)
+ ThrowOutOfMemory();
+
+ // initialize the array
+ FillMemory(*pNativeHome, cbArray, 0);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ BASEARRAYREF* pArrayRef = (BASEARRAYREF *) pManagedHome;
+
+ if (*pArrayRef != NULL)
+ {
+ const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
+ SIZE_T cElements = (*pArrayRef)->GetNumComponents();
+ if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
+ {
+ if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
+
+ _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
+ memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cElements);
+ }
+ else
+ {
+ pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap,
+ pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid, cElements);
+ }
+ }
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL4(void, MngdNativeArrayMarshaler::ConvertSpaceToManaged, MngdNativeArrayMarshaler* pThis,
+ OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome == NULL)
+ {
+ SetObjectReference(pManagedHome, NULL, GetAppDomain());
+ }
+ else
+ {
+ // <TODO>@todo: lookup this class before marshal time</TODO>
+ if (pThis->m_Array.IsNull())
+ {
+ // Get proper array class name & type
+ pThis->m_Array = OleVariant::GetArrayForVarType(pThis->m_vt, TypeHandle(pThis->m_pElementMT));
+ if (pThis->m_Array.IsNull())
+ COMPlusThrow(kTypeLoadException);
+ }
+ //
+ // Allocate array
+ //
+ SetObjectReference(pManagedHome, AllocateArrayEx(pThis->m_Array, &cElements, 1), GetAppDomain());
+ }
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome != NULL)
+ {
+ const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
+
+ BASEARRAYREF* pArrayRef = (BASEARRAYREF*) pManagedHome;
+
+ if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
+ {
+ SIZE_T cElements = (*pArrayRef)->GetNumComponents();
+ if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
+
+ // If we are copying variants, strings, etc, we need to use write barrier
+ _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
+ memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cElements);
+ }
+ else
+ {
+ pMarshaler->OleToComArray(*pNativeHome, pArrayRef, pThis->m_pElementMT);
+ }
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdNativeArrayMarshaler::ClearNative, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome != NULL)
+ {
+ DoClearNativeContents(pThis, pNativeHome, cElements);
+ CoTaskMemFree(*pNativeHome);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdNativeArrayMarshaler::ClearNativeContents, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ DoClearNativeContents(pThis, pNativeHome, cElements);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+void MngdNativeArrayMarshaler::DoClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ if (*pNativeHome != NULL)
+ {
+ const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, FALSE);
+
+ if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
+ {
+ pMarshaler->ClearOleArray(*pNativeHome, cElements, pThis->m_pElementMT);
+ }
+ }
+}
+
+#endif // CROSSGEN_COMPILE
+
+
+#ifdef FEATURE_COMINTEROP
+void ILSafeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ pslILEmit->EmitLDC(sizeof(MngdSafeArrayMarshaler));
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
+
+ CREATE_MARSHALER_CARRAY_OPERANDS mops;
+ m_pargs->m_pMarshalInfo->GetMops(&mops);
+
+ DWORD dwFlags = mops.elementType;
+ BYTE fStatic = 0;
+
+ if (NeedsCheckForStatic())
+ {
+ fStatic |= MngdSafeArrayMarshaler::SCSF_CheckForStatic;
+ }
+
+ if (!IsCLRToNative(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
+ {
+ // Unmanaged->managed in/out is the only case where we expect the native buffer to contain valid data.
+ fStatic |= MngdSafeArrayMarshaler::SCSF_NativeDataValid;
+ }
+
+ dwFlags |= fStatic << 16;
+ dwFlags |= ((BYTE)!!m_pargs->m_pMarshalInfo->GetNoLowerBounds()) << 24;
+
+ pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(mops.methodTable));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+ pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetArrayRank());
+ pslILEmit->EmitLDC(dwFlags);
+
+ pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CREATE_MARSHALER, 4, 0);
+}
+
+void ILSafeArrayMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILMngdMarshaler::EmitConvertContentsNativeToCLR(pslILEmit);
+
+ if (NeedsCheckForStatic())
+ {
+ CONSISTENCY_CHECK(-1 == m_dwOriginalManagedLocalNum);
+ m_dwOriginalManagedLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_OBJECT);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitSTLOC(m_dwOriginalManagedLocalNum);
+ }
+}
+
+void ILSafeArrayMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadMngdMarshaler(pslILEmit);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ if (NeedsCheckForStatic())
+ {
+ CONSISTENCY_CHECK(-1 != m_dwOriginalManagedLocalNum);
+ pslILEmit->EmitLDLOC(m_dwOriginalManagedLocalNum);
+ }
+ else
+ {
+ pslILEmit->EmitLDNULL();
+ }
+ pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE, 4, 0);
+}
+
+
+#ifndef CROSSGEN_COMPILE
+
+FCIMPL4(void, MngdSafeArrayMarshaler::CreateMarshaler, MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags)
+{
+ FCALL_CONTRACT;
+
+ pThis->m_pElementMT = pMT;
+ pThis->m_iRank = iRank;
+ pThis->m_vt = (VARTYPE)dwFlags;
+ pThis->m_fStatic = (BYTE)(dwFlags >> 16);
+ pThis->m_nolowerbounds = (BYTE)(dwFlags >> 24);
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdSafeArrayMarshaler::ConvertSpaceToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ if (pThis->m_fStatic & SCSF_IsStatic)
+ return;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pThis->m_vt != VT_EMPTY);
+ PRECONDITION(CheckPointer(pThis->m_pElementMT));
+ }
+ CONTRACTL_END;
+
+ if (*pManagedHome != NULL)
+ {
+ *pNativeHome = (void *) OleVariant::CreateSafeArrayForArrayRef((BASEARRAYREF*) pManagedHome, pThis->m_vt, pThis->m_pElementMT);
+ }
+ else
+ {
+ *pNativeHome = NULL;
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL4(void, MngdSafeArrayMarshaler::ConvertContentsToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, Object* pOriginalManagedUNSAFE)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pThis->m_vt != VT_EMPTY);
+ PRECONDITION(CheckPointer(pThis->m_pElementMT));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF pOriginalManaged = ObjectToOBJECTREF(pOriginalManagedUNSAFE);
+ HELPER_METHOD_FRAME_BEGIN_1(pOriginalManaged);
+
+ if ((pThis->m_fStatic & SCSF_IsStatic) &&
+ (*pManagedHome != pOriginalManaged))
+ {
+ COMPlusThrow(kInvalidOperationException, IDS_INVALID_REDIM);
+ }
+
+ if (*pManagedHome != NULL)
+ {
+ OleVariant::MarshalSafeArrayForArrayRef((BASEARRAYREF *) pManagedHome,
+ (SAFEARRAY*)*pNativeHome,
+ pThis->m_vt,
+ pThis->m_pElementMT,
+ (pThis->m_fStatic & SCSF_NativeDataValid));
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdSafeArrayMarshaler::ConvertSpaceToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pThis->m_vt != VT_EMPTY);
+ PRECONDITION(CheckPointer(pThis->m_pElementMT));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome != NULL)
+ {
+ // If the managed array has a rank defined then make sure the rank of the
+ // SafeArray matches the defined rank.
+ if (pThis->m_iRank != -1)
+ {
+ int iSafeArrayRank = SafeArrayGetDim((SAFEARRAY*) *pNativeHome);
+ if (pThis->m_iRank != iSafeArrayRank)
+ {
+ WCHAR strExpectedRank[64];
+ WCHAR strActualRank[64];
+ _ltow_s(pThis->m_iRank, strExpectedRank, COUNTOF(strExpectedRank), 10);
+ _ltow_s(iSafeArrayRank, strActualRank, COUNTOF(strActualRank), 10);
+ COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYRANKMISMATCH, strActualRank, strExpectedRank);
+ }
+ }
+
+ if (pThis->m_nolowerbounds)
+ {
+ LONG lowerbound;
+ if ( (SafeArrayGetDim( (SAFEARRAY*)*pNativeHome ) != 1) ||
+ (FAILED(SafeArrayGetLBound( (SAFEARRAY*)*pNativeHome, 1, &lowerbound))) ||
+ lowerbound != 0 )
+ {
+ COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
+ }
+ }
+
+ SetObjectReference(pManagedHome,
+ (OBJECTREF) OleVariant::CreateArrayRefForSafeArray((SAFEARRAY*) *pNativeHome,
+ pThis->m_vt,
+ pThis->m_pElementMT), GetAppDomain());
+ }
+ else
+ {
+ SetObjectReference(pManagedHome, NULL, GetAppDomain());
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdSafeArrayMarshaler::ConvertContentsToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pThis->m_vt != VT_EMPTY);
+ PRECONDITION(CheckPointer(pThis->m_pElementMT));
+ }
+ CONTRACTL_END;
+
+ SAFEARRAY* pNative = *(SAFEARRAY**)pNativeHome;
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (pNative && pNative->fFeatures & FADF_STATIC)
+ {
+ pThis->m_fStatic |= SCSF_IsStatic;
+ }
+
+ if (*pNativeHome != NULL)
+ {
+ OleVariant::MarshalArrayRefForSafeArray((SAFEARRAY*)*pNativeHome,
+ (BASEARRAYREF *) pManagedHome,
+ pThis->m_vt,
+ pThis->m_pElementMT);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdSafeArrayMarshaler::ClearNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ if (pThis->m_fStatic & SCSF_IsStatic)
+ return;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome != NULL)
+ {
+ GCX_PREEMP();
+ _ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
+ // SafeArray has been created. Oleaut32.dll must have been loaded.
+ CONTRACT_VIOLATION(ThrowsViolation);
+ SafeArrayDestroy((SAFEARRAY*)*pNativeHome);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+#endif // CROSSGEN_COMPILE
+
+
+LocalDesc ILHiddenLengthArrayMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILHiddenLengthArrayMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_OBJECT);
+}
+
+void ILHiddenLengthArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!CanUsePinnedArray())
+ {
+ m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ pslILEmit->EmitLDC(sizeof(MngdHiddenLengthArrayMarshaler));
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
+
+ MethodTable *pElementMT = m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().GetMethodTable();
+ pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(pElementMT));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+
+ pslILEmit->EmitLDC(m_pargs->na.m_cbElementSize);
+ pslILEmit->EmitLDC(m_pargs->na.m_vt);
+
+ pslILEmit->EmitCALL(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CREATE_MARSHALER, 4, 0);
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitMarshalArgumentCLRToNative()
+{
+ STANDARD_VM_CONTRACT;
+
+ // If we can pin the array, then do that rather than marshaling it in a more heavy weight way
+ // Otherwise, fall back to doing a full marshal
+ if (CanUsePinnedArray())
+ {
+ EmitSetupSigAndDefaultHomesCLRToNative();
+
+ LocalDesc managedType = GetManagedType();
+ managedType.MakePinned();
+ DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedType);
+
+ ILCodeLabel* pMarshalDoneLabel = m_pcsMarshal->NewCodeLabel();
+
+ // native = NULL
+ m_pcsMarshal->EmitLoadNullPtr();
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ // if (managed == null) goto MarshalDone
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitBRFALSE(pMarshalDoneLabel);
+
+ // pinnedLocal = managed;
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
+
+ // native = pinnedLocal + dataOffset
+ m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
+ m_pcsMarshal->EmitCONV_I();
+ m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
+ m_pcsMarshal->EmitADD();
+ EmitStoreNativeValue(m_pcsMarshal);
+
+ if (g_pConfig->InteropLogArguments())
+ {
+ m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
+ }
+
+ // MarshalDone:
+ m_pcsMarshal->EmitLabel(pMarshalDoneLabel);
+ }
+ else
+ {
+ ILMngdMarshaler::EmitMarshalArgumentCLRToNative();
+ }
+
+}
+
+void ILHiddenLengthArrayMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!CanUsePinnedArray())
+ {
+ EmitLoadMngdMarshaler(pslILEmit);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadNativeArrayLength(pslILEmit);
+
+ // MngdHiddenLengthArrayMarshaler::ConvertSpaceToManaged
+ pslILEmit->EmitCALL(pslILEmit->GetToken(GetConvertSpaceToManagedMethod()), 4, 0);
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // If we're marshaling out to native code, then we need to set the length out parameter
+ if (!IsCLRToNative(m_dwMarshalFlags))
+ {
+ if (IsByref(m_dwMarshalFlags) || IsRetval(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags))
+ {
+ ILCodeLabel *pSkipGetLengthLabel = m_pcsMarshal->NewCodeLabel();
+
+ // nativeLen = 0
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitCONV_T(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
+ pslILEmit->EmitSTLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
+
+ // if (array == null) goto SkipGetLength
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitBRFALSE(pSkipGetLengthLabel);
+
+ // nativeLen = array.Length
+ // SkipGetLength:
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLEN();
+ pslILEmit->EmitCONV_T(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
+ pslILEmit->EmitSTLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
+ pslILEmit->EmitLabel(pSkipGetLengthLabel);
+
+ // nativeLenParam = nativeLen
+ LocalDesc nativeParamType(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
+ pslILEmit->EmitLDARG(m_pargs->m_pMarshalInfo->HiddenLengthParamIndex());
+ pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
+ pslILEmit->EmitSTIND_T(&nativeParamType);
+ }
+ }
+
+ if (!CanUsePinnedArray())
+ {
+ ILMngdMarshaler::EmitConvertSpaceCLRToNative(pslILEmit);
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!CanUsePinnedArray())
+ {
+ if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE &&
+ (m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Uri ||
+ m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs ||
+ m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs))
+ {
+ // System.Uri/NotifyCollectionChangedEventArgs don't live in mscorlib so there's no marshaling helper to call - inline the loop
+ DWORD dwLoopCounterLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ DWORD dwNativePtrLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+ ILCodeLabel *pConditionLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel *pLoopBodyLabel = pslILEmit->NewCodeLabel();
+
+ // for (IntPtr ptr = pNative, int i = 0; ...
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
+ pslILEmit->EmitBR(pConditionLabel);
+
+ // *ptr = EmitConvertCLR*ToWinRT*(pManaged[i]);
+ pslILEmit->EmitLabel(pLoopBodyLabel);
+ pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDELEM_REF();
+
+ switch (m_pargs->na.m_redirectedTypeIndex)
+ {
+ case WinMDAdapter::RedirectedTypeIndex_System_Uri:
+ ILUriMarshaler::EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
+ ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
+ ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ default: UNREACHABLE();
+ }
+
+ pslILEmit->EmitSTIND_I();
+
+ // ... i++, ptr += IntPtr.Size ...
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
+ pslILEmit->EmitLDC(sizeof(LPVOID));
+ pslILEmit->EmitADD();
+ pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
+
+ // ... i < pManaged.Length; ...
+ pslILEmit->EmitLabel(pConditionLabel);
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ EmitLoadNativeArrayLength(pslILEmit);
+ pslILEmit->EmitBLT(pLoopBodyLabel);
+ }
+ else
+ {
+ ILMngdMarshaler::EmitConvertContentsCLRToNative(pslILEmit);
+ }
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!CanUsePinnedArray())
+ {
+ if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE &&
+ (m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Uri ||
+ m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs ||
+ m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs))
+ {
+ // System.Uri/NotifyCollectionChangedEventArgs don't live in mscorlib so there's no marshaling helper to call - inline the loop
+ DWORD dwLoopCounterLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
+ DWORD dwNativePtrLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+ ILCodeLabel *pConditionLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel *pLoopBodyLabel = pslILEmit->NewCodeLabel();
+
+ // for (IntPtr ptr = pNative, int i = 0; ...
+ pslILEmit->EmitLDC(0);
+ pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
+ pslILEmit->EmitBR(pConditionLabel);
+
+ // pManaged[i] = EmitConvertWinRT*ToCLR*(*ptr);
+ pslILEmit->EmitLabel(pLoopBodyLabel);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
+ pslILEmit->EmitLDIND_I();
+
+ switch (m_pargs->na.m_redirectedTypeIndex)
+ {
+ case WinMDAdapter::RedirectedTypeIndex_System_Uri:
+ ILUriMarshaler::EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
+ ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
+ ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ break;
+
+ default: UNREACHABLE();
+ }
+
+ pslILEmit->EmitSTELEM_REF();
+
+ // ... i++, ptr += IntPtr.Size)
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDC(1);
+ pslILEmit->EmitADD();
+ pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
+ pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
+ pslILEmit->EmitLDC(sizeof(LPVOID));
+ pslILEmit->EmitADD();
+ pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
+
+ // ... i < pManaged.Length; ...
+ pslILEmit->EmitLabel(pConditionLabel);
+ pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
+ EmitLoadNativeArrayLength(pslILEmit);
+ pslILEmit->EmitBLT(pLoopBodyLabel);
+ }
+ else
+ {
+ ILMngdMarshaler::EmitConvertContentsNativeToCLR(pslILEmit);
+ }
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitClearNativeContents(pslILEmit);
+
+ if (!CanUsePinnedArray())
+ {
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeMethod()), 1, 0);
+ }
+}
+
+void ILHiddenLengthArrayMarshaler::EmitClearNativeContents(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!CanUsePinnedArray())
+ {
+ MethodDesc *pMD = GetClearNativeContentsMethod();
+ if (pMD != NULL)
+ {
+ MetaSig sig(pMD);
+ UINT numArgs = sig.NumFixedArgs();
+
+ if (numArgs == 3)
+ {
+ EmitLoadMngdMarshaler(pslILEmit);
+ }
+ else
+ {
+ _ASSERTE(numArgs == 2);
+ }
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadNativeArrayLength(pslILEmit);
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), numArgs, 0);
+ }
+ }
+}
+
+// Determine if we can simply pin the managed array, rather than doing a full marshal
+bool ILHiddenLengthArrayMarshaler::CanUsePinnedArray()
+{
+ STANDARD_VM_CONTRACT;
+
+ // If the array is only going from managed to native, and it contains only blittable data, and
+ // we know where that data is located in the array then we can take the fast path
+ if (!IsCLRToNative(m_dwMarshalFlags))
+ {
+ return false;
+ }
+
+ if (m_pargs->na.m_vt != VTHACK_BLITTABLERECORD)
+ {
+ return false;
+ }
+
+ if (IsByref(m_dwMarshalFlags))
+ {
+ return false;
+ }
+
+ if (!IsIn(m_dwMarshalFlags))
+ {
+ return false;
+ }
+
+ if (IsRetval(m_dwMarshalFlags))
+ {
+ return false;
+ }
+
+ if (m_pargs->na.m_optionalbaseoffset == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ILHiddenLengthArrayMarshaler::EmitLoadNativeArrayLength(ILCodeStream *pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // For return values, the native length won't yet be marshaled back to its managed home
+ // so it needs to be read directly
+ if (IsRetval(m_dwMarshalFlags))
+ {
+ pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
+ }
+ else
+ {
+ pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthManagedHome());
+ }
+
+ pslILEmit->EmitCONV_OVF_I4();
+}
+
+MethodDesc *ILHiddenLengthArrayMarshaler::GetConvertContentsToManagedMethod()
+{
+ STANDARD_VM_CONTRACT;
+
+ if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE)
+ {
+ switch (m_pargs->na.m_redirectedTypeIndex)
+ {
+ case WinMDAdapter::RedirectedTypeIndex_System_DateTimeOffset:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_DATETIME);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Type:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_TYPE);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Exception:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_EXCEPTION);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
+ {
+ MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_NULLABLE);
+ return GetExactMarshalerMethod(pMD);
+ }
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
+ {
+ MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_KEYVALUEPAIR);
+ return GetExactMarshalerMethod(pMD);
+ }
+
+ default:
+ UNREACHABLE_MSG("Unrecognized redirected type.");
+ }
+ }
+ return ILMngdMarshaler::GetConvertContentsToManagedMethod();
+}
+
+MethodDesc *ILHiddenLengthArrayMarshaler::GetConvertContentsToNativeMethod()
+{
+ STANDARD_VM_CONTRACT;
+
+ if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE)
+ {
+ switch (m_pargs->na.m_redirectedTypeIndex)
+ {
+ case WinMDAdapter::RedirectedTypeIndex_System_DateTimeOffset:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_DATETIME);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Type:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_TYPE);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Exception:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_EXCEPTION);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
+ {
+ MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_NULLABLE);
+ return GetExactMarshalerMethod(pMD);
+ }
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
+ {
+ MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_KEYVALUEPAIR);
+ return GetExactMarshalerMethod(pMD);
+ }
+
+ default:
+ UNREACHABLE_MSG("Unrecognized redirected type.");
+ }
+ }
+ return ILMngdMarshaler::GetConvertContentsToNativeMethod();
+}
+
+MethodDesc *ILHiddenLengthArrayMarshaler::GetClearNativeContentsMethod()
+{
+ switch (m_pargs->na.m_vt)
+ {
+ // HSTRINGs, interface pointers, and non-blittable structs need contents cleanup
+ case VTHACK_HSTRING:
+ case VTHACK_INSPECTABLE:
+ case VTHACK_NONBLITTABLERECORD:
+ break;
+
+ // blittable structs don't need contents cleanup
+ case VTHACK_BLITTABLERECORD:
+ return NULL;
+
+ case VTHACK_REDIRECTEDTYPE:
+ {
+ switch (m_pargs->na.m_redirectedTypeIndex)
+ {
+ // System.Type, Uri, Nullable, KeyValuePair, NCCEventArgs, and PCEventArgs need cleanup
+ case WinMDAdapter::RedirectedTypeIndex_System_Type:
+ return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS_TYPE);
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Uri:
+ case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
+ case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
+ break;
+
+ // other redirected types don't
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("Unexpected hidden-length array element VT");
+ }
+
+ return ILMngdMarshaler::GetClearNativeContentsMethod();
+}
+
+MethodDesc *ILHiddenLengthArrayMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
+{
+ STANDARD_VM_CONTRACT;
+
+ return MethodDesc::FindOrCreateAssociatedMethodDesc(
+ pGenericMD,
+ pGenericMD->GetMethodTable(),
+ FALSE, // forceBoxedEntryPoint
+ m_pargs->na.m_pMT->GetInstantiation(), // methodInst
+ FALSE, // allowInstParam
+ TRUE); // forceRemotableMethod
+}
+
+#ifndef CROSSGEN_COMPILE
+
+FCIMPL4(void, MngdHiddenLengthArrayMarshaler::CreateMarshaler, MngdHiddenLengthArrayMarshaler* pThis, MethodTable* pMT, SIZE_T cbElementSize, UINT16 vt)
+{
+ FCALL_CONTRACT;
+
+ pThis->m_pElementMT = pMT;
+ pThis->m_cbElementSize = cbElementSize;
+ pThis->m_vt = (VARTYPE)vt;
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertSpaceToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ BASEARRAYREF arrayRef = (BASEARRAYREF) *pManagedHome;
+ HELPER_METHOD_FRAME_BEGIN_1(arrayRef);
+
+ if (arrayRef == NULL)
+ {
+ *pNativeHome = NULL;
+ }
+ else
+ {
+ SIZE_T cbArray = pThis->GetArraySize(arrayRef->GetNumComponents());
+
+ *pNativeHome = CoTaskMemAlloc(cbArray);
+ if (*pNativeHome == NULL)
+ {
+ ThrowOutOfMemory();
+ }
+
+ // initialize the array
+ FillMemory(*pNativeHome, cbArray, 0);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertContentsToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ struct
+ {
+ PTRARRAYREF arrayRef;
+ STRINGREF currentStringRef;
+ OBJECTREF currentObjectRef;
+ }
+ gc;
+ ZeroMemory(&gc, sizeof(gc));
+ gc.arrayRef = (PTRARRAYREF)*pManagedHome;
+
+ HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
+
+ if (gc.arrayRef != NULL)
+ {
+ // There are these choices:
+ // * the array is made up of entirely blittable data, in which case we can directly copy it,
+ // * it is an array of strings that need to be marshaled as HSTRING,
+ // * it is an array of non-blittable structures
+ // * it is an array of interface pointers (interface, runtime class, delegate, System.Object)
+ switch (pThis->m_vt)
+ {
+ case VTHACK_BLITTABLERECORD:
+ {
+ // Just do a raw memcpy into the array
+ SIZE_T cbArray = pThis->GetArraySize(gc.arrayRef->GetNumComponents());
+ memcpyNoGCRefs(*pNativeHome, gc.arrayRef->GetDataPtr(), cbArray);
+ break;
+ }
+
+ case VTHACK_HSTRING:
+ {
+ // Marshal a string array as an array of HSTRINGs
+ if (!WinRTSupported())
+ {
+ COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
+ }
+
+ HSTRING *pDestinationStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
+
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ gc.currentStringRef = (STRINGREF)gc.arrayRef->GetAt(i);
+ if (gc.currentStringRef == NULL)
+ {
+ StackSString ssIndex;
+ ssIndex.Printf(W("%d"), i);
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHALARRAY_NULL_HSTRING, ssIndex.GetUnicode());
+ }
+
+ IfFailThrow(WindowsCreateString(gc.currentStringRef->GetBuffer(), gc.currentStringRef->GetStringLength(), &(pDestinationStrings[i])));
+ }
+ break;
+ }
+
+ case VTHACK_NONBLITTABLERECORD:
+ {
+ BYTE *pNativeStart = reinterpret_cast<BYTE *>(*pNativeHome);
+ SIZE_T managedOffset = ArrayBase::GetDataPtrOffset(gc.arrayRef->GetMethodTable());
+ SIZE_T nativeOffset = 0;
+ SIZE_T managedSize = gc.arrayRef->GetComponentSize();
+ SIZE_T nativeSize = pThis->m_pElementMT->GetNativeSize();
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ LayoutUpdateNative(reinterpret_cast<LPVOID *>(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset, NULL);
+ managedOffset += managedSize;
+ nativeOffset += nativeSize;
+ }
+ break;
+ }
+
+ case VTHACK_INSPECTABLE:
+ {
+ // interface pointers
+ IUnknown **pDestinationIPs = reinterpret_cast<IUnknown **>(*pNativeHome);
+
+ // If this turns out to be a perf issue, we can precompute the ItfMarshalInfo
+ // and generate code that passes it to the marshaler at creation time.
+ ItfMarshalInfo itfInfo;
+ MarshalInfo::GetItfMarshalInfo(TypeHandle(pThis->m_pElementMT), TypeHandle(), FALSE, TRUE, MarshalInfo::MARSHAL_SCENARIO_WINRT, &itfInfo);
+
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ gc.currentObjectRef = gc.arrayRef->GetAt(i);
+ pDestinationIPs[i] = MarshalObjectToInterface(
+ &gc.currentObjectRef,
+ itfInfo.thNativeItf.GetMethodTable(),
+ itfInfo.thClass.GetMethodTable(),
+ itfInfo.dwFlags);
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("Unrecognized array element VARTYPE");
+
+ }
+ }
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL4(void, MngdHiddenLengthArrayMarshaler::ConvertSpaceToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome == NULL)
+ {
+ SetObjectReference(pManagedHome, NULL, GetAppDomain());
+ }
+ else
+ {
+ TypeHandle elementType(pThis->m_pElementMT);
+ TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing(elementType);
+ SetObjectReference(pManagedHome, AllocateArrayEx(arrayType, &cElements, 1), GetAppDomain());
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertContentsToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ struct
+ {
+ PTRARRAYREF arrayRef;
+ STRINGREF stringRef;
+ OBJECTREF objectRef;
+ }
+ gc;
+ ZeroMemory(&gc, sizeof(gc));
+ gc.arrayRef = (PTRARRAYREF)*pManagedHome;
+
+ HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
+
+ if (*pNativeHome != NULL)
+ {
+ // There are these choices:
+ // * the array is made up of entirely blittable data, in which case we can directly copy it,
+ // * it is an array of strings that need to be marshaled as HSTRING,
+ // * it is an array of non-blittable structures
+ // * it is an array of interface pointers (interface, runtime class, delegate, System.Object)
+ switch (pThis->m_vt)
+ {
+ case VTHACK_BLITTABLERECORD:
+ {
+ // Just do a raw memcpy into the array
+ SIZE_T cbArray = pThis->GetArraySize(gc.arrayRef->GetNumComponents());
+ memcpyNoGCRefs(gc.arrayRef->GetDataPtr(), *pNativeHome, cbArray);
+ break;
+ }
+
+ case VTHACK_HSTRING:
+ {
+ // Strings are in HSRING format on the native side
+ if (!WinRTSupported())
+ {
+ COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
+ }
+
+ HSTRING *pSourceStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
+
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ // NULL HSTRINGS are equivilent to empty strings
+ UINT32 cchString = 0;
+ LPCWSTR pwszString = W("");
+
+ if (pSourceStrings[i] != NULL)
+ {
+ pwszString = WindowsGetStringRawBuffer(pSourceStrings[i], &cchString);
+ }
+
+ gc.stringRef = StringObject::NewString(pwszString, cchString);
+ gc.arrayRef->SetAt(i, gc.stringRef);
+ }
+ break;
+ }
+
+ case VTHACK_NONBLITTABLERECORD:
+ {
+ // Defer to the field marshaler to handle structures
+ BYTE *pNativeStart = reinterpret_cast<BYTE *>(*pNativeHome);
+ SIZE_T managedOffset = ArrayBase::GetDataPtrOffset(gc.arrayRef->GetMethodTable());
+ SIZE_T nativeOffset = 0;
+ SIZE_T managedSize = gc.arrayRef->GetComponentSize();
+ SIZE_T nativeSize = pThis->m_pElementMT->GetNativeSize();
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ LayoutUpdateCLR(reinterpret_cast<LPVOID *>(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset);
+ managedOffset += managedSize;
+ nativeOffset += nativeSize;
+ }
+ break;
+ }
+
+ case VTHACK_INSPECTABLE:
+ {
+ // interface pointers
+ IUnknown **pSourceIPs = reinterpret_cast<IUnknown **>(*pNativeHome);
+
+ // If this turns out to be a perf issue, we can precompute the ItfMarshalInfo
+ // and generate code that passes it to the marshaler at creation time.
+ ItfMarshalInfo itfInfo;
+ MarshalInfo::GetItfMarshalInfo(TypeHandle(pThis->m_pElementMT), TypeHandle(), FALSE, TRUE, MarshalInfo::MARSHAL_SCENARIO_WINRT, &itfInfo);
+
+ for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
+ {
+ gc.objectRef = gc.arrayRef->GetAt(i);
+ UnmarshalObjectFromInterface(
+ &gc.objectRef,
+ &pSourceIPs[i],
+ itfInfo.thItf.GetMethodTable(),
+ itfInfo.thClass.GetMethodTable(),
+ itfInfo.dwFlags);
+ gc.arrayRef->SetAt(i, gc.objectRef);
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("Unrecognized array element VARTYPE");
+ }
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ClearNativeContents, MngdHiddenLengthArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ if (*pNativeHome != NULL)
+ {
+ pThis->DoClearNativeContents(pNativeHome, cElements);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+#endif // CROSSGEN_COMPILE
+
+
+SIZE_T MngdHiddenLengthArrayMarshaler::GetArraySize(SIZE_T elements)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE_MSG(m_cbElementSize != 0, "You have to set the native size for your array element type");
+
+ SIZE_T cbArray;
+
+ if (!ClrSafeInt<SIZE_T>::multiply(elements, m_cbElementSize, cbArray))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
+ }
+
+ // This array size limit is carried over from the equivilent limit for other array marshaling code
+ if (cbArray > MAX_SIZE_FOR_INTEROP)
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
+ }
+
+ return cbArray;
+}
+
+#ifndef CROSSGEN_COMPILE
+void MngdHiddenLengthArrayMarshaler::DoClearNativeContents(void** pNativeHome, INT32 cElements)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pNativeHome != NULL);
+ }
+ CONTRACTL_END;
+
+ VARTYPE vt = m_vt;
+ if (vt == VTHACK_REDIRECTEDTYPE)
+ {
+ // the redirected types that use this helper are interface pointers on the WinRT side
+ vt = VTHACK_INSPECTABLE;
+ }
+
+ switch (vt)
+ {
+ case VTHACK_HSTRING:
+ {
+ if (WinRTSupported())
+ {
+ HSTRING *pStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
+ for (INT32 i = 0; i < cElements; ++i)
+ {
+ if (pStrings[i] != NULL)
+ {
+ WindowsDeleteString(pStrings[i]);
+ }
+ }
+ }
+ break;
+ }
+
+ case VTHACK_NONBLITTABLERECORD:
+ {
+ SIZE_T cbArray = GetArraySize(cElements);
+ BYTE *pNativeCurrent = reinterpret_cast<BYTE *>(*pNativeHome);
+ BYTE *pNativeEnd = pNativeCurrent + cbArray;
+
+ while (pNativeCurrent < pNativeEnd)
+ {
+ LayoutDestroyNative(pNativeCurrent, m_pElementMT);
+ pNativeCurrent += m_pElementMT->GetNativeSize();
+ }
+ break;
+ }
+
+ case VTHACK_INSPECTABLE:
+ {
+ IInspectable **pIPs = reinterpret_cast<IInspectable **>(*pNativeHome);
+ for (INT32 i = 0; i < cElements; ++i)
+ {
+ if (pIPs[i] != NULL)
+ {
+ SafeRelease(pIPs[i]);
+ }
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("Unexpected hidden-length array element VT");
+ }
+}
+#endif //CROSSGEN_COMPILE
+#endif // FEATURE_COMINTEROP
+
+void ILReferenceCustomMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(-1 == m_dwMngdMarshalerLocalNum);
+ }
+ CONTRACTL_END;
+
+ //
+ // allocate space for marshaler
+ //
+
+ m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
+
+ pslILEmit->EmitLDC(sizeof(MngdRefCustomMarshaler));
+ pslILEmit->EmitLOCALLOC();
+ pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
+
+ pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum); // arg to CreateMarshaler
+
+ //
+ // call CreateCustomMarshalerHelper
+ //
+
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->rcm.m_pMD));
+ pslILEmit->EmitCALL(METHOD__METHOD_HANDLE__GETVALUEINTERNAL, 1, 1);
+
+ pslILEmit->EmitLDC(m_pargs->rcm.m_paramToken);
+
+ pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(TypeHandle::FromPtr(m_pargs->rcm.m_hndManagedType)));
+ pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
+
+ pslILEmit->EmitCALL(METHOD__STUBHELPERS__CREATE_CUSTOM_MARSHALER_HELPER, 3, 1); // arg to CreateMarshaler
+
+ //
+ // call MngdRefCustomMarshaler::CreateMarshaler
+ //
+
+ pslILEmit->EmitCALL(METHOD__MNGD_REF_CUSTOM_MARSHALER__CREATE_MARSHALER, 2, 0);
+}
+
+
+#ifndef CROSSGEN_COMPILE
+
+FCIMPL2(void, MngdRefCustomMarshaler::CreateMarshaler, MngdRefCustomMarshaler* pThis, void* pCMHelper)
+{
+ FCALL_CONTRACT;
+
+ pThis->m_pCMHelper = (CustomMarshalerHelper*)pCMHelper;
+}
+FCIMPLEND
+
+
+FCIMPL3(void, MngdRefCustomMarshaler::ConvertContentsToNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(pManagedHome));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ *pNativeHome = pThis->m_pCMHelper->InvokeMarshalManagedToNativeMeth(*pManagedHome);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+FCIMPL3(void, MngdRefCustomMarshaler::ConvertContentsToManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(pManagedHome));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ SetObjectReference(pManagedHome, pThis->m_pCMHelper->InvokeMarshalNativeToManagedMeth(*pNativeHome), GetAppDomain());
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdRefCustomMarshaler::ClearNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ pThis->m_pCMHelper->InvokeCleanUpNativeMeth(*pNativeHome);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(void, MngdRefCustomMarshaler::ClearManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(pManagedHome));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ pThis->m_pCMHelper->InvokeCleanUpManagedMeth(*pManagedHome);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+#endif // CROSSGEN_COMPILE
+
+
+#ifdef FEATURE_COMINTEROP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILUriMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILUriMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILUriMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;;
+ BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ TypeHandle hndUriType = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriType();
+
+ return LocalDesc(hndUriType); // System.Uri
+}
+
+bool ILUriMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+// Note that this method expects the CLR Uri on top of the evaluation stack and leaves the WinRT Uri there.
+//static
+void ILUriMarshaler::EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ UriMarshalingInfo* marshalingInfo = pDomain->GetMarshalingData()->GetUriMarshalingInfo();
+
+ ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitBRTRUE(pNotNullLabel);
+
+ pslILEmit->EmitPOP();
+ pslILEmit->EmitLoadNullPtr();
+ pslILEmit->EmitBR(pDoneLabel);
+
+ pslILEmit->EmitLabel(pNotNullLabel);
+
+ // System.Uri.get_OriginalString()
+ MethodDesc* pSystemUriOriginalStringMD = marshalingInfo->GetSystemUriOriginalStringMD();
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pSystemUriOriginalStringMD), 1, 1);
+
+ pslILEmit->EmitCALL(METHOD__URIMARSHALER__CREATE_NATIVE_URI_INSTANCE, 1, 1);
+
+ pslILEmit->EmitLabel(pDoneLabel);
+}
+
+void ILUriMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreNativeValue(pslILEmit);
+}
+
+// Note that this method expects the WinRT Uri on top of the evaluation stack and leaves the CLR Uri there.
+//static
+void ILUriMarshaler::EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ MethodDesc* pSystemUriCtorMD = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriCtorMD();
+
+ ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
+ ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
+
+ pslILEmit->EmitDUP();
+ pslILEmit->EmitBRTRUE(pNotNullLabel);
+
+ pslILEmit->EmitPOP();
+ pslILEmit->EmitLDNULL();
+ pslILEmit->EmitBR(pDoneLabel);
+
+ pslILEmit->EmitLabel(pNotNullLabel);
+
+ // string UriMarshaler.GetRawUriFromNative(IntPtr)
+ pslILEmit->EmitCALL(METHOD__URIMARSHALER__GET_RAWURI_FROM_NATIVE, 1, 1);
+
+ // System.Uri..ctor(string)
+ pslILEmit->EmitNEWOBJ(pslILEmit->GetToken(pSystemUriCtorMD), 1);
+
+ pslILEmit->EmitLabel(pDoneLabel);
+}
+
+void ILUriMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreManagedValue(pslILEmit);
+}
+
+void ILUriMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILNCCEventArgsMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILNCCEventArgsMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILNCCEventArgsMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;;
+
+ BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ TypeHandle hndNCCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsType();
+
+ return LocalDesc(hndNCCEventArgType); // System.Collections.Specialized.NotifyCollectionChangedEventArgs
+}
+
+bool ILNCCEventArgsMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+// Note that this method expects the CLR NotifyCollectionChangedEventArgs on top of the evaluation stack and
+// leaves the WinRT NotifyCollectionChangedEventArgs IP there.
+//static
+void ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsToWinRTNCCEventArgsMD();
+
+ // IntPtr System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToNative(NotifyCollectionChangedEventArgs)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+}
+
+void ILNCCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreNativeValue(pslILEmit);
+}
+
+// Note that this method expects the WinRT NotifyCollectionChangedEventArgs on top of the evaluation stack and
+// leaves the CLR NotifyCollectionChangedEventArgs there.
+//static
+void ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
+
+ // NotifyCollectionChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+}
+
+void ILNCCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreManagedValue(pslILEmit);
+}
+
+void ILNCCEventArgsMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILPCEventArgsMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILPCEventArgsMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILPCEventArgsMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;;
+
+ BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
+ TypeHandle hndPCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsType();
+
+ return LocalDesc(hndPCEventArgType); // System.ComponentModel.PropertyChangedEventArgs
+}
+
+bool ILPCEventArgsMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+// Note that this method expects the CLR PropertyChangedEventArgs on top of the evaluation stack and
+// leaves the WinRT PropertyChangedEventArgs IP there.
+//static
+void ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsToWinRTPCEventArgsMD();
+
+ // IntPtr System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToNative(PropertyChangedEventArgs)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+}
+
+void ILPCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadManagedValue(pslILEmit);
+ EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreNativeValue(pslILEmit);
+}
+
+// Note that this method expects the WinRT PropertyChangedEventArgs on top of the evaluation stack and
+// leaves the CLR PropertyChangedEventArgs there.
+//static
+void ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+{
+ STANDARD_VM_CONTRACT;
+
+ MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTPCEventArgsToSystemPCEventArgsMD();
+
+ // PropertyChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
+}
+
+void ILPCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeValue(pslILEmit);
+ EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+ EmitStoreManagedValue(pslILEmit);
+}
+
+void ILPCEventArgsMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILDateTimeMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILDateTimeMarshaler::GetNativeType()
+{
+ STANDARD_VM_CONTRACT;;
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__DATETIMENATIVE));
+}
+
+LocalDesc ILDateTimeMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;;
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__DATE_TIME_OFFSET));
+}
+
+bool ILDateTimeMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return false;
+}
+
+void ILDateTimeMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // DateTimeOffsetMarshaler.ConvertManagedToNative(ref managedDTO, out nativeTicks);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE, 2, 0);
+}
+
+void ILDateTimeMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // DateTimeOffsetMarshaler.ConvertNativeToManaged(out managedLocalDTO, ref nativeTicks);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED, 2, 0);
+}
+
+void ILDateTimeMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__DATETIMENATIVE)));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILNullableMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILNullableMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILNullableMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;;
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+bool ILNullableMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILNullableMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // pNative = NullableMarshaler<T>.ConvertToNative(ref pManaged);
+ EmitLoadManagedHomeAddr(pslILEmit);
+
+ MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE));
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILNullableMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // pManaged = NullableMarshaler.ConvertToManaged(pNative);
+ EmitLoadNativeValue(pslILEmit);
+
+ MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED));
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
+
+ EmitStoreManagedValue(pslILEmit);
+}
+
+void ILNullableMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+
+MethodDesc *ILNullableMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
+{
+ STANDARD_VM_CONTRACT;
+
+ return MethodDesc::FindOrCreateAssociatedMethodDesc(
+ pGenericMD,
+ pGenericMD->GetMethodTable(),
+ FALSE, // forceBoxedEntryPoint
+ m_pargs->m_pMT->GetInstantiation(), // methodInst
+ FALSE, // allowInstParam
+ TRUE); // forceRemotableMethod
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILSystemTypeMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILSystemTypeMarshaler::GetNativeType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__TYPENAMENATIVE));
+}
+
+LocalDesc ILSystemTypeMarshaler::GetManagedType()
+{
+ STANDARD_VM_CONTRACT;
+
+ return LocalDesc(MscorlibBinder::GetClass(CLASS__TYPE));
+}
+
+bool ILSystemTypeMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILSystemTypeMarshaler::EmitConvertContentsCLRToNative(ILCodeStream * pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // SystemTypeMarshaler.ConvertToNative(Type, pTypeName);
+ EmitLoadManagedValue(pslILEmit);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE, 2, 0);
+}
+
+void ILSystemTypeMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream * pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // type = SystemTypeMarshaler.ConvertNativeToManaged(pTypeName, ref Type);
+ EmitLoadNativeHomeAddr(pslILEmit);
+ EmitLoadManagedHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED, 2, 0);
+}
+
+
+void ILSystemTypeMarshaler::EmitClearNative(ILCodeStream * pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // SystemTypeMarshaler.ClearNative(pTypeName)
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CLEAR_NATIVE, 1, 0);
+}
+
+void ILSystemTypeMarshaler::EmitReInitNative(ILCodeStream * pslILEmit)
+{
+ EmitLoadNativeHomeAddr(pslILEmit);
+ pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__TYPENAMENATIVE)));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILHResultExceptionMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILHResultExceptionMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I4);
+}
+
+LocalDesc ILHResultExceptionMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_pargs->m_pMT != NULL);
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+bool ILHResultExceptionMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return false;
+}
+
+void ILHResultExceptionMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // int HResultExceptionMarshaler.ConvertManagedToNative(Exception);
+ EmitLoadManagedValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE, 1, 1);
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILHResultExceptionMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pslILEmit));
+ }
+ CONTRACTL_END;
+
+ // Exception HResultExceptionMarshaler.ConvertNativeToManaged(int hr);
+ EmitLoadNativeValue(pslILEmit);
+ pslILEmit->EmitCALL(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED, 1, 1);
+ EmitStoreManagedValue(pslILEmit);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ILKeyValuePairMarshaler implementation
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocalDesc ILKeyValuePairMarshaler::GetNativeType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return LocalDesc(ELEMENT_TYPE_I);
+}
+
+LocalDesc ILKeyValuePairMarshaler::GetManagedType()
+{
+ LIMITED_METHOD_CONTRACT;;
+ return LocalDesc(m_pargs->m_pMT);
+}
+
+bool ILKeyValuePairMarshaler::NeedsClearNative()
+{
+ LIMITED_METHOD_CONTRACT;
+ return true;
+}
+
+void ILKeyValuePairMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // Native = KeyValueMarshaler<K, V>.ConvertToNative([In] ref Managed);
+ EmitLoadManagedHomeAddr(pslILEmit);
+
+ MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__KEYVALUEPAIRMARSHALER__CONVERT_TO_NATIVE));
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
+
+ EmitStoreNativeValue(pslILEmit);
+}
+
+void ILKeyValuePairMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+
+ // Managed = KeyValuePairMarshaler<K, V>.ConvertToManaged(Native);
+ EmitLoadNativeValue(pslILEmit);
+
+ MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__KEYVALUEPAIRMARSHALER__CONVERT_TO_MANAGED));
+ pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
+
+ EmitStoreManagedValue(pslILEmit);
+}
+
+void ILKeyValuePairMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
+{
+ STANDARD_VM_CONTRACT;
+ EmitInterfaceClearNative(pslILEmit);
+}
+
+MethodDesc *ILKeyValuePairMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
+{
+ STANDARD_VM_CONTRACT;
+
+ // KeyValuePairMarshaler methods are generic - find/create the exact method.
+ return MethodDesc::FindOrCreateAssociatedMethodDesc(
+ pGenericMD,
+ pGenericMD->GetMethodTable(),
+ FALSE, // forceBoxedEntryPoint
+ m_pargs->m_pMT->GetInstantiation(), // methodInst
+ FALSE, // allowInstParam
+ TRUE); // forceRemotableMethod
+}
+
+#endif // FEATURE_COMINTEROP