Skip to content

Commit 70a2d1a

Browse files
jakobbotschSimaTian
authored andcommitted
JIT: Avoid implicit byref retbufs in async calls (#115888)
The check in the importer did not take into account that a `LCL_ADDR` of an implicit byref local will turn into `LCL_VAR` after morph. The async transformation requires the retbuf to be the address of a local, so enhance the check to take this into account. Also switch the `compIsAsync()` check to `call->IsAsync()`. Inside async functions it is ok for non-async calls to use the normal logic.
1 parent c6ec65c commit 70a2d1a

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4797,6 +4797,7 @@ class Compiler
47974797
Statement** pAfterStmt = nullptr,
47984798
const DebugInfo& di = DebugInfo(),
47994799
BasicBlock* block = nullptr);
4800+
bool impIsLegalRetBuf(GenTree* retBuf, GenTreeCall* call);
48004801
GenTree* impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned curLevel, GenTreeFlags indirFlags = GTF_EMPTY);
48014802

48024803
GenTree* impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags);

src/coreclr/jit/importer.cpp

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -844,10 +844,7 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
844844
GenTreeFlags indirFlags = GTF_EMPTY;
845845
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
846846

847-
// Make sure we don't pass something other than a local address to the return buffer arg.
848-
// It is allowed to pass current's method return buffer as it is a local too.
849-
if ((fgAddrCouldBeHeap(destAddr) && !eeIsByrefLike(srcCall->gtRetClsHnd)) ||
850-
(compIsAsync() && !destAddr->OperIs(GT_LCL_ADDR)))
847+
if (!impIsLegalRetBuf(destAddr, srcCall))
851848
{
852849
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
853850
lvaSetStruct(tmp, srcCall->gtRetClsHnd, false);
@@ -971,10 +968,7 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
971968
GenTreeFlags indirFlags = GTF_EMPTY;
972969
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
973970

974-
// Make sure we don't pass something other than a local address to the return buffer arg.
975-
// It is allowed to pass current's method return buffer as it is a local too.
976-
if ((fgAddrCouldBeHeap(destAddr) && !eeIsByrefLike(call->gtRetClsHnd)) ||
977-
(compIsAsync() && !destAddr->OperIs(GT_LCL_ADDR)))
971+
if (!impIsLegalRetBuf(destAddr, call))
978972
{
979973
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
980974
lvaSetStruct(tmp, call->gtRetClsHnd, false);
@@ -1068,6 +1062,46 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
10681062
return store;
10691063
}
10701064

1065+
//------------------------------------------------------------------------
1066+
// impIsLegalRetbuf:
1067+
// Check if a return buffer is of a legal shape.
1068+
//
1069+
// Arguments:
1070+
// retBuf - The return buffer
1071+
// call - The call that is passed the return buffer
1072+
//
1073+
// Return Value:
1074+
// True if it is legal according to ABI and IR invariants.
1075+
//
1076+
// Notes:
1077+
// ABI requires all return buffers to point to stack. Also, we have an IR
1078+
// invariant for async calls that return buffers must be the address of a
1079+
// local.
1080+
//
1081+
bool Compiler::impIsLegalRetBuf(GenTree* retBuf, GenTreeCall* call)
1082+
{
1083+
if (call->IsAsync())
1084+
{
1085+
// Async calls require LCL_ADDR shape for the retbuf to know where to
1086+
// save the value on resumption.
1087+
if (!retBuf->OperIs(GT_LCL_ADDR))
1088+
{
1089+
return false;
1090+
}
1091+
1092+
// LCL_ADDR on an implicit byref will turn into LCL_VAR in morph.
1093+
if (lvaIsImplicitByRefLocal(retBuf->AsLclVarCommon()->GetLclNum()))
1094+
{
1095+
return false;
1096+
}
1097+
1098+
return true;
1099+
}
1100+
1101+
// The ABI requires the retbuffer to point to stack.
1102+
return !fgAddrCouldBeHeap(retBuf) || eeIsByrefLike(call->gtRetClsHnd);
1103+
}
1104+
10711105
//------------------------------------------------------------------------
10721106
// impStoreStructPtr: Store (copy) the structure from 'src' to 'destAddr'.
10731107
//

0 commit comments

Comments
 (0)