Skip to content
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

Simplify "secret stub arg" handling between JIT and EE #100823

Merged
merged 19 commits into from
May 12, 2024
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
2 changes: 1 addition & 1 deletion eng/native/sanitizer-ignorelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ fun:_ZN11CMiniMdBase19UsesAllocatedMemoryEP11CMiniColDef
# 2 0x4e8051 in __ubsan_handle_dynamic_type_cache_miss
# 3 0x7f02ce676cd8 in JIT_InitPInvokeFrame(InlinedCallFrame*, void*) /home/steveharter/git/dotnet_coreclr/vm/jithelpers.cpp:6491:9
# 4 0x7f0252bbceb2 (<unknown module>)
fun:_Z20JIT_InitPInvokeFrameP16InlinedCallFramePv
fun:_Z20JIT_InitPInvokeFrameP16InlinedCallFrame

4 changes: 4 additions & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1754,13 +1754,17 @@ struct CORINFO_EE_INFO
// Size of the Frame structure
unsigned size;

// Size of the Frame structure when it also contains the secret stub arg
unsigned sizeWithSecretStubArg;

unsigned offsetOfGSCookie;
unsigned offsetOfFrameVptr;
unsigned offsetOfFrameLink;
unsigned offsetOfCallSiteSP;
unsigned offsetOfCalleeSavedFP;
unsigned offsetOfCallTarget;
unsigned offsetOfReturnAddress;
unsigned offsetOfSecretStubArg;
// This offset is used only for ARM
unsigned offsetOfSPAfterProlog;
}
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

constexpr GUID JITEEVersionIdentifier = { /* 43854594-cd60-45df-a89f-5b7697586f46 */
0x43854594,
0xcd60,
0x45df,
{0xa8, 0x9f, 0x5b, 0x76, 0x97, 0x58, 0x6f, 0x46}
constexpr GUID JITEEVersionIdentifier = { /* 227e46fa-1be3-4770-b613-4a239e7c28aa */
0x227e46fa,
0x1be3,
0x4770,
{0xb6, 0x13, 0x4a, 0x23, 0x9e, 0x7c, 0x28, 0xaa}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class CodeGen final : public CodeGenInterface

var_types genParamStackStoreType(LclVarDsc* dsc, const ABIPassingSegment& seg);
void genSpillOrAddRegisterParam(unsigned lclNum, class RegGraph* graph);
void genSpillOrAddNonStandardRegisterParam(unsigned lclNum, regNumber sourceReg, class RegGraph* graph);
void genEnregisterIncomingStackArgs();
#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
void genEnregisterOSRArgsAndLocals(regNumber initReg, bool* pInitRegZeroed);
Expand Down
53 changes: 36 additions & 17 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3246,6 +3246,31 @@ void CodeGen::genSpillOrAddRegisterParam(unsigned lclNum, RegGraph* graph)
}
}

// -----------------------------------------------------------------------------
// genSpillOrAddNonStandardRegisterParam: Handle a non-standard register parameter either
// by homing it to stack immediately, or by adding it to the register graph.
//
// Parameters:
// lclNum - Local that represents the non-standard parameter
// sourceReg - Register that the non-standard parameter is in on entry to the function
// graph - The register graph to add to
//
void CodeGen::genSpillOrAddNonStandardRegisterParam(unsigned lclNum, regNumber sourceReg, RegGraph* graph)
{
LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
{
GetEmitter()->emitIns_S_R(ins_Store(varDsc->TypeGet()), emitActualTypeSize(varDsc), sourceReg, lclNum, 0);
}

if (varDsc->lvIsInReg())
{
RegNode* sourceRegNode = graph->GetOrAdd(sourceReg);
RegNode* destRegNode = graph->GetOrAdd(varDsc->GetRegNum());
graph->AddEdge(sourceRegNode, destRegNode, TYP_I_IMPL, 0);
}
}

