Skip to content

Commit 26a4882

Browse files
committed
Introduce globalVarsStackTop, the high water mark for global vars that might contain refs or interior pointers
Use globalVarsStackTop to reduce how much stack we zero on method entry
1 parent 7e9524f commit 26a4882

File tree

3 files changed

+53
-20
lines changed

3 files changed

+53
-20
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -945,8 +945,9 @@ class InterpGcSlotAllocator
945945
uint32_t startOffset = m_compiler->ConvertOffset(m_compiler->GetLiveStartOffset(varIndex)),
946946
endOffset = m_compiler->ConvertOffset(m_compiler->GetLiveEndOffset(varIndex));
947947
INTERP_DUMP(
948-
"Recording slot %u (var #%d offset %u) live range [IR_%04x - IR_%04x] [%u - %u]\n",
949-
slot, varIndex, pVar->offset,
948+
"Slot %u (%s var #%d offset %u) live [IR_%04x - IR_%04x] [%u - %u]\n",
949+
slot, pVar->global ? "global" : "local",
950+
varIndex, pVar->offset,
950951
m_compiler->GetLiveStartOffset(varIndex), m_compiler->GetLiveEndOffset(varIndex),
951952
startOffset, endOffset
952953
);
@@ -1045,6 +1046,7 @@ int32_t* InterpCompiler::GetCode(int32_t *pCodeSize)
10451046
InterpCompiler::InterpCompiler(COMP_HANDLE compHnd,
10461047
CORINFO_METHOD_INFO* methodInfo)
10471048
: m_pInitLocalsIns(nullptr)
1049+
, m_globalVarsStackTop(0)
10481050
{
10491051
// Fill in the thread-local used for assertions
10501052
t_InterpJitInfoTls = compHnd;
@@ -1111,14 +1113,24 @@ void InterpCompiler::PatchInitLocals(CORINFO_METHOD_INFO* methodInfo)
11111113
// zeroing was enabled for this method. We want to preserve that so we don't unnecessarily
11121114
// zero the IL locals if the method's author didn't want them zeroed
11131115
int32_t startOffset = m_pInitLocalsIns->data[0];
1114-
// FIXME: We need a version of m_totalVarsStackSize that is only global vars, not all vars
1115-
int32_t totalSize = m_totalVarsStackSize - startOffset;
1116-
INTERP_DUMP(
1117-
"Expanding initlocals from [%d-%d] to [%d-%d]\n",
1118-
startOffset, startOffset + m_pInitLocalsIns->data[1],
1119-
startOffset, startOffset + totalSize
1120-
);
1121-
m_pInitLocalsIns->data[1] = totalSize;
1116+
int32_t totalSize = m_globalVarsStackTop - startOffset;
1117+
if (totalSize > m_pInitLocalsIns->data[1])
1118+
{
1119+
INTERP_DUMP(
1120+
"Expanding initlocals from [%d-%d] to [%d-%d]\n",
1121+
startOffset, startOffset + m_pInitLocalsIns->data[1],
1122+
startOffset, startOffset + totalSize
1123+
);
1124+
m_pInitLocalsIns->data[1] = totalSize;
1125+
}
1126+
else
1127+
{
1128+
INTERP_DUMP(
1129+
"Not expanding initlocals from [%d-%d] for global vars stack top of %d\n",
1130+
startOffset, startOffset + m_pInitLocalsIns->data[1],
1131+
m_globalVarsStackTop
1132+
);
1133+
}
11221134
}
11231135

11241136
// Adds a conversion instruction for the value pointed to by sp, also updating the stack information

src/coreclr/interpreter/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ class InterpCompiler
359359

360360
int32_t CreateVarExplicit(InterpType interpType, CORINFO_CLASS_HANDLE clsHnd, int size);
361361

362-
int32_t m_totalVarsStackSize;
362+
int32_t m_totalVarsStackSize, m_globalVarsStackTop;
363363
int32_t m_paramAreaOffset = 0;
364364
int32_t m_ILLocalsOffset, m_ILLocalsSize;
365365
void AllocVarOffsetCB(int *pVar, void *pData);

src/coreclr/interpreter/compileropt.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,19 @@ void InterpCompiler::InitializeGlobalVars()
103103
// the max offset of all call offsets on which the call depends. Stack ensures that all call offsets
104104
// on which the call depends are calculated before the call in question, by deferring calls from the
105105
// last to the first one.
106-
//
106+
//
107107
// This method allocates offsets of resolved calls following a constraint where the base offset
108108
// of a call must be greater than the offset of any argument of other active call args. It first
109109
// removes the call from an array of active calls. If a match is found, the call is removed from
110110
// the array by moving the last entry into its place. Otherwise, it is a call without arguments.
111-
//
111+
//
112112
// If there are active calls, the call in question is pushed onto the stack as a deferred call.
113113
// The call contains a list of other active calls on which it depends. Those calls need to be
114114
// resolved first in order to determine optimal base offset for the call in question. Otherwise,
115115
// if there are no active calls, we resolve the call in question and deferred calls from the stack.
116-
//
116+
//
117117
// For better understanding, consider a simple example:
118-
// a <- _
118+
// a <- _
119119
// b <- _
120120
// call1 c <- b
121121
// d <- _
@@ -145,7 +145,7 @@ void InterpCompiler::EndActiveCall(InterpInst *call)
145145
for (int i = 0; i < m_pActiveCalls->GetSize(); i++)
146146
callDeps = TSList<InterpInst*>::Push(callDeps, m_pActiveCalls->Get(i));
147147
call->info.pCallInfo->callDeps = callDeps;
148-
148+
149149
m_pDeferredCalls = TSList<InterpInst*>::Push(m_pDeferredCalls, call);
150150
}
151151
else
@@ -226,7 +226,8 @@ void InterpCompiler::AllocOffsets()
226226

227227
INTERP_DUMP("\nAllocating var offsets\n");
228228

229-
int finalVarsStackSize = m_totalVarsStackSize;
229+
int finalVarsStackSize = m_totalVarsStackSize,
230+
globalVarsStackTop = m_totalVarsStackSize;
230231

231232
// We now have the top of stack offset. All local regs are allocated after this offset, with each basic block
232233
for (pBB = m_pEntryBB; pBB != NULL; pBB = pBB->pNextBB)
@@ -396,14 +397,34 @@ void InterpCompiler::AllocOffsets()
396397
m_paramAreaOffset = finalVarsStackSize;
397398
for (int32_t i = 0; i < m_varsSize; i++)
398399
{
400+
InterpVar *pVar = &m_pVars[i];
399401
// These are allocated separately at the end of the stack
400-
if (m_pVars[i].callArgs)
402+
if (pVar->callArgs)
401403
{
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;
404406
if (finalVarsStackSize < topOffset)
405407
finalVarsStackSize = topOffset;
406408
}
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+
}
407426
}
427+
428+
m_globalVarsStackTop = globalVarsStackTop;
408429
m_totalVarsStackSize = ALIGN_UP_TO(finalVarsStackSize, INTERP_STACK_ALIGNMENT);
409430
}

0 commit comments

Comments
 (0)