Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ class AsmOffsets
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x132;
#elif TARGET_X86
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
public const int SIZEOF__StackFrameIterator = 0x3cc;
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x3ba;
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3c8;
public const int SIZEOF__StackFrameIterator = 0x3d4;
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x3c2;
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3d0;
#else // TARGET_64BIT
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
public const int SIZEOF__StackFrameIterator = 0xcc;
Expand Down Expand Up @@ -134,9 +134,9 @@ class AsmOffsets
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x12a;
#elif TARGET_X86
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
public const int SIZEOF__StackFrameIterator = 0x3c4;
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x3b2;
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3c0;
public const int SIZEOF__StackFrameIterator = 0x3cc;
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x3ba;
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3c8;
#else // TARGET_64BIT
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
public const int SIZEOF__StackFrameIterator = 0xc4;
Expand Down
36 changes: 36 additions & 0 deletions src/coreclr/gcdump/i386/gcdumpx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@ size_t GCDump::DumpInfoHdr (PTR_CBYTE gcInfoBlock,
header->revPInvokeOffset = count;
}

if (header->noGCRegionCnt == HAS_NOGCREGIONS)
{
hasArgTabOffset = TRUE;
table += decodeUnsigned(table, &count);
header->noGCRegionCnt = count;
}
else if (header->noGCRegionCnt > 0)
{
hasArgTabOffset = TRUE;
}

//
// First print out all the basic information
//
Expand Down Expand Up @@ -156,6 +167,8 @@ size_t GCDump::DumpInfoHdr (PTR_CBYTE gcInfoBlock,
gcPrintf(" Sync region = [%u,%u] ([0x%x,0x%x])\n",
header->syncStartOffset, header->syncEndOffset,
header->syncStartOffset, header->syncEndOffset);
if (header->noGCRegionCnt > 0)
gcPrintf(" no GC region count = %2u \n", header->noGCRegionCnt);

if (header->epilogCount > 1 || (header->epilogCount != 0 &&
header->epilogAtEnd == 0))
Expand Down Expand Up @@ -232,6 +245,23 @@ size_t GCDump::DumpGCTable(PTR_CBYTE table,
if (header.ebxSaved) calleeSavedRegs++;
}

/* Dump the no GC region table */

if (header.noGCRegionCnt > 0)
{
count = header.noGCRegionCnt;
while (count-- > 0)
{
unsigned regionOffset;
unsigned regionSize;

table += decodeUnsigned(table, &regionOffset);
table += decodeUnsigned(table, &regionSize);

gcPrintf("[%04X-%04X) no GC region\n", regionOffset, regionOffset + regionSize);
}
}

/* Dump the untracked frame variable table */

count = header.untrackedCnt;
Expand Down Expand Up @@ -995,6 +1025,12 @@ void GCDump::DumpPtrsInFrame(PTR_CBYTE gcInfoBlock,
header.revPInvokeOffset = offset;
_ASSERTE(offset != INVALID_REV_PINVOKE_OFFSET);
}
if (header.noGCRegionCnt == HAS_NOGCREGIONS)
{
unsigned count;
table += decodeUnsigned(table, &count);
header.noGCRegionCnt = count;
}

prologSize = header.prologSize;
epilogSize = header.epilogSize;
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/inc/gc_unwind_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ struct hdrInfo
unsigned int syncEpilogStart; // The start of the epilog. Synchronized methods are guaranteed to have no more than one epilog.
unsigned int revPInvokeOffset; // INVALID_REV_PINVOKE_OFFSET if there is no Reverse PInvoke frame

unsigned int noGCRegionCnt;

enum { NOT_IN_PROLOG = -1, NOT_IN_EPILOG = -1 };

int prologOffs; // NOT_IN_PROLOG if not in prolog
Expand Down Expand Up @@ -403,4 +405,8 @@ size_t DecodeGCHdrInfo(GCInfoToken gcInfoToken,
unsigned curOffset,
hdrInfo * infoPtr);

bool IsInNoGCRegion(hdrInfo * infoPtr,
PTR_CBYTE table,
unsigned curOffset);

#endif // _UNWIND_X86_H
27 changes: 22 additions & 5 deletions src/coreclr/inc/gcdecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,22 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, UINT32 version, InfoHdr* header
nextByte = *table++;
encoding = nextByte & ADJ_ENCODING_MAX;
// encoding here always corresponds to codes in InfoHdrAdjust2 set

_ASSERTE(encoding < SET_RET_KIND_MAX);
header->returnKind = (ReturnKind)encoding;
if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;
}
else if (encoding == FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = HAS_NOGCREGIONS;
}
else
{
_ASSERTE(!"Unexpected encoding");
}
break;
}
}
Expand Down Expand Up @@ -470,7 +483,8 @@ bool InfoHdrSmall::isHeaderMatch(const InfoHdr& target) const
target.varPtrTableSize != HAS_VARPTR &&
target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
target.syncStartOffset != HAS_SYNC_OFFSET &&
target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET);
target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET &&
target.noGCRegionCnt != HAS_NOGCREGIONS);
#endif

