diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index af557d5d49de3b..a87cb2f4a6c982 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -1076,6 +1076,10 @@ insGroup* emitter::emitSavIG(bool emitAdd) ig->igInsCnt = (BYTE)emitCurIGinsCnt; ig->igSize = (unsigned short)emitCurIGsize; + if (ig->igSize != 0) + { + emitLastSavedIGWasNoGC = (ig->igFlags & IGF_NOGCINTERRUPT) != 0; + } emitCurCodeOffset += emitCurIGsize; assert(IsCodeAligned(emitCurCodeOffset)); @@ -1372,6 +1376,7 @@ void emitter::emitBegFN(bool hasFramePtr emitFwdJumps = false; emitNoGCRequestCount = 0; emitNoGCIG = false; + emitLastSavedIGWasNoGC = false; emitForceNewIG = false; emitContainsRemovableJmpCandidates = false; @@ -2190,6 +2195,7 @@ void emitter::emitCreatePlaceholderIG(insGroupPlaceholderType igType, // increment emitCurCodeOffset since we are not calling emitNewIG() // emitCurIGsize += MAX_PLACEHOLDER_IG_SIZE; + emitLastSavedIGWasNoGC = true; emitCurCodeOffset += emitCurIGsize; // Add the appropriate IP mapping debugging record for this placeholder @@ -10820,6 +10826,21 @@ regMaskTP emitter::emitGetGCRegsKilledByNoGCCall(CorInfoHelpFunc helper) void emitter::emitDisableGC() { + // For debuggable codegen, ensure there is an interruptible instruction between + // adjacent no-gc regions, if we're at a stack-empty point. + // + if (m_compiler->opts.compDbgCode && (emitNoGCRequestCount == 0) && emitLastCodeIsNoGC() && + !m_compiler->genIPmappings.empty()) + { + const IPmappingDsc& mapping = m_compiler->genIPmappings.back(); + if ((mapping.ipmdKind == IPmappingDscKind::Normal) && + ((mapping.ipmdLoc.GetSourceTypes() & ICorDebugInfo::STACK_EMPTY) != 0) && + mapping.ipmdNativeLoc.IsCurrentLocation(this)) + { + emitIns(INS_nop); + } + } + assert(emitNoGCRequestCount < 10); // We really shouldn't have many nested "no gc" requests. ++emitNoGCRequestCount; @@ -10846,9 +10867,20 @@ void emitter::emitDisableGC() } } -bool emitter::emitGCDisabled() +//------------------------------------------------------------------------ +// emitLastCodeIsNoGC: Check whether the last emitted native code is in a non-interruptible region. +// +// Return Value: +// true if the last non-empty instruction group is non-interruptible. +// +bool emitter::emitLastCodeIsNoGC() const { - return emitNoGCIG == true; + if ((emitCurIG != nullptr) && (emitCurIGsize != 0)) + { + return (emitCurIG->igFlags & IGF_NOGCINTERRUPT) != 0; + } + + return emitLastSavedIGWasNoGC; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 780f06bd1b138c..7a6c916cc1742c 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -2983,9 +2983,10 @@ class emitter void emitCheckFuncletBranch(instrDesc* jmp, insGroup* jmpIG); // Check for illegal branches between funclets - bool emitFwdJumps; // forward jumps present? - unsigned emitNoGCRequestCount; // Count of number of nested "NO GC" region requests we have. - bool emitNoGCIG; // Are we generating IGF_NOGCINTERRUPT insGroups (for prologs, epilogs, etc.) + bool emitFwdJumps; // forward jumps present? + unsigned emitNoGCRequestCount; // Count of number of nested "NO GC" region requests we have. + bool emitNoGCIG; // Are we generating IGF_NOGCINTERRUPT insGroups (for prologs, epilogs, etc.) + bool emitLastSavedIGWasNoGC; // Was the last non-empty saved IG non-interruptible? bool emitForceNewIG; // If we generate an instruction, and not another instruction group, force create a new emitAdd // instruction group. @@ -3072,7 +3073,7 @@ class emitter void emitDisableGC(); void emitEnableGC(); - bool emitGCDisabled(); + bool emitLastCodeIsNoGC() const; #if defined(TARGET_XARCH) static bool emitAlignInstHasNoCode(instrDesc* id);