Skip to content

Commit

Permalink
Remove AggressiveOpt from CastHelpers.LdelemaRef/StelemRef (#90412)
Browse files Browse the repository at this point in the history
Co-authored-by: Koundinya Veluri <kouvel@users.noreply.github.com>
  • Loading branch information
EgorBo and kouvel authored Aug 16, 2023
1 parent 63bf69d commit 42862cc
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,6 @@ internal struct ArrayElement
[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ref object? LdelemaRef(Array array, nint index, void* type)
{
// this will throw appropriate exceptions if array is null or access is out of range.
Expand All @@ -427,7 +426,6 @@ internal struct ArrayElement
[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void StelemRef(Array array, nint index, object? obj)
{
// this will throw appropriate exceptions if array is null or access is out of range.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/appdomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,8 @@ void SystemDomain::LoadBaseSystemClasses()
g_pWeakReferenceClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCE);
g_pWeakReferenceOfTClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCEGENERIC);

g_pCastHelpers = CoreLibBinder::GetClass(CLASS__CASTHELPERS);

#ifdef FEATURE_COMINTEROP
if (g_pConfig->IsBuiltInCOMSupported())
{
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/vm/callcounting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,13 @@ bool CallCountingManager::SetCodeEntryPoint(
CallCount callCountThreshold = g_pConfig->TieredCompilation_CallCountThreshold();
_ASSERTE(callCountThreshold != 0);

// Let's tier up all cast helpers faster than other methods. This is because we want to import them as
// direct calls in codegen and they need to be promoted earlier than their callers.
if (methodDesc->GetMethodTable() == g_pCastHelpers)
{
callCountThreshold = max(1, (CallCount)(callCountThreshold / 2));
}

NewHolder<CallCountingInfo> callCountingInfoHolder = new CallCountingInfo(activeCodeVersion, callCountThreshold);
callCountingInfoByCodeVersionHash.Add(callCountingInfoHolder);
callCountingInfo = callCountingInfoHolder.Extract();
Expand Down
19 changes: 2 additions & 17 deletions src/coreclr/vm/ecall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,12 @@ void ECall::PopulateManagedCastHelpers()
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_UNBOX, pDest);

// Array element accessors are more perf sensitive than other managed helpers and indirection
// costs introduced by PreStub could be noticeable (7% to 30% depending on platform).
// Other helpers are either more complex, less common, or have their trivial case inlined by the JIT,
// so indirection is not as big concern.
// We JIT-compile the following helpers eagerly here to avoid indirection costs.

//TODO: revise if this specialcasing is still needed when crossgen supports tailcall optimizations
// see: https://github.com/dotnet/runtime/issues/5857

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__STELEMREF));
pMD->DoPrestub(NULL);
// This helper is marked AggressiveOptimization and its native code is in its final form.
// Get the code directly to avoid PreStub indirection.
pDest = pMD->GetNativeCode();
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_ARRADDR_ST, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__LDELEMAREF));
pMD->DoPrestub(NULL);
// This helper is marked AggressiveOptimization and its native code is in its final form.
// Get the code directly to avoid PreStub indirection.
pDest = pMD->GetNativeCode();
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_LDELEMA_REF, pDest);
}

Expand Down
43 changes: 42 additions & 1 deletion src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10587,6 +10587,14 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
}
#endif

// Check if we already have a cached address of the final target
static LPVOID hlpFinalTierAddrTable[DYNAMIC_CORINFO_HELP_COUNT] = {};
LPVOID finalTierAddr = hlpFinalTierAddrTable[dynamicFtnNum];
if (finalTierAddr != NULL)
{
return finalTierAddr;
}

if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFINTERFACE ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFANY ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFARRAY ||
Expand All @@ -10596,10 +10604,43 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTINTERFACE ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS_SPECIAL ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_UNBOX)
dynamicFtnNum == DYNAMIC_CORINFO_HELP_UNBOX ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_ARRADDR_ST ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_LDELEMA_REF)
{
Precode* pPrecode = Precode::GetPrecodeFromEntryPoint((PCODE)hlpDynamicFuncTable[dynamicFtnNum].pfnHelper);
_ASSERTE(pPrecode->GetType() == PRECODE_FIXUP);

// Check if the target MethodDesc is already jitted to its final Tier
// so we no longer need to use indirections and can emit a direct call instead.
//
// Avoid taking the lock for foreground jit compilations
if (!GetAppDomain()->GetTieredCompilationManager()->IsTieringDelayActive())
{
MethodDesc* helperMD = pPrecode->GetMethodDesc();
_ASSERT(helperMD != nullptr);

CodeVersionManager* manager = helperMD->GetCodeVersionManager();
NativeCodeVersion activeCodeVersion;

{
// Get active code version under a lock
CodeVersionManager::LockHolder codeVersioningLockHolder;
activeCodeVersion = manager->GetActiveILCodeVersion(helperMD).GetActiveNativeCodeVersion(helperMD);
}

if (activeCodeVersion.IsFinalTier())
{
finalTierAddr = (LPVOID)activeCodeVersion.GetNativeCode();
if (finalTierAddr != NULL)
{
// Cache it for future uses to avoid taking the lock again.
hlpFinalTierAddrTable[dynamicFtnNum] = finalTierAddr;
return finalTierAddr;
}
}
}

*ppIndirection = ((FixupPrecode*)pPrecode)->GetTargetSlot();
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/tieredcompilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ class TieredCompilationManager
void BackgroundWorkerStart();

private:
bool IsTieringDelayActive();
bool TryDeactivateTieringDelay();

public:
bool IsTieringDelayActive();
void AsyncCompleteCallCounting();

private:
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ GVAL_IMPL_INIT(DWORD, g_debuggerWordTLSIndex, TLS_OUT_OF_INDEXES);
#endif
GVAL_IMPL_INIT(DWORD, g_TlsIndex, TLS_OUT_OF_INDEXES);

MethodTable* g_pCastHelpers;

#ifndef DACCESS_COMPILE

// <TODO> @TODO - PROMOTE. </TODO>
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ EXTERN OBJECTHANDLE g_pPreallocatedExecutionEngineException;
// we use this as a dummy object to indicate free space in the handle tables -- this object is never visible to the world
EXTERN OBJECTHANDLE g_pPreallocatedSentinelObject;

EXTERN MethodTable* g_pCastHelpers;

GPTR_DECL(Thread,g_pFinalizerThread);
GPTR_DECL(Thread,g_pSuspensionThread);

Expand Down

0 comments on commit 42862cc

Please sign in to comment.