Skip to content

Commit

Permalink
Fix interpreter (#97935)
Browse files Browse the repository at this point in the history
* Implement getMethodName for CoreCLR interpreter to support IL Stub.

* Support intrinsic method GetStubContext for CoreCLR interpreter.

* Remove callconv check in CallTargetWorker for CoreCLR interpreter.

* Skip hardware accelerate in CoreCLR interpreter.

* Update constraind check in CoreCLR interpreter.

* Support intrinsic method GetArrayDataReference for CoreCLR interpreter.

* Mark methods which have not been supported by CoreCLR interpreter.

* Move `getNamedIntrinsicID()` and `getMethodName()` into Interpreter Type.

* Update src/coreclr/vm/interpreter.cpp

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
nikolahua and jkotas authored Feb 8, 2024
1 parent 039cd77 commit 2b01564
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 26 deletions.
8 changes: 1 addition & 7 deletions src/coreclr/vm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,7 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
//
ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();

#ifdef FEATURE_INTERPRETER
_ASSERTE(isCallConv(m_methodSig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_DEFAULT)
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_C))
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_VARARG))
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_NATIVEVARARG))
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_STDCALL)));
#else
#ifndef FEATURE_INTERPRETER
_ASSERTE(isCallConv(m_methodSig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_DEFAULT));
_ASSERTE(!(m_methodSig.GetCallingConventionInfo() & CORINFO_CALLCONV_PARAMTYPE));
#endif
Expand Down
154 changes: 135 additions & 19 deletions src/coreclr/vm/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ InterpreterMethodInfo::InterpreterMethodInfo(CEEInfo* comp, CORINFO_METHOD_INFO*
#if defined(_DEBUG)
m_methName = ::eeGetMethodFullName(comp, methInfo->ftn, &clsName);
#else
m_methName = comp->getMethodNameFromMetadata(methInfo->ftn, &clsName, NULL, NULL);
m_methName = getMethodName(comp, methInfo->ftn, &clsName);
#endif
char* myClsName = new char[strlen(clsName) + 1];
strcpy(myClsName, clsName);
Expand Down Expand Up @@ -752,7 +752,7 @@ CorJitResult Interpreter::GenerateInterpreterStub(CEEInfo* comp,
if (!jmpCall)
{
const char* clsName;
const char* methName = comp->getMethodNameFromMetadata(info->ftn, &clsName, NULL, NULL);
const char* methName = getMethodName(comp, info->ftn, &clsName);
if ( !s_InterpretMeths.contains(methName, clsName, info->args.pSig)
|| s_InterpretMethsExclude.contains(methName, clsName, info->args.pSig))
{
Expand Down Expand Up @@ -9226,26 +9226,27 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
// Point A in our cycle count.


// TODO: enable when NamedIntrinsic is available to interpreter

/*
// Is the method an intrinsic? If so, and if it's one we've written special-case code for
// handle intrinsically.
NamedIntrinsic intrinsicName;
InterpreterNamedIntrinsics intrinsicId;
{
GCX_PREEMP();
intrinsicName = getIntrinsicName(CORINFO_METHOD_HANDLE(methToCall), nullptr);
intrinsicId = getNamedIntrinsicID(&m_interpCeeInfo, CORINFO_METHOD_HANDLE(methToCall));
}

#if INTERP_TRACING
if (intrinsicName == NI_Illegal)
if (intrinsicId == NI_Illegal)
InterlockedIncrement(&s_totalInterpCallsToIntrinsics);
#endif // INTERP_TRACING
bool didIntrinsic = false;
if (!m_constrainedFlag)
{
switch (intrinsicId)
{
case NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference:
DoGetArrayDataReference();
didIntrinsic = true;
break;
#if INTERP_ILSTUBS
case NI_System_StubHelpers_GetStubContext:
OpStackSet<void*>(m_curStackHt, GetStubContext());
Expand Down Expand Up @@ -9283,20 +9284,31 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
// Hardware intrinsics are recognized by name.
const char* namespaceName = NULL;
const char* className = NULL;
const char* methodName = m_interpCeeInfo.getMethodNameFromMetadata((CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
const char* methodName = getMethodName(&m_interpCeeInfo, (CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
if (
(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0 ||
#if defined(TARGET_X86) || defined(TARGET_AMD64)
strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0 &&
strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0
#elif defined(TARGET_ARM64)
strcmp(namespaceName, "System.Runtime.Intrinsics.Arm") == 0 &&
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
strcmp(namespaceName, "System.Runtime.Intrinsics.Arm") == 0
#else
0
#endif
) &&
strcmp(methodName, "get_IsSupported") == 0
)
{
GCX_COOP();
DoGetIsSupported();
didIntrinsic = true;
}

if (strcmp(methodName, "get_IsHardwareAccelerated") == 0 && strcmp(namespaceName, "System.Runtime.Intrinsics") == 0)
{
GCX_COOP();
DoGetIsSupported();
didIntrinsic = true;
}
}

#if FEATURE_SIMD
Expand All @@ -9310,7 +9322,7 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
// SIMD intrinsics are recognized by name.
const char* namespaceName = NULL;
const char* className = NULL;
const char* methodName = m_interpCeeInfo.getMethodNameFromMetadata((CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
const char* methodName = getMethodName(&m_interpCeeInfo, (CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
if ((strcmp(methodName, "get_IsHardwareAccelerated") == 0) && (strcmp(className, "Vector") == 0) && (strcmp(namespaceName, "System.Numerics") == 0))
{
GCX_COOP();
Expand Down Expand Up @@ -9339,7 +9351,6 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
// Now we can return.
return;
}
*/

// Handle other simple special cases:

Expand Down Expand Up @@ -9571,9 +9582,20 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
{
_ASSERTE(m_callThisArg == NULL); // "m_callThisArg" non-null only for .ctor, which are not callvirts.

CorInfoType argCIT = OpStackTypeGet(argsBase + arg).ToCorInfoType();
if (argCIT != CORINFO_TYPE_BYREF)
VerificationError("This arg of constrained call must be managed pointer.");
// The constrained. prefix will be immediately followed by a ldftn, call or callvirt instruction.
// See Ecma-335-Augments.md#iii21-constrained---prefix-invoke-a-member-on-a-value-of-a-variable-type-page-316 for more detail
if (sigInfo.hasThis())
{
// For the callvirt instruction, the ptr argument will be a managed pointer (&) to thisType.
CorInfoType argCIT = OpStackTypeGet(argsBase + arg).ToCorInfoType();
if (argCIT != CORINFO_TYPE_BYREF)
VerificationError("This arg of constrained call must be managed pointer.");
}
else
{
// If the constrained. prefix is applied to a call or ldftn instruction, method must be a virtual static method.
// TODO: Assert it is a virtual static method.
}

// We only cache for the CORINFO_NO_THIS_TRANSFORM case, so we may assume that if we have a cached call site,
// there's no thisTransform to perform.
Expand Down Expand Up @@ -9658,7 +9680,7 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
const char* methToCallName = NULL;
{
GCX_PREEMP();
methToCallName = m_interpCeeInfo.getMethodNameFromMetadata(CORINFO_METHOD_HANDLE(methToCall), &clsOfMethToCallName, NULL, NULL);
methToCallName = getMethodName(&m_interpCeeInfo, CORINFO_METHOD_HANDLE(methToCall), &clsOfMethToCallName);
}
#if INTERP_TRACING
if (strncmp(methToCallName, "get_", 4) == 0)
Expand Down Expand Up @@ -10851,6 +10873,39 @@ void Interpreter::DoGetIsSupported()
m_curStackHt++;
}

void Interpreter::DoGetArrayDataReference()
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
} CONTRACTL_END;

_ASSERTE(m_curStackHt > 0);
unsigned ind = m_curStackHt - 1;

#ifdef _DEBUG
_ASSERTE(OpStackTypeGet(ind).ToCorInfoType() == CORINFO_TYPE_CLASS);
#endif // _DEBUG

Object* obj = OpStackGet<Object*>(ind);

if (obj == NULL)
{
ThrowNullPointerException();
}

#ifdef _DEBUG
_ASSERTE(obj->GetMethodTable()->IsArray());
#endif // _DEBUG

ArrayBase* a = reinterpret_cast<ArrayBase*>(obj);
ThrowOnInvalidPointer(a);
PTR_BYTE dataPtr = a->GetDataPtr();
OpStackSet<void*>(ind, dataPtr);
OpStackTypeSet(ind, InterpreterType(CORINFO_TYPE_BYREF));
}

void Interpreter::RecordConstrainedCall()
{
CONTRACTL {
Expand Down Expand Up @@ -11672,6 +11727,67 @@ static const char* CorInfoTypeNames[] = {
"var"
};

// Also see Compiler::lookupNamedIntrinsic
Interpreter::InterpreterNamedIntrinsics Interpreter::getNamedIntrinsicID(CEEInfo* info, CORINFO_METHOD_HANDLE methodHnd)
{
InterpreterNamedIntrinsics result = NI_Illegal;

const char* namespaceName = NULL;
const char* className = NULL;
const char* methodName = getMethodName(info, (CORINFO_METHOD_HANDLE)methodHnd, &className, &namespaceName, NULL);

if (strncmp(namespaceName, "System", 6) == 0)
{
namespaceName += 6;
if (namespaceName[0] == '.')
{
namespaceName += 1;
if (strcmp(namespaceName, "StubHelpers") == 0)
{
if (strcmp(className, "StubHelpers") == 0)
{
if (strcmp(methodName, "GetStubContext") == 0)
{
result = NI_System_StubHelpers_GetStubContext;
}
}
}
else if (strncmp(namespaceName, "Runtime.", 8) == 0)
{
namespaceName += 8;
if (strcmp(namespaceName, "InteropServices") == 0)
{
if (strcmp(className, "MemoryMarshal") == 0)
{
if (strcmp(methodName, "GetArrayDataReference") == 0)
{
result = NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference;
}
}
}
}
}
}
return result;
}

// Simple version of getMethodName which supports IL Stubs such as IL_STUB_PInvoke additionally.
// Also see getMethodNameFromMetadata and printMethodName in corinfo.h
const char* Interpreter::getMethodName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** className, const char** namespaceName, const char **enclosingClassName)
{
MethodDesc *pMD = GetMethod(hnd);
if (pMD->IsILStub())
{
if (className != NULL)
{
*className = ILStubResolver::GetStubClassName(pMD);
}
return pMD->GetName();
}

return info->getMethodNameFromMetadata(hnd, className, namespaceName, enclosingClassName);
}

const char* eeGetMethodFullName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** clsName)
{
CONTRACTL {
Expand All @@ -11685,7 +11801,7 @@ const char* eeGetMethodFullName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const
const char* returnType = NULL;

const char* className;
const char* methodName = info->getMethodNameFromMetadata(hnd, &className, NULL, NULL);
const char* methodName = Interpreter::getMethodName(info, hnd, &className);
if (clsName != NULL)
{
*clsName = className;
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/vm/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,16 @@ class Interpreter

void* GetParamTypeArg() { return m_genericsCtxtArg; }

// Also see namedintrinsiclist.h
enum InterpreterNamedIntrinsics : unsigned short
{
NI_Illegal = 0,
NI_System_StubHelpers_GetStubContext,
NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference,
};
static InterpreterNamedIntrinsics getNamedIntrinsicID(CEEInfo* info, CORINFO_METHOD_HANDLE methodHnd);
static const char* getMethodName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** className, const char** namespaceName = NULL, const char **enclosingClassName = NULL);

private:
// Architecture-dependent helpers.
inline static unsigned short NumberOfIntegerRegArgs();
Expand Down Expand Up @@ -1779,6 +1789,7 @@ class Interpreter
void DoGetTypeFromHandle();
void DoSIMDHwAccelerated();
void DoGetIsSupported();
void DoGetArrayDataReference();

// Returns the proper generics context for use in resolving tokens ("precise" in the sense of including generic instantiation
// information).
Expand Down

0 comments on commit 2b01564

Please sign in to comment.