From f1531cea9443488d464d5beb2c318deff73b1327 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 6 Nov 2025 15:28:55 -0800 Subject: [PATCH 1/2] continuation object reading with cordb --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 12 ++++++++++-- src/coreclr/debug/ee/debugger.cpp | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 284d3fd1172842..e0dbefc83679db 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -2315,6 +2315,10 @@ void DacDbiInterfaceImpl::GetClassTypeInfo(TypeHandle typeH DebuggerIPCE_ExpandedTypeData * pTypeInfo, AppDomain * pAppDomain) { + if (typeHandle.AsMethodTable()->IsContinuation()) + { + typeHandle = TypeHandle(g_pContinuationClassIfSubTypeCreated); + } Module * pModule = typeHandle.GetModule(); if (typeHandle.HasInstantiation()) // the type handle represents a generic instantiation @@ -2402,9 +2406,13 @@ void DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo(TypeHandle case ELEMENT_TYPE_CLASS: case ELEMENT_TYPE_VALUETYPE: { - Module * pModule = typeHandle.GetModule(); + if (typeHandle.AsMethodTable()->IsContinuation()) + { + typeHandle = TypeHandle(g_pContinuationClassIfSubTypeCreated); + } - if (typeHandle.HasInstantiation()) // only set if instantiated + Module * pModule = typeHandle.GetModule(); + if (typeHandle.HasInstantiation()) // only set if instantiated { pTypeInfo->vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr()); } diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 546ef251ea71f1..42c7c1482f35aa 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -11657,6 +11657,10 @@ void Debugger::TypeHandleToBasicTypeInfo(AppDomain *pAppDomain, TypeHandle th, D case ELEMENT_TYPE_CLASS: case ELEMENT_TYPE_VALUETYPE: { + if (th.AsMethodTable()->IsContinuation()) + { + th = TypeHandle(g_pContinuationClassIfSubTypeCreated); + } res->vmTypeHandle = th.HasInstantiation() ? WrapTypeHandle(th) : VMPTR_TypeHandle::NullPtr(); // only set if instantiated res->metadataToken = th.GetCl(); @@ -11739,6 +11743,10 @@ void Debugger::TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed, case ELEMENT_TYPE_CLASS: { treatAllValuesAsBoxed: + if (th.AsMethodTable()->IsContinuation()) + { + th = TypeHandle(g_pContinuationClassIfSubTypeCreated); + } res->ClassTypeData.typeHandle = th.HasInstantiation() ? WrapTypeHandle(th) : VMPTR_TypeHandle::NullPtr(); // only set if instantiated res->ClassTypeData.metadataToken = th.GetCl(); DebuggerModule * pModule = LookupOrCreateModule(th.GetModule()); From 5cf0fdd8f21bc5cd67ecf9593fc3621a0d4ce5f2 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 7 Nov 2025 11:30:17 -0800 Subject: [PATCH 2/2] code review --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 10 ++-------- src/coreclr/debug/ee/debugger.cpp | 10 ++-------- src/coreclr/vm/typehandle.h | 1 + src/coreclr/vm/typehandle.inl | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index e0dbefc83679db..b0461e50e7daa4 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -2315,10 +2315,7 @@ void DacDbiInterfaceImpl::GetClassTypeInfo(TypeHandle typeH DebuggerIPCE_ExpandedTypeData * pTypeInfo, AppDomain * pAppDomain) { - if (typeHandle.AsMethodTable()->IsContinuation()) - { - typeHandle = TypeHandle(g_pContinuationClassIfSubTypeCreated); - } + typeHandle = typeHandle.UpCastTypeIfNeeded(); Module * pModule = typeHandle.GetModule(); if (typeHandle.HasInstantiation()) // the type handle represents a generic instantiation @@ -2406,10 +2403,7 @@ void DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo(TypeHandle case ELEMENT_TYPE_CLASS: case ELEMENT_TYPE_VALUETYPE: { - if (typeHandle.AsMethodTable()->IsContinuation()) - { - typeHandle = TypeHandle(g_pContinuationClassIfSubTypeCreated); - } + typeHandle = typeHandle.UpCastTypeIfNeeded(); Module * pModule = typeHandle.GetModule(); if (typeHandle.HasInstantiation()) // only set if instantiated diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 42c7c1482f35aa..eb5bc42d206f8a 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -11657,10 +11657,7 @@ void Debugger::TypeHandleToBasicTypeInfo(AppDomain *pAppDomain, TypeHandle th, D case ELEMENT_TYPE_CLASS: case ELEMENT_TYPE_VALUETYPE: { - if (th.AsMethodTable()->IsContinuation()) - { - th = TypeHandle(g_pContinuationClassIfSubTypeCreated); - } + th = th.UpCastTypeIfNeeded(); res->vmTypeHandle = th.HasInstantiation() ? WrapTypeHandle(th) : VMPTR_TypeHandle::NullPtr(); // only set if instantiated res->metadataToken = th.GetCl(); @@ -11743,10 +11740,7 @@ void Debugger::TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed, case ELEMENT_TYPE_CLASS: { treatAllValuesAsBoxed: - if (th.AsMethodTable()->IsContinuation()) - { - th = TypeHandle(g_pContinuationClassIfSubTypeCreated); - } + th = th.UpCastTypeIfNeeded(); res->ClassTypeData.typeHandle = th.HasInstantiation() ? WrapTypeHandle(th) : VMPTR_TypeHandle::NullPtr(); // only set if instantiated res->ClassTypeData.metadataToken = th.GetCl(); DebuggerModule * pModule = LookupOrCreateModule(th.GetModule()); diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 92af9c513a7641..9c5e5f8b424625 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -386,6 +386,7 @@ class TypeHandle // And some types (like ByRef or generic type parameters) have no // method table and this function returns NULL for them. inline PTR_MethodTable GetMethodTable() const; + inline TypeHandle UpCastTypeIfNeeded() const; // Returns the type which should be used for visibility checking. inline MethodTable* GetMethodTableOfRootTypeParam() const; diff --git a/src/coreclr/vm/typehandle.inl b/src/coreclr/vm/typehandle.inl index 1e022e268d1d7f..d1916c121e56c2 100644 --- a/src/coreclr/vm/typehandle.inl +++ b/src/coreclr/vm/typehandle.inl @@ -27,6 +27,24 @@ inline PTR_MethodTable TypeHandle::GetMethodTable() const return AsMethodTable(); } +// This method allows you to get the "upcasted" type handle. Currently we need this +// because continuation types for runtime-async methods are dynamically created subtypes of a +// parent continuation class that have no metadata of their own. This way, when we need to get +// the TypeHandle to retrieve metadata, we are able to get a reasonable approximation. +// If we need to handle more such types in the future we can add them here. +inline TypeHandle TypeHandle::UpCastTypeIfNeeded() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return *this; + if (AsMethodTable()->IsContinuation()) + { + return TypeHandle(g_pContinuationClassIfSubTypeCreated); + } + return *this; +} + inline void TypeHandle::SetIsFullyLoaded() { LIMITED_METHOD_CONTRACT;