Skip to content

Commit 2fa82a2

Browse files
VSadovjakobbotsch
andauthored
[RuntimeAsync] Follow up for unboxing and instantiating stubs. (#118301)
* Support continuation arg in the portable arg shuffler * Unboxing stubs in IL * Instantiating stubs in IL * fix for x86 * keep the modreq * TOKEN_ILSTUB_TARGET_SIG_ASYNC * Insert null continuation arg on VM side * undo unnecessary test changes * typo fix lost in rebase --------- Co-authored-by: Jakob Botsch Nielsen <[email protected]>
1 parent cc1bffe commit 2fa82a2

File tree

11 files changed

+240
-32
lines changed

11 files changed

+240
-32
lines changed

src/coreclr/inc/corhdr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,8 @@ typedef enum CorCallingConvention
975975
IMAGE_CEE_CS_CALLCONV_UNMANAGED = 0x9, // Unmanaged calling convention encoded as modopts
976976
IMAGE_CEE_CS_CALLCONV_GENERICINST = 0xa, // generic method instantiation
977977
IMAGE_CEE_CS_CALLCONV_NATIVEVARARG = 0xb, // used ONLY for 64bit vararg PInvoke calls
978-
IMAGE_CEE_CS_CALLCONV_MAX = 0xc, // first invalid calling convention
978+
IMAGE_CEE_CS_CALLCONV_ASYNC = 0xc, // used for calli in IL stubs
979+
IMAGE_CEE_CS_CALLCONV_MAX = 0xd, // first invalid calling convention
979980

980981

981982
// The high bits of the calling convention convey additional info

src/coreclr/jit/importercalls.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,11 @@ var_types Compiler::impImportCall(OPCODE opcode,
701701
JITDUMP(" Continuation continues on thread pool\n");
702702
}
703703
}
704+
else if (opcode == CEE_CALLI)
705+
{
706+
// Used for unboxing/instantiating stubs
707+
JITDUMP("Call is an async calli\n");
708+
}
704709
else
705710
{
706711
JITDUMP("Call is an async non-task await\n");
@@ -917,7 +922,9 @@ var_types Compiler::impImportCall(OPCODE opcode,
917922
.WellKnown(WellKnownArg::VarArgsCookie));
918923
}
919924

920-
if (call->AsCall()->IsAsync())
925+
// Add async continuation arg. For calli these are used for IL
926+
// stubs and the VM inserts the arg itself.
927+
if (call->AsCall()->IsAsync() && (opcode != CEE_CALLI))
921928
{
922929
call->AsCall()->gtArgs.PushFront(this, NewCallArg::Primitive(gtNewNull(), TYP_REF)
923930
.WellKnown(WellKnownArg::AsyncContinuation));
@@ -931,7 +938,9 @@ var_types Compiler::impImportCall(OPCODE opcode,
931938
}
932939
else
933940
{
934-
if (call->AsCall()->IsAsync())
941+
// Add async continuation arg. For calli these are used for IL
942+
// stubs and the VM inserts the arg itself.
943+
if (call->AsCall()->IsAsync() && (opcode != CEE_CALLI))
935944
{
936945
call->AsCall()->gtArgs.PushBack(this, NewCallArg::Primitive(gtNewNull(), TYP_REF)
937946
.WellKnown(WellKnownArg::AsyncContinuation));

src/coreclr/vm/callingconvention.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
676676
// explicit arguments have been scanned is platform dependent.
677677
void GetThisLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetThisOffset(), pLoc); }
678678
void GetParamTypeLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetParamTypeArgOffset(), pLoc); }
679+
void GetAsyncContinuationLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetAsyncContinuationArgOffset(), pLoc); }
679680
void GetVASigCookieLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetVASigCookieOffset(), pLoc); }
680681

681682
#ifndef CALLDESCR_RETBUFFARGREG

src/coreclr/vm/comdelegate.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,18 @@ BOOL GenerateShuffleArrayPortable(MethodDesc* pMethodSrc, MethodDesc *pMethodDst
475475
#endif // !defined(TARGET_ARM64) || !defined(CALLDESCR_RETBUFFARGREG)
476476
}
477477

