Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41b7ad5

Browse files
jakobbotschRuihan-Yin
authored andcommitted
Simplify "secret stub arg" handling between JIT and EE (dotnet#100823)
When a pinvoke/reverse pinvoke needs marshalling the VM creates an IL stub to perform this marshalling. These IL stubs have a non-standard parameter called the "secret stub parameter". The VM uses this parameter to map the IL stub back to the user defined function that caused the IL stub to be required (multiple user functions can share the same IL stubs, so the mapping cannot be done by other means). To facilitate the access of this value the JIT must make the parameter's value available to the VM somehow. Previously this was done in two separate ways for 32-bit and 64-bit target: - For 32-bit targets the parameter was marked as do-not-enregister and always spilled to the stack frame at a location that was known by the VM. - For 64-bit targets the parameter was saved in the `InlinedCallFrame` as part of a VM helper call. We still marked it as do-not-enregister, probably because parameter homing did not handle it. For 64-bit targets this introduces a bit of inefficiency: the secret stub parameter is only needed for the IL stubs case, but `InlinedCallFrame` is used for all inlined pinvokes. So we ended up with a larger frame than necessary and with an additional store to the frame, even outside IL stubs. This change removes that inefficiency by unifying how 32-bit and 64-bit targets work: - Switch all platforms to only allocate space in `InlinedCallFrame` for the secret stub parameter when necessary - Move responsibility of storing the secret stub parameter out of `CORINFO_HELP_INIT_PINVOKE_FRAME` and to the JIT generated code - Remove special casing of frame layout around the secret stub parameter and frame structures within the JIT - Enable enregistration for the secret stub parameter Fix dotnet#100662
1 parent e47e1d6 commit 41b7ad5

33 files changed

+191
-281
lines changed

eng/native/sanitizer-ignorelist.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ fun:_ZN11CMiniMdBase19UsesAllocatedMemoryEP11CMiniColDef
1010
# 2 0x4e8051 in __ubsan_handle_dynamic_type_cache_miss
1111
# 3 0x7f02ce676cd8 in JIT_InitPInvokeFrame(InlinedCallFrame*, void*) /home/steveharter/git/dotnet_coreclr/vm/jithelpers.cpp:6491:9
1212
# 4 0x7f0252bbceb2 (<unknown module>)
13-
fun:_Z20JIT_InitPInvokeFrameP16InlinedCallFramePv
13+
fun:_Z20JIT_InitPInvokeFrameP16InlinedCallFrame
1414

src/coreclr/inc/corinfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,13 +1754,17 @@ struct CORINFO_EE_INFO
17541754
// Size of the Frame structure
17551755
unsigned size;
17561756

1757+
// Size of the Frame structure when it also contains the secret stub arg
1758+
unsigned sizeWithSecretStubArg;
1759+
17571760
unsigned offsetOfGSCookie;
17581761
unsigned offsetOfFrameVptr;
17591762
unsigned offsetOfFrameLink;
17601763
unsigned offsetOfCallSiteSP;
17611764
unsigned offsetOfCalleeSavedFP;
17621765
unsigned offsetOfCallTarget;
17631766
unsigned offsetOfReturnAddress;
1767+
unsigned offsetOfSecretStubArg;
17641768
// This offset is used only for ARM
17651769
unsigned offsetOfSPAfterProlog;
17661770
}

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

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

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/jit/codegen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ class CodeGen final : public CodeGenInterface
277277

278278
var_types genParamStackStoreType(LclVarDsc* dsc, const ABIPassingSegment& seg);
279279
void genSpillOrAddRegisterParam(unsigned lclNum, class RegGraph* graph);
280+
void genSpillOrAddNonStandardRegisterParam(unsigned lclNum, regNumber sourceReg, class RegGraph* graph);
280281
void genEnregisterIncomingStackArgs();
281282
#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
282283
void genEnregisterOSRArgsAndLocals(regNumber initReg, bool* pInitRegZeroed);

src/coreclr/jit/codegencommon.cpp

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3246,6 +3246,31 @@ void CodeGen::genSpillOrAddRegisterParam(unsigned lclNum, RegGraph* graph)
32463246
}
32473247
}
32483248

3249+
// -----------------------------------------------------------------------------
3250+
// genSpillOrAddNonStandardRegisterParam: Handle a non-standard register parameter either
3251+
// by homing it to stack immediately, or by adding it to the register graph.
3252+
//
3253+
// Parameters:
3254+
// lclNum - Local that represents the non-standard parameter
3255+
// sourceReg - Register that the non-standard parameter is in on entry to the function
3256+
// graph - The register graph to add to
3257+
//
3258+
void CodeGen::genSpillOrAddNonStandardRegisterParam(unsigned lclNum, regNumber sourceReg, RegGraph* graph)
3259+
{
3260+
LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
3261+
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
3262+
{
3263+
GetEmitter()->emitIns_S_R(ins_Store(varDsc->TypeGet()), emitActualTypeSize(varDsc), sourceReg, lclNum, 0);
3264+
}
3265+
3266+
if (varDsc->lvIsInReg())
3267+
{
3268+
RegNode* sourceRegNode = graph->GetOrAdd(sourceReg);
3269+
RegNode* destRegNode = graph->GetOrAdd(varDsc->GetRegNum());
3270+
graph->AddEdge(sourceRegNode, destRegNode, TYP_I_IMPL, 0);
3271+
}
3272+
}
3273+
32493274
// -----------------------------------------------------------------------------
32503275
// genHomeRegisterParams: Move all register parameters to their initial
32513276
// assigned location.
@@ -3289,6 +3314,12 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
32893314
}
32903315
}
32913316

