Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
First pass of adding support for copy-constructors when marshalling.
  • Loading branch information
jkoritzinsky committed Feb 22, 2019
commit bd5c462a9fcb20e379446df59d29ed001ed3ebad
1 change: 1 addition & 0 deletions src/dlls/mscorrc/mscorrc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ BEGIN
IDS_EE_BADMARSHAL_ASANYRESTRICTION "AsAny cannot be used on return types, ByRef parameters, ArrayWithOffset, or parameters passed from unmanaged to managed."
IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION "VBByRefStr can only be used in combination with in/out, ByRef managed-to-unmanaged strings."
IDS_EE_BADMARSHAL_AWORESTRICTION "ArrayWithOffsets can only be marshaled as inout, non-ByRef, managed-to-unmanaged parameters."
IDS_EE_BADMARSHAL_COPYCTORRESTRICTION "Classes with copy-ctors can only be marshaled by value."
IDS_EE_BADMARSHAL_ARGITERATORRESTRICTION "ArgIterators cannot be marshaled ByRef."
IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION "HandleRefs cannot be marshaled ByRef or from unmanaged to managed."
IDS_EE_BADMARSHAL_SAFEHANDLENATIVETOCOM "SafeHandles cannot be marshaled from unmanaged to managed."
Expand Down
4 changes: 4 additions & 0 deletions src/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4139,6 +4139,10 @@ static void CreateNDirectStubWorker(StubState* pss,
COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
}

if (info.GetMarshalType() == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR)
{
fHasCopyCtorArgs = true;
}

argidx++;
}
Expand Down
80 changes: 80 additions & 0 deletions src/vm/ilmarshalers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3292,6 +3292,86 @@ ILCriticalHandleMarshaler::ReturnOverride(
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)
{
pslIL->EmitLDLOCA(dwNewValueTypeLocal);
pslIL->EmitLDARG(argidx);
pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pCopyCtor), 2, 0);
}
else
{
pslIL->EmitLDARG(argidx);
pslIL->EmitLDOBJ(pslIL->GetToken(pargs->mm.m_pMT));
pslIL->EmitSTLOC(dwNewValueTypeLocal);
}

// Step 3
if (pargs->mm.m_pDtor)
{
pslIL->EmitLDARG(argidx);
pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pDtor), 1, 0);
}

pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer
pslILDispatch->EmitLDLOCA(dwNewValueTypeLocal);

return OVERRIDDEN;
}
else
{
// nothing to do but pass the value along
// note that on x86 the argument comes by-value but is converted to pointer by the UM thunk
// so that we don't make copies that would not be accounted for by copy ctors
LocalDesc locDesc(pargs->mm.m_pMT);
locDesc.MakeCopyConstructedPointer();

pslIL->SetStubTargetArgType(&locDesc); // native type is a pointer
pslILDispatch->EmitLDARG(argidx);

return OVERRIDDEN;
}
}

LocalDesc ILArgIteratorMarshaler::GetNativeType()
{
Expand Down
32 changes: 32 additions & 0 deletions src/vm/ilmarshalers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2725,8 +2725,40 @@ class ILBlittablePtrMarshaler : public ILLayoutClassPtrMarshalerBase
virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
};

class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler
{
public:
enum
{
c_fInOnly = TRUE,
c_nativeSize = VARIABLESIZE,
c_CLRSize = sizeof(OBJECTREF),
};

LocalDesc GetManagedType()
{
LIMITED_METHOD_CONTRACT;
return LocalDesc();
}

LocalDesc GetNativeType()
{
LIMITED_METHOD_CONTRACT;
return LocalDesc();
}

static MarshalerOverrideStatus ArgumentOverride(NDirectStubLinker* psl,
BOOL byref,
BOOL fin,
BOOL fout,
BOOL fManagedToNative,
OverrideProcArgs* pargs,
UINT* pResID,
UINT argidx,
UINT nativeStackOffset);


};