478+
// Handle async continuation argument.
479+
_ASSERTE(!!sArgPlacerDst.HasAsyncContinuation() == !!sArgPlacerSrc.HasAsyncContinuation());
480+
if (sArgPlacerDst.HasAsyncContinuation())
481+
{
482+
// The async continuation is implicit in both signatures.
483+
sArgPlacerSrc.GetAsyncContinuationLoc(&sArgSrc);
484+
sArgPlacerDst.GetAsyncContinuationLoc(&sArgDst);
485+
486+
if (!AddNextShuffleEntryToArray(sArgSrc, sArgDst, pShuffleEntryArray, shuffleType))
487+
return FALSE;
488+
}
489+
478490
// Iterate all the regular arguments. mapping source registers and stack locations to the corresponding
479491
// destination locations.
480492
while ((ofsSrc = sArgPlacerSrc.GetNextOffset()) != TransitionBlock::InvalidOffset)

src/coreclr/vm/ilstubcache.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ void CreateModuleIndependentSignature(LoaderHeap* pCreationHeap,
7070
// static
7171
MethodDesc* ILStubCache::CreateAndLinkNewILStubMethodDesc(LoaderAllocator* pAllocator, MethodTable* pMT, DWORD dwStubFlags,
7272
Module* pSigModule, PCCOR_SIGNATURE pSig, DWORD cbSig, SigTypeContext *pTypeContext,
73-
ILStubLinker* pStubLinker)
73+
ILStubLinker* pStubLinker, BOOL isAsync /* = FALSE */)
7474
{
7575
CONTRACT (MethodDesc*)
7676
{
@@ -86,6 +86,7 @@ MethodDesc* ILStubCache::CreateAndLinkNewILStubMethodDesc(LoaderAllocator* pAllo
8686
dwStubFlags,
8787
pSigModule,
8888
pSig, cbSig,
89+
isAsync,
8990
pTypeContext,
9091
&amTracker);
9192

@@ -143,7 +144,7 @@ namespace
143144

144145
// static
145146
MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTable* pMT, DWORD dwStubFlags,
146-
Module* pSigModule, PCCOR_SIGNATURE pSig, DWORD cbSig, SigTypeContext *pTypeContext,
147+
Module* pSigModule, PCCOR_SIGNATURE pSig, DWORD cbSig, BOOL isAsync, SigTypeContext *pTypeContext,
147148
AllocMemTracker* pamTracker)
148149
{
149150
CONTRACT (MethodDesc*)
@@ -160,7 +161,7 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa
160161
mcDynamic,
161162
TRUE /* fNonVtableSlot */,
162163
TRUE /* fNativeCodeSlot */,
163-
FALSE /* HasAsyncMethodData */,
164+
isAsync /* HasAsyncMethodData */,
164165
pMT,
165166
pamTracker);
166167

@@ -175,6 +176,13 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa
175176
pMD->InitializeFlags(DynamicMethodDesc::FlagPublic | DynamicMethodDesc::FlagIsILStub);
176177
pMD->SetTemporaryEntryPoint(pamTracker);
177178

179+
if (isAsync)
180+
{
181+
pMD->SetHasAsyncMethodData();
182+
// Async stubs are standalone methods that do not form async/task-returning variant pairs.
183+
pMD->GetAddrOfAsyncMethodData()->kind = AsyncMethodKind::AsyncExplicitImpl;
184+
}
185+
178186
//
179187
// convert signature to a compatible signature if needed
180188
//
@@ -531,7 +539,8 @@ MethodDesc* ILStubCache::GetStubMethodDesc(
531539
}
532540

533541
MethodTable *pStubMT = GetOrCreateStubMethodTable(pSigLoaderModule);
534-
pMD = ILStubCache::CreateNewMethodDesc(m_pAllocator->GetHighFrequencyHeap(), pStubMT, dwStubFlags, pSigModule, pSig, cbSig, pTypeContext, pamTracker);
542+
BOOL isAsync = pTargetMD == NULL ? FALSE: pTargetMD->IsAsyncMethod();
543+
pMD = ILStubCache::CreateNewMethodDesc(m_pAllocator->GetHighFrequencyHeap(), pStubMT, dwStubFlags, pSigModule, pSig, cbSig, isAsync, pTypeContext, pamTracker);
535544

536545
if (SF_IsSharedStub(dwStubFlags))
537546
{

src/coreclr/vm/ilstubcache.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ class ILStubCache final
7373
PCCOR_SIGNATURE pSig,
7474
DWORD cbSig,
7575
SigTypeContext *pTypeContext,
76-
ILStubLinker* pStubLinker);
76+
ILStubLinker* pStubLinker,
77+
BOOL isAsync = FALSE);
7778

