Skip to content
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
16 changes: 16 additions & 0 deletions docs/design/coreclr/botr/clr-abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,22 @@ The extra state created by the JIT for synchronized methods (lock taken flag) mu

EnC is supported for adding and editing generic methods and methods on generic types and generic methods on non-generic types.

# Portable entrypoints

On platforms that allow dynamic code generation, the runtime abstracts away execution strategies for dynamically loaded methods by allocating [`Precode`](method-descriptor.md#precode)s. The `Precode` is a small code fragment that is used as a temporary method entrypoint until the actual method code is acquired. `Precode`s are also used as part of the execution for methods that do not have regular JITed or AOT-compiled code, for example stubs or interpreted methods. `Precode`s allow native code to use the same native code calling convention irrespective of the execution strategy used by the target method.

On platforms that do not allow dynamic code generation (Wasm), the runtime abstracts away execution strategies by allocating portable entrypoints for dynamically loaded methods. The `PortableEntryPoint` is a data structure that allows efficient transition to the desired execution strategy for the target method. When the runtime is configured to use portable entrypoints, the managed calling convention is modified as follows:

- The native code to call is obtained by dereferencing the entrypoint

- The entrypoint address is passed in as an extra last hidden argument. The extra hidden argument must be present in signatures of all methods. It is unused by the code of JITed or AOT-compiled methods.

Pseudo code for a call with portable entrypoints:

> `(*(void**)pfn)(arg0, arg1, ..., argN, pfn)`

Portable entrypoints are used for Wasm with interpreter only currently. Note that portable entrypoints are unnecessary for Wasm with native AOT since native AOT does not support dynamic loading.

# System V x86_64 support

This section relates mostly to calling conventions on System V systems (such as Ubuntu Linux and Mac OS X).
Expand Down
4 changes: 4 additions & 0 deletions eng/OSArch.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<Platform Condition="'$(Platform)' == '' and '$(InferPlatformFromTargetArchitecture)' == 'true'">$(TargetArchitecture)</Platform>
</PropertyGroup>

<PropertyGroup>
<TargetsWasm Condition="'$(TargetArchitecture)' == 'wasm'">true</TargetsWasm>
</PropertyGroup>

<PropertyGroup>
<_ImportedOSArchProps>true</_ImportedOSArchProps>
</PropertyGroup>
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/clr.featuredefines.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
<FeatureCoreCLR>true</FeatureCoreCLR>
<FeaturePerfTracing>true</FeaturePerfTracing>
<FeatureEHFunclets>true</FeatureEHFunclets>
<FeaturePortableEntryPoints>false</FeaturePortableEntryPoints>
<ProfilingSupportedBuild>true</ProfilingSupportedBuild>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetsAndroid)' == 'true' OR '$(Configuration)' == 'debug' OR '$(Configuration)' == 'checked'">
<FeatureJavaMarshal>true</FeatureJavaMarshal>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetsWasm)' == 'true'">
<FeaturePortableEntryPoints>true</FeaturePortableEntryPoints>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
<FeatureXplatEventSource Condition="'$(FeatureXplatEventSource)' == '' AND '$(TargetOS)' == 'linux'">true</FeatureXplatEventSource>
<FeatureComWrappers>true</FeatureComWrappers>
Expand Down Expand Up @@ -43,6 +48,7 @@
<DefineConstants Condition="'$(FeatureTypeEquivalence)' == 'true'">$(DefineConstants);FEATURE_TYPEEQUIVALENCE</DefineConstants>
<DefineConstants Condition="'$(FeatureEHFunclets)' == 'true'">$(DefineConstants);FEATURE_EH_FUNCLETS</DefineConstants>
<DefineConstants Condition="'$(FeatureInterpreter)' == 'true'">$(DefineConstants);FEATURE_INTERPRETER</DefineConstants>
<DefineConstants Condition="'$(FeaturePortableEntryPoints)' == 'true'">$(DefineConstants);FEATURE_PORTABLE_ENTRYPOINTS</DefineConstants>

