Skip to content

Stub Precode variant for DynamicHelpers #113402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 19, 2025
Merged
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
3 changes: 3 additions & 0 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_
add_definitions(-DFEATURE_SPECIAL_USER_MODE_APC)
endif()

if (FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
add_definitions(-DFEATURE_STUBPRECODE_DYNAMIC_HELPERS)
endif()

# Use this function to enable building with a specific target OS and architecture set of defines
# This is known to work for the set of defines used by the JIT and gcinfo, it is not likely correct for
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/clrfeatures.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ if (CLR_CMAKE_HOST_UNIX AND CLR_CMAKE_HOST_ARCH_AMD64)
# Allow 16 byte compare-exchange (cmpxchg16b)
add_compile_options($<${FEATURE_CORECLR_CACHED_INTERFACE_DISPATCH}:-mcx16>)
endif()

if (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
set(FEATURE_STUBPRECODE_DYNAMIC_HELPERS 1)
endif()
7 changes: 6 additions & 1 deletion src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3674,6 +3674,9 @@ static const char *LoaderAllocatorLoaderHeapNames[] =
"ExecutableHeap",
"FixupPrecodeHeap",
"NewStubPrecodeHeap",
#if defined(FEATURE_READYTORUN) && defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
"DynamicHelpersStubHeap",
#endif // defined(FEATURE_READYTORUN) && defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
"IndcellHeap",
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH
"CacheEntryHeap",
Expand Down Expand Up @@ -3711,7 +3714,9 @@ HRESULT ClrDataAccess::GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocatorAd
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetFixupPrecodeHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetNewStubPrecodeHeap());

#if defined(FEATURE_READYTORUN) && defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetDynamicHelpersStubHeap());
#endif // defined(FEATURE_READYTORUN) && defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
VirtualCallStubManager *pVcsMgr = pLoaderAllocator->GetVirtualCallStubManager();
if (pVcsMgr == nullptr)
{
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/ExternalMethodFixupThunk.asm
${ARCH_SOURCES_DIR}/UMThunkStub.asm
${ARCH_SOURCES_DIR}/VirtualCallStubAMD64.asm
${ARCH_SOURCES_DIR}/StubPrecodeDynamicHelpers.asm
)

set(VM_HEADERS_WKS_ARCH_ASM
Expand Down Expand Up @@ -666,7 +667,8 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
${RUNTIME_DIR}/${ARCH_SOURCES_DIR}/StubDispatch.asm
${ARCH_SOURCES_DIR}/thunktemplates.asm
${ARCH_SOURCES_DIR}/CachedInterfaceDispatchCoreCLR.asm
)
${ARCH_SOURCES_DIR}/StubPrecodeDynamicHelpers.asm
)

