@@ -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+
22112228bool 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