<DefineConstants Condition="'$(ProfilingSupportedBuild)' == 'true'">$(DefineConstants);PROFILING_SUPPORTED</DefineConstants>
</PropertyGroup>
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_
endif (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64))

add_compile_definitions($<${FEATURE_INTERPRETER}:FEATURE_INTERPRETER>)
if (FEATURE_PORTABLE_ENTRYPOINTS)
add_compile_definitions(FEATURE_PORTABLE_ENTRYPOINTS)
endif()

if (CLR_CMAKE_TARGET_WIN32)
add_definitions(-DFEATURE_ISYM_READER)
Expand Down Expand Up @@ -160,7 +163,9 @@ add_definitions(-DFEATURE_READYTORUN)

set(FEATURE_READYTORUN 1)

add_compile_definitions(FEATURE_REJIT)
if(FEATURE_REJIT)
add_compile_definitions(FEATURE_REJIT)
endif()

if (CLR_CMAKE_HOST_UNIX AND CLR_CMAKE_TARGET_UNIX)
add_definitions(-DFEATURE_REMOTE_PROC_MEM)
Expand All @@ -174,7 +179,11 @@ if (NOT CLR_CMAKE_HOST_ANDROID)
add_definitions(-DFEATURE_SVR_GC)
endif(NOT CLR_CMAKE_HOST_ANDROID)
add_definitions(-DFEATURE_SYMDIFF)
add_compile_definitions(FEATURE_TIERED_COMPILATION)

if (FEATURE_TIERED_COMPILATION)
add_compile_definitions(FEATURE_TIERED_COMPILATION)
endif(FEATURE_TIERED_COMPILATION)

add_compile_definitions(FEATURE_PGO)
if (CLR_CMAKE_TARGET_ARCH_AMD64)
# Enable the AMD64 Unix struct passing JIT-EE interface for all AMD64 platforms, to enable altjit.
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/clrfeatures.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if (NOT CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_MACCATALYST)
set(FEATURE_JIT 1)
set(FEATURE_TIERED_COMPILATION 1)
set(FEATURE_REJIT 1)
endif()

if (CLR_CMAKE_TARGET_ARCH_WASM OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS OR CLR_CMAKE_TARGET_MACCATALYST)
Expand Down Expand Up @@ -39,6 +41,7 @@ if(NOT DEFINED FEATURE_INTERPRETER)
set(FEATURE_INTERPRETER 0)
elseif(CLR_CMAKE_TARGET_ARCH_WASM)
set(FEATURE_INTERPRETER 1)
set(FEATURE_PORTABLE_ENTRYPOINTS 1)
else()
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
set(FEATURE_INTERPRETER $<IF:$<CONFIG:Debug,Checked>,1,0>)
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2233,7 +2233,7 @@ int32_t InterpCompiler::GetDataForHelperFtn(CorInfoHelpFunc ftn)

static_assert(sizeof(InterpHelperData) == sizeof(int32_t), "InterpHelperData must be the same size as an int32_t");

InterpHelperData result;
InterpHelperData result{};
result.accessType = ftnLookup.accessType;
int32_t dataItemIndex = GetDataItemIndex(ftnLookup.addr);
result.addressDataItemIndex = dataItemIndex;
Expand Down Expand Up @@ -6577,8 +6577,8 @@ void InterpCompiler::PrintPointer(void* pointer)

