@@ -1392,8 +1392,6 @@ int32_t InterpCompiler::GetInterpTypeStackSize(CORINFO_CLASS_HANDLE clsHnd, Inte
1392
1392
size = m_compHnd->getClassSize (clsHnd);
1393
1393
align = m_compHnd->getClassAlignmentRequirement (clsHnd);
1394
1394
1395
- assert (align <= INTERP_STACK_ALIGNMENT);
1396
-
1397
1395
// All vars are stored at 8 byte aligned offsets
1398
1396
if (align < INTERP_STACK_SLOT_SIZE)
1399
1397
align = INTERP_STACK_SLOT_SIZE;
@@ -2208,6 +2206,25 @@ static int32_t GetLdindForType(InterpType interpType)
2208
2206
return -1 ;
2209
2207
}
2210
2208
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
+
2211
2228
bool InterpCompiler::EmitNamedIntrinsicCall (NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig)
2212
2229
{
2213
2230
bool mustExpand = (method == m_methodHnd);
@@ -2308,19 +2325,7 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HAN
2308
2325
2309
2326
if (isValueType)
2310
2327
{
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);
2324
2329
}
2325
2330
2326
2331
int32_t result = (!isValueType || hasGCRefs) ? 1 : 0 ;
@@ -2732,12 +2737,17 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
2732
2737
2733
2738
CORINFO_CALLINFO_FLAGS flags = (CORINFO_CALLINFO_FLAGS)(CORINFO_CALLINFO_ALLOWINSTPARAM | CORINFO_CALLINFO_SECURITYCHECKS | CORINFO_CALLINFO_DISALLOW_STUB);
2734
2739
if (isVirtual)
2735
- flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT);
2740
+ flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT);
2736
2741
2737
2742
m_compHnd->getCallInfo (&resolvedCallToken, pConstrainedToken, m_methodInfo->ftn , flags, &callInfo);
2738
2743
if (callInfo.methodFlags & CORINFO_FLG_INTRINSIC)
2739
2744
{
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)
2741
2751
{
2742
2752
NamedIntrinsic ni = GetNamedIntrinsic (m_compHnd, m_methodHnd, callInfo.hMethod );
2743
2753
if (EmitNamedIntrinsicCall (ni, resolvedCallToken.hClass , callInfo.hMethod , callInfo.sig ))
0 commit comments