Skip to content

Commit e206974

Browse files
authored
Separate code manager for the interpreter (#112985)
* Separate code manager for the interpreter This change adds a separate code manager for the interpreted code. Here is an overview of the changes: * A base class EECodeGenManager is extracted from the EEJitManager * A new class InterpreterJitManager derived from the EECodeGenManager is added and implemented. * Similarly, a base class CEECodeGenInfo is extracted from the CEEJitInfo * A new class CInterpreterJitInfo derived from the CEECodeGenInfo is added and implemented * The CodeHeader and RealCodeHeader became base classes and JitCodeHeader, RealJitCodeHeader, InterpreterCodeHeader and RealInterpreterCodeHeader were added. The CodeHeader derivates don't add any extra data, the JitCodeHeader just provides the methods that are needed to access Jit specific members of the RealJitCodeHeader. * The UnsafeJitFunction is refactored so that the interpreter (if enabled) is invoked first and then the AltJit / Jit ones are called. * A new DOTNET_Interpreter, DOTNET_InterpreterPath and DOTNET_InterpreterName env vars are added to match the existing AltJit ones. * Make the code headers independent Make the jit and interpreter code headers independent * Added missing #ifdef * Fix MUSL build break * Rework of the CodeHeader separation The previous way was introducing 5% regression in all exception handling microbenchmarks, this gets us back to the same perf as without any code manager changes. * PR feedback and some cleanup * Fix Unix build failure The clang doesn't do late parsing of the template code, so the helpers cannot be in the .inl file as they reference some types that are not defined yet at that point. * Fix a bug * Fix build break * Add dummy ICodeManager derived InterpreterCodeManager * Remove unused ICodeManager methods * PR feedback * PR feedback * Refactored GC and EH info allocation * Added Interpreter-TODO at some places * Reverted some changes that were not needed anymore * PR Feedback * Get rid of some template usages by small refactoring * Reflect feedback
1 parent 623b8e3 commit e206974

18 files changed

+2321
-1039
lines changed

src/coreclr/debug/daccess/enummem.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,12 @@ HRESULT ClrDataAccess::EnumMemDumpJitManagerInfo(IN CLRDataEnumMemoryFlags flags
318318

319319
if (flags == CLRDATA_ENUM_MEM_HEAP2)
320320
{
321-
EEJitManager* managerPtr = ExecutionManager::GetEEJitManager();
321+
EECodeGenManager* managerPtr = ExecutionManager::GetEEJitManager();
322322
managerPtr->EnumMemoryRegions(flags);
323+
#ifdef FEATURE_INTERPRETER
324+
managerPtr = ExecutionManager::GetInterpreterJitManager();
325+
managerPtr->EnumMemoryRegions(flags);
326+
#endif // FEATURE_INTERPRETER
323327
}
324328

325329
return status;

src/coreclr/inc/clrconfigvalues.h

+6
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,12 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitOs, W("AltJitOS"), "Sets target OS for
325325
RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.")
326326
#endif // defined(ALLOW_SXS_JIT)
327327

328+
#ifdef FEATURE_INTERPRETER
329+
RETAIL_CONFIG_STRING_INFO(EXTERNAL_InterpreterName, W("InterpreterName"), "Primary interpreter to use")
330+
CONFIG_STRING_INFO(INTERNAL_InterpreterPath, W("InterpreterPath"), "Full path to the interpreter to use")
331+
RETAIL_CONFIG_STRING_INFO(EXTERNAL_Interpreter, W("Interpreter"), "Enables Interpreter and selectively limits it to the specified methods.")
332+
#endif // FEATURE_INTERPRETER
333+
328334
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitHostMaxSlabCache, W("JitHostMaxSlabCache"), 0x1000000, "Sets jit host max slab cache size, 16MB default")
329335

330336
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitOptimizeType, W("JitOptimizeType"), 0 /* OPT_DEFAULT */, "")