// -----------------------------------------------------------------------------
// genHomeRegisterParams: Move all register parameters to their initial
// assigned location.
Expand Down Expand Up @@ -3289,6 +3314,12 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
}
}

if (compiler->info.compPublishStubParam && ((paramRegs & RBM_SECRET_STUB_PARAM) != RBM_NONE))
{
GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SECRET_STUB_PARAM,
compiler->lvaStubArgumentVar, 0);
}

return;
}

Expand Down Expand Up @@ -3321,6 +3352,11 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
}
}

if (compiler->info.compPublishStubParam && ((paramRegs & RBM_SECRET_STUB_PARAM) != RBM_NONE))
{
genSpillOrAddNonStandardRegisterParam(compiler->lvaStubArgumentVar, REG_SECRET_STUB_PARAM, &graph);
}

DBEXEC(VERBOSE, graph.Dump());

regMaskTP busyRegs = intRegState.rsCalleeRegArgMaskLiveIn | floatRegState.rsCalleeRegArgMaskLiveIn;
Expand Down Expand Up @@ -3784,13 +3820,6 @@ void CodeGen::genCheckUseBlockInit()
{
regMaskTP maskCalleeRegArgMask = intRegState.rsCalleeRegArgMaskLiveIn;

// If there is a secret stub param, don't count it, as it will no longer
// be live when we do block init.
if (compiler->info.compPublishStubParam)
{
maskCalleeRegArgMask &= ~RBM_SECRET_STUB_PARAM;
}

#ifdef TARGET_ARM
//
// On the Arm if we are using a block init to initialize, then we
Expand Down Expand Up @@ -5572,16 +5601,6 @@ void CodeGen::genFnProlog()
}
#endif // TARGET_ARM

if (compiler->info.compPublishStubParam)
{
GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SECRET_STUB_PARAM,
compiler->lvaStubArgumentVar, 0);
assert(intRegState.rsCalleeRegArgMaskLiveIn & RBM_SECRET_STUB_PARAM);

// It's no longer live; clear it out so it can be used after this in the prolog
intRegState.rsCalleeRegArgMaskLiveIn &= ~RBM_SECRET_STUB_PARAM;
}

//
// Zero out the frame as needed
//
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4602,11 +4602,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
assert(lvaStubArgumentVar == BAD_VAR_NUM);
lvaStubArgumentVar = lvaGrabTempWithImplicitUse(false DEBUGARG("stub argument"));
lvaGetDesc(lvaStubArgumentVar)->lvType = TYP_I_IMPL;
// TODO-CQ: there is no need to mark it as doNotEnreg. There are no stores for this local
// before codegen so liveness and LSRA mark it as "liveIn" and always allocate a stack slot for it.
// However, it would be better to process it like other argument locals and keep it in
// a reg for the whole method without spilling to the stack when possible.
lvaSetVarDoNotEnregister(lvaStubArgumentVar DEBUGARG(DoNotEnregisterReason::VMNeedsStackAddr));
}
};
DoPhase(this, PHASE_PRE_IMPORT, preImportPhase);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4243,7 +4243,7 @@ class Compiler
return lvaGetDesc(lclNum)->lvInSsa;
}

unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
unsigned lvaStubArgumentVar; // variable representing the secret stub argument

unsigned lvaPSPSym; // variable representing the PSPSym

Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2438,7 +2438,10 @@ PhaseStatus Compiler::fgAddInternal()

LclVarDsc* varDsc = lvaGetDesc(lvaInlinedPInvokeFrameVar);
// Make room for the inlined frame.
lvaSetStruct(lvaInlinedPInvokeFrameVar, typGetBlkLayout(eeGetEEInfo()->inlinedCallFrameInfo.size), false);
const CORINFO_EE_INFO* eeInfo = eeGetEEInfo();
unsigned frameSize = info.compPublishStubParam ? eeInfo->inlinedCallFrameInfo.sizeWithSecretStubArg
: eeInfo->inlinedCallFrameInfo.size;
lvaSetStruct(lvaInlinedPInvokeFrameVar, typGetBlkLayout(frameSize), false);
}