3317+
if (compiler->info.compPublishStubParam && ((paramRegs & RBM_SECRET_STUB_PARAM) != RBM_NONE))
3318+
{
3319+
GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SECRET_STUB_PARAM,
3320+
compiler->lvaStubArgumentVar, 0);
3321+
}
3322+
32923323
return;
32933324
}
32943325

@@ -3321,6 +3352,11 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
33213352
}
33223353
}
33233354

3355+
if (compiler->info.compPublishStubParam && ((paramRegs & RBM_SECRET_STUB_PARAM) != RBM_NONE))
3356+
{
3357+
genSpillOrAddNonStandardRegisterParam(compiler->lvaStubArgumentVar, REG_SECRET_STUB_PARAM, &graph);
3358+
}
3359+
33243360
DBEXEC(VERBOSE, graph.Dump());
33253361

33263362
regMaskTP busyRegs = intRegState.rsCalleeRegArgMaskLiveIn | floatRegState.rsCalleeRegArgMaskLiveIn;
@@ -3784,13 +3820,6 @@ void CodeGen::genCheckUseBlockInit()
37843820
{
37853821
regMaskTP maskCalleeRegArgMask = intRegState.rsCalleeRegArgMaskLiveIn;
37863822

3787-
// If there is a secret stub param, don't count it, as it will no longer
3788-
// be live when we do block init.
3789-
if (compiler->info.compPublishStubParam)
3790-
{
3791-
maskCalleeRegArgMask &= ~RBM_SECRET_STUB_PARAM;
3792-
}
3793-
37943823
#ifdef TARGET_ARM
37953824
//
37963825
// On the Arm if we are using a block init to initialize, then we
@@ -5572,16 +5601,6 @@ void CodeGen::genFnProlog()
55725601
}
55735602
#endif // TARGET_ARM
55745603

5575-
if (compiler->info.compPublishStubParam)
5576-
{
5577-
GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SECRET_STUB_PARAM,
5578-
compiler->lvaStubArgumentVar, 0);
5579-
assert(intRegState.rsCalleeRegArgMaskLiveIn & RBM_SECRET_STUB_PARAM);
5580-
5581-
// It's no longer live; clear it out so it can be used after this in the prolog
5582-
intRegState.rsCalleeRegArgMaskLiveIn &= ~RBM_SECRET_STUB_PARAM;
5583-
}
5584-
55855604
//
55865605
// Zero out the frame as needed
55875606
//

src/coreclr/jit/compiler.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4602,11 +4602,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
46024602
assert(lvaStubArgumentVar == BAD_VAR_NUM);
46034603
lvaStubArgumentVar = lvaGrabTempWithImplicitUse(false DEBUGARG("stub argument"));
46044604
lvaGetDesc(lvaStubArgumentVar)->lvType = TYP_I_IMPL;
4605-
// TODO-CQ: there is no need to mark it as doNotEnreg. There are no stores for this local
4606-
// before codegen so liveness and LSRA mark it as "liveIn" and always allocate a stack slot for it.
4607-
// However, it would be better to process it like other argument locals and keep it in
4608-
// a reg for the whole method without spilling to the stack when possible.
4609-
lvaSetVarDoNotEnregister(lvaStubArgumentVar DEBUGARG(DoNotEnregisterReason::VMNeedsStackAddr));
46104605
}
46114606
};
46124607
DoPhase(this, PHASE_PRE_IMPORT, preImportPhase);

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4243,7 +4243,7 @@ class Compiler
42434243
return lvaGetDesc(lclNum)->lvInSsa;
42444244
}
42454245

4246-
unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
4246+
unsigned lvaStubArgumentVar; // variable representing the secret stub argument
42474247

42484248
unsigned lvaPSPSym; // variable representing the PSPSym
42494249

src/coreclr/jit/flowgraph.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2438,7 +2438,10 @@ PhaseStatus Compiler::fgAddInternal()
24382438

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

24442447
// Do we need to insert a "JustMyCode" callback?

src/coreclr/jit/gentree.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13136,8 +13136,6 @@ const char* Compiler::gtGetWellKnownArgNameForArgMsg(WellKnownArg arg)
1313613136
return "retbuf";
1313713137
case WellKnownArg::PInvokeFrame:
1313813138
return "pinv frame";
13139-
case WellKnownArg::SecretStubParam:
13140-
return "stub param";
1314113139
case WellKnownArg::WrapperDelegateCell:
1314213140
return "wrap cell";
1314313141
case WellKnownArg::ShiftLow:

src/coreclr/jit/gentree.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4465,7 +4465,6 @@ enum class WellKnownArg : unsigned
44654465
InstParam,
44664466
RetBuffer,
44674467
PInvokeFrame,
4468-
SecretStubParam,
44694468
WrapperDelegateCell,
44704469
ShiftLow,
44714470
ShiftHigh,

0 commit comments

Comments
 (0)