// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license 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 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); // 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 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 = false ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream(); DWORD dwHandleAddRefedLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN); pcsSetup->EmitLDC(0); pcsSetup->EmitSTLOC(dwHandleAddRefedLocalNum); // = StubHelpers::SafeHandleAddRef(, ref ) EmitLoadManagedValue(m_pcsMarshal); m_pcsMarshal->EmitLDLOCA(dwHandleAddRefedLocalNum); m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_ADD_REF, 2, 1); EmitStoreNativeValue(m_pcsMarshal); // cleanup: // if () StubHelpers.SafeHandleRelease() 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(); } // .SetData(, , 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); if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL) { SIZE_T cElements = (*pArrayRef)->GetNumComponents(); SIZE_T cbArray = cElements; if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > MAX_SIZE_FOR_INTEROP) COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE); _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers()); memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cbArray); } else { pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap, pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid); } } 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: lookup this class before marshal time 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(); SIZE_T cbArray = cElements; if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > 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, cbArray ); } 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(*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(*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(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset, NULL); managedOffset += managedSize; nativeOffset += nativeSize; } break; } case VTHACK_INSPECTABLE: { // interface pointers IUnknown **pDestinationIPs = reinterpret_cast(*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(*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(*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(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset); managedOffset += managedSize; nativeOffset += nativeSize; } break; } case VTHACK_INSPECTABLE: { // interface pointers IUnknown **pSourceIPs = reinterpret_cast(*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::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(*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(*pNativeHome); BYTE *pNativeEnd = pNativeCurrent + cbArray; while (pNativeCurrent < pNativeEnd) { LayoutDestroyNative(pNativeCurrent, m_pElementMT); pNativeCurrent += m_pElementMT->GetNativeSize(); } break; } case VTHACK_INSPECTABLE: { IInspectable **pIPs = reinterpret_cast(*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.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.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.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