// Do we need to insert a "JustMyCode" callback?
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13136,8 +13136,6 @@ const char* Compiler::gtGetWellKnownArgNameForArgMsg(WellKnownArg arg)
return "retbuf";
case WellKnownArg::PInvokeFrame:
return "pinv frame";
case WellKnownArg::SecretStubParam:
return "stub param";
case WellKnownArg::WrapperDelegateCell:
return "wrap cell";
case WellKnownArg::ShiftLow:
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4465,7 +4465,6 @@ enum class WellKnownArg : unsigned
InstParam,
RetBuffer,
PInvokeFrame,
SecretStubParam,
WrapperDelegateCell,
ShiftLow,
ShiftHigh,
Expand Down
35 changes: 0 additions & 35 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6694,22 +6694,6 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
continue;
}

// This should be low on the stack. Hence, it will be assigned later.
if (lclNum == lvaStubArgumentVar)
{
#ifdef JIT32_GCENCODER
noway_assert(codeGen->isFramePointerUsed());
#endif
continue;
}

// This should be low on the stack. Hence, it will be assigned later.
if (lclNum == lvaInlinedPInvokeFrameVar)
{
noway_assert(codeGen->isFramePointerUsed());
continue;
}

if (varDsc->lvIsParam)
{
#ifdef TARGET_ARM64
Expand Down Expand Up @@ -6852,25 +6836,6 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
*-------------------------------------------------------------------------
*/

// lvaInlinedPInvokeFrameVar and lvaStubArgumentVar need to be assigned last
// Important: The stack walker depends on lvaStubArgumentVar immediately
// following lvaInlinedPInvokeFrameVar in the frame.

if (lvaStubArgumentVar != BAD_VAR_NUM)
{
#ifdef JIT32_GCENCODER
noway_assert(codeGen->isFramePointerUsed());
#endif
stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaStubArgumentVar, lvaLclSize(lvaStubArgumentVar), stkOffs);
}

if (lvaInlinedPInvokeFrameVar != BAD_VAR_NUM)
{
noway_assert(codeGen->isFramePointerUsed());
stkOffs =
lvaAllocLocalAndSetVirtualOffset(lvaInlinedPInvokeFrameVar, lvaLclSize(lvaInlinedPInvokeFrameVar), stkOffs);
}

#ifdef JIT32_GCENCODER
// JIT32 encoder cannot handle GS cookie at fp+0 since NO_GS_COOKIE == 0.
// Add some padding if it is the last allocated local.
Expand Down
78 changes: 30 additions & 48 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5515,7 +5515,7 @@ GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
const CORINFO_EE_INFO::InlinedCallFrameInfo& callFrameInfo = pInfo->inlinedCallFrameInfo;

GenTree* TCB = new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot);
GenTree* TCB = comp->gtNewLclVarNode(comp->info.compLvFrameListRoot, TYP_I_IMPL);

