Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 98 additions & 3 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,15 @@ int32_t* InterpCompiler::EmitCodeIns(int32_t *ip, InterpInst *ins, TArray<Reloc*

if (opcode == INTOP_HANDLE_CONTINUATION_SUSPEND)
{
// Capture meaningful start IP for async suspend diagnostics
((InterpAsyncSuspendData*)GetDataItemAtIndex(ins->data[0]))->resumeInfo.DiagnosticIP = (size_t)startIp - (size_t)m_pMethodCode;
InterpAsyncSuspendData* pSuspendData = (InterpAsyncSuspendData*)GetDataItemAtIndex(ins->data[0]);
// Store as native offset from the start of the method (including the InterpByteCodeStart header)
// so it matches OffsetMapping.nativeOffset and AsyncSuspensionPoint.DiagnosticNativeOffset.
pSuspendData->resumeInfo.DiagnosticIP = sizeof(InterpByteCodeStart) + ((size_t)startIp - (size_t)m_pMethodCode);

// SUSPEND occupies 3 int32_t slots; the matching RESUME starts immediately after.
size_t resumeOffset = sizeof(InterpByteCodeStart) + ((size_t)(startIp - m_pMethodCode) + 3) * sizeof(int32_t);
assert(pSuspendData->suspensionPointIndex == m_suspensionPointIPOffsets.GetSize());
m_suspensionPointIPOffsets.Add((int32_t)resumeOffset);
Comment thread
kotlarmilos marked this conversation as resolved.
}

if (opcode == INTOP_SWITCH)
Expand Down Expand Up @@ -1261,6 +1268,40 @@ void InterpCompiler::EmitCode()
}
m_compHnd->setBoundaries(m_methodInfo->ftn, m_ILToNativeMapSize, m_pILToNativeMap);
m_pILToNativeMap = NULL; // Ownership transferred to the VM

ReportAsyncDebugInfo();
}

void InterpCompiler::ReportAsyncDebugInfo()
{
int32_t numSuspensionPoints = m_asyncDebugSuspensionPoints.GetSize();
Comment thread
kotlarmilos marked this conversation as resolved.
if (numSuspensionPoints == 0)
return;

for (int32_t i = 0; i < numSuspensionPoints; i++)
{
m_asyncDebugSuspensionPoints.GetUnderlyingArray()[i].DiagnosticNativeOffset =
(uint32_t)m_asyncSuspendDataItems.Get(i)->resumeInfo.DiagnosticIP;
}

ICorDebugInfo::AsyncInfo asyncInfo;
asyncInfo.NumSuspensionPoints = (uint32_t)numSuspensionPoints;

size_t spBytes = (size_t)numSuspensionPoints * sizeof(ICorDebugInfo::AsyncSuspensionPoint);
ICorDebugInfo::AsyncSuspensionPoint* hostSuspensionPoints =
(ICorDebugInfo::AsyncSuspensionPoint*)m_compHnd->allocateArray(spBytes);
memcpy(hostSuspensionPoints, m_asyncDebugSuspensionPoints.GetUnderlyingArray(), spBytes);

int32_t numVars = m_asyncDebugContinuationVars.GetSize();
ICorDebugInfo::AsyncContinuationVarInfo* hostVars = NULL;
if (numVars > 0)
{
size_t vBytes = (size_t)numVars * sizeof(ICorDebugInfo::AsyncContinuationVarInfo);
hostVars = (ICorDebugInfo::AsyncContinuationVarInfo*)m_compHnd->allocateArray(vBytes);
memcpy(hostVars, m_asyncDebugContinuationVars.GetUnderlyingArray(), vBytes);
}

m_compHnd->reportAsyncDebugInfo(&asyncInfo, hostSuspensionPoints, hostVars, (uint32_t)numVars);
}

#ifdef FEATURE_INTERPRETER
Expand Down Expand Up @@ -1909,6 +1950,12 @@ void InterpCompiler::PrepareInterpMethod()
count++; // Include the terminator entry
m_methodDataBuilder.AllocateIntervalMap(count);
}

if (m_asyncSuspendDataItems.GetSize() > 0)
{
m_methodDataBuilder.AllocateInSection(InterpMethodDataSection::IntervalMaps,
(uint32_t)m_asyncSuspendDataItems.GetSize() * (uint32_t)sizeof(int32_t));
}
}

int32_t* InterpCompiler::GetCode(int32_t *pCodeSize)
Expand Down Expand Up @@ -2028,10 +2075,35 @@ InterpMethod* InterpCompiler::FinalizeMethodData(void* baseAddressRW, void* base
dstDataRW->zeroedLocalsIntervals = dstMapRX;
currentIntervalMapOffset += mapSize;
}

