Skip to content

Commit 075d2c7

Browse files
[clr-interp] Add support for catching exceptions which are dependent on the context param (#119336)
- Add support to the InterpreterCodeManager for the ability to understand the generic context of a given frame - This is done by adding implementation for InterpreterCodeManager::GetInstance, InterpreterCodeManager::GetParamTypeArg and InterpreterCodeManager::GetParamContextType - In addition, provide an implementation of InterpreterJitManager::ResolveEHClause. The enhancement with this is that it will support doing shared generic catch of a generically dependent exception type. (The JIT implements this by translating these sorts of catches into filters, but that doesn't seem like a good approach for the interpreter. The existing function is noted as being sensitive to stack overflow issues, so I didn't update this for all scenarios) As a bonus, this work also enables !clrstack -i -a to understand the actual accurate generic types of all of the locals.
1 parent 6a8720f commit 075d2c7

File tree

5 files changed

+139
-6
lines changed

5 files changed

+139
-6
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,50 @@ void InterpCompiler::BuildGCInfo(InterpMethod *pInterpMethod)
10721072

10731073
gcInfoEncoder->SetCodeLength(ConvertOffset(m_methodCodeSize));
10741074

1075+
GENERIC_CONTEXTPARAM_TYPE paramType;
1076+
1077+
switch (m_methodInfo->options & CORINFO_GENERICS_CTXT_MASK)
1078+
{
1079+
case CORINFO_GENERICS_CTXT_FROM_METHODDESC:
1080+
paramType = GENERIC_CONTEXTPARAM_MD;
1081+
break;
1082+
case CORINFO_GENERICS_CTXT_FROM_METHODTABLE:
1083+
paramType = GENERIC_CONTEXTPARAM_MT;
1084+
break;
1085+
case CORINFO_GENERICS_CTXT_FROM_THIS:
1086+
case 0:
1087+
paramType = GENERIC_CONTEXTPARAM_NONE;
1088+
break;
1089+
default:
1090+
paramType = GENERIC_CONTEXTPARAM_NONE;
1091+
assert(!"Unexpected generic context parameter type");
1092+
break;
1093+
}
1094+
1095+
gcInfoEncoder->SetSizeOfStackOutgoingAndScratchArea(0);
1096+
1097+
if (m_compHnd->getMethodAttribs(m_methodInfo->ftn) & CORINFO_FLG_SHAREDINST)
1098+
{
1099+
if ((m_methodInfo->options & CORINFO_GENERICS_CTXT_MASK) != CORINFO_GENERICS_CTXT_FROM_THIS)
1100+
{
1101+
assert(paramType != GENERIC_CONTEXTPARAM_NONE);
1102+
1103+
int32_t genericArgStackOffset = m_pVars[getParamArgIndex()].offset;
1104+
INTERP_DUMP("SetGenericsInstContextStackSlot at %u\n", (unsigned)genericArgStackOffset);
1105+
gcInfoEncoder->SetPrologSize(4); // Size of 1 instruction
1106+
gcInfoEncoder->SetStackBaseRegister(0);
1107+
gcInfoEncoder->SetGenericsInstContextStackSlot(genericArgStackOffset, paramType);
1108+
}
1109+
else
1110+
{
1111+
assert((paramType == GENERIC_CONTEXTPARAM_NONE));
1112+
}
1113+
}
1114+
else
1115+
{
1116+
assert((paramType == GENERIC_CONTEXTPARAM_NONE));
1117+
}
1118+
10751119
INTERP_DUMP("Allocating gcinfo slots for %u vars\n", m_varsSize);
10761120

10771121
for (int pass = 0; pass < 2; pass++)

src/coreclr/vm/codeman.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,6 +3358,63 @@ PTR_EXCEPTION_CLAUSE_TOKEN EECodeGenManager::GetNextEHClause(EH_CLAUSE_ENUMERATO
33583358
}
33593359

33603360
#ifndef DACCESS_COMPILE
3361+
3362+
#ifdef FEATURE_INTERPRETER
3363+
TypeHandle InterpreterJitManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
3364+
CrawlFrame *pCf)
3365+
{
3366+
// We don't want to use a runtime contract here since this codepath is used during
3367+
// the processing of a hard SO. Contracts use a significant amount of stack
3368+
// which we can't afford for those cases.
3369+
STATIC_CONTRACT_THROWS;
3370+
STATIC_CONTRACT_GC_TRIGGERS;
3371+
3372+
TypeHandle thResolved = EECodeGenManager::ResolveEHClause(pEHClause, pCf);
3373+
3374+
if (thResolved.IsSharedByGenericInstantiations())
3375+
{
3376+
_ASSERTE(!HasCachedTypeHandle(pEHClause));
3377+
3378+
GenericParamContextType paramContextType = pCf->GetCodeManager()->GetParamContextType(pCf->GetRegisterSet(), pCf->GetCodeInfo());
3379+
_ASSERTE(SafeToReportGenericParamContext(pCf));
3380+
if (SafeToReportGenericParamContext(pCf))
3381+
{
3382+
MethodDesc *pMD = pCf->GetFunction();
3383+
TypeHandle declaringType = (TypeHandle)pMD->GetMethodTable();
3384+
3385+
// Handle the case where the method is a static shared generic method and we need to keep the type
3386+
// of the generic parameters alive
3387+
if (paramContextType == GENERIC_PARAM_CONTEXT_METHODDESC)
3388+
{
3389+
pMD = dac_cast<PTR_MethodDesc>(pCf->GetParamTypeArg());
3390+
declaringType = (TypeHandle)pMD->GetMethodTable();
3391+
}
3392+
else if (paramContextType == GENERIC_PARAM_CONTEXT_METHODTABLE)
3393+
{
3394+
declaringType = (TypeHandle)dac_cast<PTR_MethodTable>(pCf->GetParamTypeArg());
3395+
}
3396+
else
3397+
{
3398+
_ASSERTE(paramContextType == GENERIC_PARAM_CONTEXT_THIS);
3399+
GCX_COOP();
3400+
declaringType = (TypeHandle)dac_cast<PTR_MethodTable>(pCf->GetExactGenericArgsToken());
3401+
}
3402+
3403+
_ASSERTE(!declaringType.IsNull());
3404+
3405+
SigTypeContext typeContext(pMD, declaringType);
3406+
3407+
Module* pModule = pMD->GetModule();
3408+
3409+
thResolved = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, pEHClause->ClassToken, &typeContext,
3410+
ClassLoader::ReturnNullIfNotFound);
3411+
}
3412+
}
3413+
3414+
return thResolved;
3415+
}
3416+
#endif // FEATURE_INTERPRETER
3417+
33613418
TypeHandle EECodeGenManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
33623419
CrawlFrame *pCf)
33633420
{

src/coreclr/vm/codeman.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,6 +2795,11 @@ class InterpreterJitManager final : public EECodeGenManager
27952795
OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings,
27962796
OUT ULONG32* pNumRichMappings);
27972797

