Skip to content

Commit e00043b

Browse files
committed
don't use gc heap for ret buffer
1 parent ad7b829 commit e00043b

File tree

9 files changed

+78
-9
lines changed

9 files changed

+78
-9
lines changed

src/coreclr/inc/corinfo.h

+1
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ enum CorInfoHelpFunc
440440
CORINFO_HELP_ASSIGN_REF, // universal helpers with F_CALL_CONV calling convention
441441
CORINFO_HELP_CHECKED_ASSIGN_REF,
442442
CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, // Do the store, and ensure that the target was not in the heap.
443+
CORINFO_HELP_ENSURE_NONHEAP, // Ensure that the target was not in the heap.
443444

444445
CORINFO_HELP_ASSIGN_BYREF,
445446
CORINFO_HELP_BULK_WRITEBARRIER,

src/coreclr/inc/jiteeversionguid.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* cc0e7adf-e397-40b6-9d14-a7149815c991 */
47-
0xcc0e7adf,
48-
0xe397,
49-
0x40b6,
50-
{0x9d, 0x14, 0xa7, 0x14, 0x98, 0x15, 0xc9, 0x91}
46+
constexpr GUID JITEEVersionIdentifier = { /* bcc768c7-c29d-467d-89f6-f5adca5f2e59 */
47+
0xbcc768c7,
48+
0xc29d,
49+
0x467d,
50+
{0x89, 0xf6, 0xf5, 0xad, 0xca, 0x5f, 0x2e, 0x59}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/inc/jithelpers.h

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
DYNAMICJITHELPER(CORINFO_HELP_ASSIGN_REF, JIT_WriteBarrier, METHOD__NIL)
158158
DYNAMICJITHELPER(CORINFO_HELP_CHECKED_ASSIGN_REF, JIT_CheckedWriteBarrier,METHOD__NIL)
159159
JITHELPER(CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, JIT_WriteBarrierEnsureNonHeapTarget,METHOD__NIL)
160+
JITHELPER(CORINFO_HELP_ENSURE_NONHEAP, JIT_EnsureNonHeapTarget,METHOD__NIL)
160161

161162
DYNAMICJITHELPER(CORINFO_HELP_ASSIGN_BYREF, JIT_ByRefWriteBarrier,METHOD__NIL)
162163
DYNAMICJITHELPER(CORINFO_HELP_BULK_WRITEBARRIER, NULL, METHOD__BUFFER__MEMCOPYGC)

src/coreclr/jit/importer.cpp

+44-2
Original file line numberDiff line numberDiff line change
@@ -1024,8 +1024,20 @@ GenTree* Compiler::impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned
10241024
{
10251025
var_types type = value->TypeGet();
10261026
ClassLayout* layout = (type == TYP_STRUCT) ? value->GetLayout(this) : nullptr;
1027-
GenTree* store = gtNewStoreValueNode(type, layout, destAddr, value);
1028-
store = impStoreStruct(store, curLevel);
1027+
1028+
bool isRetBuffer = false;
1029+
if (!compIsForInlining() && destAddr->OperIs(GT_LCL_VAR))
1030+
{
1031+
isRetBuffer = destAddr->AsLclVar()->GetLclNum() == info.compRetBuffArg;
1032+
}
1033+
1034+
GenTree* store = gtNewStoreValueNode(type, layout, destAddr, value);
1035+
if (isRetBuffer)
1036+
{
1037+
store->gtFlags |= GTF_IND_TGT_NOT_HEAP;
1038+
}
1039+
1040+
store = impStoreStruct(store, curLevel);
10291041

10301042
return store;
10311043
}
@@ -3333,6 +3345,16 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
33333345
StackEntry se = impPopStack();
33343346
GenTree* exprToBox = se.val;
33353347

3348+
if (varTypeIsStruct(exprToBox) && (exprToBox->IsCall() || exprToBox->OperIs(GT_RET_EXPR)))
3349+
{
3350+
unsigned callTmp = lvaGrabTemp(true DEBUGARG("spill struct call to tmp"));
3351+
CORINFO_CLASS_HANDLE cls = exprToBox->IsCall() ? exprToBox->AsCall()->gtRetClsHnd
3352+
: exprToBox->AsRetExpr()->gtInlineCandidate->gtRetClsHnd;
3353+
lvaSetStruct(callTmp, cls, false);
3354+
impStoreToTemp(callTmp, exprToBox, CHECK_SPILL_ALL);
3355+
exprToBox = gtNewLclVarNode(callTmp);
3356+
}
3357+
33363358
// Look at what helper we should use.
33373359
CorInfoHelpFunc boxHelper = info.compCompHnd->getBoxHelper(pResolvedToken->hClass);
33383360

@@ -6429,6 +6451,17 @@ void Compiler::impImportBlockCode(BasicBlock* block)
64296451
JITDUMP("\n [%2u] %3u (0x%03x) ", stackState.esStackDepth, impCurOpcOffs, impCurOpcOffs);
64306452
#endif
64316453

6454+
// CI testing. To be enabled only for jitstress
6455+
if (!opts.IsReadyToRun() && !compIsForInlining() && (info.compRetBuffArg != BAD_VAR_NUM) &&
6456+
(block == fgFirstBB))
6457+
{
6458+
// Write something into the buffer to make sure it's not on the gc heap.
6459+
// We write the value already in the buffer, so that we don't have to worry about
6460+
GenTree* retBuffAddr = gtNewLclvNode(info.compRetBuffArg, TYP_BYREF);
6461+
GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_ENSURE_NONHEAP, TYP_VOID, retBuffAddr);
6462+
impAppendTree(call, CHECK_SPILL_NONE, impCurStmtDI);
6463+
}
6464+
64326465
DECODE_OPCODE:
64336466