currentAsyncOffset += sizeof(InterpAsyncSuspendData);
}

{
int32_t numSuspensionPoints = m_asyncSuspendDataItems.GetSize();
InterpMethod* pInterpMethodRW = (InterpMethod*)(rwBase + interpMethodOffset);
if (numSuspensionPoints > 0)
{
uint32_t tableSize = (uint32_t)numSuspensionPoints * (uint32_t)sizeof(int32_t);
assert(currentIntervalMapOffset + tableSize <= intervalMapsSectionEnd);

int32_t* tableRW = (int32_t*)(rwBase + currentIntervalMapOffset);
int32_t* tableRX = (int32_t*)(rxBase + currentIntervalMapOffset);
for (int32_t i = 0; i < numSuspensionPoints; i++)
{
tableRW[i] = m_suspensionPointIPOffsets.Get(i);
}
pInterpMethodRW->numSuspensionPoints = numSuspensionPoints;
pInterpMethodRW->suspensionPointIPOffsets = tableRX;
currentIntervalMapOffset += tableSize;
}
else
{
pInterpMethodRW->numSuspensionPoints = 0;
pInterpMethodRW->suspensionPointIPOffsets = NULL;
}
}

assert(currentAsyncOffset <= asyncSuspendDataSectionEnd);
assert(currentIntervalMapOffset <= intervalMapsSectionEnd);

