Skip to content

Commit 2b01564

Browse files
nikolahuajkotas
andauthored
Fix interpreter (#97935)
* 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>
1 parent 039cd77 commit 2b01564

File tree

3 files changed

+147
-26
lines changed

3 files changed

+147
-26
lines changed

src/coreclr/vm/callhelpers.cpp

+1-7
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,7 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
312312
//
313313
ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
314314

315-
#ifdef FEATURE_INTERPRETER
316-
_ASSERTE(isCallConv(m_methodSig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_DEFAULT)
317-
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_C))
318-
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_VARARG))
319-
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_NATIVEVARARG))
320-
|| isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_STDCALL)));
321-
#else
315+
#ifndef FEATURE_INTERPRETER
322316
_ASSERTE(isCallConv(m_methodSig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_DEFAULT));
323317
_ASSERTE(!(m_methodSig.GetCallingConventionInfo() & CORINFO_CALLCONV_PARAMTYPE));
324318
#endif

src/coreclr/vm/interpreter.cpp

+135-19
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ InterpreterMethodInfo::InterpreterMethodInfo(CEEInfo* comp, CORINFO_METHOD_INFO*
7373
#if defined(_DEBUG)
7474
m_methName = ::eeGetMethodFullName(comp, methInfo->ftn, &clsName);
7575
#else
76-
m_methName = comp->getMethodNameFromMetadata(methInfo->ftn, &clsName, NULL, NULL);
76+
m_methName = getMethodName(comp, methInfo->ftn, &clsName);
7777
#endif
7878
char* myClsName = new char[strlen(clsName) + 1];
7979
strcpy(myClsName, clsName);
@@ -752,7 +752,7 @@ CorJitResult Interpreter::GenerateInterpreterStub(CEEInfo* comp,
752752
if (!jmpCall)
753753
{
754754
const char* clsName;
755-
const char* methName = comp->getMethodNameFromMetadata(info->ftn, &clsName, NULL, NULL);
755+
const char* methName = getMethodName(comp, info->ftn, &clsName);
756756
if ( !s_InterpretMeths.contains(methName, clsName, info->args.pSig)
757757
|| s_InterpretMethsExclude.contains(methName, clsName, info->args.pSig))
758758
{
@@ -9226,26 +9226,27 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
92269226
// Point A in our cycle count.
92279227

92289228

9229-
// TODO: enable when NamedIntrinsic is available to interpreter
9230-
9231-
/*
92329229
// Is the method an intrinsic? If so, and if it's one we've written special-case code for
92339230
// handle intrinsically.
9234-
NamedIntrinsic intrinsicName;
9231+
InterpreterNamedIntrinsics intrinsicId;
92359232
{
92369233
GCX_PREEMP();
9237-
intrinsicName = getIntrinsicName(CORINFO_METHOD_HANDLE(methToCall), nullptr);
9234+
intrinsicId = getNamedIntrinsicID(&m_interpCeeInfo, CORINFO_METHOD_HANDLE(methToCall));
92389235
}
92399236

92409237
#if INTERP_TRACING
9241-
if (intrinsicName == NI_Illegal)
9238+
if (intrinsicId == NI_Illegal)
92429239
InterlockedIncrement(&s_totalInterpCallsToIntrinsics);
92439240
#endif // INTERP_TRACING
92449241
bool didIntrinsic = false;
92459242
if (!m_constrainedFlag)
92469243
{
92479244
switch (intrinsicId)
92489245
{
9246+
case NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference:
9247+
DoGetArrayDataReference();
9248+
didIntrinsic = true;
9249+
break;
92499250
#if INTERP_ILSTUBS
92509251
case NI_System_StubHelpers_GetStubContext:
92519252
OpStackSet<void*>(m_curStackHt, GetStubContext());
@@ -9283,20 +9284,31 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
92839284
// Hardware intrinsics are recognized by name.
92849285
const char* namespaceName = NULL;
92859286
const char* className = NULL;
9286-
const char* methodName = m_interpCeeInfo.getMethodNameFromMetadata((CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
9287+
const char* methodName = getMethodName(&m_interpCeeInfo, (CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
92879288
if (
9289+
(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0 ||
92889290
#if defined(TARGET_X86) || defined(TARGET_AMD64)
9289-
strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0 &&
9291+
strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0
92909292
#elif defined(TARGET_ARM64)
9291-
strcmp(namespaceName, "System.Runtime.Intrinsics.Arm") == 0 &&
9292-
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
9293+
strcmp(namespaceName, "System.Runtime.Intrinsics.Arm") == 0
9294+
#else
9295+
0
9296+
#endif
9297+
) &&
92939298
strcmp(methodName, "get_IsSupported") == 0
92949299
)
92959300
{
92969301
GCX_COOP();
92979302
DoGetIsSupported();
92989303
didIntrinsic = true;
92999304
}
9305+
9306+
if (strcmp(methodName, "get_IsHardwareAccelerated") == 0 && strcmp(namespaceName, "System.Runtime.Intrinsics") == 0)
9307+
{
9308+
GCX_COOP();
9309+
DoGetIsSupported();
9310+
didIntrinsic = true;
9311+
}
93009312
}
93019313

93029314
#if FEATURE_SIMD
@@ -9310,7 +9322,7 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
93109322
// SIMD intrinsics are recognized by name.
93119323
const char* namespaceName = NULL;
93129324
const char* className = NULL;
9313-
const char* methodName = m_interpCeeInfo.getMethodNameFromMetadata((CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
9325+
const char* methodName = getMethodName(&m_interpCeeInfo, (CORINFO_METHOD_HANDLE)methToCall, &className, &namespaceName, NULL);
93149326
if ((strcmp(methodName, "get_IsHardwareAccelerated") == 0) && (strcmp(className, "Vector") == 0) && (strcmp(namespaceName, "System.Numerics") == 0))
93159327
{
93169328
GCX_COOP();
@@ -9339,7 +9351,6 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
93399351
// Now we can return.
93409352
return;
93419353
}
9342-
*/
93439354

93449355
// Handle other simple special cases:
93459356

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

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

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

10876+
void Interpreter::DoGetArrayDataReference()
10877+
{
10878+
CONTRACTL {
10879+
THROWS;
10880+
GC_TRIGGERS;
10881+
MODE_COOPERATIVE;
10882+
} CONTRACTL_END;
10883+
10884+
_ASSERTE(m_curStackHt > 0);
10885+
unsigned ind = m_curStackHt - 1;
10886+
10887+
#ifdef _DEBUG
10888+
_ASSERTE(OpStackTypeGet(ind).ToCorInfoType() == CORINFO_TYPE_CLASS);
10889+
#endif // _DEBUG
10890+
10891+
Object* obj = OpStackGet<Object*>(ind);
10892+
10893+
if (obj == NULL)
10894+
{
10895+
ThrowNullPointerException();
10896+
}
10897+
10898+
#ifdef _DEBUG
10899+
_ASSERTE(obj->GetMethodTable()->IsArray());
10900+
#endif // _DEBUG
10901+
10902+
ArrayBase* a = reinterpret_cast<ArrayBase*>(obj);
10903+
ThrowOnInvalidPointer(a);
10904+
PTR_BYTE dataPtr = a->GetDataPtr();
10905+
OpStackSet<void*>(ind, dataPtr);
10906+
OpStackTypeSet(ind, InterpreterType(CORINFO_TYPE_BYREF));
10907+
}
10908+
1085410909
void Interpreter::RecordConstrainedCall()
1085510910
{
1085610911
CONTRACTL {
@@ -11672,6 +11727,67 @@ static const char* CorInfoTypeNames[] = {
1167211727
"var"
1167311728
};
1167411729

11730+
// Also see Compiler::lookupNamedIntrinsic
11731+
Interpreter::InterpreterNamedIntrinsics Interpreter::getNamedIntrinsicID(CEEInfo* info, CORINFO_METHOD_HANDLE methodHnd)
11732+
{
11733+
InterpreterNamedIntrinsics result = NI_Illegal;
11734+
11735+
const char* namespaceName = NULL;
11736+
const char* className = NULL;
11737+
const char* methodName = getMethodName(info, (CORINFO_METHOD_HANDLE)methodHnd, &className, &namespaceName, NULL);
11738+
11739+
if (strncmp(namespaceName, "System", 6) == 0)
11740+
{
11741+
namespaceName += 6;
11742+
if (namespaceName[0] == '.')
11743+
{
11744+
namespaceName += 1;
11745+
if (strcmp(namespaceName, "StubHelpers") == 0)
11746+
{
11747+
if (strcmp(className, "StubHelpers") == 0)
11748+
{
11749+
if (strcmp(methodName, "GetStubContext") == 0)
11750+
{
11751+
result = NI_System_StubHelpers_GetStubContext;
11752+
}
11753+
}
11754+
}
11755+
else if (strncmp(namespaceName, "Runtime.", 8) == 0)
11756+
{
11757+
namespaceName += 8;
11758+
if (strcmp(namespaceName, "InteropServices") == 0)
11759+
{
11760+
if (strcmp(className, "MemoryMarshal") == 0)
11761+
{
11762+
if (strcmp(methodName, "GetArrayDataReference") == 0)
11763+
{
11764+
result = NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference;
11765+
}
11766+
}
11767+
}
11768+
}
11769+
}
11770+
}
11771+
return result;
11772+
}
11773+
11774+
// Simple version of getMethodName which supports IL Stubs such as IL_STUB_PInvoke additionally.
11775+
// Also see getMethodNameFromMetadata and printMethodName in corinfo.h
11776+
const char* Interpreter::getMethodName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** className, const char** namespaceName, const char **enclosingClassName)
11777+
{
11778+
MethodDesc *pMD = GetMethod(hnd);
11779+
if (pMD->IsILStub())
11780+
{
11781+
if (className != NULL)
11782+
{
11783+
*className = ILStubResolver::GetStubClassName(pMD);
11784+
}
11785+
return pMD->GetName();
11786+
}
11787+
11788+
return info->getMethodNameFromMetadata(hnd, className, namespaceName, enclosingClassName);
11789+
}
11790+
1167511791
const char* eeGetMethodFullName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** clsName)
1167611792
{
1167711793
CONTRACTL {
@@ -11685,7 +11801,7 @@ const char* eeGetMethodFullName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const
1168511801
const char* returnType = NULL;
1168611802

1168711803
const char* className;
11688-
const char* methodName = info->getMethodNameFromMetadata(hnd, &className, NULL, NULL);
11804+
const char* methodName = Interpreter::getMethodName(info, hnd, &className);
1168911805
if (clsName != NULL)
1169011806
{
1169111807
*clsName = className;

src/coreclr/vm/interpreter.h

+11
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,16 @@ class Interpreter
914914

915915
void* GetParamTypeArg() { return m_genericsCtxtArg; }
916916

917+
// Also see namedintrinsiclist.h
918+
enum InterpreterNamedIntrinsics : unsigned short
919+
{
920+
NI_Illegal = 0,
921+
NI_System_StubHelpers_GetStubContext,
922+
NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference,
923+
};
924+
static InterpreterNamedIntrinsics getNamedIntrinsicID(CEEInfo* info, CORINFO_METHOD_HANDLE methodHnd);
925+
static const char* getMethodName(CEEInfo* info, CORINFO_METHOD_HANDLE hnd, const char** className, const char** namespaceName = NULL, const char **enclosingClassName = NULL);
926+
917927
private:
918928
// Architecture-dependent helpers.
919929
inline static unsigned short NumberOfIntegerRegArgs();
@@ -1779,6 +1789,7 @@ class Interpreter
17791789
void DoGetTypeFromHandle();
17801790
void DoSIMDHwAccelerated();
17811791
void DoGetIsSupported();
1792+
void DoGetArrayDataReference();
17821793

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

0 commit comments

Comments
 (0)