// compare two InfoHdr's up to but not including the untrackCnt field
Expand All @@ -495,7 +509,10 @@ bool InfoHdrSmall::isHeaderMatch(const InfoHdr& target) const
if (target.syncStartOffset != INVALID_SYNC_OFFSET)
return false;

if (target.revPInvokeOffset!= INVALID_REV_PINVOKE_OFFSET)
if (target.revPInvokeOffset != INVALID_REV_PINVOKE_OFFSET)
return false;

if (target.noGCRegionCnt > 0)
return false;

return true;
Expand Down
22 changes: 18 additions & 4 deletions src/coreclr/inc/gcinfotypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ enum infoHdrAdjustConstants {
SET_EPILOGSIZE_MAX = 10, // Change to 6
SET_EPILOGCNT_MAX = 4,
SET_UNTRACKED_MAX = 3,
SET_RET_KIND_MAX = 4, // 2 bits for ReturnKind
SET_RET_KIND_MAX = 3, // 2 bits for ReturnKind
SET_NOGCREGIONS_MAX = 4,
ADJ_ENCODING_MAX = 0x7f, // Maximum valid encoding in a byte
// Also used to mask off next bit from each encoding byte.
MORE_BYTES_TO_FOLLOW = 0x80 // If the High-bit of a header or adjustment byte
Expand Down Expand Up @@ -372,10 +373,13 @@ enum infoHdrAdjust {
// Second set of opcodes, when first code is 0x4F
enum infoHdrAdjust2 {
SET_RETURNKIND = 0, // 0x00-SET_RET_KIND_MAX Set ReturnKind to value
SET_NOGCREGIONS_CNT = SET_RETURNKIND + SET_RET_KIND_MAX + 1, // 0x04
FFFF_NOGCREGION_CNT = SET_NOGCREGIONS_CNT + SET_NOGCREGIONS_MAX + 1 // 0x09 There is a count (>SET_NOGCREGIONS_MAX) after the header encoding
};

#define HAS_UNTRACKED ((unsigned int) -1)
#define HAS_VARPTR ((unsigned int) -1)
#define HAS_NOGCREGIONS ((unsigned int) -1)

// 0 is a valid offset for the Reverse P/Invoke block
// So use -1 as the sentinel for invalid and -2 as the sentinel for present.
Expand Down Expand Up @@ -424,7 +428,7 @@ struct InfoHdrSmall {
unsigned short argCount; // 5,6 in bytes
unsigned int frameSize; // 7,8,9,10 in bytes
unsigned int untrackedCnt; // 11,12,13,14
unsigned int varPtrTableSize; // 15.16,17,18
unsigned int varPtrTableSize; // 15,16,17,18

// Checks whether "this" is compatible with "target".
// It is not an exact bit match as "this" could have some
Expand All @@ -442,7 +446,8 @@ struct InfoHdr : public InfoHdrSmall {
unsigned int syncStartOffset; // 23,24,25,26
unsigned int syncEndOffset; // 27,28,29,30
unsigned int revPInvokeOffset; // 31,32,33,34 Available GcInfo v2 onwards, previously undefined
// 35 bytes total
unsigned int noGCRegionCnt; // 35,36,37,38
// 39 bytes total

// Checks whether "this" is compatible with "target".
// It is not an exact bit match as "this" could have some
Expand All @@ -457,7 +462,8 @@ struct InfoHdr : public InfoHdrSmall {
target.varPtrTableSize != HAS_VARPTR &&
target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
target.syncStartOffset != HAS_SYNC_OFFSET &&
target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET);
target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET &&
target.noGCRegionCnt != HAS_NOGCREGIONS);
#endif

// compare two InfoHdr's up to but not including the untrackCnt field
Expand Down Expand Up @@ -488,6 +494,13 @@ struct InfoHdr : public InfoHdrSmall {
(target.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET))
return false;

if (noGCRegionCnt != target.noGCRegionCnt) {
if (target.noGCRegionCnt <= SET_NOGCREGIONS_MAX)
return false;
else if (noGCRegionCnt != HAS_UNTRACKED)
return false;
}

return true;
}
};
Expand Down Expand Up @@ -518,6 +531,7 @@ inline void GetInfoHdr(int index, InfoHdr * header)
header->syncStartOffset = INVALID_SYNC_OFFSET;
header->syncEndOffset = INVALID_SYNC_OFFSET;
header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
header->noGCRegionCnt = 0;
}

PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, UINT32 version, InfoHdr* header);
Expand Down
18 changes: 0 additions & 18 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,10 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
}
else
{
// TODO-Linux-x86: Do we need to handle the GC information for this NOP or JMP specially, as is done for other
// architectures?
#ifndef JIT32_GCENCODER
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ This is the primary issue addressed by this PR

// Because of the way the flowgraph is connected, the liveness info for this one instruction
// after the call is not (can not be) correct in cases where a variable has a last use in the
// handler. So turn off GC reporting once we execute the call and reenable after the jmp/nop
GetEmitter()->emitDisableGC();
#endif // JIT32_GCENCODER

GetEmitter()->emitIns_J(INS_call, block->GetTarget());

Expand All @@ -229,9 +225,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
inst_JMP(EJ_jmp, finallyContinuation);
}