Expand Down Expand Up @@ -2089,6 +2161,9 @@ InterpCompiler::InterpCompiler(COMP_HANDLE compHnd,
, m_leavesTable(GetMemPoolAllocator(IMK_EHClause))
, m_dataItems(GetMemPoolAllocator(IMK_DataItem))
, m_asyncSuspendDataItems(GetMemPoolAllocator(IMK_DataItem))
, m_suspensionPointIPOffsets(GetMemPoolAllocator(IMK_DataItem))
, m_asyncDebugSuspensionPoints(GetMemPoolAllocator(IMK_DataItem))
, m_asyncDebugContinuationVars(GetMemPoolAllocator(IMK_DataItem))
, m_dataItemAsyncSuspendRefs(GetMemPoolAllocator(IMK_DataItem))
, m_initLocals(false)
, m_unmanagedCallersOnly(false)
Expand Down Expand Up @@ -5783,6 +5858,7 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation

TArray<int32_t, MemPoolAllocator> liveVars(GetMemPoolAllocator(IMK_AsyncSuspend));
TArray<int32_t, MemPoolAllocator> varsToZero(GetMemPoolAllocator(IMK_AsyncSuspend));
int32_t debugVarsStartCount = m_asyncDebugContinuationVars.GetSize();

// Step 2: Handle live stack vars (excluding return value)
int32_t stackDepth = (int32_t)(m_pStackPointer - m_pStackBase);
Expand Down Expand Up @@ -5935,6 +6011,14 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation

INTERP_DUMP("Allocate var %d at data offset %d (size %d) (offsetFromStartOfReturnValue = %d)\n", var, currentOffset, size, currentOffset - returnValueDataStartOffset);

if (var >= 0 && var < m_numILVars && var != returnValueVar)
{
ICorDebugInfo::AsyncContinuationVarInfo varInf;
varInf.VarNumber = (uint32_t)var;
varInf.Offset = (uint32_t)(currentOffset + OFFSETOF__CORINFO_Continuation__data);
m_asyncDebugContinuationVars.Add(varInf);
}

if (interpType == InterpTypeO)
{
// Mark as GC reference
Expand Down Expand Up @@ -5990,7 +6074,9 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation
}

InterpAsyncSuspendData* suspendData = (InterpAsyncSuspendData*)AllocMethodData(sizeof(InterpAsyncSuspendData));
int32_t suspensionPointIndex = m_asyncSuspendDataItems.GetSize();
m_asyncSuspendDataItems.Add(suspendData);
suspendData->suspensionPointIndex = suspensionPointIndex;
CORINFO_ASYNC_INFO asyncInfo;
m_compHnd->getAsyncInfo(&asyncInfo);

Expand All @@ -6015,6 +6101,15 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation
suspendData->resumeInfo.DiagnosticIP = (size_t)NULL;
suspendData->methodStartIP = 0; // This is filled in by logic later in emission once we know the final address of the method
suspendData->continuationArgOffset = m_pVars[m_continuationArgIndex].offset;

{
ICorDebugInfo::AsyncSuspensionPoint sp;
sp.DiagnosticNativeOffset = (uint32_t)suspendData->resumeInfo.DiagnosticIP;
sp.NumContinuationVars = (uint32_t)(m_asyncDebugContinuationVars.GetSize() - debugVarsStartCount);
m_asyncDebugSuspensionPoints.Add(sp);
assert(m_asyncDebugSuspensionPoints.GetSize() - 1 == suspensionPointIndex);
}

suspendData->asyncMethodReturnType = NULL;
switch (m_methodInfo->args.retType)
{
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/interpreter/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,10 @@ class InterpCompiler

TArray<InterpAsyncSuspendData*, MemPoolAllocator> m_asyncSuspendDataItems;

TArray<int32_t, MemPoolAllocator> m_suspensionPointIPOffsets;
TArray<ICorDebugInfo::AsyncSuspensionPoint, MemPoolAllocator> m_asyncDebugSuspensionPoints;
TArray<ICorDebugInfo::AsyncContinuationVarInfo, MemPoolAllocator> m_asyncDebugContinuationVars;

// Tracks which data items contain pointers to async suspend data
// First = data item index, Second = index into m_asyncSuspendDataItems
struct DataItemAsyncSuspendRef
Expand Down Expand Up @@ -1045,6 +1049,7 @@ class InterpCompiler
void AllocOffsets();
int32_t ComputeCodeSize();
void EmitCode();
void ReportAsyncDebugInfo();
int32_t* EmitBBCode(int32_t *ip, InterpBasicBlock *bb, TArray<Reloc*, MemPoolAllocator> *relocs);
int32_t* EmitCodeIns(int32_t *ip, InterpInst *pIns, TArray<Reloc*, MemPoolAllocator> *relocs);
void PatchRelocations(TArray<Reloc*, MemPoolAllocator> *relocs);
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/interpreter/inc/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ struct InterpMethod
bool publishSecretStubParam;
int32_t codeSize; // size in int32_t slots

// Maps Continuation.State (suspension-point index) to the byte offset of the matching
// INTOP_HANDLE_CONTINUATION_RESUME opcode from InterpByteCodeStart.
int32_t numSuspensionPoints;
int32_t* suspensionPointIPOffsets;

#ifdef INTERPRETER_COMPILER_INTERNAL
InterpMethod(
CORINFO_METHOD_HANDLE methodHnd, int32_t argsSize, int32_t allocaSize,
Expand All @@ -66,6 +71,8 @@ struct InterpMethod
this->unmanagedCallersOnly = unmanagedCallersOnly;
this->publishSecretStubParam = publishSecretStubParam;
this->codeSize = codeSize;
this->numSuspensionPoints = 0;
this->suspensionPointIPOffsets = NULL;
pCallStub = NULL;
}
#endif
Expand Down Expand Up @@ -218,6 +225,9 @@ struct InterpAsyncSuspendData
COMPILER_SHARED_TYPE(CORINFO_METHOD_HANDLE, DPTR(MethodDesc), captureSyncContextMethod);
COMPILER_SHARED_TYPE(CORINFO_METHOD_HANDLE, DPTR(MethodDesc), restoreExecutionContextMethod);
COMPILER_SHARED_TYPE(CORINFO_METHOD_HANDLE, DPTR(MethodDesc), restoreContextsOnSuspensionMethod);

// Written into Continuation.State at suspend; matches the JIT encoding.
int32_t suspensionPointIndex;
};

#endif
8 changes: 5 additions & 3 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4528,7 +4528,7 @@ do \
}
}

continuation->SetState((int32_t)((uint8_t*)ip - (uint8_t*)pFrame->startIp));
continuation->SetState(pAsyncSuspendData->suspensionPointIndex);
_ASSERTE(pAsyncSuspendData->methodStartIP != 0);
continuation->SetResumeInfo(&pAsyncSuspendData->resumeInfo);
pInterpreterFrame->SetContinuation(continuation);
Expand Down Expand Up @@ -4591,9 +4591,11 @@ do \
_ASSERTE(pInterpreterFrame->GetContinuation() == NULL);
if (continuation != NULL)
{
// A continuation is present, begin the restoration process
// State is the suspension-point index; map it to the resume IP.
int32_t state = continuation->GetState();
ip = (int32_t*)((uint8_t*)pFrame->startIp + state);
_ASSERTE(state >= 0 && state < pMethod->numSuspensionPoints);
_ASSERTE(pMethod->suspensionPointIPOffsets != NULL);
ip = (int32_t*)((uint8_t*)pFrame->startIp + pMethod->suspensionPointIPOffsets[state]);

// Now we have an IP to where we should resume execution. This should be an INTOP_HANDLE_CONTINUATION_RESUME opcode
// And before it should be an INTOP_HANDLE_CONTINUATION_SUSPEND opcode
Expand Down
Loading