src/coreclr/inc/dacvars.h

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ DEFINE_DACVAR(PTR_EEJitManager, ExecutionManager__m_pEEJitManager, ExecutionMana
8484
#ifdef FEATURE_READYTORUN
8585
DEFINE_DACVAR(PTR_ReadyToRunJitManager, ExecutionManager__m_pReadyToRunJitManager, ExecutionManager::m_pReadyToRunJitManager)
8686
#endif
87+
#ifdef FEATURE_INTERPRETER
88+
DEFINE_DACVAR(PTR_InterpreterJitManager, ExecutionManager__m_pInterpreterJitManager, ExecutionManager::m_pInterpreterJitManager)
89+
DEFINE_DACVAR(PTR_InterpreterCodeManager, ExecutionManager__m_pInterpreterCodeMan, ExecutionManager::m_pInterpreterCodeMan)
90+
#endif
8791

8892
DEFINE_DACVAR_NO_DUMP(VMHELPDEF *, dac__hlpFuncTable, ::hlpFuncTable)
8993
DEFINE_DACVAR(VMHELPDEF *, dac__hlpDynamicFuncTable, ::hlpDynamicFuncTable)

src/coreclr/inc/eetwain.h

+209-32
Original file line numberDiff line numberDiff line change
@@ -217,17 +217,6 @@ virtual bool IsGcSafe(EECodeInfo *pCodeInfo,
217217
virtual bool HasTailCalls(EECodeInfo *pCodeInfo) = 0;
218218
#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
219219

220-
#if defined(TARGET_AMD64) && defined(_DEBUG)
221-
/*
222-
Locates the end of the last interruptible region in the given code range.
223-
Returns 0 if the entire range is uninterruptible. Returns the end point
224-
if the entire range is interruptible.
225-
*/
226-
virtual unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
227-
unsigned endOffset,
228-
GCInfoToken gcInfoToken) = 0;
229-
#endif // TARGET_AMD64 && _DEBUG
230-
231220
/*
232221
Enumerate all live object references in that function using
233222
the virtual register set. Same reference location cannot be enumerated
@@ -321,11 +310,6 @@ virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) = 0;
321310
#ifndef FEATURE_EH_FUNCLETS
322311
virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)=0;
323312

324-
virtual BOOL IsInFilter(GCInfoToken gcInfoToken,
325-
unsigned offset,
326-
PCONTEXT pCtx,
327-
DWORD curNestLevel) = 0;
328-
329313
virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
330314
unsigned offset,
331315
PCONTEXT pCtx) = 0;
@@ -462,18 +446,6 @@ virtual
462446
bool HasTailCalls(EECodeInfo *pCodeInfo);
463447
#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64)
464448

465-
#if defined(TARGET_AMD64) && defined(_DEBUG)
466-
/*
467-
Locates the end of the last interruptible region in the given code range.
468-
Returns 0 if the entire range is uninterruptible. Returns the end point
469-
if the entire range is interruptible.
470-
*/
471-
virtual
472-
unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
473-
unsigned endOffset,
474-
GCInfoToken gcInfoToken);
475-
#endif // TARGET_AMD64 && _DEBUG
476-
477449
/*
478450
Enumerate all live object references in that function using
479451
the virtual register set. Same reference location cannot be enumerated
@@ -588,10 +560,6 @@ unsigned int GetFrameSize(GCInfoToken gcInfoToken);
588560

589561
#ifndef FEATURE_EH_FUNCLETS
590562
virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg);
591-
virtual BOOL IsInFilter(GCInfoToken gcInfoToken,
592-
unsigned offset,
593-
PCONTEXT pCtx,
594-
DWORD curNestLevel);
595563
virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
596564
unsigned offset,
597565
PCONTEXT pCtx);
@@ -646,6 +614,215 @@ struct CodeManStateBuf
646614

647615
#endif
648616

617+
#ifdef FEATURE_INTERPRETER
618+
619+
class InterpreterCodeManager : public ICodeManager {
620+
621+
VPTR_VTABLE_CLASS_AND_CTOR(InterpreterCodeManager, ICodeManager)
622+
623+
public:
624+
625+
626+
#ifndef DACCESS_COMPILE
627+
#ifndef FEATURE_EH_FUNCLETS
628+
virtual
629+
void FixContext(ContextType ctxType,
630+
EHContext *ctx,
631+
EECodeInfo *pCodeInfo,
632+
DWORD dwRelOffset,
633+
DWORD nestingLevel,
634+
OBJECTREF thrownObject,
635+
CodeManState *pState,
636+
size_t ** ppShadowSP, // OUT
637+
size_t ** ppEndRegion) // OUT
638+
{
639+
// Interpreter-TODO: Implement this if needed
640+
_ASSERTE(FALSE);
641+
}
642+
#endif // !FEATURE_EH_FUNCLETS
643+
#endif // !DACCESS_COMPILE
644+
645+
#ifdef TARGET_X86
646+
/*
647+
Gets the ambient stack pointer value at the given nesting level within
648+
the method.
649+
*/
650+
virtual
651+
TADDR GetAmbientSP(PREGDISPLAY pContext,
652+
EECodeInfo *pCodeInfo,
653+
DWORD dwRelOffset,
654+
DWORD nestingLevel,
655+
CodeManState *pState)
656+
{
657+
// Interpreter-TODO: Implement this if needed
658+
_ASSERTE(FALSE);
659+
return NULL;
660+
}
661+
#endif // TARGET_X86
662+
663+
virtual
664+
ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo)
665+
{
666+
// Interpreter-TODO: Implement this if needed
667+
_ASSERTE(FALSE);
668+
return 0;
669+
}
670+
671+
virtual
672+
bool UnwindStackFrame(
673+
PREGDISPLAY pContext,
674+
EECodeInfo *pCodeInfo,
675+
unsigned flags,
676+
CodeManState *pState);
677+
678+
virtual
679+
bool IsGcSafe( EECodeInfo *pCodeInfo,
680+
DWORD dwRelOffset);
681+
682+
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
683+
virtual
684+
bool HasTailCalls(EECodeInfo *pCodeInfo)
685+
{
686+
_ASSERTE(FALSE);
687+
return false;
688+
}
689+
#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64)
690+
691+
virtual
692+
bool EnumGcRefs(PREGDISPLAY pContext,
693+
EECodeInfo *pCodeInfo,
694+
unsigned flags,
695+
GCEnumCallback pCallback,
696+
LPVOID hCallBack,
697+
DWORD relOffsetOverride = NO_OVERRIDE_OFFSET);
698+
699+
virtual
700+
OBJECTREF GetInstance(
701+
PREGDISPLAY pContext,
702+
EECodeInfo * pCodeInfo);
703+
704+
virtual
705+
PTR_VOID GetParamTypeArg(PREGDISPLAY pContext,
706+
EECodeInfo * pCodeInfo);
707+
708+
virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext,
709+
EECodeInfo * pCodeInfo);
710+
711+
virtual
712+
void * GetGSCookieAddr(PREGDISPLAY pContext,
713+
EECodeInfo * pCodeInfo,
714+
unsigned flags,
715+
CodeManState * pState)
716+
{
717+
// Interpreter-TODO: Implement this if needed
718+
_ASSERTE(FALSE);
719+
return NULL;
720+
}
721+
722+
723+
#ifndef USE_GC_INFO_DECODER
724+
virtual
725+
bool IsInPrologOrEpilog(
726+
DWORD relOffset,
727+
GCInfoToken gcInfoToken,
728+
size_t* prologSize)
729+
{
730+
// Interpreter-TODO: Implement this if needed
731+
_ASSERTE(FALSE);
732+
return false;
733+
}
734+
735+
virtual
736+
bool IsInSynchronizedRegion(
737+
DWORD relOffset,
738+
GCInfoToken gcInfoToken,
739+
unsigned flags)
740+
{
741+
// Interpreter-TODO: Implement this if needed
742+
_ASSERTE(FALSE);
743+
return false;
744+
}
745+
#endif // !USE_GC_INFO_DECODER
746+
747+
virtual
748+
size_t GetFunctionSize(GCInfoToken gcInfoToken);
749+
750+
virtual bool GetReturnAddressHijackInfo(GCInfoToken gcInfoToken X86_ARG(ReturnKind * returnKind))
751+
{
752+
// Interpreter-TODO: Implement this if needed
753+
_ASSERTE(FALSE);
754+
return false;
755+
}
756+
757+
#ifndef USE_GC_INFO_DECODER
758+
759+
virtual
760+
unsigned int GetFrameSize(GCInfoToken gcInfoToken)
761+
{
762+
// Interpreter-TODO: Implement this if needed
763+
_ASSERTE(FALSE);
764+
return 0;
765+
}
766+
#endif // USE_GC_INFO_DECODER
767+
768+
#ifndef DACCESS_COMPILE
769+
770+
#ifndef FEATURE_EH_FUNCLETS
771+
virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)
772+
{
773+
// Interpreter-TODO: Implement this if needed
774+
_ASSERTE(FALSE);
775+
return NULL;
776+
}
777+
778+
virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
779+
unsigned offset,
780+
PCONTEXT pCtx)
781+
{
782+
// Interpreter-TODO: Implement this if needed
783+
_ASSERTE(FALSE);
784+
return FALSE;
785+
}
786+
787+
virtual void LeaveCatch(GCInfoToken gcInfoToken,
788+
unsigned offset,
789+
PCONTEXT pCtx)
790+
{
791+
// Interpreter-TODO: Implement this if needed
792+
_ASSERTE(FALSE);
793+
}
794+
#endif // FEATURE_EH_FUNCLETS
795+
796+
#ifdef FEATURE_REMAP_FUNCTION
797+
798+
virtual
799+
HRESULT FixContextForEnC(PCONTEXT pCtx,
800+
EECodeInfo * pOldCodeInfo,
801+
const ICorDebugInfo::NativeVarInfo * oldMethodVars,
802+
SIZE_T oldMethodVarsCount,
803+
EECodeInfo * pNewCodeInfo,
804+
const ICorDebugInfo::NativeVarInfo * newMethodVars,
805+
SIZE_T newMethodVarsCount)
806+
{
807+
// Interpreter-TODO: Implement this
808+
_ASSERTE(FALSE);
809+
return E_NOTIMPL;
810+
}
811+
#endif // FEATURE_REMAP_FUNCTION
812+
813+
#endif // !DACCESS_COMPILE
814+
815+
#ifdef DACCESS_COMPILE
816+
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
817+
{
818+
// Nothing to do
819+
}
820+
#endif
821+
822+
};
823+
824+
#endif // FEATURE_INTERPRETER
825+
649826
//*****************************************************************************
650827
#endif // _EETWAIN_H
651828
//*****************************************************************************