void InterpCompiler::PrintHelperFtn(int32_t _data)
{
InterpHelperData data;
memcpy(&data, &_data, sizeof(int32_t));
InterpHelperData data{};
memcpy(&data, &_data, sizeof(_data));

void *helperAddr = GetDataItemAtIndex(data.addressDataItemIndex);
PrintPointer(helperAddr);
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/interpreter/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ struct InterpMethod
InterpMethod *self;
#endif
CORINFO_METHOD_HANDLE methodHnd;
int32_t argsSize, allocaSize;
int32_t argsSize;
int32_t allocaSize;
void** pDataItems;
// This stub is used for calling the interpreted method from JITted/AOTed code
CallStubHeader *pCallStub;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
peimage.cpp
perfmap.cpp
pgo.cpp
precode_portable.cpp
precode.cpp
prestub.cpp
readytorunstandalonemethodmetadata.cpp
Expand Down Expand Up @@ -215,6 +216,7 @@ set(VM_HEADERS_DAC_AND_WKS_COMMON
peimagelayout.inl
perfmap.h
pgo.h
precode_portable.hpp
precode.h
rejit.h
rejit.inl
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/appdomain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1549,8 +1549,6 @@ class AppDomain final

#endif

#if defined(FEATURE_TIERED_COMPILATION)

public:
TieredCompilationManager * GetTieredCompilationManager()
{
Expand All @@ -1561,8 +1559,6 @@ class AppDomain final
private:
TieredCompilationManager m_tieredCompilationManager;

#endif

friend struct cdac_data<AppDomain>;
}; // class AppDomain

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/vm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,11 @@ void CopyReturnedFpStructFromRegisters(void* dest, UINT64 returnRegs[2], FpStruc
#endif // TARGET_RISCV64 || TARGET_LOONGARCH64

// Helper for VM->managed calls with simple signatures.
void * DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags)
void* DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags)
{
CONTRACTL
{
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/vm/callhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ void CallDescrWorkerWithHandler(
BOOL fCriticalCall = FALSE);

// Helper for VM->managed calls with simple signatures.
void * DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags);
void* DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags);

#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
// Copy structs returned according to floating-point calling convention from 'returnRegs' containing struct fields
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/cdacplatformmetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ void CDacPlatformMetadata::Init()

void CDacPlatformMetadata::InitPrecodes()
{
#ifndef FEATURE_PORTABLE_ENTRYPOINTS
PrecodeMachineDescriptor::Init(&(&g_cdacPlatformMetadata)->precode);
#endif // !FEATURE_PORTABLE_ENTRYPOINTS
}

#endif // !DACCESS_COMPILE
4 changes: 4 additions & 0 deletions src/coreclr/vm/ceemain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,10 @@ void EEStartupHelper()
JITInlineTrackingMap::StaticInitialize();
MethodDescBackpatchInfoTracker::StaticInitialize();
CodeVersionManager::StaticInitialize();
#ifdef FEATURE_TIERED_COMPILATION
TieredCompilationManager::StaticInitialize();
CallCountingManager::StaticInitialize();
#endif // FEATURE_TIERED_COMPILATION
OnStackReplacementManager::StaticInitialize();
MethodTable::InitMethodDataCache();

Expand Down Expand Up @@ -804,9 +806,11 @@ void EEStartupHelper()
CoreLibBinder::Startup();

StubLinkerCPU::Init();
#ifndef FEATURE_PORTABLE_ENTRYPOINTS
StubPrecode::StaticInitialize();
FixupPrecode::StaticInitialize();
CDacPlatformMetadata::InitPrecodes();
#endif // !FEATURE_PORTABLE_ENTRYPOINTS

InitializeGarbageCollector();

Expand Down
19 changes: 12 additions & 7 deletions src/coreclr/vm/codeversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,23 @@ MethodDescVersioningState* NativeCodeVersion::GetMethodDescVersioningState()
}
#endif

bool NativeCodeVersion::IsFinalTier() const
{
LIMITED_METHOD_DAC_CONTRACT;

#ifdef FEATURE_TIERED_COMPILATION
OptimizationTier tier = GetOptimizationTier();
return tier == OptimizationTier1 || tier == OptimizationTierOptimized;
#else // !FEATURE_TIERED_COMPILATION
return true;
#endif // FEATURE_TIERED_COMPILATION
}

