Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix interpreter #97935

Merged
merged 9 commits into from
Feb 8, 2024
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 (
nikolahua marked this conversation as resolved.
Show resolved Hide resolved
(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;
jkotas marked this conversation as resolved.
Show resolved Hide resolved

_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
jkotas marked this conversation as resolved.
Show resolved Hide resolved
{
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
Loading