Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
markples committed Sep 8, 2023
1 parent 34e0b9e commit 9a96694
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 46 deletions.
180 changes: 142 additions & 38 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50738,24 +50738,29 @@ bool CFinalize::Initialize()
GC_NOTRIGGER;
} CONTRACTL_END;

m_Array = new (nothrow)(Object*[100]);
const int INITIAL_FINALIZER_ARRAY_SIZE = 100;
m_Array = new (nothrow)(Object*[INITIAL_FINALIZER_ARRAY_SIZE]);

if (!m_Array)
{
ASSERT (m_Array);
STRESS_LOG_OOM_STACK(sizeof(Object*[100]));
STRESS_LOG_OOM_STACK(sizeof(Object*[INITIAL_FINALIZER_ARRAY_SIZE]));
if (GCConfig::GetBreakOnOOM())
{
GCToOSInterface::DebugBreak();
}
return false;
}
m_EndArray = &m_Array[100];
m_EndArray = &m_Array[INITIAL_FINALIZER_ARRAY_SIZE];

for (int i =0; i < FreeList; i++)
for (int i = 0; i < FreeListSeg; i++)
{
SegQueueLimit (i) = m_Array;
}
for (int i = FreeListSeg; i < MaxSeg; i++)
{
SegQueueLimit (i) = m_EndArray;
}
m_PromotedCount = 0;
lock = -1;
#ifdef _DEBUG
Expand Down Expand Up @@ -50840,8 +50845,8 @@ CFinalize::RegisterForFinalization (int gen, Object* obj, size_t size)
unsigned int dest = gen_segment (gen);

// Adjust boundary for segments so that GC will keep objects alive.
Object*** s_i = &SegQueue (FreeList);
if ((*s_i) == m_EndArray)
Object*** s_i = &SegQueue (FreeListSeg);
if ((*s_i) == SegQueueLimit(FreeListSeg))
{
if (!GrowArray())
{
Expand All @@ -50861,20 +50866,31 @@ CFinalize::RegisterForFinalization (int gen, Object* obj, size_t size)
return false;
}
}

// | loop: /->-->-\ /->->-\ |
// | / \ / \ |
// Start: | ... | dest |a other |b gen0 |_ free | ...
// | / |
// final store: o -->-/ |
// | |
// Result: | ... | dest o| other a| gen0 b| free | ...

assert (dest < FreeListSeg);
Object*** end_si = &SegQueueLimit (dest);
do
while (s_i > end_si)
{
assert (s_i > &SegQueue(0));
//is the segment empty?
if (!(*s_i == *(s_i-1)))
{
//no, swap the end elements.
//no, move the first element of the segment to the (new) last location in the segment
*(*s_i) = *(*(s_i-1));
}
//increment the fill pointer
(*s_i)++;
//go to the next segment.
s_i--;
} while (s_i > end_si);
}

// We have reached the destination segment
// store the object
Expand All @@ -50895,14 +50911,14 @@ CFinalize::GetNextFinalizableObject (BOOL only_non_critical)