2798+
#ifndef DACCESS_COMPILE
2799+
virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
2800+
CrawlFrame *pCf);
2801+
#endif // #ifndef DACCESS_COMPILE
2802+
27982803
#if defined(FEATURE_EH_FUNCLETS)
27992804
virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo)
28002805
{
@@ -3059,4 +3064,6 @@ inline TADDR InterpreterJitManager::JitTokenToStartAddress(const METHODTOKEN& Me
30593064

30603065
void ThrowOutOfMemoryWithinRange();
30613066

3067+
bool SafeToReportGenericParamContext(CrawlFrame* pCF);
3068+
30623069
#endif // !__CODEMAN_HPP__

src/coreclr/vm/eetwain.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,22 +2603,47 @@ bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext,
26032603
OBJECTREF InterpreterCodeManager::GetInstance(PREGDISPLAY pContext,
26042604
EECodeInfo * pCodeInfo)
26052605
{
2606-
// Interpreter-TODO: Implement this
2607-
return NULL;
2606+
TADDR baseStackSlot = GetFP(pContext->pCurrentContext);
2607+
return *dac_cast<PTR_OBJECTREF>(baseStackSlot);
26082608
}
26092609

26102610
PTR_VOID InterpreterCodeManager::GetParamTypeArg(PREGDISPLAY pContext,
26112611
EECodeInfo * pCodeInfo)
26122612
{
2613-
// Interpreter-TODO: Implement this
2613+
LIMITED_METHOD_DAC_CONTRACT;
2614+
2615+
GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
2616+
2617+
InterpreterGcInfoDecoder gcInfoDecoder(
2618+
gcInfoToken,
2619+
GcInfoDecoderFlags (DECODE_GENERICS_INST_CONTEXT)
2620+
);
2621+
2622+
INT32 spOffsetGenericsContext = gcInfoDecoder.GetGenericsInstContextStackSlot();
2623+
if (spOffsetGenericsContext != NO_GENERICS_INST_CONTEXT)
2624+
{
2625+
TADDR baseStackSlot = GetFP(pContext->pCurrentContext);
2626+
TADDR taSlot = (TADDR)( spOffsetGenericsContext + baseStackSlot );
2627+
TADDR taExactGenericsToken = *PTR_TADDR(taSlot);
2628+
return PTR_VOID(taExactGenericsToken);
2629+
}
26142630
return NULL;
26152631
}
26162632

26172633
GenericParamContextType InterpreterCodeManager::GetParamContextType(PREGDISPLAY pContext,
26182634
EECodeInfo * pCodeInfo)
26192635
{
2620-
// Interpreter-TODO: Implement this
2621-
return GENERIC_PARAM_CONTEXT_NONE;
2636+
MethodDesc *pMD = pCodeInfo->GetMethodDesc();
2637+
GenericParamContextType paramContextType = GENERIC_PARAM_CONTEXT_NONE;
2638+
2639+
if (pMD->RequiresInstMethodDescArg())
2640+
paramContextType = GENERIC_PARAM_CONTEXT_METHODDESC;
2641+
else if (pMD->RequiresInstMethodTableArg())
2642+
paramContextType = GENERIC_PARAM_CONTEXT_METHODTABLE;
2643+
else if (pMD->AcquiresInstMethodTableFromThis())
2644+
paramContextType = GENERIC_PARAM_CONTEXT_THIS;
2645+
2646+
return paramContextType;
26222647
}
26232648

26242649
size_t InterpreterCodeManager::GetFunctionSize(GCInfoToken gcInfoToken)

src/coreclr/vm/gcenv.ee.common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned en
110110
// there's no context provided by the caller).
111111
// See code:getMethodSigInternal
112112
//
113-
inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
113+
bool SafeToReportGenericParamContext(CrawlFrame* pCF)
114114
{
115115
LIMITED_METHOD_CONTRACT;
116116

0 commit comments

Comments
 (0)