#ifndef JIT32_GCENCODER
GetEmitter()->emitEnableGC();
#endif // JIT32_GCENCODER
}
}
#if defined(FEATURE_EH_WINDOWS_X86)
Expand Down Expand Up @@ -1879,11 +1873,9 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)

switch (treeNode->gtOper)
{
#ifndef JIT32_GCENCODER
case GT_START_NONGC:
GetEmitter()->emitDisableGC();
break;
#endif // !defined(JIT32_GCENCODER)

case GT_START_PREEMPTGC:
// Kill callee saves GC registers, and create a label
Expand Down Expand Up @@ -3160,9 +3152,7 @@ void CodeGen::genCodeForStoreBlk(GenTreeBlk* storeBlkNode)
{
case GenTreeBlk::BlkOpKindCpObjRepInstr:
case GenTreeBlk::BlkOpKindCpObjUnroll:
#ifndef JIT32_GCENCODER
assert(!storeBlkNode->gtBlkOpGcUnsafe);
#endif
genCodeForCpObj(storeBlkNode->AsBlk());
break;

Expand All @@ -3172,9 +3162,7 @@ void CodeGen::genCodeForStoreBlk(GenTreeBlk* storeBlkNode)
break;

case GenTreeBlk::BlkOpKindRepInstr:
#ifndef JIT32_GCENCODER
assert(!storeBlkNode->gtBlkOpGcUnsafe);
#endif
if (isCopyBlk)
{
genCodeForCpBlkRepMovs(storeBlkNode);
Expand All @@ -3188,12 +3176,10 @@ void CodeGen::genCodeForStoreBlk(GenTreeBlk* storeBlkNode)
case GenTreeBlk::BlkOpKindUnroll:
if (isCopyBlk)
{
#ifndef JIT32_GCENCODER
if (storeBlkNode->gtBlkOpGcUnsafe)
{
GetEmitter()->emitDisableGC();
}
#endif
if (storeBlkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
{
genCodeForCpBlkUnroll(storeBlkNode);
Expand All @@ -3203,18 +3189,14 @@ void CodeGen::genCodeForStoreBlk(GenTreeBlk* storeBlkNode)
assert(storeBlkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnrollMemmove);
genCodeForMemmove(storeBlkNode);
}
#ifndef JIT32_GCENCODER
if (storeBlkNode->gtBlkOpGcUnsafe)
{
GetEmitter()->emitEnableGC();
}
#endif
}
else
{
#ifndef JIT32_GCENCODER
assert(!storeBlkNode->gtBlkOpGcUnsafe);
#endif
genCodeForInitBlkUnroll(storeBlkNode);
}
break;
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10597,7 +10597,6 @@ regMaskTP emitter::emitGetGCRegsKilledByNoGCCall(CorInfoHelpFunc helper)
return result;
}

#if !defined(JIT32_GCENCODER)
//------------------------------------------------------------------------
// emitDisableGC: Requests that the following instruction groups are not GC-interruptible.
//
Expand Down Expand Up @@ -10689,4 +10688,3 @@ void emitter::emitEnableGC()
JITDUMP("Enable GC: still %u no-gc requests\n", emitNoGCRequestCount);
}
}
#endif // !defined(JIT32_GCENCODER)
2 changes: 0 additions & 2 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -2891,11 +2891,9 @@ class emitter

void emitNewIG();

#if !defined(JIT32_GCENCODER)
void emitDisableGC();
void emitEnableGC();
bool emitGCDisabled();
#endif // !defined(JIT32_GCENCODER)

#if defined(TARGET_XARCH)
static bool emitAlignInstHasNoCode(instrDesc* id);
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/jit/emitinl.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,10 +585,17 @@ inline bool insIsCMOV(instruction ins)
* false. Returns the final result of the callback.
*/
template <typename Callback>
bool emitter::emitGenNoGCLst(Callback& cb)
bool emitter::emitGenNoGCLst(Callback& cb, bool skipAllPrologsAndEpilogs /* = false */)
{
for (insGroup* ig = emitIGlist; ig; ig = ig->igNext)
{
if (skipAllPrologsAndEpilogs)
{
if (ig == emitPrologIG)
continue;
if (ig->igFlags & (IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG))
continue;
}
if ((ig->igFlags & IGF_NOGCINTERRUPT) && ig->igSize > 0)
{
emitter::instrDesc* id = emitFirstInstrDesc(ig->igData);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emitpub.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ unsigned emitEndCodeGen(Compiler* comp,
unsigned emitGetEpilogCnt();

template <typename Callback>
bool emitGenNoGCLst(Callback& cb);
bool emitGenNoGCLst(Callback& cb, bool skipAllPrologsAndEpilogs = false);

void emitBegProlog();
unsigned emitGetPrologOffsetEstimate();
Expand Down
Loading
Loading