64346467
// Return if any previous code has caused inline to fail.
@@ -9416,6 +9449,15 @@ void Compiler::impImportBlockCode(BasicBlock* block)
94169449
// Pull the value from the stack.
94179450
op2 = impPopStack().val;
94189451

9452+
// For STFLD(CALL) we need to spill the call, as the JIT
9453+
if (varTypeIsStruct(op2) && (op2->IsCall() || op2->OperIs(GT_RET_EXPR)))
9454+
{
9455+
unsigned callTmp = lvaGrabTemp(true DEBUGARG("spill struct call to tmp"));
9456+
lvaSetStruct(callTmp, fieldInfo.structType, false);
9457+
impStoreToTemp(callTmp, op2, CHECK_SPILL_ALL);
9458+
op2 = gtNewLclVarNode(callTmp);
9459+
}
9460+
94199461
if (opcode == CEE_STFLD)
94209462
{
94219463
obj = impPopStack().val;

src/coreclr/jit/utils.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,7 @@ void HelperCallProperties::init()
17701770
isNoGC = true;
17711771
FALLTHROUGH;
17721772
case CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP:
1773+
case CORINFO_HELP_ENSURE_NONHEAP:
17731774
case CORINFO_HELP_BULK_WRITEBARRIER:
17741775
mutatesHeap = true;
17751776
break;

src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ which is the right helper to use to allocate an object of a given type. */
131131
CORINFO_HELP_ASSIGN_REF, // universal helpers with F_CALL_CONV calling convention
132132
CORINFO_HELP_CHECKED_ASSIGN_REF,
133133
CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, // Do the store, and ensure that the target was not in the heap.
134+
CORINFO_HELP_ENSURE_NONHEAP, // Ensure that the target was not in the heap.
134135

135136
CORINFO_HELP_ASSIGN_BYREF,
136137
CORINFO_HELP_BULK_WRITEBARRIER,

src/coreclr/vm/gchelpers.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,16 @@ extern "C" HCIMPL2_RAW(VOID, JIT_WriteBarrierEnsureNonHeapTarget, Object **dst,
14661466
}
14671467
HCIMPLEND_RAW
14681468

1469+
extern "C" HCIMPL1_RAW(VOID, JIT_EnsureNonHeapTarget, void *dst)
1470+
{
1471+
STATIC_CONTRACT_MODE_COOPERATIVE;
1472+
STATIC_CONTRACT_THROWS;
1473+
STATIC_CONTRACT_GC_NOTRIGGER;
1474+
1475+
assert(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((void*)dst));
1476+
}
1477+
HCIMPLEND_RAW
1478+
14691479
// This function sets the card table with the granularity of 1 byte, to avoid ghost updates
14701480
// that could occur if multiple threads were trying to set different bits in the same card.
14711481

src/coreclr/vm/jitinterface.h

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ extern "C" FCDECL2(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref);
231231

232232
extern "C" FCDECL2(VOID, JIT_WriteBarrier, Object **dst, Object *ref);
233233
extern "C" FCDECL2(VOID, JIT_WriteBarrierEnsureNonHeapTarget, Object **dst, Object *ref);
234+
extern "C" FCDECL1(VOID, JIT_EnsureNonHeapTarget, void *dst);
234235

235236
// ARM64 JIT_WriteBarrier uses special ABI and thus is not callable directly
236237
// Copied write barriers must be called at a different location

src/coreclr/vm/reflectioninvocation.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
492492
// If an exception occurs a gc may happen but we are going to dump the stack anyway and we do
493493
// not need to protect anything.
494494

495+
// Allocate a local buffer for the return buffer if necessary
496+
DWORD objSize = retTH.GetMethodTable()->GetBaseSize();
497+
PVOID pLocalRetBuf = _alloca(objSize);
498+
495499
{
496500
BEGINFORBIDGC();
497501
#ifdef _DEBUG
@@ -501,8 +505,10 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
501505
// Take care of any return arguments
502506
if (fHasRetBuffArg)
503507
{
504-
PVOID pRetBuff = gc.retVal->GetData();
505-
*((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBuff;
508+
_ASSERT(hasValueTypeReturn);
509+
510+
memset(pLocalRetBuf, 0, objSize);
511+
*((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pLocalRetBuf;
506512
}
507513

508514
// copy args
@@ -572,6 +578,12 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
572578
// Call the method
573579
CallDescrWorkerWithHandler(&callDescrData);
574580

581+
if (fHasRetBuffArg)
582+
{
583+
// Copy the return value from the return buffer to the object
584+
memmoveGCRefs(gc.retVal->GetData(), pLocalRetBuf, objSize);
585+
}
586+
575587
// It is still illegal to do a GC here. The return type might have/contain GC pointers.
576588
if (fConstructor)
577589
{

0 commit comments

Comments
 (0)