From 8d59367e303ff95122b6e7bdf40a317c48239251 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 23 Jan 2026 10:50:52 +0100 Subject: [PATCH 1/3] SPMI: Tolerate missing getContinuationType calls The continuation type returned to the JIT by getContinuationType is more or less opaque. The only thing we need to do with that handle is embed it in the code stream. Teach SPMI to fake up a class handle instead of missing contexts when the continuation layout is not found. This is going to be a common scenario for async changes because any change resulting in new live state around an async call ends up requiring a different continuation type. --- .../superpmi-shared/methodcontext.cpp | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index a356862e5a3443..3bc27a86437ec5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4153,6 +4153,7 @@ CORINFO_MODULE_HANDLE MethodContext::repEmbedModuleHandle(CORINFO_MODULE_HANDLE return (CORINFO_MODULE_HANDLE)value.B; } +const DWORDLONG CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE = (DWORDLONG)0x12345678beef0000; void MethodContext::recEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection, CORINFO_CLASS_HANDLE result) { if (EmbedClassHandle == nullptr) @@ -4176,6 +4177,24 @@ void MethodContext::dmpEmbedClassHandle(DWORDLONG key, DLDL value) CORINFO_CLASS_HANDLE MethodContext::repEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection) { DWORDLONG key = CastHandle(handle); + if (key == CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE) + { + if ((EmbedClassHandle->GetCount() > 0) && (EmbedClassHandle->GetItem(0).A != 0)) + { + // Some other embedded handle required an indirection, so do the same for the pseudo handle + // (avoids spurious improvements in R2R scenarios) + if (ppIndirection != nullptr) + { + *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; + } + + return nullptr; + } + + *ppIndirection = nullptr; + return handle; + } + DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key %016" PRIX64 "", key); DEBUG_REP(dmpEmbedClassHandle(key, value)); @@ -6958,17 +6977,26 @@ CORINFO_CLASS_HANDLE MethodContext::repGetContinuationType(size_t dataSize, { AssertMapExistsNoMessage(GetContinuationType); - int objRefsBuffer = GetContinuationType->Contains((unsigned char*)objRefs, (unsigned)objRefsSize); - if (objRefsBuffer == -1) - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing obj refs buffer)", ""); - Agnostic_GetContinuationTypeIn key; ZeroMemory(&key, sizeof(key)); key.dataSize = (DWORDLONG)dataSize; - key.objRefs = objRefsBuffer; + key.objRefs = (DWORD)GetContinuationType->Contains((unsigned char*)objRefs, (unsigned)objRefsSize); key.objRefsSize = (DWORD)objRefsSize; - DWORDLONG value = LookupByKeyOrMiss(GetContinuationType, key, ": dataSize %016" PRIX64 ", objRefs %u", key.dataSize, key.objRefs); + DWORDLONG value; + int index = GetContinuationType->GetIndex(key); + if (index == -1) + { + // This handle is more or less opaque, we can tolerate a miss here and + // just fake up handle. Otherwise SPMI will be useless for + // any async change that results in changes in live state. + value = CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; + } + else + { + value = GetContinuationType->GetItem(index); + } + DEBUG_REP(dmpGetContinuationType(key, value)); return (CORINFO_CLASS_HANDLE)value; From 6baebf8c714d0fa33b4bf220ccb539329ca6bd9e Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 23 Jan 2026 11:10:28 +0100 Subject: [PATCH 2/3] Simplify --- .../tools/superpmi/superpmi-shared/methodcontext.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 3bc27a86437ec5..75a8e96e9d779f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4183,10 +4183,7 @@ CORINFO_CLASS_HANDLE MethodContext::repEmbedClassHandle(CORINFO_CLASS_HANDLE han { // Some other embedded handle required an indirection, so do the same for the pseudo handle // (avoids spurious improvements in R2R scenarios) - if (ppIndirection != nullptr) - { - *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; - } + *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; return nullptr; } @@ -4199,8 +4196,7 @@ CORINFO_CLASS_HANDLE MethodContext::repEmbedClassHandle(CORINFO_CLASS_HANDLE han DEBUG_REP(dmpEmbedClassHandle(key, value)); - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; + *ppIndirection = (void*)value.A; return (CORINFO_CLASS_HANDLE)value.B; } From 407a2ccb55eb223b5202c1867034771f17a1b6b8 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 23 Jan 2026 11:12:30 +0100 Subject: [PATCH 3/3] Nit --- src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 75a8e96e9d779f..9d8c64356a9a5d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4184,7 +4184,6 @@ CORINFO_CLASS_HANDLE MethodContext::repEmbedClassHandle(CORINFO_CLASS_HANDLE han // Some other embedded handle required an indirection, so do the same for the pseudo handle // (avoids spurious improvements in R2R scenarios) *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; - return nullptr; }