class ILArgIteratorMarshaler : public ILMarshaler
{
Expand Down
55 changes: 55 additions & 0 deletions src/vm/mlinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,7 @@ MarshalInfo::MarshalInfo(Module* pModule,

CorNativeType nativeType = NATIVE_TYPE_DEFAULT;
Assembly *pAssembly = pModule->GetAssembly();
BOOL fNeedsCopyCtor = FALSE;
m_BestFit = BestFit;
m_ThrowOnUnmappableChar = ThrowOnUnmappableChar;
m_ms = ms;
Expand Down Expand Up @@ -1548,6 +1549,21 @@ MarshalInfo::MarshalInfo(Module* pModule,
IfFailGoto(sig.GetElemType(NULL), lFail);
mtype = sig.PeekElemTypeNormalized(pModule, pTypeContext);

// Check for Copy Constructor Modifier - peek closed elem type here to prevent ELEMENT_TYPE_VALUETYPE
// turning into a primitive.
if (sig.PeekElemTypeClosed(pModule, pTypeContext) == ELEMENT_TYPE_VALUETYPE)
{
// Skip ET_BYREF
IfFailGoto(sigtmp.GetByte(NULL), lFail);

if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) ||
sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) )
{
mtype = ELEMENT_TYPE_VALUETYPE;
fNeedsCopyCtor = TRUE;
m_byref = FALSE;
}
}
}
else
{
Expand Down Expand Up @@ -1590,6 +1606,19 @@ MarshalInfo::MarshalInfo(Module* pModule,
IfFailGoto(E_FAIL, lFail);
}

// Check for Copy Constructor Modifier
if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) ||
sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) )
{
mtype = mtype2;

// Keep the sig pointer in sync with mtype (skip ELEMENT_TYPE_PTR) because for the rest
// of this method we are pretending that the parameter is a value type passed by-value.
IfFailGoto(sig.GetElemType(NULL), lFail);

fNeedsCopyCtor = TRUE;
m_byref = FALSE;
}
}
}
else
Expand Down Expand Up @@ -2684,6 +2713,27 @@ MarshalInfo::MarshalInfo(Module* pModule,
}
else
{
if (fNeedsCopyCtor)
{
if (m_ms == MARSHAL_SCENARIO_WINRT)
{
// our WinRT-optimized GetCOMIPFromRCW helpers don't support copy
// constructor stubs so make sure that this marshaler will not be used
m_resID = IDS_EE_BADMARSHAL_WINRT_COPYCTOR;
IfFailGoto(E_FAIL, lFail);
}

MethodDesc *pCopyCtor;
MethodDesc *pDtor;
FindCopyCtor(pModule, m_pMT, &pCopyCtor);
FindDtor(pModule, m_pMT, &pDtor);

m_args.mm.m_pMT = m_pMT;
m_args.mm.m_pCopyCtor = pCopyCtor;
m_args.mm.m_pDtor = pDtor;
m_type = MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR;
}
else
#ifdef _TARGET_X86_
// JIT64 is not aware of normalized value types and this optimization
// (returning small value types by value in registers) is already done in JIT64.
Expand Down Expand Up @@ -3398,6 +3448,7 @@ UINT16 MarshalInfo::GetNativeSize(MarshalType mtype, MarshalScenario ms)
{
case MARSHAL_TYPE_BLITTABLEVALUECLASS:
case MARSHAL_TYPE_VALUECLASS:
case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
return (UINT16) m_pMT->GetNativeSize();

default:
Expand Down Expand Up @@ -4049,6 +4100,7 @@ DispParamMarshaler *MarshalInfo::GenerateDispParamMarshaler()
case MARSHAL_TYPE_BLITTABLEVALUECLASS:
case MARSHAL_TYPE_BLITTABLEPTR:
case MARSHAL_TYPE_LAYOUTCLASSPTR:
case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
pDispParamMarshaler = new DispParamRecordMarshaler(m_pMT);
break;

Expand Down Expand Up @@ -4350,6 +4402,9 @@ VOID MarshalInfo::MarshalTypeToString(SString& strMarshalType, BOOL fSizeIsSpeci
case MARSHAL_TYPE_ARGITERATOR:
strRetVal = W("ArgIterator");
break;
case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
strRetVal = W("blittable value class with copy constructor");
break;
#ifdef FEATURE_COMINTEROP
case MARSHAL_TYPE_OBJECT:
strRetVal = W("VARIANT");
Expand Down
2 changes: 1 addition & 1 deletion src/vm/mtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_VALUECLASS, ValueClassMa

DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_REFERENCECUSTOMMARSHALER, ReferenceCustomMarshaler, false)
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_ARGITERATOR, ArgIteratorMarshaler, false)

DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR, BlittableValueClassWithCopyCtorMarshaler, false)

#ifdef FEATURE_COMINTEROP
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_OBJECT, ObjectMarshaler, false)
Expand Down