if (!IsSegEmpty(FinalizerListSeg))
{
obj = *(--SegQueueLimit (FinalizerListSeg));
obj = *(SegQueue (FinalizerListSeg)++);
}
else if (!only_non_critical && !IsSegEmpty(CriticalFinalizerListSeg))
{
//the FinalizerList is empty, we can adjust both
// limit instead of moving the object to the free list
obj = *(--SegQueueLimit (CriticalFinalizerListSeg));
--SegQueueLimit (FinalizerListSeg);
obj = *(SegQueue (CriticalFinalizerListSeg)++);
SegQueue (FinalizerListSeg)++;
}
if (obj)
{
Expand All @@ -50915,7 +50931,7 @@ CFinalize::GetNextFinalizableObject (BOOL only_non_critical)
size_t
CFinalize::GetNumberFinalizableObjects()
{
return SegQueueLimit(FinalizerListSeg) - SegQueue(FinalizerListSeg);
return SegQueueLimit(FinalizerMaxSeg) - SegQueue(FinalizerStartSeg);
}

void
Expand All @@ -50930,11 +50946,16 @@ CFinalize::MoveItem (Object** fromIndex,
step = -1;
else
step = +1;
// Place the element at the boundary closest to dest
// Each iteration places the element at the boundary closest to dest
// and then adjusts the boundary to move that element one segment closer
// to dest.
Object** srcIndex = fromIndex;
for (unsigned int i = fromSeg; i != toSeg; i+= step)
{
// Select SegQueue[i] for step==-1, SegQueueLimit[i] for step==1
Object**& destFill = m_FillPointers[i+(step - 1 )/2];
// Select SegQueue[i] for step==-1, SegQueueLimit[i]-1 for step==1
// (SegQueueLimit[i]-1 is the last entry in segment i)
Object** destIndex = destFill - (step + 1)/2;
if (srcIndex != destIndex)
{
Expand All @@ -50957,8 +50978,8 @@ CFinalize::GcScanRoots (promote_func* fn, int hn, ScanContext *pSC)
pSC->thread_number = hn;

//scan the finalization queue
Object** startIndex = SegQueue (CriticalFinalizerListSeg);
Object** stopIndex = SegQueueLimit (FinalizerListSeg);
Object** startIndex = SegQueue (FinalizerStartSeg);
Object** stopIndex = SegQueueLimit (FinalizerMaxSeg);

for (Object** po = startIndex; po < stopIndex; po++)
{
Expand All @@ -50972,12 +50993,20 @@ CFinalize::GcScanRoots (promote_func* fn, int hn, ScanContext *pSC)

void CFinalize::WalkFReachableObjects (fq_walk_fn fn)
{
Object** startIndex = SegQueue (CriticalFinalizerListSeg);
Object** stopCriticalIndex = SegQueueLimit (CriticalFinalizerListSeg);
Object** stopIndex = SegQueueLimit (FinalizerListSeg);
Object** startIndex = SegQueue (FinalizerListSeg);
Object** stopIndex = SegQueueLimit (FinalizerListSeg);
for (Object** po = startIndex; po < stopIndex; po++)
{
fn(po < stopCriticalIndex, *po);
bool isCriticalFinalizer = false;
fn(isCriticalFinalizer, *po);
}

startIndex = SegQueue (CriticalFinalizerListSeg);
stopIndex = SegQueueLimit (CriticalFinalizerListSeg);
for (Object** po = startIndex; po < stopIndex; po++)
{
bool isCriticalFinalizer = true;
fn(isCriticalFinalizer, *po);
}
}

Expand Down Expand Up @@ -51016,13 +51045,13 @@ CFinalize::ScanForFinalization (promote_func* pfn, int gen, BOOL mark_only_p,

if (GCToEEInterface::EagerFinalized(obj))
{
MoveItem (i, Seg, FreeList);
MoveItem (i, Seg, FreeListSeg);
}
else if ((obj->GetHeader()->GetBits()) & BIT_SBLK_FINALIZER_RUN)
{
//remove the object because we don't want to
//run the finalizer
MoveItem (i, Seg, FreeList);
MoveItem (i, Seg, FreeListSeg);

//Reset the bit so it will be put back on the queue
//if resurrected and re-registered.
Expand Down Expand Up @@ -51106,10 +51135,21 @@ CFinalize::RelocateFinalizationData (int gen, gc_heap* hp)
unsigned int Seg = gen_segment (gen);

Object** startIndex = SegQueue (Seg);
Object** endIndex = SegQueue (FreeListSeg);

dprintf (3, ("RelocateFinalizationData gen=%d, [%p,%p[", gen, startIndex, SegQueue (FreeList)));
dprintf (3, ("RelocateFinalizationData gen=%d, [%p,%p[", gen, startIndex, endIndex));

for (Object** po = startIndex; po < SegQueue (FreeList);po++)
for (Object** po = startIndex; po < endIndex; po++)
{
GCHeap::Relocate (po, &sc);
}

startIndex = SegQueueLimit (FreeListSeg);
endIndex = SegQueueLimit (MaxSeg);

dprintf (3, ("RelocateFinalizationData gen=%d, [%p,%p[", gen, startIndex, endIndex));

for (Object** po = startIndex; po < endIndex; po++)
{
GCHeap::Relocate (po, &sc);
}
Expand Down Expand Up @@ -51178,15 +51218,28 @@ CFinalize::GrowArray()
{
return FALSE;
}
memcpy (newArray, m_Array, oldArraySize*sizeof(Object*));

// Start: | genX | genY | free | final | crit |
//
// Result: | genX | genY | free | final | crit |

size_t prefixCount = SegQueue(FreeListSeg) - m_Array;
memcpy (newArray, m_Array, prefixCount * sizeof(Object*));
size_t postfixCount = m_EndArray - SegQueueLimit(FreeListSeg);
memcpy (newArray + newArraySize - postfixCount, SegQueueLimit(FreeListSeg), postfixCount * sizeof(Object*));

dprintf (3, ("Grow finalizer array [%p,%p[ -> [%p,%p[", m_Array, m_EndArray, newArray, &m_Array[newArraySize]));

//adjust the fill pointers
for (int i = 0; i < FreeList; i++)
for (int i = 0; i < FreeListSeg; i++)
{
m_FillPointers [i] += (newArray - m_Array);
}
//additional space in new array is added to FreeListSeg, not the end
for (int i = FreeListSeg; i < MaxSeg; ++i)
{
m_FillPointers [i] += (newArray - m_Array) + (newArraySize - oldArraySize);
}
delete[] m_Array;
m_Array = newArray;
m_EndArray = &m_Array [newArraySize];
Expand All @@ -51199,15 +51252,16 @@ CFinalize::GrowArray()
bool CFinalize::MergeFinalizationData (CFinalize* other_fq)
{
// compute how much space we will need for the merged data
size_t otherNeededArraySize = other_fq->SegQueue (FreeList) - other_fq->m_Array;
size_t otherNeededArraySize = other_fq->UsedCount();
if (otherNeededArraySize == 0)
{
// the other queue is empty - nothing to do!
return true;
}
size_t thisArraySize = (m_EndArray - m_Array);
size_t thisNeededArraySize = SegQueue (FreeList) - m_Array;
size_t thisNeededArraySize = UsedCount();
size_t neededArraySize = thisNeededArraySize + otherNeededArraySize;
size_t growthCount = 0;

Object ** newArray = m_Array;

Expand All @@ -51216,6 +51270,7 @@ bool CFinalize::MergeFinalizationData (CFinalize* other_fq)
{
// if not allocate new array
newArray = new (nothrow) Object*[neededArraySize];
growthCount = neededArraySize - thisArraySize;

// if unsuccessful, return false without changing anything
if (!newArray)
Expand All @@ -51225,8 +51280,13 @@ bool CFinalize::MergeFinalizationData (CFinalize* other_fq)
}
}

// copy the finalization data from this and the other finalize queue
for (int i = FreeList - 1; i >= 0; i--)
// Since the target might be the original array (with the original data),
// the order of copying must not overwrite any data until it has been
// copied. Both loops skip 'FreeListSeg' because there is no need to copy
// the unused data in the freelist.

// copy the generation data from this and the other finalize queue
for (int i = FreeListSeg - 1; i >= 0; i--)
{
size_t thisIndex = SegQueue (i) - m_Array;
size_t otherIndex = other_fq->SegQueue (i) - other_fq->m_Array;
Expand All @@ -51239,14 +51299,35 @@ bool CFinalize::MergeFinalizationData (CFinalize* other_fq)
memmove (&newArray[thisLimit + otherIndex], &other_fq->m_Array[otherIndex], sizeof(newArray[0])*otherSize);
}

// copy the finalization data from this and the other finalize queue
//
// note reverse order from above to preserve the existing data
for (int i = FreeListSeg + 1; i <= MaxSeg; i++)
{
size_t thisIndex = SegQueue (i) - m_Array;
size_t otherIndex = other_fq->SegQueue (i) - other_fq->m_Array;
size_t thisLimit = SegQueueLimit (i) - m_Array;
size_t otherLimit = other_fq->SegQueueLimit (i) - other_fq->m_Array;
size_t thisSize = thisLimit - thisIndex;
size_t otherSize = otherLimit - otherIndex;

memmove (&newArray[thisIndex + otherIndex + growthCount], &m_Array[thisIndex ], sizeof(newArray[0])*thisSize );
memmove (&newArray[thisLimit + otherIndex + growthCount], &other_fq->m_Array[otherIndex], sizeof(newArray[0])*otherSize);
}

// adjust the m_FillPointers to reflect the sum of both queues on this queue,
// and reflect that the other queue is now empty
for (int i = FreeList - 1; i >= 0; i--)
//
// unlike copying, this loop does include 'FreeListSeg' since the
// boundary needs to be set correctly, but including MaxSeg itself would
// set m_EndArray
for (int i = MaxSeg - 1; i >= 0; i--)
{
size_t thisLimit = SegQueueLimit (i) - m_Array;
size_t otherLimit = other_fq->SegQueueLimit (i) - other_fq->m_Array;
size_t offset = ((i >= FreeListSeg) ? growthCount : 0);

SegQueueLimit (i) = &newArray[thisLimit + otherLimit];
SegQueueLimit (i) = &newArray[thisLimit + otherLimit + offset];

other_fq->SegQueueLimit (i) = other_fq->m_Array;
}
Expand All @@ -51264,10 +51345,10 @@ bool CFinalize::MergeFinalizationData (CFinalize* other_fq)
bool CFinalize::SplitFinalizationData (CFinalize* other_fq)
{
// the other finalization queue is assumed to be empty at this point
size_t otherCurrentArraySize = other_fq->SegQueue (FreeList) - other_fq->m_Array;
size_t otherCurrentArraySize = other_fq->UsedCount();
assert (otherCurrentArraySize == 0);

size_t thisCurrentArraySize = SegQueue (FreeList) - m_Array;
size_t thisCurrentArraySize = UsedCount();
if (thisCurrentArraySize == 0)
{
// this queue is empty - nothing to split!
Expand All @@ -51293,9 +51374,9 @@ bool CFinalize::SplitFinalizationData (CFinalize* other_fq)
}

// move half of the items in each section over to the other queue
PTR_PTR_Object newFillPointers[FreeList];
PTR_PTR_Object newFillPointers[MaxSeg];
PTR_PTR_Object segQueue = m_Array;
for (int i = 0; i < FreeList; i++)
for (int i = 0; i < FreeListSeg; i++)
{
size_t thisIndex = SegQueue (i) - m_Array;
size_t thisLimit = SegQueueLimit (i) - m_Array;
Expand All @@ -51309,14 +51390,37 @@ bool CFinalize::SplitFinalizationData (CFinalize* other_fq)
memmove (&other_fq->m_Array[otherIndex], &m_Array[thisIndex + thisNewSize], sizeof(other_fq->m_Array[0])*otherSize);
other_fq->SegQueueLimit (i) = &other_fq->m_Array[otherIndex + otherSize];

// we delete the moved half from this queue
// slide the unmoved half to its new position in the queue
// (this will delete the moved half once copies and m_FillPointers updates are completed)
memmove (segQueue, &m_Array[thisIndex], sizeof(m_Array[0])*thisNewSize);
segQueue += thisNewSize;
newFillPointers[i] = segQueue;
}

segQueue = m_EndArray;
for (int i = MaxSeg; i > FreeListSeg; i++)
{
size_t thisIndex = SegQueue (i) - m_Array;
size_t thisLimit = SegQueueLimit (i) - m_Array;
size_t thisSize = thisLimit - thisIndex;

// we move half to the other queue
size_t otherSize = thisSize / 2;
size_t otherIndex = other_fq->SegQueueLimit (i) - other_fq->m_Array;
size_t thisNewSize = thisSize - otherSize;

memmove (&other_fq->m_Array[otherIndex], &m_Array[thisIndex + thisNewSize], sizeof(other_fq->m_Array[0])*otherSize);
other_fq->SegQueue (i) = &other_fq->m_Array[otherIndex];

// slide the unmoved half to its new position in the queue
// (this will delete the moved half once copies and m_FillPointers updates are completed)
segQueue -= thisNewSize;
memmove (segQueue, &m_Array[thisIndex], sizeof(m_Array[0])*thisNewSize);
newFillPointers[i - 1] = segQueue;
}

// finally update the fill pointers from the new copy we generated
for (int i = 0; i < FreeList; i++)
for (int i = 0; i < MaxSeg; i++)
{
m_FillPointers[i] = newFillPointers[i];
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/gc/gcinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ typedef bool (* walk_fn)(Object*, void*);
typedef bool (* walk_fn2)(Object*, uint8_t**, void*);
typedef void (* gen_walk_fn)(void* context, int generation, uint8_t* range_start, uint8_t* range_end, uint8_t* range_reserved);
typedef void (* record_surv_fn)(uint8_t* begin, uint8_t* end, ptrdiff_t reloc, void* context, bool compacting_p, bool bgc_p);
typedef void (* fq_walk_fn)(bool, void*);
typedef void (* fq_walk_fn)(bool isCritical, void* pObject);
typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlags);
typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent);
typedef bool (* async_pin_enum_fn)(Object* object, void* context);
Expand Down
Loading

0 comments on commit 9a96694

Please sign in to comment.