// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
- // We keep the call count for the second call to gcMakeRegPtrTable() below.
- unsigned callCnt = 0;
// First we figure out the encoder ID's for the stack slots and registers.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS);
// Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
gcInfoEncoder->FinalizeSlotIds();
// Now we can actually use those slot ID's to declare live ranges.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK);
gcInfoEncoder->Build();
// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
- // We keep the call count for the second call to gcMakeRegPtrTable() below.
- unsigned callCnt = 0;
-
// First we figure out the encoder ID's for the stack slots and registers.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS);
// Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
gcInfoEncoder->FinalizeSlotIds();
// Now we can actually use those slot ID's to declare live ranges.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK);
if (compiler->opts.compDbgEnC)
{
// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
- // We keep the call count for the second call to gcMakeRegPtrTable() below.
- unsigned callCnt = 0;
// First we figure out the encoder ID's for the stack slots and registers.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS);
// Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
gcInfoEncoder->FinalizeSlotIds();
// Now we can actually use those slot ID's to declare live ranges.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK);
gcInfoEncoder->Build();
// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
- // We keep the call count for the second call to gcMakeRegPtrTable() below.
- unsigned callCnt = 0;
// First we figure out the encoder ID's for the stack slots and registers.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS);
// Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
gcInfoEncoder->FinalizeSlotIds();
// Now we can actually use those slot ID's to declare live ranges.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK);
if (compiler->opts.compDbgEnC)
{
}
};
-void GCInfo::gcMakeRegPtrTable(
- GcInfoEncoder* gcInfoEncoder, unsigned codeSize, unsigned prologSize, MakeRegPtrMode mode, unsigned* callCntRef)
+void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
+ unsigned codeSize,
+ unsigned prologSize,
+ MakeRegPtrMode mode)
{
GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
- const bool noTrackedGCSlots =
- (compiler->opts.MinOpts() && !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) &&
- !JitConfig.JitMinOptsTrackGCrefs());
-
if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
{
m_regSlotMap = new (compiler->getAllocator()) RegSlotMap(compiler->getAllocator());
{
stackSlotBase = GC_FRAMEREG_REL;
}
- if (noTrackedGCSlots)
+ StackSlotIdKey sskey(varDsc->lvStkOffs, (stackSlotBase == GC_FRAMEREG_REL), flags);
+ GcSlotId varSlotId;
+ if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
{
- // No need to hash/lookup untracked GC refs; just grab a new Slot Id.
- if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
- {
- gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
- }
- }
- else
- {
- StackSlotIdKey sskey(varDsc->lvStkOffs, (stackSlotBase == GC_FRAMEREG_REL), flags);
- GcSlotId varSlotId;
- if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
+ if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
{
- if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
- {
- varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
- m_stackSlotMap->Set(sskey, varSlotId);
- }
+ varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
+ m_stackSlotMap->Set(sskey, varSlotId);
}
}
}
{
if (gcCallDescList != nullptr)
{
- if (noTrackedGCSlots)
+ for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
{
- // We have the call count from the previous run.
- numCallSites = *callCntRef;
-
- // If there are no calls, tell the world and bail.
- if (numCallSites == 0)
- {
- gcInfoEncoderWithLog->DefineCallSites(nullptr, nullptr, 0);
- return;
- }
- }
- else
- {
- for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
- {
- numCallSites++;
- }
+ numCallSites++;
}
pCallSites = new (compiler, CMK_GC) unsigned[numCallSites];
pCallSiteSizes = new (compiler, CMK_GC) BYTE[numCallSites];
// Now consider every call.
for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
{
+ if (mode == MAKE_REG_PTR_MODE_DO_WORK)
+ {
+ pCallSites[callSiteNum] = call->cdOffs - call->cdCallInstrSize;
+ pCallSiteSizes[callSiteNum] = call->cdCallInstrSize;
+ callSiteNum++;
+ }
+
+ unsigned nextOffset;
+
// Figure out the code offset of this entry.
- unsigned nextOffset = call->cdOffs;
+ nextOffset = call->cdOffs;
// As far as I (DLD, 2010) can determine by asking around, the "call->u1.cdArgMask"
// and "cdArgCnt" cases are to handle x86 situations in which a call expression is nested as an
assert(call->cdOffs >= call->cdCallInstrSize);
// call->cdOffs is actually the offset of the instruction *following* the call, so subtract
// the call instruction size to get the offset of the actual call instruction...
- unsigned callOffset = nextOffset - call->cdCallInstrSize;
-
- if (noTrackedGCSlots && regMask == 0)
- {
- // No live GC refs in regs at the call -> don't record the call.
- }
- else
- {
- // Append an entry for the call if doing the real thing.
- if (mode == MAKE_REG_PTR_MODE_DO_WORK)
- {
- pCallSites[callSiteNum] = callOffset;
- pCallSiteSizes[callSiteNum] = call->cdCallInstrSize;
- }
- callSiteNum++;
-
- // Record that these registers are live before the call...
- gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, callOffset, regMask, GC_SLOT_LIVE, byrefRegMask,
- nullptr);
- // ...and dead after.
- gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, nextOffset, regMask, GC_SLOT_DEAD, byrefRegMask,
- nullptr);
- }
+ unsigned callOffset = call->cdOffs - call->cdCallInstrSize;
+ // Record that these registers are live before the call...
+ gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, callOffset, regMask, GC_SLOT_LIVE, byrefRegMask, nullptr);
+ // ...and dead after.
+ gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, call->cdOffs, regMask, GC_SLOT_DEAD, byrefRegMask,
+ nullptr);
}
-
- // Make sure we've recorded the expected number of calls
- assert(mode != MAKE_REG_PTR_MODE_DO_WORK || numCallSites == callSiteNum);
- // Return the actual recorded call count to the caller
- *callCntRef = callSiteNum;
-
// OK, define the call sites.
if (mode == MAKE_REG_PTR_MODE_DO_WORK)
{
CONFIG_INTEGER(JitEnableNoWayAssert, W("JitEnableNoWayAssert"), 1)
#endif // !defined(DEBUG) && !defined(_DEBUG)
-#if !defined(JIT32_GCENCODER)
-#if defined(_TARGET_AMD64_) && defined(FEATURE_CORECLR)
-#define JitMinOptsTrackGCrefs_Default 0 // Not tracking GC refs in MinOpts is new behavior
-#else
-#define JitMinOptsTrackGCrefs_Default 1
-#endif
-CONFIG_INTEGER(JitMinOptsTrackGCrefs, W("JitMinOptsTrackGCrefs"), JitMinOptsTrackGCrefs_Default) // Track GC roots
-#endif // !defined(JIT32_GCENCODER)
-
// The following should be wrapped inside "#if MEASURE_MEM_ALLOC / #endif", but
// some files include this one without bringing in the definitions from "jit.h"
// so we don't always know what the "true" value of that flag should be. For now
// references, building up mappings from tuples of <reg/offset X byref/pinning> to the corresponding
// slot id (in the two member fields declared above). In the "do work" mode, we use these slot ids to
// actually declare live ranges to the encoder.
- void gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
- unsigned codeSize,
- unsigned prologSize,
- MakeRegPtrMode mode,
- unsigned* callCntRef);
+ void gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder, unsigned codeSize, unsigned prologSize, MakeRegPtrMode mode);
#endif
#ifdef JIT32_GCENCODER
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_PinningRef));
#endif
}
- else if (opts.MinOpts() && !JitConfig.JitMinOptsTrackGCrefs() && varTypeIsGC(varDsc->TypeGet()))
- {
- varDsc->lvTracked = 0;
- }
// Are we not optimizing and we have exception handlers?
// if so mark all args and locals "do not enregister".
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- bool noTrackedRefs = false;
-
if(m_SafePointIndex < m_NumSafePoints && !executionAborted)
{
// Skip interruptibility information
//
if(!executionAborted)
{
- if(m_NumInterruptibleRanges == 0)
- {
- // No ranges and no explicit safepoint - must be MinOpts with untracked refs.
- noTrackedRefs = true;
- }
+ _ASSERTE(m_NumInterruptibleRanges);
}
- if(m_NumInterruptibleRanges != 0)
+ int countIntersections = 0;
+ UINT32 lastNormStop = 0;
+ for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
{
- int countIntersections = 0;
- UINT32 lastNormStop = 0;
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
- {
- UINT32 normStartDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA1_ENCBASE );
- UINT32 normStopDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA2_ENCBASE ) + 1;
+ UINT32 normStartDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA1_ENCBASE );
+ UINT32 normStopDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA2_ENCBASE ) + 1;
- UINT32 normStart = lastNormStop + normStartDelta;
- UINT32 normStop = normStart + normStopDelta;
- if(normBreakOffset >= normStart && normBreakOffset < normStop)
- {
- _ASSERTE(pseudoBreakOffset == 0);
- countIntersections++;
- pseudoBreakOffset = numInterruptibleLength + normBreakOffset - normStart;
- }
- numInterruptibleLength += normStopDelta;
- lastNormStop = normStop;
- }
- _ASSERTE(countIntersections <= 1);
- if(countIntersections == 0)
+ UINT32 normStart = lastNormStop + normStartDelta;
+ UINT32 normStop = normStart + normStopDelta;
+ if(normBreakOffset >= normStart && normBreakOffset < normStop)
{
- _ASSERTE(executionAborted);
- LOG((LF_GCROOTS, LL_INFO100000, "Not reporting this frame because it is aborted and not fully interruptible.\n"));
- goto ExitSuccess;
+ _ASSERTE(pseudoBreakOffset == 0);
+ countIntersections++;
+ pseudoBreakOffset = numInterruptibleLength + normBreakOffset - normStart;
}
+ numInterruptibleLength += normStopDelta;
+ lastNormStop = normStop;
+ }
+ _ASSERTE(countIntersections <= 1);
+ if(countIntersections == 0)
+ {
+ _ASSERTE(executionAborted);
+ LOG((LF_GCROOTS, LL_INFO100000, "Not reporting this frame because it is aborted and not fully interruptible.\n"));
+ goto ExitSuccess;
}
}
#else // !PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
if(executionAborted)
{
- // Skip over safepoint info (if any is present).
+ _ASSERTE(m_NumSafePoints == 0);
m_Reader.Skip(m_NumSafePoints * numSlots);
}
else if( m_SafePointIndex != m_NumSafePoints )
else
{
m_Reader.Skip(m_NumSafePoints * numSlots);
- if(noTrackedRefs)
- goto ReportUntracked;
}
#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
}
- public static void RunTest2()
- {
- Dummy2 obj2 = new Dummy2();
- obj2 = null;
- }
-
-
public static void RunTest()
{
Dummy obj = new Dummy();
-
- RunTest2();
+ Dummy2 obj2 = new Dummy2();
// *uncomment the for loop to make test fail with complus_jitminops set
// by design as per briansul
//for (int i=0; i<5; i++) {
+ obj2 = null;
GC.Collect();
GC.WaitForPendingFinalizers();
//}
MakeLeak(iObj);
}
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
-
Console.WriteLine("~LeakObject() was called {0} times.", LeakObject.icFinal);
return (LeakObject.icFinal == iObj*iRep);
}
mem[mem.Length-1] = 1;
}
+ Mv_Obj = null;
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
}
static public ResurrectObj ResObjHolder; // Defaults to null
- // These methods demonstrate how the GC supports resurrection.
+ // This method demonstrates how the GC supports resurrection.
// NOTE: Resurrection is discouraged.
- private static void ResurrectionInit() {
+ private static void ResurrectionDemo() {
+ Display(0, "\n\nDemo start: Object Resurrection.", +1);
+
// Create a ResurrectionObj
ResurrectObj obj = new ResurrectObj("Resurrection");
// Destroy all strong references to the new ResurrectionObj
obj = null;
- }
-
- private static void ResurrectionDemo() {
- Display(0, "\n\nDemo start: Object Resurrection.", +1);
-
- // Create a ResurrectionObj and drop it on the floor.
- ResurrectionInit();
// Force the GC to determine that the object is unreachable.
Collect();
public bool RunTest(int iObj,int iSwitch)
{
DeleteObj(iObj,iSwitch);
-
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
-
bool result = CheckResult(iObj,iSwitch);
return result;
}
{
rgNode[i] = null;
}
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
}
public bool CheckResult(int iObj,int iSwitch)
return 100;
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
- private static void CollectAndFinalize()
- {
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- }
- [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test1()
{
for (int i = 0; i < 50; i++)
s_arr[i] = new Test(i);
- CollectAndFinalize();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test2()
s_arr[i].CheckValid();
s_arr[i] = null;
}
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test3()
{
- CollectAndFinalize();
for (int i = 0; i < 50; i++)
{
if (s_arr[i] == null) throw new Exception();
s_arr[i].CheckValid();
s_arr[i] = null;
}
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test4()
{
- CollectAndFinalize();
for (int i = 0; i < 50; i++)
{
if (s_arr[i] == null) throw new Exception();
s_arr[i].CheckValid();
s_arr[i] = null;
}
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test5()
{
- CollectAndFinalize();
for (int i = 0; i < 50; i++)
{
if (s_arr[i] == null) throw new Exception();
s_arr[i].CheckValid();
s_arr[i] = null;
}
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test6()
{
- CollectAndFinalize();
for (int i = 0; i < 50; i++)
{
if (s_arr[i] == null) throw new Exception();