MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
IL_OFFSETX ilOffset,
regNumber base = REG_NA,
- bool isJump = false,
- bool isNoGC = false);
+ bool isJump = false);
// clang-format on
// clang-format off
BAD_IL_OFFSET, // ilOffset
callTargetReg, // ireg
REG_NA, 0, 0, // xreg, xmul, disp
- false, // isJump
- emitter::emitNoGChelper(helper),
- (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
+ false // isJump
+ );
}
else
{
getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, compiler->eeFindHelper(helper),
INDEBUG_LDISASM_COMMA(nullptr) addr, argSize, retSize, gcInfo.gcVarPtrSetCur,
gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
- 0, /* ilOffset, ireg, xreg, xmul, disp */
- false, /* isJump */
- emitter::emitNoGChelper(helper),
- (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
+ 0, /* ilOffset, ireg, xreg, xmul, disp */
+ false /* isJump */
+ );
}
regSet.verifyRegistersUsed(RBM_CALLEE_TRASH);
gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, /* IL offset */
callTarget, /* ireg */
REG_NA, 0, 0, /* xreg, xmul, disp */
- false, /* isJump */
- emitter::emitNoGChelper(helper));
+ false /* isJump */
+ );
regMaskTP killMask = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
regSet.verifyRegistersUsed(killMask);
}
//----------------------------------------------------------------------
-// compNoGCHelperCallKillSet:
-//
-// Gets a register mask that represents the kill set for a helper call.
+// compHelperCallKillSet: Gets a register mask that represents the kill set for a helper call.
// Not all JIT Helper calls follow the standard ABI on the target architecture.
//
// TODO-CQ: Currently this list is incomplete (not all helpers calls are
case CORINFO_HELP_ASSIGN_REF:
case CORINFO_HELP_CHECKED_ASSIGN_REF:
return RBM_CALLEE_GCTRASH_WRITEBARRIER;
+ case CORINFO_HELP_PROF_FCN_LEAVE:
+ // In case of Leave profiler callback, we need to preserve liveness of REG_PROFILER_RET_SCRATCH on ARMARCH.
+ return RBM_CALLEE_TRASH_NOGC & ~RBM_PROFILER_RET_SCRATCH;
#endif
#if defined(_TARGET_X86_)
gcInfo.gcRegGCrefSetCur,
gcInfo.gcRegByrefSetCur,
BAD_IL_OFFSET, REG_NA, REG_NA, 0, 0, /* iloffset, ireg, xreg, xmul, disp */
- true); /* isJump */
+ true /* isJump */
+ );
// clang-format on
}
#if FEATURE_FASTTAILCALL
MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
IL_OFFSETX ilOffset,
regNumber base,
- bool isJump,
- bool isNoGC)
+ bool isJump)
{
#if !defined(_TARGET_X86_)
int argSize = 0;
gcInfo.gcVarPtrSetCur,
gcInfo.gcRegGCrefSetCur,
gcInfo.gcRegByrefSetCur,
- ilOffset, base, REG_NA, 0, 0, isJump,
- emitter::emitNoGChelper(compiler->eeGetHelperNum(methHnd)));
+ ilOffset, base, REG_NA, 0, 0, isJump);
}
// clang-format on
BAD_IL_OFFSET, // IL offset
callTarget, // ireg
REG_NA, 0, 0, // xreg, xmul, disp
- false, // isJump
- emitter::emitNoGChelper(helper));
+ false // isJump
+ );
// clang-format on
regSet.verifyRegistersUsed(killMask);
}
}
-/*****************************************************************************
- *
- * Returns true if garbage-collection won't happen within the helper call.
- * Don't need to record live pointers for such call sites.
- */
-
-bool emitter::emitNoGChelper(unsigned IHX)
+//------------------------------------------------------------------------
+// emitNoGChelper: Returns true if garbage collection won't happen within the helper call.
+//
+// Notes:
+// There is no need to record live pointers for such call sites.
+//
+// Arguments:
+// helpFunc - a helper signature for the call, can be CORINFO_HELP_UNDEF, that means that the call is not a helper.
+//
+// Return value:
+// true if GC can't happen within this call, false otherwise.
+bool emitter::emitNoGChelper(CorInfoHelpFunc helpFunc)
{
// TODO-Throughput: Make this faster (maybe via a simple table of bools?)
- switch (IHX)
+ switch (helpFunc)
{
case CORINFO_HELP_UNDEF:
return false;
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_INIT_PINVOKE_FRAME:
-
return true;
+
+ default:
+ return false;
}
+}
- return false;
+//------------------------------------------------------------------------
+// emitNoGChelper: Returns true if garbage collection won't happen within the helper call.
+//
+// Notes:
+// There is no need to record live pointers for such call sites.
+//
+// Arguments:
+// methHnd - a method handle for the call.
+//
+// Return value:
+// true if GC can't happen within this call, false otherwise.
+bool emitter::emitNoGChelper(CORINFO_METHOD_HANDLE methHnd)
+{
+ CorInfoHelpFunc helpFunc = Compiler::eeGetHelperNum(methHnd);
+ if (helpFunc == CORINFO_HELP_UNDEF)
+ {
+ return false;
+ }
+ return emitNoGChelper(helpFunc);
}
/*****************************************************************************
}
#endif // DEBUG
+
+//------------------------------------------------------------------------
+// emitGetGCRegsSavedOrModified: Returns the set of registers that keeps gcrefs and byrefs across the call.
+//
+// Notes: it returns union of two sets:
+// 1) registers that could contain GC/byRefs before the call and call doesn't touch them;
+// 2) registers that contain GC/byRefs before the call and call modifies them, but they still
+// contain GC/byRefs.
+//
+// Arguments:
+// methHnd - the method handler of the call.
+//
+// Return value:
+// the saved set of registers.
+//
+regMaskTP emitter::emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd)
+{
+ // Is it a helper with a special saved set?
+ bool isNoGCHelper = emitNoGChelper(methHnd);
+ if (isNoGCHelper)
+ {
+ CorInfoHelpFunc helpFunc = Compiler::eeGetHelperNum(methHnd);
+
+ // Get the set of registers that this call kills and remove it from the saved set.
+ regMaskTP savedSet = RBM_ALLINT & ~emitComp->compNoGCHelperCallKillSet(helpFunc);
+
+#ifdef DEBUG
+ if (emitComp->verbose)
+ {
+ printf("NoGC Call: savedSet=");
+ printRegMaskInt(savedSet);
+ emitDispRegSet(savedSet);
+ printf("\n");
+ }
+#endif
+ return savedSet;
+ }
+ else
+ {
+ // This is the saved set of registers after a normal call.
+ return RBM_CALLEE_SAVED;
+ }
+}
/* The following is used to distinguish helper vs non-helper calls */
/************************************************************************/
- static bool emitNoGChelper(unsigned IHX);
+ static bool emitNoGChelper(CorInfoHelpFunc helpFunc);
+ static bool emitNoGChelper(CORINFO_METHOD_HANDLE methHnd);
/************************************************************************/
/* The following logic keeps track of live GC ref values */
bool emitFullGCinfo; // full GC pointer maps?
bool emitFullyInt; // fully interruptible code?
+ regMaskTP emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd);
+
#if EMIT_TRACK_STACK_DEPTH
unsigned emitCntStackDepth; // 0 in prolog/epilog, One DWORD elsewhere
unsigned emitMaxStackDepth; // actual computed max. stack depth
regNumber xreg /* = REG_NA */,
unsigned xmul /* = 0 */,
ssize_t disp /* = 0 */,
- bool isJump /* = false */,
- bool isNoGC /* = false */,
- bool isProfLeaveCB /* = false */)
+ bool isJump /* = false */)
{
/* Sanity check the arguments depending on callType */
// a sanity test.
assert((unsigned)abs(argSize) <= codeGen->genStackLevel);
- int argCnt;
- instrDesc* id;
-
- /* This is the saved set of registers after a normal call */
- regMaskTP savedSet = RBM_CALLEE_SAVED;
-
- /* some special helper calls have a different saved set registers */
-
- if (isNoGC)
- {
- assert(emitNoGChelper(Compiler::eeGetHelperNum(methHnd)));
-
- // Get the set of registers that this call kills and remove it from the saved set.
- savedSet = RBM_ALLINT & ~emitComp->compNoGCHelperCallKillSet(Compiler::eeGetHelperNum(methHnd));
-
- // In case of Leave profiler callback, we need to preserve liveness of REG_PROFILER_RET_SCRATCH
- if (isProfLeaveCB)
- {
- savedSet |= RBM_PROFILER_RET_SCRATCH;
- }
-
-#ifdef DEBUG
- if (emitComp->verbose)
- {
- printf("NOGC Call: savedSet=");
- printRegMaskInt(savedSet);
- emitDispRegSet(savedSet);
- printf("\n");
- }
-#endif
- }
- else
- {
- assert(!emitNoGChelper(Compiler::eeGetHelperNum(methHnd)));
- }
-
- /* Trim out any callee-trashed registers from the live set */
-
+ // Trim out any callee-trashed registers from the live set.
+ regMaskTP savedSet = emitGetGCRegsSavedOrModified(methHnd);
gcrefRegs &= savedSet;
byrefRegs &= savedSet;
}
#endif
- assert(argSize % REGSIZE_BYTES == 0);
- argCnt = argSize / REGSIZE_BYTES;
-
/* Managed RetVal: emit sequence point for the call */
if (emitComp->opts.compDbgInfo && ilOffset != BAD_IL_OFFSET)
{
Direct call with GC vars 9,440
Indir. call with GC vars 5,768
*/
+ instrDesc* id;
+
+ assert(argSize % REGSIZE_BYTES == 0);
+ int argCnt = argSize / REGSIZE_BYTES;
if (callType >= EC_INDIR_R)
{
emitThisGCrefRegs = gcrefRegs;
emitThisByrefRegs = byrefRegs;
+ id->idSetIsNoGC(emitNoGChelper(methHnd));
+
/* Set the instruction - special case jumping a function */
instruction ins;
insFormat fmt = IF_NONE;
- id->idSetIsNoGC(isNoGC);
-
/* Record the address: method, indirection, or funcptr */
if (callType > EC_FUNC_ADDR)
VARSET_VALARG_TP ptrVars,
regMaskTP gcrefRegs,
regMaskTP byrefRegs,
- IL_OFFSETX ilOffset = BAD_IL_OFFSET,
- regNumber ireg = REG_NA,
- regNumber xreg = REG_NA,
- unsigned xmul = 0,
- ssize_t disp = 0,
- bool isJump = false,
- bool isNoGC = false,
- bool isProfLeaveCB = false);
+ IL_OFFSETX ilOffset = BAD_IL_OFFSET,
+ regNumber ireg = REG_NA,
+ regNumber xreg = REG_NA,
+ unsigned xmul = 0,
+ ssize_t disp = 0,
+ bool isJump = false);
/*****************************************************************************
*
regNumber xreg /* = REG_NA */,
unsigned xmul /* = 0 */,
ssize_t disp /* = 0 */,
- bool isJump /* = false */,
- bool isNoGC /* = false */,
- bool isProfLeaveCB /* = false */)
+ bool isJump /* = false */)
{
/* Sanity check the arguments depending on callType */
// a sanity test.
assert((unsigned)abs(argSize) <= codeGen->genStackLevel);
- int argCnt;
- instrDesc* id;
-
- /* This is the saved set of registers after a normal call */
- regMaskTP savedSet = RBM_CALLEE_SAVED;
-
- /* some special helper calls have a different saved set registers */
-
- if (isNoGC)
- {
- assert(emitNoGChelper(Compiler::eeGetHelperNum(methHnd)));
-
- // Get the set of registers that this call kills and remove it from the saved set.
- savedSet = RBM_ALLINT & ~emitComp->compNoGCHelperCallKillSet(Compiler::eeGetHelperNum(methHnd));
-
- // In case of Leave profiler callback, we need to preserve liveness of REG_PROFILER_RET_SCRATCH
- if (isProfLeaveCB)
- {
- savedSet |= RBM_PROFILER_RET_SCRATCH;
- }
-
-#ifdef DEBUG
- if (emitComp->verbose)
- {
- printf("NOGC Call: savedSet=");
- printRegMaskInt(savedSet);
- emitDispRegSet(savedSet);
- printf("\n");
- }
-#endif
- }
- else
- {
- assert(!emitNoGChelper(Compiler::eeGetHelperNum(methHnd)));
- }
-
- /* Trim out any callee-trashed registers from the live set */
-
+ // Trim out any callee-trashed registers from the live set.
+ regMaskTP savedSet = emitGetGCRegsSavedOrModified(methHnd);
gcrefRegs &= savedSet;
byrefRegs &= savedSet;
}
#endif
- assert(argSize % REGSIZE_BYTES == 0);
- argCnt = (int)(argSize / (int)REGSIZE_BYTES);
-
/* Managed RetVal: emit sequence point for the call */
if (emitComp->opts.compDbgInfo && ilOffset != BAD_IL_OFFSET)
{
on whether this is a direct/indirect call, and whether we need to
record an updated set of live GC variables.
*/
+ instrDesc* id;
+
+ assert(argSize % REGSIZE_BYTES == 0);
+ int argCnt = (int)(argSize / (int)REGSIZE_BYTES);
if (callType >= EC_INDIR_R)
{
emitThisGCrefRegs = gcrefRegs;
emitThisByrefRegs = byrefRegs;
+ id->idSetIsNoGC(emitNoGChelper(methHnd));
+
/* Set the instruction - special case jumping a function */
instruction ins;
insFormat fmt = IF_NONE;
- id->idSetIsNoGC(isNoGC);
-
/* Record the address: method, indirection, or funcptr */
if (callType > EC_FUNC_ADDR)
VARSET_VALARG_TP ptrVars,
regMaskTP gcrefRegs,
regMaskTP byrefRegs,
- IL_OFFSETX ilOffset = BAD_IL_OFFSET,
- regNumber ireg = REG_NA,
- regNumber xreg = REG_NA,
- unsigned xmul = 0,
- ssize_t disp = 0,
- bool isJump = false,
- bool isNoGC = false,
- bool isProfLeaveCB = false);
+ IL_OFFSETX ilOffset = BAD_IL_OFFSET,
+ regNumber ireg = REG_NA,
+ regNumber xreg = REG_NA,
+ unsigned xmul = 0,
+ ssize_t disp = 0,
+ bool isJump = false);
BYTE* emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i);
unsigned emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* i, code_t code);
regNumber xreg, // = REG_NA
unsigned xmul, // = 0
ssize_t disp, // = 0
- bool isJump, // = false
- bool isNoGC) // = false
+ bool isJump) // = false
// clang-format on
{
/* Sanity check the arguments depending on callType */
}
#endif // STACK_PROBES
- int argCnt;
-
- UNATIVE_OFFSET sz;
- instrDesc* id;
-
- /* This is the saved set of registers after a normal call */
- unsigned savedSet = RBM_CALLEE_SAVED;
-
- /* some special helper calls have a different saved set registers */
-
- if (isNoGC)
- {
- // Get the set of registers that this call kills and remove it from the saved set.
- savedSet = RBM_ALLINT & ~emitComp->compNoGCHelperCallKillSet(Compiler::eeGetHelperNum(methHnd));
- }
- else
- {
- assert(!emitNoGChelper(Compiler::eeGetHelperNum(methHnd)));
- }
-
- /* Trim out any callee-trashed registers from the live set */
-
+ // Trim out any callee-trashed registers from the live set.
+ regMaskTP savedSet = emitGetGCRegsSavedOrModified(methHnd);
gcrefRegs &= savedSet;
byrefRegs &= savedSet;
}
#endif
- assert(argSize % REGSIZE_BYTES == 0);
- argCnt = (int)(argSize / (int)REGSIZE_BYTES); // we need a signed-divide
-
/* Managed RetVal: emit sequence point for the call */
if (emitComp->opts.compDbgInfo && ilOffset != BAD_IL_OFFSET)
{
Indir. call with GC vars 5,768
*/
+ instrDesc* id;
+
+ assert(argSize % REGSIZE_BYTES == 0);
+ int argCnt = (int)(argSize / (int)REGSIZE_BYTES); // we need a signed-divide
+
if (callType >= EC_FUNC_VIRTUAL)
{
/* Indirect call, virtual calls */
}
id->idIns(ins);
- id->idSetIsNoGC(isNoGC);
+ id->idSetIsNoGC(emitNoGChelper(methHnd));
+
+ UNATIVE_OFFSET sz;
// Record the address: method, indirection, or funcptr
if (callType >= EC_FUNC_VIRTUAL)
EC_COUNT
};
-// clang-format off
-void emitIns_Call(EmitCallType callType,
- CORINFO_METHOD_HANDLE methHnd,
- CORINFO_SIG_INFO* sigInfo, // used to report call sites to the EE
- void* addr,
- ssize_t argSize,
- emitAttr retSize
- MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
- VARSET_VALARG_TP ptrVars,
- regMaskTP gcrefRegs,
- regMaskTP byrefRegs,
- GenTreeIndir* indir,
- bool isJump = false,
- bool isNoGC = false);
-// clang-format on
-
// clang-format off
void emitIns_Call(EmitCallType callType,
CORINFO_METHOD_HANDLE methHnd,
regNumber xreg = REG_NA,
unsigned xmul = 0,
ssize_t disp = 0,
- bool isJump = false,
- bool isNoGC = false);
+ bool isJump = false);
// clang-format on
#ifdef _TARGET_AMD64_