Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,12 @@ internal static unsafe void CallToString(object* pObj, string* pResult, Exceptio
}
}

// Dummy method providing a MethodDesc with the correct signature (IntPtr -> object)
// for newobj allocator JIT helpers on portable entry point platforms. The interpreter
// uses the MethodDesc to derive the call cookie; the method itself is never executed.
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object NewobjHelperDummy(IntPtr methodTable);

[UnmanagedCallersOnly]
internal static unsafe void CallDefaultConstructor(object* pObj, delegate*<object, void> pCtor, Exception* pException)
{
Expand Down
19 changes: 19 additions & 0 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4796,7 +4796,18 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re

callIFunctionPointerVar = m_pStackPointer[-1].var;
m_pStackPointer--;
#ifdef FEATURE_PORTABLE_ENTRYPOINTS
// Get cookie for unmanaged calli. For managed calli, the cookie will be NULL
// and the interpreter will resolve the call at runtime from the PortableEntryPoint's MethodDesc.
CorInfoCallConv callConv = (CorInfoCallConv)(callInfo.sig.callConv & IMAGE_CEE_CS_CALLCONV_MASK);
bool isUnmanaged = (callConv != CORINFO_CALLCONV_DEFAULT && callConv != CORINFO_CALLCONV_VARARG);
if (isUnmanaged)
{
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
}
#else
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
#endif
m_ip += 5;
}
else
Expand Down Expand Up @@ -5445,7 +5456,11 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
m_pStackPointer--;
int codePointerLookupResult = m_pStackPointer[0].var;

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
calliCookie = NULL;
#else
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
#endif

EmitCalli(tailcall, calliCookie, codePointerLookupResult, &callInfo.sig);

Expand Down Expand Up @@ -5488,7 +5503,11 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
m_pStackPointer--;
int synthesizedLdvirtftnPtrVar = m_pStackPointer[0].var;

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
calliCookie = NULL;
#else
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
#endif

EmitCalli(tailcall, calliCookie, synthesizedLdvirtftnPtrVar, &callInfo.sig);
}
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,9 @@ DEFINE_METHOD(RUNTIME_HELPERS, COPY_CONSTRUCT, CopyConstruct, NoSig
DEFINE_METHOD(RUNTIME_HELPERS, SET_NEXT_CALL_GENERIC_CONTEXT, SetNextCallGenericContext, NoSig)
DEFINE_METHOD(RUNTIME_HELPERS, SET_NEXT_CALL_ASYNC_CONTINUATION, SetNextCallAsyncContinuation, NoSig)
DEFINE_METHOD(RUNTIME_HELPERS, CALL_TO_STRING, CallToString, SM_PtrObj_PtrStr_PtrException_RetVoid)
#ifdef FEATURE_PORTABLE_ENTRYPOINTS
DEFINE_METHOD(RUNTIME_HELPERS, NEWOBJ_HELPER_DUMMY, NewobjHelperDummy, SM_IntPtr_RetObj)
#endif // FEATURE_PORTABLE_ENTRYPOINTS
DEFINE_METHOD(RUNTIME_HELPERS, CALL_DEFAULT_CONSTRUCTOR, CallDefaultConstructor, NoSig)

DEFINE_CLASS(ASYNC_HELPERS, CompilerServices, AsyncHelpers)
Expand Down
18 changes: 11 additions & 7 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet
void InvokeCalliStub(CalliStubParam* pParam);
void InvokeUnmanagedCalli(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet);
void InvokeDelegateInvokeMethod(DelegateInvokeMethodParam* pParam);
void* GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD);
extern "C" PCODE CID_VirtualOpenDelegateDispatch(TransitionBlock * pTransitionBlock);

// Filter to ignore SEH exceptions representing C++ exceptions.
Expand Down Expand Up @@ -3037,15 +3038,18 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
else
{
#ifdef FEATURE_PORTABLE_ENTRYPOINTS
// WASM-TODO: We may end up here with native JIT helper entrypoint without MethodDesc
// that CALL_INTERP_METHOD is not able to handle. This is a potential problem for
// interpreter<->native code stub generator.
// https://github.com/dotnet/runtime/pull/119516#discussion_r2337631271
// On portable entry point platforms, managed calli targets are portable
// entry points and always have a MethodDesc.
targetMethod = PortableEntryPoint::GetMethodDesc(calliFunctionPointer);
// If the method has native code, call it via InvokeCalliStub without going
// through CALL_INTERP_METHOD. It is a small optimization and also necessary
// for correctness for Newobj allocator helpers where the MethodDesc does not
// represent the actual entrypoint.
if (!PortableEntryPoint::HasNativeEntryPoint(calliFunctionPointer))
{
targetMethod = PortableEntryPoint::GetMethodDesc(calliFunctionPointer);
goto CALL_INTERP_METHOD;
}

MetaSig sig(targetMethod);
cookie = GetCookieForCalliSig(sig, NULL);
#endif // FEATURE_PORTABLE_ENTRYPOINTS
CalliStubParam param = { calliFunctionPointer, cookie, callArgsAddress, returnValueAddress, pInterpreterFrame->GetContinuationPtr() };
InvokeCalliStub(&param);
Expand Down
11 changes: 10 additions & 1 deletion src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11094,7 +11094,16 @@ PCODE CEECodeGenInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
{
_ASSERTE(pfnHelper != NULL);
AllocMemHolder<PortableEntryPoint> portableEntryPoint = SystemDomain::GetGlobalLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T{ sizeof(PortableEntryPoint) });
portableEntryPoint->Init((void*)pfnHelper);
if (ftnNum >= CORINFO_HELP_NEWFAST && ftnNum <= CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE)
{
// CoreLib calls newobj helpers via calli. Give these helpers a MethodDesc
// so the interpreter can find the method signature for the call cookie.
portableEntryPoint->Init((void*)pfnHelper, CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__NEWOBJ_HELPER_DUMMY));
}
else
{
portableEntryPoint->Init((void*)pfnHelper);
}
pfnHelper = (PCODE)(PortableEntryPoint*)(portableEntryPoint);

if (InterlockedCompareExchangeT<PCODE>(&hlpFuncEntryPoints[ftnNum], pfnHelper, (PCODE)NULL) == (PCODE)NULL)
Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/vm/precode_portable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ void PortableEntryPoint::Init(void* nativeEntryPoint)
INDEBUG(_canary = CANARY_VALUE);
}

void PortableEntryPoint::Init(void* nativeEntryPoint, MethodDesc* pMD)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(nativeEntryPoint != NULL);
_ASSERTE(pMD != NULL);
_pActualCode = nativeEntryPoint;
_pMD = pMD;
_pInterpreterData = NULL;
_flags = kNone;
INDEBUG(_canary = CANARY_VALUE);
}

namespace
{
bool HasFlags(Volatile<int32_t>& flags, int32_t flagMask)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/precode_portable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class PortableEntryPoint final
public:
void Init(MethodDesc* pMD);
void Init(void* nativeEntryPoint);
void Init(void* nativeEntryPoint, MethodDesc* pMD);

// Check if the entry point represents a method with the UnmanagedCallersOnly attribute.
// If it does, update the entry point to point to the UnmanagedCallersOnly thunk if not
Expand Down
Loading
Loading