set(VM_HEADERS_WKS_ARCH_ASM
${ARCH_SOURCES_DIR}/asmconstants.h
Expand Down Expand Up @@ -697,6 +699,7 @@ else(CLR_CMAKE_TARGET_WIN32)
${ARCH_SOURCES_DIR}/unixasmhelpers.S
${ARCH_SOURCES_DIR}/umthunkstub.S
${ARCH_SOURCES_DIR}/virtualcallstubamd64.S
${ARCH_SOURCES_DIR}/StubPrecodeDynamicHelpers.S
)
elseif(CLR_CMAKE_TARGET_ARCH_I386)
set(VM_SOURCES_WKS_ARCH_ASM
Expand Down Expand Up @@ -725,6 +728,7 @@ else(CLR_CMAKE_TARGET_WIN32)
${ARCH_SOURCES_DIR}/pinvokestubs.S
${RUNTIME_DIR}/${ARCH_SOURCES_DIR}/StubDispatch.S
${ARCH_SOURCES_DIR}/thunktemplates.S
${ARCH_SOURCES_DIR}/StubPrecodeDynamicHelpers.S
)
elseif(CLR_CMAKE_TARGET_ARCH_LOONGARCH64)
set(VM_SOURCES_WKS_ARCH_ASM
Expand Down
264 changes: 264 additions & 0 deletions src/coreclr/vm/amd64/StubPrecodeDynamicHelpers.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.intel_syntax noprefix
#include "unixasmmacros.inc"
#include "asmconstants.h"

#ifdef FEATURE_STUBPRECODE_DYNAMIC_HELPERS

#define SecretArg_Reg r10
#define FirstArg_Reg rdi
#define SecondArg_Reg rsi
#define SecondArg_DwordReg esi
#define ThirdArg_Reg rdx
#define ThirdArg_DwordReg edx
#define FourthArg_Reg rcx

#define DATA_SLOT(field) r10 + OFFSETOF__DynamicHelperStubArgs__ ## field
#define GENERIC_DICT_DATA_SLOT(field) r10 + OFFSETOF__GenericDictionaryDynamicHelperStubData__ ## field

LEAF_ENTRY DynamicHelper_CallHelper_1Arg, _TEXT
mov FirstArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_1Arg, _TEXT

LEAF_ENTRY DynamicHelper_CallHelper_AddSecondArg, _TEXT
mov SecondArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_AddSecondArg, _TEXT

LEAF_ENTRY DynamicHelper_CallHelper_2Arg, _TEXT
mov FirstArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
mov SecondArg_Reg, QWORD PTR [DATA_SLOT(Constant2)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_2Arg, _TEXT

LEAF_ENTRY DynamicHelper_CallHelper_ArgMove, _TEXT
mov SecondArg_Reg, FirstArg_Reg
mov FirstArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_ArgMove, _TEXT

LEAF_ENTRY DynamicHelper_Return, _TEXT
ret
LEAF_END DynamicHelper_Return, _TEXT

LEAF_ENTRY DynamicHelper_ReturnConst, _TEXT
mov rax, SecretArg_Reg
ret
LEAF_END DynamicHelper_ReturnConst, _TEXT

LEAF_ENTRY DynamicHelper_ReturnIndirConst, _TEXT
mov rax, QWORD PTR [SecretArg_Reg]
ret
LEAF_END DynamicHelper_ReturnIndirConst, _TEXT

LEAF_ENTRY DynamicHelper_ReturnIndirConstWithOffset, _TEXT
mov rax, QWORD PTR [DATA_SLOT(Constant1)]
mov rax, QWORD PTR [rax]
add rax, QWORD PTR [DATA_SLOT(Constant2)]
ret
LEAF_END DynamicHelper_ReturnIndirConstWithOffset, _TEXT

LEAF_ENTRY DynamicHelper_CallHelper_AddThirdArg, _TEXT
mov ThirdArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_AddThirdArg, _TEXT

LEAF_ENTRY DynamicHelper_CallHelper_AddThirdAndFourthArg, _TEXT
mov ThirdArg_Reg, QWORD PTR [DATA_SLOT(Constant1)]
mov FourthArg_Reg, QWORD PTR [DATA_SLOT(Constant2)]
jmp QWORD PTR [DATA_SLOT(Helper)]
LEAF_END DynamicHelper_CallHelper_AddThirdAndFourthArg, _TEXT

// Generic dictionaries can have 2 or 3 indirections (5 indirs of 32bit size, and 2 8 byte quantities) = 40 bytes
// If it has 2 its for a Method, and the first indirection is always offsetof(InstantiatiedMethodDesc, m_pPerInstInfo)
// If it has 3 its for a Class, and the first indirection is always MethodTable::GetOffsetOfPerInstInfo
// It can also have 0, 0, to just return the class type
// Test For Null Or Not (If not present, cannot have a size check)
// SizeCheck or not (Only needed if size > Some number)
//
// Also special case where we just return the TypeHandle or MethodDesc itself
// Should probably have special case for 1, 2, 3 generic arg of MethodDesc/MethodTable

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SecondIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// SizeCheck
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SizeOffset)]
mov ThirdArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SlotOffset)]
cmp qword ptr[rax + SecondArg_Reg], ThirdArg_Reg
jle LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull_HelperCall)
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Null test
test rax, rax
je LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull_HelperCall)
ret
LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull_HelperCall):
mov SecondArg_Reg, QWORD PTR [GENERIC_DICT_DATA_SLOT(HandleArgs)]
PREPARE_EXTERNAL_VAR g_pClassWithSlotAndModule, rax
jmp [rax]
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_TestForNull, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SecondIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Null test
test rax, rax
je LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Class_TestForNull_HelperCall)
ret
LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Class_TestForNull_HelperCall):
mov SecondArg_Reg, QWORD PTR [GENERIC_DICT_DATA_SLOT(HandleArgs)]
PREPARE_EXTERNAL_VAR g_pClassWithSlotAndModule, rax
jmp [rax]
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_TestForNull, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SecondIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Class, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// SizeCheck
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SizeOffset)]
mov ThirdArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(SlotOffset)]
cmp qword ptr[rax + SecondArg_Reg], ThirdArg_Reg
jle LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull_HelperCall)
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Null test
test rax, rax
je LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull_HelperCall)
ret
LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull_HelperCall):
mov SecondArg_Reg, QWORD PTR [GENERIC_DICT_DATA_SLOT(HandleArgs)]
PREPARE_EXTERNAL_VAR g_pMethodWithSlotAndModule, rax
jmp [rax]
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_TestForNull, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
// Null test
test rax, rax
je LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Method_TestForNull_HelperCall)
ret
LOCAL_LABEL(DynamicHelper_GenericDictionaryLookup_Method_TestForNull_HelperCall):
mov SecondArg_Reg, QWORD PTR [GENERIC_DICT_DATA_SLOT(HandleArgs)]
PREPARE_EXTERNAL_VAR g_pMethodWithSlotAndModule, rax
jmp [rax]
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_TestForNull, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov SecondArg_DwordReg, DWORD PTR [GENERIC_DICT_DATA_SLOT(LastIndir)]
mov rax, QWORD PTR [SecondArg_Reg+rax]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Method, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_0_0, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax]
// Standard Indirection
mov rax, QWORD PTR [rax]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_0_0, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_0_1, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x8]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_0_1, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_0_2, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x10]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_0_2, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Class_0_3, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__MethodTable__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x18]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Class_0_3, _TEXT

LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_0, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_0, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_1, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x8]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_1, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_2, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x10]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_2, _TEXT


LEAF_ENTRY DynamicHelper_GenericDictionaryLookup_Method_3, _TEXT
// First indirection
mov rax, QWORD PTR [FirstArg_Reg+OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo]
// Standard Indirection
mov rax, QWORD PTR [rax + 0x18]
ret
LEAF_END DynamicHelper_GenericDictionaryLookup_Method_3, _TEXT

#endif //// FEATURE_STUBPRECODE_DYNAMIC_HELPERS
Loading
Loading