mirror of
https://github.com/ZuneDev/dotnet-runtime.git
synced 2026-07-27 13:22:01 -07:00
4965 lines
156 KiB
C++
4965 lines
156 KiB
C++
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
//
|
|
// 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(CoreLibBinder::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(CoreLibBinder::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(CoreLibBinder::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))
|
|
{
|
|
EmitKeepAliveManagedValue();
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
if (IsCLRToNative(m_dwMarshalFlags))
|
|
{
|
|
EmitKeepAliveManagedValue();
|
|
}
|
|
|
|
pslILEmit->EmitLabel(pNullLabel);
|
|
}
|
|
|
|
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)
|
|
|
|
// COMPAT: There is a subtle difference between argument and field marshaling with Delegate types.
|
|
// During field marshaling, the plain Delegate type can be used even though that type doesn't
|
|
// represent a concrete type. Argument marshaling doesn't permit this so we use the public
|
|
// API which will validate that Delegate isn't directly used.
|
|
if (IsFieldMarshal(m_dwMarshalFlags))
|
|
{
|
|
// Delegate System.Marshal.GetDelegateForFunctionPointerInternal(IntPtr p, Type t)
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER_INTERNAL, 2, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
|
|
// Field marshaling of delegates supports marshaling back null from native code.
|
|
// COMPAT: Parameter and return value marshalling does not marshal back a null value.
|
|
// e.g. `extern static void SetNull(ref Action f);` <- f will not be null on return.
|
|
ILCodeLabel* pFinishedLabel = pslILEmit->NewCodeLabel();
|
|
pslILEmit->EmitBR(pFinishedLabel);
|
|
pslILEmit->EmitLabel(pNullLabel);
|
|
pslILEmit->EmitLDNULL();
|
|
EmitStoreManagedValue(pslILEmit);
|
|
pslILEmit->EmitLabel(pFinishedLabel);
|
|
}
|
|
else
|
|
{
|
|
// Delegate System.Marshal.GetDelegateForFunctionPointer(IntPtr p, Type t)
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER, 2, 1);
|
|
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("All paths to this function are covered by the EmitConvertSpaceAndContents* paths");
|
|
}
|
|
|
|
void ILWSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
// This code path should only be called by an out marshalling. Other codepaths that convert a string to native
|
|
// should all go through EmitConvertSpaceAndContentsCLRToNative
|
|
_ASSERTE(IsOut(m_dwMarshalFlags) && !IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitCheckManagedStringLength(pslILEmit);
|
|
|
|
// static void System.String.InternalCopy(String src, IntPtr dest,int len)
|
|
pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILWSTRMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
// We currently don't marshal strings from the native to the CLR side in a Reverse-PInvoke unless
|
|
// the parameter is explicitly annotated as an [In] parameter.
|
|
pslILEmit->EmitLDNULL();
|
|
EmitStoreManagedValue(pslILEmit);
|
|
}
|
|
|
|
void ILWSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pIsNullLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pIsNullLabel);
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitDUP();
|
|
EmitCheckNativeStringLength(pslILEmit);
|
|
pslILEmit->EmitPOP(); // pop num chars
|
|
|
|
pslILEmit->EmitNEWOBJ(METHOD__STRING__CTOR_CHARPTR, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
|
|
pslILEmit->EmitLabel(pIsNullLabel);
|
|
}
|
|
|
|
//
|
|
// input stack: 0: managed string
|
|
// output stack: 0: (string_length+1) * sizeof(WCHAR)
|
|
//
|
|
void ILWSTRMarshaler::EmitCheckManagedStringLength(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
// Note: The maximum size of managed string is under 2GB bytes. This cannot overflow.
|
|
pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
|
|
pslILEmit->EmitLDC(1);
|
|
pslILEmit->EmitADD();
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitADD(); // (length+1) * sizeof(WCHAR)
|
|
}
|
|
|
|
void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
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::EmitMarshalViaPinning(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
LocalDesc locDesc = GetManagedType();
|
|
locDesc.MakePinned();
|
|
DWORD dwPinnedLocal = pslILEmit->NewLocal(locDesc);
|
|
int fieldDef = pslILEmit->GetToken(CoreLibBinder::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);
|
|
|
|
EmitLogNativeArgument(pslILEmit, dwPinnedLocal);
|
|
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
DWORD dwLengthLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
|
|
|
|
pslILEmit->EmitLoadNullPtr();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitCheckManagedStringLength(pslILEmit);
|
|
|
|
pslILEmit->EmitSTLOC(dwLengthLocalNum);
|
|
|
|
ILCodeLabel* pAllocRejoin = pslILEmit->NewCodeLabel();
|
|
ILCodeLabel* pNoOptimize = pslILEmit->NewCodeLabel();
|
|
m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
|
|
// LocalBuffer = 0
|
|
pslILEmit->EmitLoadNullPtr();
|
|
pslILEmit->EmitSTLOC(m_dwLocalBuffer);
|
|
|
|
pslILEmit->EmitLDLOC(dwLengthLocalNum);
|
|
// 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);
|
|
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
|
|
pslILEmit->EmitLabel(pAllocRejoin);
|
|
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);
|
|
}
|
|
|
|
LocalDesc ILOptimizedAllocMarshaler::GetNativeType()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return LocalDesc(ELEMENT_TYPE_I);
|
|
}
|
|
|
|
bool ILOptimizedAllocMarshaler::NeedsClearNative()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return true;
|
|
}
|
|
|
|
void ILOptimizedAllocMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel *pOptimize = NULL;
|
|
|
|
if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
|
|
{
|
|
pOptimize = pslILEmit->NewCodeLabel();
|
|
|
|
// if (m_dwLocalBuffer) goto Optimize
|
|
pslILEmit->EmitLDLOC(m_dwLocalBuffer);
|
|
pslILEmit->EmitBRTRUE(pOptimize);
|
|
}
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
// static void m_idClearNative(IntPtr ptr)
|
|
pslILEmit->EmitCALL(m_idClearNative, 1, 0);
|
|
|
|
// Optimize:
|
|
if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
|
|
{
|
|
pslILEmit->EmitLabel(pOptimize);
|
|
}
|
|
}
|
|
|
|
LocalDesc ILUTF8BufferMarshaler::GetManagedType()
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
return LocalDesc(CoreLibBinder::GetClass(CLASS__STRING_BUILDER));
|
|
}
|
|
|
|
void ILUTF8BufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
|
|
pslILEmit->EmitLoadNullPtr();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
// int System.Text.StringBuilder.get_Capacity()
|
|
pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
|
|
pslILEmit->EmitDUP();
|
|
|
|
// static void StubHelpers.CheckStringLength(int length)
|
|
pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
|
|
|
|
// Max number of bytes for UTF8 string in BMP plane is ( StringBuilder.Capacity + 1 ) * 3 + 1
|
|
// first +1 if the high surrogate is '?' and second +1 for null byte.
|
|
|
|
// stack: capacity_in_bytes
|
|
pslILEmit->EmitLDC(1);
|
|
pslILEmit->EmitADD();
|
|
|
|
// stack: capacity
|
|
pslILEmit->EmitLDC(3);
|
|
pslILEmit->EmitMUL();
|
|
|
|
// stack: offset_of_null
|
|
DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
|
|
|
|
// make space for '\0'
|
|
pslILEmit->EmitLDC(1);
|
|
pslILEmit->EmitADD();
|
|
|
|
// stack: alloc_size_in_bytes
|
|
ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
|
|
if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && !IsFieldMarshal(m_dwMarshalFlags))
|
|
{
|
|
ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel();
|
|
m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
|
|
// LocalBuffer = 0
|
|
pslILEmit->EmitLoadNullPtr();
|
|
pslILEmit->EmitSTLOC(m_dwLocalBuffer);
|
|
|
|
// if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
|
|
pslILEmit->EmitCGT_UN();
|
|
pslILEmit->EmitBRTRUE(pNoOptimize);
|
|
|
|
pslILEmit->EmitLOCALLOC();
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitSTLOC(m_dwLocalBuffer);
|
|
pslILEmit->EmitBR(pAllocRejoin);
|
|
|
|
pslILEmit->EmitLabel(pNoOptimize);
|
|
}
|
|
|
|
// static IntPtr AllocCoTaskMem(int cb)
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
|
|
|
|
pslILEmit->EmitLabel(pAllocRejoin);
|
|
|
|
// stack: native_addr
|
|
|
|
pslILEmit->EmitDUP();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
|
|
|
|
// stack: native_addr offset_of_null
|
|
pslILEmit->EmitADD();
|
|
|
|
// stack: addr_of_null0
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitSTIND_I1();
|
|
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILUTF8BufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
DWORD dwUtf8MarshalFlags =
|
|
(m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
|
|
(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
|
|
|
|
// setup to call UTF8BufferMarshaler.ConvertToNative
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(dwUtf8MarshalFlags);
|
|
|
|
//ConvertToNative(StringBuilder sb,IntPtr pNativeBuffer, int flags)
|
|
pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_NATIVE, 3, 1);
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILUTF8BufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
|
|
{
|
|
EmitLoadNativeValue(pslILEmit);
|
|
// static int System.String.strlen(byte* ptr)
|
|
pslILEmit->EmitCALL(METHOD__STRING__STRLEN, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
// don't touch the native buffer in the native->CLR out-only case
|
|
pslILEmit->EmitLDC(0);
|
|
}
|
|
// Convert to UTF8 and then call
|
|
// System.Text.StringBuilder..ctor(int capacity)
|
|
pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILUTF8BufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
|
|
//void UTF8BufferMarshaler.ConvertToManaged(StringBuilder sb, IntPtr pNative)
|
|
pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_MANAGED, 2, 0);
|
|
}
|
|
|
|
|
|
LocalDesc ILWSTRBufferMarshaler::GetManagedType()
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
return LocalDesc(CoreLibBinder::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) && !IsFieldMarshal(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 dwTempNumCharsLocal = 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
|
|
pslILEmit->EmitDUP();
|
|
// static void StubHelpers.CheckStringLength(int length)
|
|
pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
|
|
|
|
// stack: StringBuilder length
|
|
|
|
pslILEmit->EmitSTLOC(dwTempNumCharsLocal);
|
|
|
|
// stack: StringBuilder
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDLOC(dwTempNumCharsLocal);
|
|
|
|
// stack: StringBuilder native_buffer length
|
|
|
|
// 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(dwTempNumCharsLocal);
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitADD(); // dwTempNumCharsLocal + dwTempNumCharsLocal
|
|
pslILEmit->EmitADD(); // + native_buffer
|
|
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.u16_strlen(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.u16_strlen(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(CoreLibBinder::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(CoreLibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
|
|
pslILEmit->EmitMUL_OVF();
|
|
|
|
// stack: capacity_in_bytes
|
|
|
|
pslILEmit->EmitLDC(1);
|
|
pslILEmit->EmitADD_OVF();
|
|
|
|
// 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_OVF();
|
|
|
|
// stack: alloc_size_in_bytes
|
|
ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
|
|
if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && !IsFieldMarshal(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.String.strlen(byte* ptr)
|
|
pslILEmit->EmitCALL(METHOD__STRING__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.String.strlen(byte* ptr)
|
|
pslILEmit->EmitCALL(METHOD__STRING__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;
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Cleanup);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
}
|
|
|
|
|
|
void ILValueClassMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Marshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
}
|
|
|
|
void ILValueClassMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Unmarshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
}
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
LocalDesc ILObjectMarshaler::GetNativeType()
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
return LocalDesc(TypeHandle(CoreLibBinder::GetClass(CLASS__COMVARIANT)));
|
|
}
|
|
|
|
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(CoreLibBinder::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(CoreLibBinder::GetClass(CLASS__CURRENCY)));
|
|
}
|
|
|
|
LocalDesc ILCurrencyMarshaler::GetManagedType()
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
return LocalDesc(TypeHandle(CoreLibBinder::GetClass(CLASS__DECIMAL)));
|
|
}
|
|
|
|
|
|
void ILCurrencyMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitINITOBJ(pslILEmit->GetToken(TypeHandle(CoreLibBinder::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);
|
|
}
|
|
|
|
|
|
#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__TO_INTPTR, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLoadNullPtr();
|
|
}
|
|
|
|
if (itfInfo.thClass.GetMethodTable())
|
|
{
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
|
|
pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__TO_INTPTR, 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);
|
|
}
|
|
|
|
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 (itfInfo.thItf.GetMethodTable())
|
|
{
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thItf.GetMethodTable()));
|
|
pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__TO_INTPTR, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLoadNullPtr();
|
|
}
|
|
|
|
if (itfInfo.thClass.GetMethodTable())
|
|
{
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
|
|
pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__TO_INTPTR, 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;
|
|
|
|
LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
|
|
TypeHandle hndColorType = pLoader->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
|
|
|
|
//
|
|
// value class
|
|
//
|
|
return LocalDesc(hndColorType); // System.Drawing.Color
|
|
}
|
|
|
|
void ILOleColorMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
|
|
MethodDesc* pConvertMD = pLoader->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;
|
|
|
|
LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
|
|
MethodDesc* pConvertMD = pLoader->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::EmitSetupArgumentForMarshalling(ILCodeStream* pslILEmit)
|
|
{
|
|
m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
pslILEmit->EmitLoadNullPtr();
|
|
pslILEmit->EmitSTLOC(m_dwLocalBuffer);
|
|
}
|
|
|
|
void ILVBByValStrWMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
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 preceding 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);
|
|
|
|
// <empty>
|
|
|
|
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);
|
|
|
|
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, 3, 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__MARSHAL__FREE_CO_TASK_MEM, 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);
|
|
}
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
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) && !IsFieldMarshal(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);
|
|
}
|
|
|
|
void ILFixedWSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
ILCodeLabel* pFinishedLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
|
|
pslILEmit->EmitCALL(METHOD__FIXEDWSTRMARSHALER__CONVERT_TO_NATIVE, 3, 0);
|
|
}
|
|
|
|
void ILFixedWSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
|
|
pslILEmit->EmitCALL(METHOD__FIXEDWSTRMARSHALER__CONVERT_TO_MANAGED, 2, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
}
|
|
|
|
void ILFixedCSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
DWORD dwAnsiMarshalFlags =
|
|
(m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
|
|
(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
|
|
|
|
// CSTRMarshaler.ConvertFixedToNative dwAnsiMarshalFlags, pManaged, homeAddr, fixedLength
|
|
pslILEmit->EmitLDC(dwAnsiMarshalFlags);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
|
|
pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_FIXED_TO_NATIVE, 4, 0);
|
|
}
|
|
|
|
void ILFixedCSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
|
|
pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_FIXED_TO_MANAGED, 2, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
}
|
|
|
|
LocalDesc ILCUTF8Marshaler::GetManagedType()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return LocalDesc(ELEMENT_TYPE_STRING);
|
|
}
|
|
|
|
LocalDesc ILCUTF8Marshaler::GetNativeType()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return LocalDesc(ELEMENT_TYPE_I);
|
|
}
|
|
|
|
bool ILCUTF8Marshaler::NeedsClearNative()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return true;
|
|
}
|
|
|
|
void ILCUTF8Marshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags);
|
|
if (bPassByValueInOnly)
|
|
{
|
|
if (m_dwInstance == LOCAL_NUM_UNUSED)
|
|
m_dwInstance = pslILEmit->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__UTF8STRINGMARSHALLER_IN)));
|
|
|
|
DWORD dwBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
pslILEmit->EmitLDC(LOCAL_BUFFER_LENGTH);
|
|
pslILEmit->EmitLOCALLOC();
|
|
pslILEmit->EmitSTLOC(dwBuffer);
|
|
|
|
// Load the marshaller instance.
|
|
pslILEmit->EmitLDLOCA(m_dwInstance);
|
|
|
|
// Argument 1
|
|
EmitLoadManagedValue(pslILEmit);
|
|
|
|
// Argument 2
|
|
// Create ReadOnlySpan<byte> from the stack-allocated buffer
|
|
pslILEmit->EmitLDLOC(dwBuffer);
|
|
pslILEmit->EmitLDC(LOCAL_BUFFER_LENGTH);
|
|
TypeHandle thByte = CoreLibBinder::GetClass(CLASS__BYTE);
|
|
MethodDesc* pSpanCtor = MethodDesc::FindOrCreateAssociatedMethodDesc(CoreLibBinder::GetMethod(METHOD__SPAN__CTOR_PTR_INT),
|
|
TypeHandle(CoreLibBinder::GetClass(CLASS__SPAN)).Instantiate(Instantiation(&thByte, 1)).AsMethodTable(),
|
|
FALSE, Instantiation(), FALSE);
|
|
pslILEmit->EmitNEWOBJ(pslILEmit->GetToken(pSpanCtor), 2);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__FROM_MANAGED, 2, 0);
|
|
|
|
pslILEmit->EmitLDLOCA(m_dwInstance);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__TO_UNMANAGED, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__CONVERT_TO_UNMANAGED, 1, 1);
|
|
}
|
|
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILCUTF8Marshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__CONVERT_TO_MANAGED, 1, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
}
|
|
|
|
void ILCUTF8Marshaler::EmitClearNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
if (m_dwInstance != LOCAL_NUM_UNUSED)
|
|
{
|
|
pslILEmit->EmitLDLOCA(m_dwInstance);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__FREE, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__FREE, 1, 0);
|
|
}
|
|
}
|
|
|
|
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(CoreLibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
|
|
pslILEmit->EmitMUL_OVF();
|
|
|
|
// 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);
|
|
|
|
ILCodeLabel* pTypeMismatchedLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, pTypeMismatchedLabel);
|
|
DWORD sizeLocal = pslILEmit->NewLocal(LocalDesc(ELEMENT_TYPE_I4));
|
|
|
|
pslILEmit->EmitLDC(uNativeSize);
|
|
if (emittedTypeCheck)
|
|
{
|
|
ILCodeLabel* pHaveSizeLabel = pslILEmit->NewCodeLabel();
|
|
pslILEmit->EmitBR(pHaveSizeLabel);
|
|
pslILEmit->EmitLabel(pTypeMismatchedLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__OBJECT__GET_TYPE, 1, 1);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__SIZEOF_TYPE, 1, 1);
|
|
pslILEmit->EmitLabel(pHaveSizeLabel);
|
|
}
|
|
pslILEmit->EmitSTLOC(sizeLocal);
|
|
pslILEmit->EmitLDLOC(sizeLocal);
|
|
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->EmitLDLOC(sizeLocal);
|
|
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);
|
|
|
|
ILCodeLabel* pTypeMismatchedLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, pTypeMismatchedLabel);
|
|
DWORD sizeLocal = pslILEmit->NewLocal(LocalDesc(ELEMENT_TYPE_I4));
|
|
|
|
pslILEmit->EmitLDC(uNativeSize);
|
|
if (emittedTypeCheck)
|
|
{
|
|
ILCodeLabel* pHaveSizeLabel = pslILEmit->NewCodeLabel();
|
|
pslILEmit->EmitBR(pHaveSizeLabel);
|
|
pslILEmit->EmitLabel(pTypeMismatchedLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__OBJECT__GET_TYPE, 1, 1);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__SIZEOF_TYPE, 1, 1);
|
|
pslILEmit->EmitLabel(pHaveSizeLabel);
|
|
}
|
|
pslILEmit->EmitSTLOC(sizeLocal);
|
|
pslILEmit->EmitLDLOC(sizeLocal);
|
|
|
|
pslILEmit->EmitLOCALLOC();
|
|
pslILEmit->EmitDUP(); // for INITBLK
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
// initialize local block we just allocated
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitLDLOC(sizeLocal);
|
|
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__TO_INTPTR, 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__MARSHAL__FREE_CO_TASK_MEM, 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);
|
|
}
|
|
}
|
|
|
|
bool ILLayoutClassPtrMarshalerBase::EmitExactTypeCheck(ILCodeStream* pslILEmit, ILCodeLabel* isNotMatchingTypeLabel)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
if (m_pargs->m_pMT->IsSealed())
|
|
{
|
|
// If the provided type cannot be derived from, then we don't need to emit the type check.
|
|
return false;
|
|
}
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__OBJECT__GET_TYPE, 1, 1);
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
|
|
pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1);
|
|
pslILEmit->EmitCALLVIRT(pslILEmit->GetToken(CoreLibBinder::GetMethod(METHOD__OBJECT__EQUALS)), 1, 1);
|
|
pslILEmit->EmitBRFALSE(isNotMatchingTypeLabel);
|
|
|
|
return true;
|
|
}
|
|
|
|
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();
|
|
|
|
ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, isNotMatchingTypeLabel);
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Marshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
|
|
if (emittedTypeCheck)
|
|
{
|
|
pslILEmit->EmitBR(pNullRefLabel);
|
|
|
|
pslILEmit->EmitLabel(isNotMatchingTypeLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__STRUCTURE_TO_PTR, 3, 0);
|
|
}
|
|
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILLayoutClassPtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, isNotMatchingTypeLabel);
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Unmarshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
if (emittedTypeCheck)
|
|
{
|
|
pslILEmit->EmitBR(pNullRefLabel);
|
|
|
|
pslILEmit->EmitLabel(isNotMatchingTypeLabel);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__PTR_TO_STRUCTURE, 2, 0);
|
|
}
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILLayoutClassPtrMarshaler::EmitClearNativeContents(ILCodeStream * pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel();
|
|
ILCodeLabel* cleanedUpLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, isNotMatchingTypeLabel);
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Cleanup);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
|
|
if (emittedTypeCheck)
|
|
{
|
|
pslILEmit->EmitBR(cleanedUpLabel);
|
|
|
|
pslILEmit->EmitLabel(isNotMatchingTypeLabel);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__OBJECT__GET_TYPE, 1, 1);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__DESTROY_STRUCTURE, 2, 0);
|
|
}
|
|
|
|
pslILEmit->EmitLabel(cleanedUpLabel);
|
|
}
|
|
|
|
|
|
void ILBlittablePtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
|
|
int fieldDef = pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__RAW_DATA__DATA));
|
|
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, isNotMatchingTypeLabel);
|
|
|
|
EmitLoadNativeValue(pslILEmit); // dest
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLDA(fieldDef); // src
|
|
|
|
pslILEmit->EmitLDC(uNativeSize); // size
|
|
|
|
pslILEmit->EmitCPBLK();
|
|
|
|
if (emittedTypeCheck)
|
|
{
|
|
pslILEmit->EmitBR(pNullRefLabel);
|
|
|
|
pslILEmit->EmitLabel(isNotMatchingTypeLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__STRUCTURE_TO_PTR, 3, 0);
|
|
}
|
|
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(CoreLibBinder::GetField(FIELD__RAW_DATA__DATA));
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel();
|
|
bool emittedTypeCheck = EmitExactTypeCheck(pslILEmit, isNotMatchingTypeLabel);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLDA(fieldDef); // dest
|
|
|
|
EmitLoadNativeValue(pslILEmit); // src
|
|
|
|
pslILEmit->EmitLDC(uNativeSize); // size
|
|
|
|
pslILEmit->EmitCPBLK();
|
|
|
|
if (emittedTypeCheck)
|
|
{
|
|
pslILEmit->EmitBR(pNullRefLabel);
|
|
|
|
pslILEmit->EmitLabel(isNotMatchingTypeLabel);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__MARSHAL__PTR_TO_STRUCTURE, 2, 0);
|
|
}
|
|
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
bool ILBlittablePtrMarshaler::CanMarshalViaPinning()
|
|
{
|
|
// [COMPAT] For correctness, we can't marshal via pinning if we might need to marshal differently at runtime.
|
|
// See calls to EmitExactTypeCheck where we check the runtime type of the object being marshalled.
|
|
// However, we previously supported pinning non-sealed blittable classes, even though that could result
|
|
// in some data still being unmarshalled if a subclass is provided. This optimization is incorrect,
|
|
// but libraries like NAudio have taken a hard dependency on this incorrect behavior, so we need to preserve it.
|
|
return IsCLRToNative(m_dwMarshalFlags) &&
|
|
!IsByref(m_dwMarshalFlags) &&
|
|
!IsFieldMarshal(m_dwMarshalFlags);
|
|
}
|
|
|
|
void ILBlittablePtrMarshaler::EmitMarshalViaPinning(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pSkipAddLabel = pslILEmit->NewCodeLabel();
|
|
LocalDesc managedTypePinned = GetManagedType();
|
|
managedTypePinned.MakePinned();
|
|
DWORD dwPinnedLocal = pslILEmit->NewLocal(managedTypePinned);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
|
|
pslILEmit->EmitSTLOC(dwPinnedLocal);
|
|
pslILEmit->EmitLDLOC(dwPinnedLocal);
|
|
pslILEmit->EmitCONV_U();
|
|
pslILEmit->EmitDUP();
|
|
pslILEmit->EmitBRFALSE(pSkipAddLabel);
|
|
pslILEmit->EmitLDC(Object::GetOffsetOfFirstField());
|
|
pslILEmit->EmitADD();
|
|
pslILEmit->EmitLabel(pSkipAddLabel);
|
|
|
|
EmitLogNativeArgument(pslILEmit, dwPinnedLocal);
|
|
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILLayoutClassMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
|
|
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitLDC(uNativeSize);
|
|
pslILEmit->EmitINITBLK();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Marshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILLayoutClassMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
|
|
pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_UNINITIALIZED_OBJECT, 1, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
}
|
|
|
|
void ILLayoutClassMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Unmarshal);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
}
|
|
|
|
void ILLayoutClassMarshaler::EmitClearNativeContents(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub(m_pargs->m_pMT);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_RAW_DATA, 1, 1);
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(StructMarshalStubs::MarshalOperation::Cleanup);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
|
|
pslILEmit->EmitCALL(pslILEmit->GetToken(pStructMarshalStub), 4, 0);
|
|
}
|
|
|
|
|
|
void ILBlittableLayoutClassMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
|
|
int fieldDef = pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__RAW_DATA__DATA));
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit);
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitLDC(uNativeSize);
|
|
pslILEmit->EmitINITBLK();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit); // dest
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLDA(fieldDef); // src
|
|
|
|
pslILEmit->EmitLDC(uNativeSize); // size
|
|
|
|
pslILEmit->EmitCPBLK();
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
void ILBlittableLayoutClassMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
|
|
int fieldDef = pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__RAW_DATA__DATA));
|
|
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
|
|
pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1);
|
|
pslILEmit->EmitCALL(METHOD__RUNTIME_HELPERS__GET_UNINITIALIZED_OBJECT, 1, 1);
|
|
EmitStoreManagedValue(pslILEmit);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLDA(fieldDef); // dest
|
|
|
|
EmitLoadNativeHomeAddr(pslILEmit); // src
|
|
|
|
pslILEmit->EmitLDC(uNativeSize); // size
|
|
|
|
pslILEmit->EmitCPBLK();
|
|
}
|
|
|
|
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();
|
|
ILCodeStream* pcsUnmarshal = psl->GetUnmarshalCodeStream();
|
|
|
|
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.
|
|
mdFieldDef handleField = pcsDispatch->GetToken(CoreLibBinder::GetField(FIELD__HANDLE_REF__HANDLE));
|
|
pcsDispatch->EmitLDARG(argidx);
|
|
pcsDispatch->EmitLDFLD(handleField);
|
|
|
|
mdFieldDef wrapperField = pcsUnmarshal->GetToken(CoreLibBinder::GetField(FIELD__HANDLE_REF__WRAPPER));
|
|
pcsUnmarshal->EmitLDARG(argidx);
|
|
pcsUnmarshal->EmitLDFLD(wrapperField);
|
|
pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
|
|
|
|
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;
|
|
}
|
|
|
|
void ILSafeHandleMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
_ASSERTE(IsFieldMarshal(m_dwMarshalFlags));
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadCleanupWorkList(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__HANDLE_MARSHALER__CONVERT_SAFEHANDLE_TO_NATIVE, 2, 1);
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILSafeHandleMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
_ASSERTE(IsFieldMarshal(m_dwMarshalFlags));
|
|
|
|
ILCodeLabel* successLabel = pslILEmit->NewCodeLabel();
|
|
ILCodeLabel* failureLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(failureLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLD(pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE)));
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitBEQ(successLabel);
|
|
pslILEmit->EmitLabel(failureLabel);
|
|
pslILEmit->EmitCALL(METHOD__HANDLE_MARSHALER__THROW_SAFEHANDLE_FIELD_CHANGED, 0, 0);
|
|
pslILEmit->EmitLabel(successLabel);
|
|
}
|
|
|
|
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)
|
|
{
|
|
pslIL->SetStubTargetArgType(ELEMENT_TYPE_I);
|
|
if (byref)
|
|
{
|
|
// 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(CoreLibBinder::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_SAFEHANDLE, 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.
|
|
EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, 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
|
|
{
|
|
// Don't use the CleanupWorkList here.
|
|
// We can't afford allocating for every SafeHandle by-value argument.
|
|
// Instead, duplicate what the CleanupWorkList does as raw IL instructions here.
|
|
psl->SetCleanupNeeded();
|
|
ILCodeStream* pslSetup = psl->GetSetupCodeStream();
|
|
ILCodeStream* pslILCleanup = psl->GetCleanupCodeStream();
|
|
|
|
DWORD dwNativeHandle = pslIL->NewLocal(ELEMENT_TYPE_I);
|
|
DWORD dwAddRefd = pslIL->NewLocal(ELEMENT_TYPE_BOOLEAN);
|
|
|
|
pslSetup->EmitLDC(0);
|
|
pslSetup->EmitSTLOC(dwAddRefd);
|
|
|
|
pslIL->EmitLDARG(argidx);
|
|
pslIL->EmitLDLOCA(dwAddRefd);
|
|
pslIL->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_ADD_REF, 2, 1);
|
|
pslIL->EmitSTLOC(dwNativeHandle);
|
|
|
|
pslILDispatch->EmitLDLOC(dwNativeHandle);
|
|
|
|
pslILCleanup->EmitLDLOC(dwAddRefd);
|
|
ILCodeLabel* pAfterReleaseLabel = pslILCleanup->NewCodeLabel();
|
|
pslILCleanup->EmitBRFALSE(pAfterReleaseLabel);
|
|
pslILCleanup->EmitLDARG(argidx);
|
|
pslILCleanup->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_RELEASE, 1, 0);
|
|
pslILCleanup->EmitLabel(pAfterReleaseLabel);
|
|
}
|
|
|
|
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())
|
|
{
|
|
COMPlusThrowNonLocalized(kMissingMethodException, COR_CTOR_METHOD_NAME_W);
|
|
}
|
|
|
|
// 2) prealloc a safehandle
|
|
MethodDesc* pMDCtor = pMT->GetDefaultConstructor();
|
|
pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
|
|
pslIL->EmitSTLOC(dwReturnHandleLocal);
|
|
|
|
mdToken tkNativeHandleField = pslPostIL->GetToken(CoreLibBinder::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
|
|
EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, 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
|
|
|
|
void ILCriticalHandleMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
_ASSERTE(IsFieldMarshal(m_dwMarshalFlags));
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLD(pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE)));
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILCriticalHandleMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
_ASSERTE(IsFieldMarshal(m_dwMarshalFlags));
|
|
|
|
ILCodeLabel* successLabel = pslILEmit->NewCodeLabel();
|
|
ILCodeLabel* failureLabel = pslILEmit->NewCodeLabel();
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(failureLabel);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDFLD(pslILEmit->GetToken(CoreLibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE)));
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitBEQ(successLabel);
|
|
pslILEmit->EmitLabel(failureLabel);
|
|
pslILEmit->EmitCALL(METHOD__HANDLE_MARSHALER__THROW_CRITICALHANDLE_FIELD_CHANGED, 0, 0);
|
|
pslILEmit->EmitLabel(successLabel);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
//
|
|
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(CoreLibBinder::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.
|
|
EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, 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(CoreLibBinder::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
|
|
EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, 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
|
|
|
|
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)
|
|
{
|
|
// 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)
|
|
{
|
|
// Managed copy constructor has signature of CopyCtor(T* new, T old);
|
|
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)
|
|
{
|
|
// Managed destructor has signature of Destructor(T old);
|
|
pslIL->EmitLDARG(argidx);
|
|
pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pDtor), 1, 0);
|
|
}
|
|
#ifdef TARGET_X86
|
|
pslIL->SetStubTargetArgType(&locDesc); // native type is the value type
|
|
pslILDispatch->EmitLDLOC(dwNewValueTypeLocal); // we load the local directly
|
|
#else
|
|
pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer
|
|
EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNewValueTypeLocal);
|
|
#endif
|
|
|
|
return OVERRIDDEN;
|
|
}
|
|
else
|
|
{
|
|
// nothing to do but pass the value along
|
|
// note that on x86 the argument comes by-value
|
|
// but on other platforms it comes by-reference
|
|
#ifdef TARGET_X86
|
|
LocalDesc locDesc(pargs->mm.m_pMT);
|
|
pslIL->SetStubTargetArgType(&locDesc);
|
|
|
|
DWORD dwNewValueTypeLocal;
|
|
dwNewValueTypeLocal = pslIL->NewLocal(locDesc);
|
|
pslILDispatch->EmitLDARG(argidx);
|
|
pslILDispatch->EmitSTLOC(dwNewValueTypeLocal);
|
|
pslILDispatch->EmitLDLOCA(dwNewValueTypeLocal);
|
|
#else
|
|
LocalDesc locDesc(pargs->mm.m_pMT);
|
|
locDesc.MakePointer();
|
|
|
|
pslIL->SetStubTargetArgType(&locDesc);
|
|
pslILDispatch->EmitLDARG(argidx);
|
|
#endif
|
|
|
|
return OVERRIDDEN;
|
|
}
|
|
}
|
|
|
|
LocalDesc ILArgIteratorMarshaler::GetNativeType()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
|
|
return LocalDesc(ELEMENT_TYPE_I); // va_list
|
|
}
|
|
|
|
LocalDesc ILArgIteratorMarshaler::GetManagedType()
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
return LocalDesc(CoreLibBinder::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::EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
// Allocate enough memory for va_list
|
|
DWORD dwVaListSizeLocal = pslILEmit->NewLocal(LocalDesc(ELEMENT_TYPE_U4));
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__STUBHELPERS__CALC_VA_LIST_SIZE, 1, 1);
|
|
pslILEmit->EmitSTLOC(dwVaListSizeLocal);
|
|
pslILEmit->EmitLDLOC(dwVaListSizeLocal);
|
|
pslILEmit->EmitLOCALLOC();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
// void MarshalToUnmanagedVaListInternal(va_list, uint vaListSize, VARARGS* data)
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitLDLOC(dwVaListSizeLocal);
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__STUBHELPERS__MARSHAL_TO_UNMANAGED_VA_LIST_INTERNAL, 3, 0);
|
|
}
|
|
|
|
void ILArgIteratorMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
EmitLoadNativeValue(pslILEmit);
|
|
EmitLoadManagedHomeAddr(pslILEmit);
|
|
|
|
// void MarshalToManagedVaList(va_list va, VARARGS *dataout)
|
|
pslILEmit->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(CoreLibBinder::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(CoreLibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_ARRAY));
|
|
int tokArrayWithOffset_m_count = pslILEmit->GetToken(CoreLibBinder::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(CoreLibBinder::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->EmitCALL(METHOD__MEMORY_MARSHAL__GET_ARRAY_DATA_REFERENCE_MDARRAY, 1, 1);
|
|
pslILEmit->EmitCONV_I();
|
|
|
|
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(CoreLibBinder::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->EmitCALL(METHOD__MEMORY_MARSHAL__GET_ARRAY_DATA_REFERENCE_MDARRAY, 1, 1);
|
|
pslILEmit->EmitCONV_I();
|
|
|
|
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__MARSHAL__FREE_CO_TASK_MEM, 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::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
THROWS;
|
|
GC_TRIGGERS;
|
|
MODE_ANY;
|
|
CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwMngdMarshalerLocalNum);
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
LocalDesc marshalerType(CoreLibBinder::GetClass(CLASS__ASANY_MARSHALER));
|
|
m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(marshalerType);
|
|
DWORD dwTmpLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
|
|
pslILEmit->EmitLDC(sizeof(MngdNativeArrayMarshaler));
|
|
pslILEmit->EmitLOCALLOC();
|
|
pslILEmit->EmitSTLOC(dwTmpLocalNum);
|
|
|
|
// marshaler = new AsAnyMarshaler(local_buffer)
|
|
pslILEmit->EmitLDLOCA(m_dwMngdMarshalerLocalNum);
|
|
pslILEmit->EmitINITOBJ(pslILEmit->GetToken(marshalerType.InternalToken));
|
|
|
|
pslILEmit->EmitLDLOCA(m_dwMngdMarshalerLocalNum);
|
|
pslILEmit->EmitLDLOC(dwTmpLocalNum);
|
|
pslILEmit->EmitCALL(METHOD__ASANY_MARSHALER__CTOR, 2, 0);
|
|
}
|
|
|
|
void ILAsAnyMarshalerBase::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
|
|
{
|
|
// nativeValue = marshaler.ConvertToNative(managedValue, flags);
|
|
EmitLoadMngdMarshalerAddr(pslILEmit);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitLDC(GetAsAnyFlags());
|
|
pslILEmit->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_NATIVE, 3, 1);
|
|
EmitStoreNativeValue(pslILEmit);
|
|
}
|
|
|
|
void ILAsAnyMarshalerBase::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
|
|
{
|
|
// marshaler.ConvertToManaged(managedValue, nativeValue)
|
|
EmitLoadMngdMarshalerAddr(pslILEmit);
|
|
EmitLoadManagedValue(pslILEmit);
|
|
EmitLoadNativeValue(pslILEmit);
|
|
pslILEmit->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_MANAGED, 3, 0);
|
|
}
|
|
|
|
|
|
bool ILAsAnyMarshalerBase::NeedsClearNative()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return true;
|
|
}
|
|
|
|
void ILAsAnyMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
// marshaler.ClearNative(nativeHome)
|
|
EmitLoadMngdMarshalerAddr(pslILEmit);
|
|
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 inheritance 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);
|
|
}
|
|
}
|
|
|
|
void ILNativeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
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__TO_INTPTR, 1, 1);
|
|
|
|
DWORD dwFlags = mops.elementType;
|
|
dwFlags |= (((DWORD)mops.bestfitmapping) << 16);
|
|
dwFlags |= (((DWORD)mops.throwonunmappablechar) << 24);
|
|
|
|
pslILEmit->EmitLDC(dwFlags);
|
|
|
|
if (!IsCLRToNative(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
|
|
{
|
|
pslILEmit->EmitLDC(1); // true
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLDC(0); // false
|
|
}
|
|
|
|
if (mops.elementType == VT_RECORD && !mops.methodTable->IsBlittable())
|
|
{
|
|
pslILEmit->EmitLDFTN(pslILEmit->GetToken(NDirect::CreateStructMarshalILStub(mops.methodTable)));
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLoadNullPtr();
|
|
}
|
|
|
|
pslILEmit->EmitCALL(METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CREATE_MARSHALER, 5, 0);
|
|
}
|
|
|
|
bool ILNativeArrayMarshaler::CanMarshalViaPinning()
|
|
{
|
|
// We can't pin an array if we have a marshaler for the var type
|
|
// or if we can't get a method-table representing the array (how we determine the offset to pin).
|
|
return IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && (NULL != m_pargs->na.m_pArrayMT) && (NULL == OleVariant::GetMarshalerForVarType(m_pargs->na.m_vt, TRUE));
|
|
}
|
|
|
|
void ILNativeArrayMarshaler::EmitMarshalViaPinning(ILCodeStream* pslILEmit)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
STANDARD_VM_CHECK;
|
|
PRECONDITION(CanMarshalViaPinning());
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
LocalDesc managedType = GetManagedType();
|
|
managedType.MakePinned();
|
|
|
|
DWORD dwPinnedLocal = pslILEmit->NewLocal(managedType);
|
|
ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
|
|
|
|
pslILEmit->EmitLoadNullPtr();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitBRFALSE(pNullRefLabel);
|
|
|
|
// COMPAT: We cannot generate the same code that the C# compiler generates for
|
|
// a fixed() statement on an array since we need to provide a non-null value
|
|
// for a 0-length array. For compat reasons, we need to preserve old behavior.
|
|
// Additionally, we need to ensure that we do not pass non-null for a zero-length
|
|
// array when interacting with GDI/GDI+ since they fail on null arrays but succeed
|
|
// on 0-length arrays.
|
|
EmitLoadManagedValue(pslILEmit);
|
|
pslILEmit->EmitSTLOC(dwPinnedLocal);
|
|
pslILEmit->EmitLDLOC(dwPinnedLocal);
|
|
pslILEmit->EmitCONV_I();
|
|
// Optimize marshalling by emitting the data ptr offset directly into the IL stream
|
|
// instead of doing an FCall to recalulate it each time when possible.
|
|
pslILEmit->EmitLDC(ArrayBase::GetDataPtrOffset(m_pargs->na.m_pArrayMT));
|
|
pslILEmit->EmitADD();
|
|
EmitStoreNativeValue(pslILEmit);
|
|
|
|
EmitLogNativeArgument(pslILEmit, dwPinnedLocal);
|
|
|
|
pslILEmit->EmitLabel(pNullRefLabel);
|
|
}
|
|
|
|
//
|
|
// 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 = GetLCIDParamIndex();
|
|
|
|
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 an 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::EmitSetupArgumentForMarshalling(ILCodeStream* pslILEmit)
|
|
{
|
|
if (IsByref(m_dwMarshalFlags))
|
|
{
|
|
EmitNewSavedSizeArgLocal(pslILEmit);
|
|
}
|
|
}
|
|
|
|
void ILNativeArrayMarshaler::EmitNewSavedSizeArgLocal(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
_ASSERTE(m_dwSavedSizeArg == LOCAL_NUM_UNUSED);
|
|
m_dwSavedSizeArg = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
|
|
pslILEmit->EmitLDC(0);
|
|
pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertSpaceToNative(MngdNativeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
if (pManagedHome.Get() == NULL)
|
|
{
|
|
*pNativeHome = NULL;
|
|
}
|
|
else
|
|
{
|
|
SIZE_T cElements = ((BASEARRAYREF)pManagedHome.Get())->GetNumComponents();
|
|
SIZE_T cbElement = OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT);
|
|
|
|
if (cbElement == 0)
|
|
COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
|
|
|
|
GCX_PREEMP();
|
|
|
|
SIZE_T cbArray;
|
|
if ( (!ClrSafeInt<SIZE_T>::multiply(cElements, cbElement, cbArray)) || cbArray > MAX_SIZE_FOR_INTEROP)
|
|
COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
|
|
|
|
*pNativeHome = CoTaskMemAlloc(cbArray);
|
|
|
|
if (*pNativeHome == NULL)
|
|
ThrowOutOfMemory();
|
|
|
|
// initialize the array
|
|
FillMemory(*pNativeHome, cbArray, 0);
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertContentsToNative(MngdNativeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
BASEARRAYREF arrayRef = NULL;
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if (arrayRef != NULL)
|
|
{
|
|
const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
|
|
SIZE_T cElements = arrayRef->GetNumComponents();
|
|
if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
|
|
{
|
|
if ( (!ClrSafeInt<SIZE_T>::multiply(cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT), cElements)) || cElements > MAX_SIZE_FOR_INTEROP)
|
|
COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
|
|
|
|
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
|
|
memcpyNoGCRefs(*pNativeHome, arrayRef->GetDataPtr(), cElements);
|
|
}
|
|
else
|
|
{
|
|
pMarshaler->ComToOleArray(&arrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap,
|
|
pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid, cElements, pThis->m_pManagedMarshaler);
|
|
}
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertSpaceToManaged(MngdNativeArrayMarshaler* pThis,
|
|
QCall::ObjectHandleOnStack managedHome, void** pNativeHome, INT32 cElements)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
if (*pNativeHome == NULL)
|
|
{
|
|
managedHome.Set(NULL);
|
|
}
|
|
else
|
|
{
|
|
// <TODO>@todo: lookup this class before marshal time</TODO>
|
|
if (pThis->m_Array.IsNull())
|
|
{
|
|
// Get proper array class name & type
|
|
pThis->m_Array = OleVariant::GetArrayForVarType(pThis->m_vt, TypeHandle(pThis->m_pElementMT));
|
|
if (pThis->m_Array.IsNull())
|
|
COMPlusThrow(kTypeLoadException);
|
|
}
|
|
//
|
|
// Allocate array
|
|
//
|
|
managedHome.Set(AllocateSzArray(pThis->m_Array, cElements));
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertContentsToManaged(MngdNativeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
BASEARRAYREF arrayRef = NULL;
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if (*pNativeHome != NULL)
|
|
{
|
|
const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
|
|
|
|
if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
|
|
{
|
|
SIZE_T cElements;
|
|
if ( (!ClrSafeInt<SIZE_T>::multiply(arrayRef->GetNumComponents(), OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT), cElements)) || cElements > MAX_SIZE_FOR_INTEROP)
|
|
COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
|
|
|
|
// If we are copying variants, strings, etc, we need to use write barrier
|
|
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
|
|
memcpyNoGCRefs(arrayRef->GetDataPtr(), *pNativeHome, cElements);
|
|
}
|
|
else
|
|
{
|
|
pMarshaler->OleToComArray(*pNativeHome, &arrayRef, pThis->m_pElementMT, pThis->m_pManagedMarshaler);
|
|
}
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
|
|
{
|
|
QCALL_CONTRACT;
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
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, pThis->m_pManagedMarshaler);
|
|
}
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
void ILFixedArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
|
|
pslILEmit->EmitLDC(sizeof(MngdFixedArrayMarshaler));
|
|
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__TO_INTPTR, 1, 1);
|
|
|
|
DWORD dwFlags = mops.elementType;
|
|
dwFlags |= (((DWORD)mops.bestfitmapping) << 16);
|
|
dwFlags |= (((DWORD)mops.throwonunmappablechar) << 24);
|
|
|
|
pslILEmit->EmitLDC(dwFlags);
|
|
|
|
pslILEmit->EmitLDC(mops.additive);
|
|
|
|
if (mops.elementType == VT_RECORD && !mops.methodTable->IsBlittable())
|
|
{
|
|
pslILEmit->EmitLDFTN(pslILEmit->GetToken(NDirect::CreateStructMarshalILStub(mops.methodTable)));
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLoadNullPtr();
|
|
}
|
|
|
|
pslILEmit->EmitCALL(METHOD__MNGD_FIXED_ARRAY_MARSHALER__CREATE_MARSHALER, 5, 0);
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ConvertContentsToNative(MngdFixedArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void* pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
BASEARRAYREF arrayRef = NULL;
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if (pThis->m_vt == VTHACK_ANSICHAR)
|
|
{
|
|
SIZE_T nativeSize = sizeof(CHAR) * pThis->m_cElements;
|
|
|
|
if (arrayRef == NULL)
|
|
{
|
|
FillMemory(pNativeHome, nativeSize, 0);
|
|
}
|
|
else
|
|
{
|
|
InternalWideToAnsi((const WCHAR*)arrayRef->GetDataPtr(),
|
|
pThis->m_cElements,
|
|
(CHAR*)pNativeHome,
|
|
(int)nativeSize,
|
|
pThis->m_BestFitMap,
|
|
pThis->m_ThrowOnUnmappableChar);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SIZE_T cbElement = OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT);
|
|
SIZE_T nativeSize = cbElement * pThis->m_cElements;
|
|
|
|
if (arrayRef == NULL)
|
|
{
|
|
FillMemory(pNativeHome, nativeSize, 0);
|
|
}
|
|
else
|
|
{
|
|
|
|
const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
|
|
SIZE_T cElements = arrayRef->GetNumComponents();
|
|
if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
|
|
{
|
|
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
|
|
memcpyNoGCRefs(pNativeHome, arrayRef->GetDataPtr(), nativeSize);
|
|
}
|
|
else
|
|
{
|
|
pMarshaler->ComToOleArray(&arrayRef, pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap,
|
|
pThis->m_ThrowOnUnmappableChar, FALSE, pThis->m_cElements, pThis->m_pManagedElementMarshaler);
|
|
}
|
|
}
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ConvertSpaceToManaged(MngdFixedArrayMarshaler* pThis,
|
|
QCall::ObjectHandleOnStack pManagedHome, void* pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
// <TODO>@todo: lookup this class before marshal time</TODO>
|
|
if (pThis->m_Array.IsNull())
|
|
{
|
|
// Get proper array class name & type
|
|
pThis->m_Array = OleVariant::GetArrayForVarType(pThis->m_vt, TypeHandle(pThis->m_pElementMT));
|
|
if (pThis->m_Array.IsNull())
|
|
COMPlusThrow(kTypeLoadException);
|
|
}
|
|
//
|
|
// Allocate array
|
|
//
|
|
|
|
OBJECTREF arrayRef = AllocateSzArray(pThis->m_Array, pThis->m_cElements);
|
|
pManagedHome.Set(arrayRef);
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ConvertContentsToManaged(MngdFixedArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void* pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
BASEARRAYREF arrayRef = NULL;
|
|
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if (pThis->m_vt == VTHACK_ANSICHAR)
|
|
{
|
|
MultiByteToWideChar(CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
(const CHAR*)pNativeHome,
|
|
pThis->m_cElements * sizeof(CHAR), // size, in bytes, of in buffer
|
|
(WCHAR*)(arrayRef->GetDataPtr()),
|
|
pThis->m_cElements); // size, in WCHAR's of outbuffer
|
|
}
|
|
else
|
|
{
|
|
const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
|
|
|
|
SIZE_T cbElement = OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT);
|
|
SIZE_T nativeSize = cbElement * pThis->m_cElements;
|
|
|
|
|
|
if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
|
|
{
|
|
// If we are copying variants, strings, etc, we need to use write barrier
|
|
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
|
|
memcpyNoGCRefs(arrayRef->GetDataPtr(), pNativeHome, nativeSize);
|
|
}
|
|
else
|
|
{
|
|
pMarshaler->OleToComArray(pNativeHome, &arrayRef, pThis->m_pElementMT, pThis->m_pManagedElementMarshaler);
|
|
}
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ClearNativeContents(MngdFixedArrayMarshaler* pThis, void* pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, FALSE);
|
|
|
|
if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
|
|
{
|
|
pMarshaler->ClearOleArray(pNativeHome, pThis->m_cElements, pThis->m_pElementMT, pThis->m_pManagedElementMarshaler);
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
void ILSafeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
|
|
{
|
|
STANDARD_VM_CONTRACT;
|
|
|
|
m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
|
|
|
|
_ASSERTE(sizeof(MngdSafeArrayMarshaler) == sizeof(void*) * 2 + 8);
|
|
pslILEmit->EmitLDC(TARGET_POINTER_SIZE * 2 + 8); // 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__TO_INTPTR, 1, 1);
|
|
pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetArrayRank());
|
|
pslILEmit->EmitLDC(dwFlags);
|
|
|
|
if (mops.elementType == VT_RECORD && !mops.methodTable->IsBlittable())
|
|
{
|
|
pslILEmit->EmitLDFTN(pslILEmit->GetToken(NDirect::CreateStructMarshalILStub(mops.methodTable)));
|
|
}
|
|
else
|
|
{
|
|
pslILEmit->EmitLoadNullPtr();
|
|
}
|
|
|
|
pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CREATE_MARSHALER, 5, 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);
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_CreateMarshaler(MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags, PCODE pManagedMarshaler)
|
|
{
|
|
QCALL_CONTRACT_NO_GC_TRANSITION;
|
|
|
|
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);
|
|
pThis->m_pManagedMarshaler = pManagedMarshaler;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_ConvertSpaceToNative(MngdSafeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
QCALL_CHECK;
|
|
PRECONDITION(pThis->m_vt != VT_EMPTY);
|
|
PRECONDITION(CheckPointer(pThis->m_pElementMT));
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
if (pThis->m_fStatic & MngdSafeArrayMarshaler::SCSF_IsStatic)
|
|
return;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
GCX_COOP();
|
|
|
|
BASEARRAYREF arrayRef = NULL;
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if (arrayRef != NULL)
|
|
{
|
|
*pNativeHome = (void *) OleVariant::CreateSafeArrayForArrayRef(&arrayRef, pThis->m_vt, pThis->m_pElementMT);
|
|
}
|
|
else
|
|
{
|
|
*pNativeHome = NULL;
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_ConvertContentsToNative(MngdSafeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome, QCall::ObjectHandleOnStack pOriginalManaged)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
QCALL_CHECK;
|
|
PRECONDITION(pThis->m_vt != VT_EMPTY);
|
|
PRECONDITION(CheckPointer(pThis->m_pElementMT));
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
struct
|
|
{
|
|
OBJECTREF originalManaged;
|
|
BASEARRAYREF arrayRef;
|
|
} gc = {NULL, NULL};
|
|
|
|
GCPROTECT_BEGIN(gc);
|
|
|
|
gc.originalManaged = pOriginalManaged.Get();
|
|
gc.arrayRef = (BASEARRAYREF)pManagedHome.Get();
|
|
|
|
if ((pThis->m_fStatic & MngdSafeArrayMarshaler::SCSF_IsStatic) &&
|
|
(gc.arrayRef != gc.originalManaged))
|
|
{
|
|
COMPlusThrow(kInvalidOperationException, IDS_INVALID_REDIM);
|
|
}
|
|
|
|
if (gc.arrayRef != NULL)
|
|
{
|
|
OleVariant::MarshalSafeArrayForArrayRef(&gc.arrayRef,
|
|
(SAFEARRAY*)*pNativeHome,
|
|
pThis->m_vt,
|
|
pThis->m_pElementMT,
|
|
pThis->m_pManagedMarshaler,
|
|
(pThis->m_fStatic & MngdSafeArrayMarshaler::SCSF_NativeDataValid));
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_ConvertSpaceToManaged(MngdSafeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
QCALL_CHECK;
|
|
PRECONDITION(pThis->m_vt != VT_EMPTY);
|
|
PRECONDITION(CheckPointer(pThis->m_pElementMT));
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
if (*pNativeHome != NULL)
|
|
{
|
|
SAFEARRAY* nativeSafeArray = (SAFEARRAY*) *pNativeHome;
|
|
|
|
// 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(nativeSafeArray);
|
|
if (pThis->m_iRank != iSafeArrayRank)
|
|
{
|
|
WCHAR strExpectedRank[64];
|
|
WCHAR strActualRank[64];
|
|
_ltow_s(pThis->m_iRank, strExpectedRank, ARRAY_SIZE(strExpectedRank), 10);
|
|
_ltow_s(iSafeArrayRank, strActualRank, ARRAY_SIZE(strActualRank), 10);
|
|
COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYRANKMISMATCH, strActualRank, strExpectedRank);
|
|
}
|
|
}
|
|
|
|
if (pThis->m_nolowerbounds)
|
|
{
|
|
LONG lowerbound;
|
|
if ( (SafeArrayGetDim(nativeSafeArray) != 1) ||
|
|
(FAILED(SafeArrayGetLBound(nativeSafeArray, 1, &lowerbound))) ||
|
|
lowerbound != 0 )
|
|
{
|
|
COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
|
|
}
|
|
}
|
|
|
|
OBJECTREF arrayRef = (OBJECTREF) OleVariant::CreateArrayRefForSafeArray(nativeSafeArray,
|
|
pThis->m_vt,
|
|
pThis->m_pElementMT);
|
|
|
|
pManagedHome.Set(arrayRef);
|
|
}
|
|
else
|
|
{
|
|
pManagedHome.Set(NULL);
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_ConvertContentsToManaged(MngdSafeArrayMarshaler* pThis, QCall::ObjectHandleOnStack pManagedHome, void** pNativeHome)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
QCALL_CHECK;
|
|
PRECONDITION(pThis->m_vt != VT_EMPTY);
|
|
PRECONDITION(CheckPointer(pThis->m_pElementMT));
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
BEGIN_QCALL;
|
|
GCX_COOP();
|
|
|
|
SAFEARRAY* pNative = *(SAFEARRAY**)pNativeHome;
|
|
BASEARRAYREF arrayRef = NULL;
|
|
|
|
GCPROTECT_BEGIN(arrayRef);
|
|
arrayRef = (BASEARRAYREF) pManagedHome.Get();
|
|
|
|
if (pNative && pNative->fFeatures & FADF_STATIC)
|
|
{
|
|
pThis->m_fStatic |= MngdSafeArrayMarshaler::SCSF_IsStatic;
|
|
}
|
|
|
|
if (*pNativeHome != NULL)
|
|
{
|
|
OleVariant::MarshalArrayRefForSafeArray(pNative,
|
|
&arrayRef,
|
|
pThis->m_vt,
|
|
pThis->m_pManagedMarshaler,
|
|
pThis->m_pElementMT);
|
|
}
|
|
|
|
GCPROTECT_END();
|
|
END_QCALL;
|
|
}
|
|
|
|
extern "C" void QCALLTYPE MngdSafeArrayMarshaler_ClearNative(MngdSafeArrayMarshaler* pThis, void** pNativeHome)
|
|
{
|
|
QCALL_CONTRACT;
|
|
|
|
if (pThis->m_fStatic & MngdSafeArrayMarshaler::SCSF_IsStatic)
|
|
return;
|
|
|
|
BEGIN_QCALL;
|
|
|
|
if (*pNativeHome != NULL)
|
|
{
|
|
SafeArrayDestroy((SAFEARRAY*)*pNativeHome);
|
|
}
|
|
|
|
END_QCALL;
|
|
}
|
|
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
void ILReferenceCustomMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
STANDARD_VM_CHECK;
|
|
PRECONDITION(-1 == m_dwMngdMarshalerLocalNum);
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
//
|
|
// allocate space for marshaler state
|
|
//
|
|
|
|
m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__ICUSTOM_MARSHALER)));
|
|
|
|
//
|
|
// call CreateCustomMarshalerHelper
|
|
//
|
|
|
|
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->rcm.m_pMD));
|
|
pslILEmit->EmitCALL(METHOD__METHOD_HANDLE__TO_INTPTR, 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__TO_INTPTR, 1, 1);
|
|
|
|
pslILEmit->EmitCALL(METHOD__STUBHELPERS__CREATE_CUSTOM_MARSHALER_HELPER, 3, 1); // Create the CustomMarshalerHelper
|
|
|
|
// Get the managed ICustomMarshaler object from the helper
|
|
pslILEmit->EmitCALL(METHOD__MNGD_REF_CUSTOM_MARSHALER__GET_MARSHALER, 1, 1);
|
|
|
|
pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum); // Store the ICustomMarshaler as our marshaler state
|
|
}
|