// Thread->m_pFrame
GenTree* addr = new (comp, GT_LEA) GenTreeAddrMode(TYP_I_IMPL, TCB, nullptr, 1, pInfo->offsetOfThreadFrame);
Expand All @@ -5525,18 +5525,17 @@ GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
if (action == PushFrame)
{
// Thread->m_pFrame = &inlinedCallFrame;
data = new (comp, GT_LCL_ADDR)
GenTreeLclFld(GT_LCL_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
data = comp->gtNewLclAddrNode(comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
}
else
{
assert(action == PopFrame);
// Thread->m_pFrame = inlinedCallFrame.m_pNext;

data = new (comp, GT_LCL_FLD) GenTreeLclFld(GT_LCL_FLD, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
data = comp->gtNewLclFldNode(comp->lvaInlinedPInvokeFrameVar, TYP_I_IMPL,
pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
}
GenTree* storeInd = new (comp, GT_STOREIND) GenTreeStoreInd(TYP_I_IMPL, addr, data);
GenTree* storeInd = comp->gtNewStoreIndNode(TYP_I_IMPL, addr, data);
return storeInd;
}

Expand All @@ -5558,28 +5557,22 @@ GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
// +08h +04h vptr for class InlinedCallFrame offsetOfFrameVptr method prolog
// +10h +08h m_Next offsetOfFrameLink method prolog
// +18h +0Ch m_Datum offsetOfCallTarget call site
// +20h n/a m_StubSecretArg not set by JIT
// +28h +10h m_pCallSiteSP offsetOfCallSiteSP x86: call site, and zeroed in method
// +20h +10h m_pCallSiteSP offsetOfCallSiteSP x86: call site, and zeroed in method
// prolog;
// non-x86: method prolog (SP remains
// constant in function, after prolog: no
// localloc and PInvoke in same function)
// +30h +14h m_pCallerReturnAddress offsetOfReturnAddress call site
// +38h +18h m_pCalleeSavedFP offsetOfCalleeSavedFP not set by JIT
// +1Ch m_pThread
// +28h +14h m_pCallerReturnAddress offsetOfReturnAddress call site
// +30h +18h m_pCalleeSavedFP offsetOfCalleeSavedFP not set by JIT
// +38h +1Ch m_pThread
// +20h m_pSPAfterProlog offsetOfSPAfterProlog arm only
// +20/24h JIT retval spill area (int) before call_gc ???
// +24/28h JIT retval spill area (long) before call_gc ???
// +28/2Ch Saved value of EBP method prolog ???
// +40h +20/24h m_StubSecretArg offsetOfSecretStubArg method prolog of IL stubs with secret arg
//
// Note that in the VM, InlinedCallFrame is a C++ class whose objects have a 'this' pointer that points
// to the InlinedCallFrame vptr (the 2nd field listed above), and the GS cookie is stored *before*
// the object. When we link the InlinedCallFrame onto the Frame chain, we must point at this location,
// and not at the beginning of the InlinedCallFrame local, which is actually the GS cookie.
//
// Return Value:
// none
//
// See the usages for USE_PER_FRAME_PINVOKE_INIT for more information.
void Lowering::InsertPInvokeMethodProlog()
{
Expand All @@ -5601,47 +5594,38 @@ void Lowering::InsertPInvokeMethodProlog()
const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
const CORINFO_EE_INFO::InlinedCallFrameInfo& callFrameInfo = pInfo->inlinedCallFrameInfo;

// First arg: &compiler->lvaInlinedPInvokeFrameVar + callFrameInfo.offsetOfFrameVptr
#if defined(DEBUG)
const LclVarDsc* inlinedPInvokeDsc = comp->lvaGetDesc(comp->lvaInlinedPInvokeFrameVar);
assert(inlinedPInvokeDsc->IsAddressExposed());
#endif // DEBUG
GenTree* frameAddr = new (comp, GT_LCL_ADDR)
GenTreeLclFld(GT_LCL_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
assert(comp->lvaGetDesc(comp->lvaInlinedPInvokeFrameVar)->IsAddressExposed());

// Call runtime helper to fill in our InlinedCallFrame and push it on the Frame list:
// TCB = CORINFO_HELP_INIT_PINVOKE_FRAME(&symFrameStart, secretArg);
GenTreeCall* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL);
GenTree* const insertionPoint = firstBlockRange.FirstNonCatchArgNode();

NewCallArg frameAddrArg = NewCallArg::Primitive(frameAddr).WellKnown(WellKnownArg::PInvokeFrame);
call->gtArgs.PushBack(comp, frameAddrArg);
// for x86/arm32 don't pass the secretArg.
#if !defined(TARGET_X86) && !defined(TARGET_ARM)
GenTree* argNode;
// Store the stub secret arg if necessary. This has to be done before the
// call to the init helper below, which links the frame into the thread
// list on 32-bit platforms.
// InlinedCallFrame.m_StubSecretArg = stubSecretArg;
if (comp->info.compPublishStubParam)
{
argNode = comp->gtNewLclvNode(comp->lvaStubArgumentVar, TYP_I_IMPL);
GenTree* value = comp->gtNewLclvNode(comp->lvaStubArgumentVar, TYP_I_IMPL);
GenTree* store = comp->gtNewStoreLclFldNode(comp->lvaInlinedPInvokeFrameVar, TYP_I_IMPL,
callFrameInfo.offsetOfSecretStubArg, value);
firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, store));
DISPTREERANGE(firstBlockRange, store);
}
else
{
argNode = comp->gtNewIconNode(0, TYP_I_IMPL);
}
NewCallArg stubParamArg = NewCallArg::Primitive(argNode).WellKnown(WellKnownArg::SecretStubParam);
call->gtArgs.PushBack(comp, stubParamArg);
#endif

// Call runtime helper to fill in our InlinedCallFrame and push it on the Frame list:
// TCB = CORINFO_HELP_INIT_PINVOKE_FRAME(&symFrameStart);
GenTree* frameAddr = comp->gtNewLclAddrNode(comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
NewCallArg frameAddrArg = NewCallArg::Primitive(frameAddr).WellKnown(WellKnownArg::PInvokeFrame);

GenTreeCall* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL);
call->gtArgs.PushBack(comp, frameAddrArg);

// some sanity checks on the frame list root vardsc
const unsigned lclNum = comp->info.compLvFrameListRoot;
const LclVarDsc* varDsc = comp->lvaGetDesc(lclNum);
noway_assert(!varDsc->lvIsParam);
noway_assert(varDsc->lvType == TYP_I_IMPL);

GenTree* store = new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, TYP_I_IMPL, lclNum);
store->AsOp()->gtOp1 = call;
store->gtFlags |= GTF_VAR_DEF;

GenTree* const insertionPoint = firstBlockRange.FirstNonCatchArgNode();

GenTree* store = comp->gtNewStoreLclVarNode(lclNum, call);
comp->fgMorphTree(store);
firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, store));
DISPTREERANGE(firstBlockRange, store);
Expand All @@ -5656,7 +5640,6 @@ void Lowering::InsertPInvokeMethodProlog()
GenTree* spValue = PhysReg(REG_SPBASE);
GenTreeLclFld* storeSP = comp->gtNewStoreLclFldNode(comp->lvaInlinedPInvokeFrameVar, TYP_I_IMPL,
callFrameInfo.offsetOfCallSiteSP, spValue);
assert(inlinedPInvokeDsc->lvDoNotEnregister);

firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeSP));
DISPTREERANGE(firstBlockRange, storeSP);
Expand All @@ -5672,7 +5655,6 @@ void Lowering::InsertPInvokeMethodProlog()
GenTree* fpValue = PhysReg(REG_FPBASE);
GenTreeLclFld* storeFP = comp->gtNewStoreLclFldNode(comp->lvaInlinedPInvokeFrameVar, TYP_I_IMPL,
callFrameInfo.offsetOfCalleeSavedFP, fpValue);
assert(inlinedPInvokeDsc->lvDoNotEnregister);

firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeFP));
DISPTREERANGE(firstBlockRange, storeFP);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/lsra.h
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ class LinearScan : public LinearScanInterface
template <bool localVarsEnregistered>
void buildIntervals();

void buildInitialParamDef(const LclVarDsc* varDsc, regNumber paramReg);

// This is where the actual assignment is done for scenarios where
// no local var enregistration is done.
void allocateRegistersMinimal();
Expand Down
Loading
Loading