src/coreclr/inc/vptr_list.h

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ VPTR_CLASS(EEJitManager)
99
#ifdef FEATURE_READYTORUN
1010
VPTR_CLASS(ReadyToRunJitManager)
1111
#endif
12+
#ifdef FEATURE_INTERPRETER
13+
VPTR_CLASS(InterpreterJitManager)
14+
VPTR_CLASS(InterpreterCodeManager)
15+
#endif
1216
VPTR_CLASS(EECodeManager)
1317

1418
VPTR_CLASS(RangeList)

src/coreclr/interpreter/eeinterp.cpp

+2-7
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd,
6666

6767
// TODO: replace this by something like the JIT does to support multiple methods being specified and we don't
6868
// keep fetching it on each call to compileMethod
69-
const char *methodToInterpret = g_interpHost->getStringConfigValue("AltJit");
69+
const char *methodToInterpret = g_interpHost->getStringConfigValue("Interpreter");
7070
doInterpret = (methodName != NULL && strcmp(methodName, methodToInterpret) == 0);
7171
g_interpHost->freeStringConfigValue(methodToInterpret);
7272
if (doInterpret)
@@ -90,9 +90,7 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd,
9090
uint32_t sizeOfCode = sizeof(InterpMethod*) + IRCodeSize * sizeof(int32_t);
9191
uint8_t unwindInfo[8] = {0, 0, 0, 0, 0, 0, 0, 0};
9292

93-
// TODO: get rid of the need to allocate fake unwind info.
94-
compHnd->reserveUnwindInfo(false /* isFunclet */, false /* isColdCode */ , sizeof(unwindInfo) /* unwindSize */);
95-
AllocMemArgs args;
93+
AllocMemArgs args {};
9694
args.hotCodeSize = sizeOfCode;
9795
args.coldCodeSize = 0;
9896
args.roDataSize = 0;
@@ -104,9 +102,6 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd,
104102
*(InterpMethod**)args.hotCodeBlockRW = pMethod;
105103
memcpy ((uint8_t*)args.hotCodeBlockRW + sizeof(InterpMethod*), pIRCode, IRCodeSize * sizeof(int32_t));
106104

107-
// TODO: get rid of the need to allocate fake unwind info
108-
compHnd->allocUnwindInfo((uint8_t*)args.hotCodeBlock, (uint8_t*)args.coldCodeBlock, 0, 1, sizeof(unwindInfo), unwindInfo, CORJIT_FUNC_ROOT);
109-
110105
*entryAddress = (uint8_t*)args.hotCodeBlock;
111106
*nativeSizeOfCode = sizeOfCode;
112107

0 commit comments

Comments
 (0)