Skip to content

Commit

Permalink
Remove helperframe marshal (#96860)
Browse files Browse the repository at this point in the history
* Remove HelperMethodFrames from Marshal APIs

Convert Marshal.GetHRForException and Marshal.GetExceptionForHRInternal to QCalls.

* Convert OffsetOfHelper to QCall

* Feedback

* Remove GC transition.

* Update src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs

* Update src/coreclr/vm/marshalnative.cpp

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
AaronRobinsonMSFT and jkotas authored Jan 12, 2024
1 parent c2ca6a4 commit 22ba7d6
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ public static IntPtr OffsetOf(Type t, string fieldName)
throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
}

return OffsetOfHelper(rtField);
nint offset = OffsetOf(rtField.GetFieldHandle());
GC.KeepAlive(rtField);
return offset;
}

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MarshalNative_OffsetOf")]
private static partial nint OffsetOf(IntPtr pFD);

[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("ReadByte(Object, Int32) may be unavailable in future releases.")]
Expand Down Expand Up @@ -361,17 +363,26 @@ public static IntPtr GetHINSTANCE(Module m)

#endif // TARGET_WINDOWS

internal static Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo)
{
Exception? exception = null;
GetExceptionForHRInternal(errorCode, errorInfo, ObjectHandleOnStack.Create(ref exception));
return exception!;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MarshalNative_GetExceptionForHR")]
private static partial void GetExceptionForHRInternal(int errorCode, IntPtr errorInfo, ObjectHandleOnStack exception);

#if FEATURE_COMINTEROP
/// <summary>
/// Converts the CLR exception to an HRESULT. This function also sets
/// up an IErrorInfo for the exception.
/// </summary>
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetHRForException(Exception? e);
public static int GetHRForException(Exception? e)
=> GetHRForException(ObjectHandleOnStack.Create(ref e));

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MarshalNative_GetHRForException")]
private static partial int GetHRForException(ObjectHandleOnStack exception);

/// <summary>
/// Given a managed object that wraps an ITypeInfo, return its name.
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,7 @@ FCFuncStart(gInteropMarshalFuncs)
FCFuncElement("GetExceptionCode", ExceptionNative::GetExceptionCode)
FCFuncElement("GetExceptionPointers", ExceptionNative::GetExceptionPointers)

FCFuncElement("OffsetOfHelper", MarshalNative::OffsetOfHelper)
FCFuncElement("GetExceptionForHRInternal", MarshalNative::GetExceptionForHR)

#ifdef FEATURE_COMINTEROP
FCFuncElement("GetHRForException", MarshalNative::GetHRForException)
FCFuncElement("AreComObjectsAvailableForCleanup", MarshalNative::AreComObjectsAvailableForCleanup)
#endif // FEATURE_COMINTEROP
FCFuncEnd()
Expand Down
111 changes: 50 additions & 61 deletions src/coreclr/vm/marshalnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,7 @@ extern "C" BOOL QCALLTYPE MarshalNative_TryGetStructMarshalStub(void* enregister
*/
extern "C" INT32 QCALLTYPE MarshalNative_SizeOfHelper(QCall::TypeHandle t, BOOL throwIfNotMarshalable)
{
CONTRACTL
{
QCALL_CHECK;
}
CONTRACTL_END;
QCALL_CONTRACT;

INT32 rv = 0;

Expand Down Expand Up @@ -176,68 +172,57 @@ extern "C" INT32 QCALLTYPE MarshalNative_SizeOfHelper(QCall::TypeHandle t, BOOL
return rv;
}


/************************************************************************
* PInvoke.OffsetOfHelper(Class, Field)
*/
FCIMPL1(UINT32, MarshalNative::OffsetOfHelper, ReflectFieldObject *pFieldUNSAFE)
extern "C" SIZE_T QCALLTYPE MarshalNative_OffsetOf(FieldDesc* pFD)
{
CONTRACTL
{
FCALL_CHECK;
PRECONDITION(CheckPointer(pFieldUNSAFE));
QCALL_CHECK;
PRECONDITION(pFD != NULL);
}
CONTRACTL_END;

REFLECTFIELDREF refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
SIZE_T offset = 0;

FieldDesc *pField = refField->GetField();
TypeHandle th = TypeHandle(pField->GetApproxEnclosingMethodTable());
BEGIN_QCALL;

TypeHandle th = TypeHandle(pFD->GetApproxEnclosingMethodTable());

if (th.IsBlittable())
{
return pField->GetOffset();
offset = pFD->GetOffset();
}

UINT32 externalOffset = 0;

HELPER_METHOD_FRAME_BEGIN_RET_1(refField);
else
{
GCX_PREEMP();
// Determine if the type is marshalable.
// Verify the type can be marshalled.
if (!IsStructMarshalable(th))
{
// It isn't marshalable so throw an ArgumentException.
StackSString strTypeName;
SString strTypeName;
TypeString::AppendType(strTypeName, th);
COMPlusThrow(kArgumentException, IDS_CANNOT_MARSHAL, strTypeName.GetUnicode(), NULL, NULL);
}
EEClassNativeLayoutInfo const* pNativeLayoutInfo = th.GetMethodTable()->GetNativeLayoutInfo();

NativeFieldDescriptor const*pNFD = pNativeLayoutInfo->GetNativeFieldDescriptors();
UINT numReferenceFields = pNativeLayoutInfo->GetNumFields();
EEClassNativeLayoutInfo const* pNativeLayoutInfo = th.GetMethodTable()->GetNativeLayoutInfo();
NativeFieldDescriptor const* pNFD = pNativeLayoutInfo->GetNativeFieldDescriptors();
UINT numReferenceFields = pNativeLayoutInfo->GetNumFields();

#ifdef _DEBUG
bool foundField = false;
#endif
INDEBUG(bool foundField = false;)
while (numReferenceFields--)
{
if (pNFD->GetFieldDesc() == pField)
if (pNFD->GetFieldDesc() == pFD)
{
externalOffset = pNFD->GetExternalOffset();
offset = pNFD->GetExternalOffset();
INDEBUG(foundField = true);
break;
}
pNFD++;
}

CONSISTENCY_CHECK_MSG(foundField, "We should never hit this point since we already verified that the requested field was present from managed code");
}
HELPER_METHOD_FRAME_END();

return externalOffset;
END_QCALL;

return offset;
}
FCIMPLEND

extern "C" void QCALLTYPE MarshalNative_GetDelegateForFunctionPointerInternal(PVOID FPtr, QCall::TypeHandle t, QCall::ObjectHandleOnStack retDelegate)
{
Expand Down Expand Up @@ -420,22 +405,20 @@ FCIMPLEND
// *** Interop Helpers ***
//====================================================================

FCIMPL2(Object *, MarshalNative::GetExceptionForHR, INT32 errorCode, LPVOID errorInfo)
extern "C" void QCALLTYPE MarshalNative_GetExceptionForHR(INT32 errorCode, LPVOID errorInfo, QCall::ObjectHandleOnStack retVal)
{
CONTRACTL
{
FCALL_CHECK;
QCALL_CHECK;
PRECONDITION(FAILED(errorCode));
PRECONDITION(CheckPointer(errorInfo, NULL_OK));
}
CONTRACTL_END;

OBJECTREF RetExceptionObj = NULL;

HELPER_METHOD_FRAME_BEGIN_RET_1(RetExceptionObj);
BEGIN_QCALL;

// Retrieve the IErrorInfo to use.
IErrorInfo *pErrorInfo = (IErrorInfo*)errorInfo;
IErrorInfo* pErrorInfo = (IErrorInfo*)errorInfo;
#ifdef FEATURE_COMINTEROP
if (pErrorInfo == (IErrorInfo*)(-1))
{
Expand All @@ -446,42 +429,48 @@ FCIMPL2(Object *, MarshalNative::GetExceptionForHR, INT32 errorCode, LPVOID erro
if (SafeGetErrorInfo(&pErrorInfo) != S_OK)
pErrorInfo = NULL;
}

#endif // FEATURE_COMINTEROP
::GetExceptionForHR(errorCode, pErrorInfo, &RetExceptionObj);

HELPER_METHOD_FRAME_END();
GCX_COOP();

OBJECTREF exceptObj = NULL;
GCPROTECT_BEGIN(exceptObj);
::GetExceptionForHR(errorCode, pErrorInfo, &exceptObj);
retVal.Set(exceptObj);
GCPROTECT_END();

return OBJECTREFToObject(RetExceptionObj);
END_QCALL;
}
FCIMPLEND

#ifdef FEATURE_COMINTEROP
FCIMPL1(int, MarshalNative::GetHRForException, Object* eUNSAFE)
extern "C" int32_t QCALLTYPE MarshalNative_GetHRForException(QCall::ObjectHandleOnStack obj)
{
CONTRACTL {
NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM
DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS
MODE_COOPERATIVE;
} CONTRACTL_END;
CONTRACTL
{
QCALL_CHECK;
NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM
}
CONTRACTL_END;

int retVal = 0;
OBJECTREF e = (OBJECTREF) eUNSAFE;
HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1({ retVal = COR_E_STACKOVERFLOW; }, e);
int32_t hr = E_FAIL;

BEGIN_QCALL;

retVal = SetupErrorInfo(e);
GCX_COOP();

HELPER_METHOD_FRAME_END_NOTHROW();
return retVal;
hr = SetupErrorInfo(obj.Get());

END_QCALL;

return hr;
}
FCIMPLEND

//====================================================================
// return the IUnknown* for an Object.
//====================================================================
extern "C" IUnknown* QCALLTYPE MarshalNative_GetIUnknownForObject(QCall::ObjectHandleOnStack o)
{
FCALL_CONTRACT;
QCALL_CONTRACT;

IUnknown* retVal = NULL;

Expand Down
22 changes: 11 additions & 11 deletions src/coreclr/vm/marshalnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@
class MarshalNative
{
public:

//====================================================================
// These methods convert between an HR and and a managed exception.
//====================================================================
static FCDECL2(Object *, GetExceptionForHR, INT32 errorCode, LPVOID errorInfo);
#ifdef FEATURE_COMINTEROP
static FCDECL1(int, GetHRForException, Object* eUNSAFE);
#endif // FEATURE_COMINTEROP

static FCDECL1(UINT32, OffsetOfHelper, ReflectFieldObject* pFieldUNSAFE);
static FCDECL0(int, GetLastPInvokeError);
static FCDECL1(void, SetLastPInvokeError, int error);

Expand All @@ -44,6 +34,8 @@ class MarshalNative
#endif // FEATURE_COMINTEROP
};

extern "C" SIZE_T QCALLTYPE MarshalNative_OffsetOf(FieldDesc* pFD);

extern "C" VOID QCALLTYPE MarshalNative_Prelink(MethodDesc * pMD);
extern "C" BOOL QCALLTYPE MarshalNative_IsBuiltInComSupported();

Expand All @@ -53,6 +45,14 @@ extern "C" INT32 QCALLTYPE MarshalNative_SizeOfHelper(QCall::TypeHandle t, BOOL
extern "C" void QCALLTYPE MarshalNative_GetDelegateForFunctionPointerInternal(PVOID FPtr, QCall::TypeHandle t, QCall::ObjectHandleOnStack retDelegate);
extern "C" PVOID QCALLTYPE MarshalNative_GetFunctionPointerForDelegateInternal(QCall::ObjectHandleOnStack delegate);

//====================================================================
// These methods convert between an HR and and a managed exception.
//====================================================================
extern "C" void QCALLTYPE MarshalNative_GetExceptionForHR(INT32 errorCode, LPVOID errorInfo, QCall::ObjectHandleOnStack obj);
#ifdef FEATURE_COMINTEROP
extern "C" int32_t QCALLTYPE MarshalNative_GetHRForException(QCall::ObjectHandleOnStack obj);
#endif // FEATURE_COMINTEROP

extern "C" OBJECTHANDLE QCALLTYPE GCHandle_InternalAllocWithGCTransition(QCall::ObjectHandleOnStack obj, int type);
extern "C" void QCALLTYPE GCHandle_InternalFreeWithGCTransition(OBJECTHANDLE handle);

Expand Down Expand Up @@ -142,6 +142,6 @@ extern "C" INT32 QCALLTYPE MarshalNative_GetStartComSlot(QCall::TypeHandle t);
extern "C" INT32 QCALLTYPE MarshalNative_GetEndComSlot(QCall::TypeHandle t);

extern "C" VOID QCALLTYPE MarshalNative_ChangeWrapperHandleStrength(QCall::ObjectHandleOnStack otp, BOOL fIsWeak);
#endif
#endif // FEATURE_COMINTEROP

#endif
5 changes: 5 additions & 0 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,17 @@ static const Entry s_QCall[] =
DllImportEntry(GCInterface_GetGenerationBudget)
DllImportEntry(GCHandle_InternalAllocWithGCTransition)
DllImportEntry(GCHandle_InternalFreeWithGCTransition)
DllImportEntry(MarshalNative_OffsetOf)
DllImportEntry(MarshalNative_Prelink)
DllImportEntry(MarshalNative_IsBuiltInComSupported)
DllImportEntry(MarshalNative_TryGetStructMarshalStub)
DllImportEntry(MarshalNative_SizeOfHelper)
DllImportEntry(MarshalNative_GetDelegateForFunctionPointerInternal)
DllImportEntry(MarshalNative_GetFunctionPointerForDelegateInternal)
DllImportEntry(MarshalNative_GetExceptionForHR)
#if defined(FEATURE_COMINTEROP)
DllImportEntry(MarshalNative_GetHRForException)
#endif // FEATURE_COMINTEROP
DllImportEntry(MarshalNative_GetHINSTANCE)
#ifdef _DEBUG
DllImportEntry(MarshalNative_GetIsInCooperativeGCModeFunctionPointer)
Expand Down

0 comments on commit 22ba7d6

Please sign in to comment.