#ifdef FEATURE_TIERED_COMPILATION
NativeCodeVersion::OptimizationTier NativeCodeVersion::GetOptimizationTier() const
{
LIMITED_METHOD_DAC_CONTRACT;

if (m_storageKind == StorageKind::Explicit)
{
return AsNode()->GetOptimizationTier();
Expand All @@ -337,13 +349,6 @@ NativeCodeVersion::OptimizationTier NativeCodeVersion::GetOptimizationTier() con
}
}

bool NativeCodeVersion::IsFinalTier() const
{
LIMITED_METHOD_DAC_CONTRACT;
OptimizationTier tier = GetOptimizationTier();
return tier == OptimizationTier1 || tier == OptimizationTierOptimized;
}

#ifndef DACCESS_COMPILE
void NativeCodeVersion::SetOptimizationTier(OptimizationTier tier)
{
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/vm/codeversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class NativeCodeVersion
BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected = 0);
#endif

bool IsFinalTier() const;

// NOTE: Don't change existing values to avoid breaking changes in event tracing
enum OptimizationTier
{
Expand All @@ -83,7 +85,7 @@ class NativeCodeVersion
};
#ifdef FEATURE_TIERED_COMPILATION
OptimizationTier GetOptimizationTier() const;
bool IsFinalTier() const;

#ifndef DACCESS_COMPILE
void SetOptimizationTier(OptimizationTier tier);
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/eeconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class EEConfig
DWORD TieredCompilation_CallCountingDelayMs() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_CallCountingDelayMs; }
bool TieredCompilation_UseCallCountingStubs() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_UseCallCountingStubs; }
DWORD TieredCompilation_DeleteCallCountingStubsAfter() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_DeleteCallCountingStubsAfter; }
#endif
#endif // FEATURE_TIERED_COMPILATION

#if defined(FEATURE_PGO)
bool TieredPGO(void) const { LIMITED_METHOD_CONTRACT; return fTieredPGO; }
Expand Down
33 changes: 24 additions & 9 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,23 +232,38 @@ static OBJECTREF CreateMultiDimArray(MethodTable* arrayClass, int8_t* stack, int
#define LOCAL_VAR(offset,type) (*LOCAL_VAR_ADDR(offset, type))
#define NULL_CHECK(o) do { if ((o) == NULL) { COMPlusThrow(kNullReferenceException); } } while (0)

template <typename THelper> static THelper GetPossiblyIndirectHelper(const InterpMethod *pMethod, int32_t _data)
template <typename THelper> static THelper GetPossiblyIndirectHelper(const InterpMethod* pMethod, int32_t _data, MethodDesc** pILTargetMethod = NULL)
{
InterpHelperData data;
memcpy(&data, &_data, sizeof(int32_t));
InterpHelperData data{};
memcpy(&data, &_data, sizeof(_data));

void *addr = pMethod->pDataItems[data.addressDataItemIndex];
switch (data.accessType) {
void* addr = pMethod->pDataItems[data.addressDataItemIndex];
switch (data.accessType)
{
case IAT_VALUE:
return (THelper)addr;
break;
case IAT_PVALUE:
return *(THelper *)addr;
addr = *(void**)addr;
break;
case IAT_PPVALUE:
return **(THelper **)addr;
addr = **(void***)addr;
break;
default:
COMPlusThrowHR(COR_E_EXECUTIONENGINE);
return (THelper)nullptr;
break;
}

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
if (!PortableEntryPoint::IsNativeEntryPoint((TADDR)addr))
{
_ASSERTE(pILTargetMethod != NULL);
*pILTargetMethod = PortableEntryPoint::GetMethodDesc((TADDR)addr);
return NULL; // Return null to interpret this entrypoint
}
addr = PortableEntryPoint::GetActualCode((TADDR)addr);
#endif // FEATURE_PORTABLE_ENTRYPOINTS

return (THelper)addr;
}

// At present our behavior for float to int conversions is to perform a saturating conversion down to either 32 or 64 bits
Expand Down
Loading
Loading