7879
MethodTable * GetStubMethodTable()
7980
{
@@ -97,6 +98,7 @@ class ILStubCache final
9798
Module* pSigModule,
9899
PCCOR_SIGNATURE pSig,
99100
DWORD cbSig,
101+
BOOL isAsync,
100102
SigTypeContext *pTypeContext,
101103
AllocMemTracker* pamTracker);
102104

src/coreclr/vm/jitinterface.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -478,19 +478,26 @@ static void ConvToJitSig(
478478

479479
uint32_t data;
480480
IfFailThrow(sig.GetCallingConvInfo(&data));
481-
sigRet->callConv = (CorInfoCallConv) data;
482481

483482
#if defined(TARGET_UNIX) || defined(TARGET_ARM)
484-
if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
485-
(isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
483+
if ((isCallConv(data, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
484+
(isCallConv(data, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
486485
{
487486
// This signature corresponds to a method that uses varargs, which are not supported.
488487
COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
489488
}
490489
#endif // defined(TARGET_UNIX) || defined(TARGET_ARM)
491490

491+
// We have an internal calling convention for async used for signatures
492+
// in IL stubs. Translate that to the flag representation in
493+
// CorInfoCallConv.
494+
if (isCallConv(data, IMAGE_CEE_CS_CALLCONV_ASYNC))
495+
sigRet->callConv = (CorInfoCallConv)(CORINFO_CALLCONV_DEFAULT | CORINFO_CALLCONV_ASYNCCALL | (data & ~IMAGE_CEE_CS_CALLCONV_MASK));
496+
else
497+
sigRet->callConv = (CorInfoCallConv) data;
498+
492499
// Skip number of type arguments
493-
if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
500+
if (data & IMAGE_CEE_CS_CALLCONV_GENERIC)
494501
IfFailThrow(sig.GetData(NULL));
495502

496503
uint32_t numArgs;
@@ -1796,7 +1803,6 @@ CEEInfo::findSig(
17961803
if (IsDynamicScope(scopeHnd))
17971804
{
17981805
sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1799-
sigTok = mdTokenNil;
18001806
}
18011807
else
18021808
{

src/coreclr/vm/prestub.cpp

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,16 +1394,18 @@ PrepareCodeConfigBuffer::PrepareCodeConfigBuffer(NativeCodeVersion codeVersion)
13941394

13951395
// CreateDerivedTargetSigWithExtraParams:
13961396
// This method is used to create the signature of the target of the ILStub for
1397-
// instantiating, unboxing, and async variant stubs, when/where we need to
1398-
// introduce a generic context/async continuation.
1399-
// And since the generic context/async continuations are hidden parameters,
1397+
// instantiating and unboxing stubs, when/where we need to
1398+
// introduce a generic context.
1399+
// And since the generic contexts are hidden parameters,
14001400
// we're creating a signature that looks like non-generic but with additional
14011401
// parameters right after the thisptr
14021402
void MethodDesc::CreateDerivedTargetSigWithExtraParams(MetaSig& msig, SigBuilder *stubSigBuilder)
14031403
{
14041404
STANDARD_VM_CONTRACT;
14051405

14061406
BYTE callingConvention = IMAGE_CEE_CS_CALLCONV_DEFAULT;
1407+
if (msig.HasAsyncContinuation())
1408+
callingConvention = IMAGE_CEE_CS_CALLCONV_ASYNC;
14071409
if (msig.HasThis())
14081410
callingConvention |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
14091411
// CallingConvention
@@ -1475,9 +1477,6 @@ Stub * CreateUnboxingILStubForSharedGenericValueTypeMethods(MethodDesc* pTargetM
14751477

14761478
_ASSERTE(msig.HasThis());
14771479

1478-
// TODO: (async) instantiating/unboxing stubs https://github.com/dotnet/runtime/issues/117266
1479-
_ASSERTE(!msig.HasAsyncContinuation());
1480-
14811480
ILStubLinker sl(pTargetMD->GetModule(),
14821481
pTargetMD->GetSignature(),
14831482
&typeContext,
@@ -1499,12 +1498,17 @@ Stub * CreateUnboxingILStubForSharedGenericValueTypeMethods(MethodDesc* pTargetM
14991498
pCode->EmitLoadThis();
15001499
pCode->EmitLDFLDA(tokRawData);
15011500

1502-
#if defined(TARGET_X86)
1501+
#ifdef TARGET_X86
15031502
// Push the rest of the arguments for x86
15041503
for (unsigned i = 0; i < msig.NumFixedArgs();i++)
15051504
{
15061505
pCode->EmitLDARG(i);
15071506
}
1507+
1508+
if (msig.HasAsyncContinuation())
1509+
{
1510+
pCode->EmitLDNULL();
1511+
}
15081512
#endif
15091513

15101514
// Push the hidden context param
@@ -1515,7 +1519,12 @@ Stub * CreateUnboxingILStubForSharedGenericValueTypeMethods(MethodDesc* pTargetM
15151519
pCode->EmitSUB();
15161520
pCode->EmitLDIND_I();
15171521

1518-
#if !defined(TARGET_X86)
1522+
#ifndef TARGET_X86
1523+
if (msig.HasAsyncContinuation())
1524+
{
1525+
pCode->EmitLDNULL();
1526+
}
1527+
15191528
// Push the rest of the arguments for not x86
15201529
for (unsigned i = 0; i < msig.NumFixedArgs();i++)
15211530
{
@@ -1540,7 +1549,8 @@ Stub * CreateUnboxingILStubForSharedGenericValueTypeMethods(MethodDesc* pTargetM
15401549
pTargetMD->GetModule(),
15411550
pSig, cbSig,
15421551
&typeContext,
1543-
&sl);
1552+
&sl,
1553+
pTargetMD->IsAsyncMethod());
15441554

15451555
ILStubResolver *pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
15461556

@@ -1593,9 +1603,6 @@ Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg)
15931603

15941604
ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch);
15951605

1596-
// TODO: (async) instantiating/unboxing stubs https://github.com/dotnet/runtime/issues/117266
1597-
_ASSERTE(!msig.HasAsyncContinuation());
1598-
15991606
// Build the new signature
16001607
SigBuilder stubSigBuilder;
16011608
MethodDesc::CreateDerivedTargetSigWithExtraParams(msig, &stubSigBuilder);
@@ -1607,25 +1614,37 @@ Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg)
16071614
pCode->EmitLoadThis();
16081615
}
16091616

1610-
#if defined(TARGET_X86)
1617+
#ifdef TARGET_X86
16111618
// Push the rest of the arguments for x86
16121619
for (unsigned i = 0; i < msig.NumFixedArgs();i++)
16131620
{
16141621
pCode->EmitLDARG(i);
16151622
}
1616-
#endif // TARGET_X86
16171623

1624+
if (msig.HasAsyncContinuation())
1625+
{
1626+
pCode->EmitLDNULL();
1627+
}
1628+
1629+
// Push the hidden context param
1630+
// InstantiatingStub
1631+
pCode->EmitLDC((TADDR)pHiddenArg);
1632+
#else
16181633
// Push the hidden context param
16191634
// InstantiatingStub
16201635
pCode->EmitLDC((TADDR)pHiddenArg);
16211636

1622-
#if !defined(TARGET_X86)
1623-
// Push the rest of the arguments for not x86
1637+
if (msig.HasAsyncContinuation())
1638+
{
1639+
pCode->EmitLDNULL();
1640+
}
1641+
1642+
// Push the rest of the arguments for x86
16241643
for (unsigned i = 0; i < msig.NumFixedArgs();i++)
16251644
{
16261645
pCode->EmitLDARG(i);
16271646
}
1628-
#endif // !TARGET_X86
1647+
#endif
16291648

16301649
// Push the target address
16311650
pCode->EmitLDC((TADDR)pTargetMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY));
@@ -1644,7 +1663,8 @@ Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg)
16441663
pTargetMD->GetModule(),
16451664
pSig, cbSig,
16461665
&typeContext,
1647-
&sl);
1666+
&sl,
1667+
pTargetMD->IsAsyncMethod());
16481668

16491669
ILStubResolver *pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
16501670

src/coreclr/vm/siginfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, const SigTypeCo
185185
{
186186
mdToken tk;
187187
IfFailThrowBF(GetToken(&tk), BFA_BAD_COMPLUS_SIG, pSigModule);
188-
TypeHandle th = ClassLoader::LoadTypeDefOrRefThrowing(pSigModule, tk);
188+
TypeHandle th = ClassLoader::LoadTypeDefOrRefThrowing(pSigModule, tk, ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef);
189189
pSigBuilder->AppendElementType(ELEMENT_TYPE_CMOD_INTERNAL);
190190
pSigBuilder->AppendByte(typ == ELEMENT_TYPE_CMOD_REQD); // "is required" byte
191191
pSigBuilder->AppendPointer(th.AsPtr());

0 commit comments

Comments
 (0)