@@ -103,19 +103,19 @@ void InterpCompiler::InitializeGlobalVars()
103
103
// the max offset of all call offsets on which the call depends. Stack ensures that all call offsets
104
104
// on which the call depends are calculated before the call in question, by deferring calls from the
105
105
// last to the first one.
106
- //
106
+ //
107
107
// This method allocates offsets of resolved calls following a constraint where the base offset
108
108
// of a call must be greater than the offset of any argument of other active call args. It first
109
109
// removes the call from an array of active calls. If a match is found, the call is removed from
110
110
// the array by moving the last entry into its place. Otherwise, it is a call without arguments.
111
- //
111
+ //
112
112
// If there are active calls, the call in question is pushed onto the stack as a deferred call.
113
113
// The call contains a list of other active calls on which it depends. Those calls need to be
114
114
// resolved first in order to determine optimal base offset for the call in question. Otherwise,
115
115
// if there are no active calls, we resolve the call in question and deferred calls from the stack.
116
- //
116
+ //
117
117
// For better understanding, consider a simple example:
118
- // a <- _
118
+ // a <- _
119
119
// b <- _
120
120
// call1 c <- b
121
121
// d <- _
@@ -145,7 +145,7 @@ void InterpCompiler::EndActiveCall(InterpInst *call)
145
145
for (int i = 0 ; i < m_pActiveCalls->GetSize (); i++)
146
146
callDeps = TSList<InterpInst*>::Push (callDeps, m_pActiveCalls->Get (i));
147
147
call->info .pCallInfo ->callDeps = callDeps;
148
-
148
+
149
149
m_pDeferredCalls = TSList<InterpInst*>::Push (m_pDeferredCalls, call);
150
150
}
151
151
else
@@ -226,7 +226,8 @@ void InterpCompiler::AllocOffsets()
226
226
227
227
INTERP_DUMP (" \n Allocating var offsets\n " );
228
228
229
- int finalVarsStackSize = m_totalVarsStackSize;
229
+ int finalVarsStackSize = m_totalVarsStackSize,
230
+ globalVarsStackTop = m_totalVarsStackSize;
230
231
231
232
// We now have the top of stack offset. All local regs are allocated after this offset, with each basic block
232
233
for (pBB = m_pEntryBB; pBB != NULL ; pBB = pBB->pNextBB )
@@ -396,14 +397,34 @@ void InterpCompiler::AllocOffsets()
396
397
m_paramAreaOffset = finalVarsStackSize;
397
398
for (int32_t i = 0 ; i < m_varsSize; i++)
398
399
{
400
+ InterpVar *pVar = &m_pVars[i];
399
401
// These are allocated separately at the end of the stack
400
- if (m_pVars[i]. callArgs )
402
+ if (pVar-> callArgs )
401
403
{
402
- m_pVars[i]. offset += m_paramAreaOffset;
403
- int32_t topOffset = m_pVars[i]. offset + m_pVars[i]. size ;
404
+ pVar-> offset += m_paramAreaOffset;
405
+ int32_t topOffset = pVar-> offset + pVar-> size ;
404
406
if (finalVarsStackSize < topOffset)
405
407
finalVarsStackSize = topOffset;
406
408
}
409
+
410
+ // For any global vars that might contain managed pointers we need to maintain a 'global stack top'
411
+ // which specifies what stack region we need to zero at method entry in order to avoid reporting
412
+ // garbage pointers to the GC when it does a stackwalk
413
+ // Non-global vars have accurate liveness ranges we report to the GC, so we don't care about them
414
+ if (
415
+ pVar->global && (
416
+ (pVar->interpType == InterpTypeO) ||
417
+ (pVar->interpType == InterpTypeByRef) ||
418
+ (pVar->interpType == InterpTypeVT)
419
+ )
420
+ )
421
+ {
422
+ int32_t endOfVar = pVar->offset + pVar->size ;
423
+ if (endOfVar > globalVarsStackTop)
424
+ globalVarsStackTop = endOfVar;
425
+ }
407
426
}
427
+
428
+ m_globalVarsStackTop = globalVarsStackTop;
408
429
m_totalVarsStackSize = ALIGN_UP_TO (finalVarsStackSize, INTERP_STACK_ALIGNMENT);
409
430
}
0 commit comments