Skip to content

Commit b6e34b8

Browse files
authored
[interp] Forcibly enable intrinsics when we encounter a must-expand call (#117727)
* When encountering a must expand intrinsic self-call in an interpreted method, always expand it even if intrinsics are turned off. * Clean up a minor edge case in the 'is reference or contains references' intrinsic * Remove an alignment assert that is causing failures in the startup path
1 parent 97d9422 commit b6e34b8

File tree

1 file changed

+27
-17
lines changed

1 file changed

+27
-17
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,8 +1392,6 @@ int32_t InterpCompiler::GetInterpTypeStackSize(CORINFO_CLASS_HANDLE clsHnd, Inte
13921392
size = m_compHnd->getClassSize(clsHnd);
13931393
align = m_compHnd->getClassAlignmentRequirement(clsHnd);
13941394

1395-
assert(align <= INTERP_STACK_ALIGNMENT);
1396-
13971395
// All vars are stored at 8 byte aligned offsets
13981396
if (align < INTERP_STACK_SLOT_SIZE)
13991397
align = INTERP_STACK_SLOT_SIZE;
@@ -2208,6 +2206,25 @@ static int32_t GetLdindForType(InterpType interpType)
22082206
return -1;
22092207
}
22102208

2209+
static bool DoesValueTypeContainGCRefs(COMP_HANDLE compHnd, CORINFO_CLASS_HANDLE clsHnd)
2210+
{
2211+
unsigned size = compHnd->getClassSize(clsHnd);
2212+
// getClassGClayout assumes it's given a buffer of exactly this size
2213+
unsigned maxGcPtrs = (size + sizeof(void *) - 1) / sizeof(void *);
2214+
BYTE *gcLayout = (BYTE *)alloca(maxGcPtrs + 1);
2215+
uint32_t numSlots = compHnd->getClassGClayout(clsHnd, gcLayout);
2216+
2217+
for (uint32_t i = 0; i < numSlots; ++i)
2218+
{
2219+
if (gcLayout[i] != TYPE_GC_NONE)
2220+
{
2221+
return true;
2222+
}
2223+
}
2224+
2225+
return false;
2226+
}
2227+
22112228
bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig)
22122229
{
22132230
bool mustExpand = (method == m_methodHnd);
@@ -2308,19 +2325,7 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HAN
23082325

23092326
if (isValueType)
23102327
{
2311-
// Walk the layout to see if any field is a GC pointer
2312-
const uint32_t maxSlots = 256;
2313-
BYTE gcLayout[maxSlots];
2314-
uint32_t numSlots = m_compHnd->getClassGClayout(clsHnd, gcLayout);
2315-
2316-
for (uint32_t i = 0; i < numSlots; ++i)
2317-
{
2318-
if (gcLayout[i] != TYPE_GC_NONE)
2319-
{
2320-
hasGCRefs = true;
2321-
break;
2322-
}
2323-
}
2328+
hasGCRefs = DoesValueTypeContainGCRefs(m_compHnd, clsHnd);
23242329
}
23252330

23262331
int32_t result = (!isValueType || hasGCRefs) ? 1 : 0;
@@ -2732,12 +2737,17 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
27322737

27332738
CORINFO_CALLINFO_FLAGS flags = (CORINFO_CALLINFO_FLAGS)(CORINFO_CALLINFO_ALLOWINSTPARAM | CORINFO_CALLINFO_SECURITYCHECKS | CORINFO_CALLINFO_DISALLOW_STUB);
27342739
if (isVirtual)
2735-
flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT);
2740+
flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT);
27362741

27372742
m_compHnd->getCallInfo(&resolvedCallToken, pConstrainedToken, m_methodInfo->ftn, flags, &callInfo);
27382743
if (callInfo.methodFlags & CORINFO_FLG_INTRINSIC)
27392744
{
2740-
if (InterpConfig.InterpMode() >= 3)
2745+
// If we are being asked explicitly to compile an intrinsic for interpreting, we need to forcibly enable
2746+
// intrinsics for the recursive call. Otherwise we will just recurse infinitely and overflow stack.
2747+
// This expansion can produce value that is inconsistent with the value seen by JIT/R2R code that can
2748+
// cause user code to misbehave. This is by design. One-off method Interpretation is for internal use only.
2749+
bool isMustExpand = (callInfo.hMethod == m_methodHnd);
2750+
if ((InterpConfig.InterpMode() == 3) || isMustExpand)
27412751
{
27422752
NamedIntrinsic ni = GetNamedIntrinsic(m_compHnd, m_methodHnd, callInfo.hMethod);
27432753
if (EmitNamedIntrinsicCall(ni, resolvedCallToken.hClass, callInfo.hMethod, callInfo.sig))

0 commit comments

Comments
 (0)