diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index d65b043f4c4001..586a73011dcdce 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -318,7 +318,7 @@ public static IntPtr AllocateTypeAssociatedMemory(Type type, int size) [StackTraceHidden] private static unsafe void DispatchTailCalls( IntPtr callersRetAddrSlot, - delegate* callTarget, + delegate* callTarget, IntPtr retVal) { IntPtr callersRetAddr; @@ -332,6 +332,9 @@ private static unsafe void DispatchTailCalls( PortableTailCallFrame newFrame; newFrame.Prev = prevFrame; + // GC uses NextCall to keep LoaderAllocator alive after we link it below, + // so we must null it out before that. + newFrame.NextCall = null; try { @@ -339,8 +342,7 @@ private static unsafe void DispatchTailCalls( do { - newFrame.NextCall = null; - callTarget(tls->ArgBuffer, retVal, &newFrame.TailCallAwareReturnAddress); + callTarget(tls->ArgBuffer, retVal, &newFrame); callTarget = newFrame.NextCall; } while (callTarget != null); } @@ -503,7 +505,7 @@ internal unsafe struct PortableTailCallFrame { public PortableTailCallFrame* Prev; public IntPtr TailCallAwareReturnAddress; - public delegate* NextCall; + public delegate* NextCall; } [StructLayout(LayoutKind.Sequential)] diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index 7849958d068746..ea327cc73d800a 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -157,7 +157,22 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) static void ScanTailCallArgBufferRoots(Thread* pThread, promote_func* fn, ScanContext* sc) { - TailCallArgBuffer* argBuffer = pThread->GetTailCallTls()->GetArgBuffer(); + TailCallTls* tls = pThread->GetTailCallTls(); + // Keep loader associated with CallTailCallTarget alive. + if (sc->promotion) + { +#ifndef DACCESS_COMPILE + const PortableTailCallFrame* frame = tls->GetFrame(); + if (frame->NextCall != NULL) + { + MethodDesc* pMD = Entry2MethodDesc((PCODE)frame->NextCall, NULL); + if (pMD != NULL) + GcReportLoaderAllocator(fn, sc, pMD->GetLoaderAllocator()); + } +#endif + } + + TailCallArgBuffer* argBuffer = tls->GetArgBuffer(); if (argBuffer == NULL || argBuffer->GCDesc == NULL) return; diff --git a/src/coreclr/vm/tailcallhelp.cpp b/src/coreclr/vm/tailcallhelp.cpp index 7a96e282275273..5cb1789aabf3d5 100644 --- a/src/coreclr/vm/tailcallhelp.cpp +++ b/src/coreclr/vm/tailcallhelp.cpp @@ -465,10 +465,10 @@ MethodDesc* TailCallHelp::CreateCallTargetStub(const TailCallInfo& info) ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); - // void CallTarget(void* argBuffer, void* retVal, void** pTailCallAwareRetAddress) + // void CallTarget(void* argBuffer, void* retVal, PortableTailCallFrame* pFrame) const int ARG_ARG_BUFFER = 0; const int ARG_RET_VAL = 1; - const int ARG_PTR_TAILCALL_AWARE_RET_ADDR = 2; + const int ARG_PTR_FRAME = 2; auto emitOffs = [&](UINT offs) { @@ -477,10 +477,16 @@ MethodDesc* TailCallHelp::CreateCallTargetStub(const TailCallInfo& info) pCode->EmitADD(); }; - // *pTailCallAwareRetAddr = NextCallReturnAddress(); - pCode->EmitLDARG(ARG_PTR_TAILCALL_AWARE_RET_ADDR); + // pFrame->NextCall = 0; + pCode->EmitLDARG(ARG_PTR_FRAME); + pCode->EmitLDC(0); + pCode->EmitCONV_U(); + pCode->EmitSTFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__NEXT_CALL); + + // pFrame->TailCallAwareReturnAddress = NextCallReturnAddress(); + pCode->EmitLDARG(ARG_PTR_FRAME); pCode->EmitCALL(METHOD__STUBHELPERS__NEXT_CALL_RETURN_ADDRESS, 0, 1); - pCode->EmitSTIND_I(); + pCode->EmitSTFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__TAILCALL_AWARE_RETURN_ADDRESS); for (COUNT_T i = 0; i < info.ArgBufLayout.Values.GetCount(); i++) { @@ -613,7 +619,7 @@ void TailCallHelp::CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder* // Return value sig->AppendElementType(ELEMENT_TYPE_I); - // Pointer to tail call aware return address + // Pointer to tail call frame sig->AppendElementType(ELEMENT_TYPE_I); #ifdef _DEBUG