summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/codegenarm.cpp6
-rw-r--r--src/jit/codegenarm64.cpp7
-rw-r--r--src/jit/codegenlegacy.cpp6
-rw-r--r--src/jit/codegenxarch.cpp6
-rw-r--r--src/jit/gcencode.cpp98
-rw-r--r--src/jit/jitconfigvalues.h9
-rw-r--r--src/jit/jitgcinfo.h6
-rw-r--r--src/jit/lclvars.cpp4
-rw-r--r--src/vm/gcinfodecoder.cpp55
-rw-r--r--tests/src/GC/API/GC/KeepAlive.cs11
-rw-r--r--tests/src/GC/Scenarios/LeakGen/leakgen.cs10
-rw-r--r--tests/src/GC/Scenarios/Samples/gc.cs13
-rw-r--r--tests/src/GC/Scenarios/WeakReference/weakreffinal.cs10
-rw-r--r--tests/src/JIT/Methodical/Arrays/misc/arrres.cs27
14 files changed, 177 insertions, 91 deletions
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp
index 580cad5053..88f576efbc 100644
--- a/src/jit/codegenarm.cpp
+++ b/src/jit/codegenarm.cpp
@@ -1916,12 +1916,14 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize,
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
gcInfoEncoder->Build();
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp
index 0fb3fb8cf1..2fac6afdd6 100644
--- a/src/jit/codegenarm64.cpp
+++ b/src/jit/codegenarm64.cpp
@@ -6055,14 +6055,17 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
if (compiler->opts.compDbgEnC)
{
diff --git a/src/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp
index c616546b0c..d61dda566d 100644
--- a/src/jit/codegenlegacy.cpp
+++ b/src/jit/codegenlegacy.cpp
@@ -20152,12 +20152,14 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
gcInfoEncoder->Build();
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index e893da6035..8499d3a13c 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -8354,12 +8354,14 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
// 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);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
if (compiler->opts.compDbgEnC)
{
diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp
index dcca19ebe8..2b9fe375b5 100644
--- a/src/jit/gcencode.cpp
+++ b/src/jit/gcencode.cpp
@@ -3844,13 +3844,15 @@ struct InterruptibleRangeReporter
}
};
-void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
- unsigned codeSize,
- unsigned prologSize,
- MakeRegPtrMode mode)
+void GCInfo::gcMakeRegPtrTable(
+ GcInfoEncoder* gcInfoEncoder, unsigned codeSize, unsigned prologSize, MakeRegPtrMode mode, unsigned* callCntRef)
{
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());
@@ -3961,14 +3963,25 @@ void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
{
stackSlotBase = GC_FRAMEREG_REL;
}
- StackSlotIdKey sskey(varDsc->lvStkOffs, (stackSlotBase == GC_FRAMEREG_REL), flags);
- GcSlotId varSlotId;
- if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
+ if (noTrackedGCSlots)
{
- if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
+ // No need to hash/lookup untracked GC refs; just grab a new Slot Id.
+ if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
{
- varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
- m_stackSlotMap->Set(sskey, varSlotId);
+ 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))
+ {
+ varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
+ m_stackSlotMap->Set(sskey, varSlotId);
+ }
}
}
}
@@ -4204,9 +4217,24 @@ void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
{
if (gcCallDescList != nullptr)
{
- for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
+ if (noTrackedGCSlots)
{
- numCallSites++;
+ // 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++;
+ }
}
pCallSites = new (compiler, CMK_GC) unsigned[numCallSites];
pCallSiteSizes = new (compiler, CMK_GC) BYTE[numCallSites];
@@ -4216,17 +4244,8 @@ void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
// 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.
- nextOffset = call->cdOffs;
+ unsigned 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
@@ -4251,13 +4270,36 @@ void GCInfo::gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
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 = 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);
+ 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);
+ }
}
+
+ // 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)
{
diff --git a/src/jit/jitconfigvalues.h b/src/jit/jitconfigvalues.h
index a3e30de10f..264b661891 100644
--- a/src/jit/jitconfigvalues.h
+++ b/src/jit/jitconfigvalues.h
@@ -214,6 +214,15 @@ CONFIG_INTEGER(JitEnableNoWayAssert, W("JitEnableNoWayAssert"), 0)
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
diff --git a/src/jit/jitgcinfo.h b/src/jit/jitgcinfo.h
index 3f8d8afe88..7b17b84204 100644
--- a/src/jit/jitgcinfo.h
+++ b/src/jit/jitgcinfo.h
@@ -295,7 +295,11 @@ public:
// 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);
+ void gcMakeRegPtrTable(GcInfoEncoder* gcInfoEncoder,
+ unsigned codeSize,
+ unsigned prologSize,
+ MakeRegPtrMode mode,
+ unsigned* callCntRef);
#endif
#ifdef JIT32_GCENCODER
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index fa1ba8282c..f0d6903b75 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -2965,6 +2965,10 @@ void Compiler::lvaSortByRefCount()
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".
diff --git a/src/vm/gcinfodecoder.cpp b/src/vm/gcinfodecoder.cpp
index 89f470499e..5dd52b9fe3 100644
--- a/src/vm/gcinfodecoder.cpp
+++ b/src/vm/gcinfodecoder.cpp
@@ -628,6 +628,8 @@ bool GcInfoDecoder::EnumerateLiveSlots(
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
+ bool noTrackedRefs = false;
+
if(m_SafePointIndex < m_NumSafePoints && !executionAborted)
{
// Skip interruptibility information
@@ -648,33 +650,40 @@ bool GcInfoDecoder::EnumerateLiveSlots(
//
if(!executionAborted)
{
- _ASSERTE(m_NumInterruptibleRanges);
+ if(m_NumInterruptibleRanges == 0)
+ {
+ // No ranges and no explicit safepoint - must be MinOpts with untracked refs.
+ noTrackedRefs = true;
+ }
}
- int countIntersections = 0;
- UINT32 lastNormStop = 0;
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
+ if(m_NumInterruptibleRanges != 0)
{
- UINT32 normStartDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA1_ENCBASE );
- UINT32 normStopDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA2_ENCBASE ) + 1;
+ 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 normStart = lastNormStop + normStartDelta;
- UINT32 normStop = normStart + normStopDelta;
- if(normBreakOffset >= normStart && normBreakOffset < normStop)
+ 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)
{
- _ASSERTE(pseudoBreakOffset == 0);
- countIntersections++;
- pseudoBreakOffset = numInterruptibleLength + normBreakOffset - normStart;
+ _ASSERTE(executionAborted);
+ LOG((LF_GCROOTS, LL_INFO100000, "Not reporting this frame because it is aborted and not fully interruptible.\n"));
+ goto ExitSuccess;
}
- 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
@@ -718,7 +727,7 @@ bool GcInfoDecoder::EnumerateLiveSlots(
if(executionAborted)
{
- _ASSERTE(m_NumSafePoints == 0);
+ // Skip over safepoint info (if any is present).
m_Reader.Skip(m_NumSafePoints * numSlots);
}
else if( m_SafePointIndex != m_NumSafePoints )
@@ -787,6 +796,8 @@ bool GcInfoDecoder::EnumerateLiveSlots(
else
{
m_Reader.Skip(m_NumSafePoints * numSlots);
+ if(noTrackedRefs)
+ goto ReportUntracked;
}
#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
diff --git a/tests/src/GC/API/GC/KeepAlive.cs b/tests/src/GC/API/GC/KeepAlive.cs
index df3d9d27c4..3174f89345 100644
--- a/tests/src/GC/API/GC/KeepAlive.cs
+++ b/tests/src/GC/API/GC/KeepAlive.cs
@@ -47,16 +47,23 @@ public class Test
}
+ public static void RunTest2()
+ {
+ Dummy2 obj2 = new Dummy2();
+ obj2 = null;
+ }
+
+
public static void RunTest()
{
Dummy obj = new Dummy();
- Dummy2 obj2 = new Dummy2();
+
+ RunTest2();
// *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();
//}
diff --git a/tests/src/GC/Scenarios/LeakGen/leakgen.cs b/tests/src/GC/Scenarios/LeakGen/leakgen.cs
index 9235256f81..8ec65313a3 100644
--- a/tests/src/GC/Scenarios/LeakGen/leakgen.cs
+++ b/tests/src/GC/Scenarios/LeakGen/leakgen.cs
@@ -62,6 +62,10 @@ namespace LGen {
MakeLeak(iObj);
}
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
Console.WriteLine("~LeakObject() was called {0} times.", LeakObject.icFinal);
return (LeakObject.icFinal == iObj*iRep);
}
@@ -80,12 +84,6 @@ namespace LGen {
mem[mem.Length-1] = 1;
}
- Mv_Obj = null;
-
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
-
}
diff --git a/tests/src/GC/Scenarios/Samples/gc.cs b/tests/src/GC/Scenarios/Samples/gc.cs
index a6c1cfeb54..7ed11bc409 100644
--- a/tests/src/GC/Scenarios/Samples/gc.cs
+++ b/tests/src/GC/Scenarios/Samples/gc.cs
@@ -273,16 +273,21 @@ class Application {
static public ResurrectObj ResObjHolder; // Defaults to null
- // This method demonstrates how the GC supports resurrection.
+ // These methods demonstrate how the GC supports resurrection.
// NOTE: Resurrection is discouraged.
- private static void ResurrectionDemo() {
- Display(0, "\n\nDemo start: Object Resurrection.", +1);
-
+ private static void ResurrectionInit() {
// 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();
diff --git a/tests/src/GC/Scenarios/WeakReference/weakreffinal.cs b/tests/src/GC/Scenarios/WeakReference/weakreffinal.cs
index a356cec433..754e88d7a1 100644
--- a/tests/src/GC/Scenarios/WeakReference/weakreffinal.cs
+++ b/tests/src/GC/Scenarios/WeakReference/weakreffinal.cs
@@ -22,6 +22,11 @@ namespace DefaultNamespace {
public bool RunTest(int iObj,int iSwitch)
{
DeleteObj(iObj,iSwitch);
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
bool result = CheckResult(iObj,iSwitch);
return result;
}
@@ -48,11 +53,6 @@ namespace DefaultNamespace {
{
rgNode[i] = null;
}
-
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
-
}
public bool CheckResult(int iObj,int iSwitch)
diff --git a/tests/src/JIT/Methodical/Arrays/misc/arrres.cs b/tests/src/JIT/Methodical/Arrays/misc/arrres.cs
index 7956cc6103..e021a59d8c 100644
--- a/tests/src/JIT/Methodical/Arrays/misc/arrres.cs
+++ b/tests/src/JIT/Methodical/Arrays/misc/arrres.cs
@@ -45,15 +45,20 @@ namespace GCTest
return 100;
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
- private static void Test1()
+ private static void CollectAndFinalize()
{
- for (int i = 0; i < 50; i++)
- s_arr[i] = new Test(i);
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();
+ }
+ [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void Test2()
{
for (int i = 0; i < 50; i++)
@@ -62,52 +67,44 @@ namespace GCTest
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();