mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 09:34:49 +09:00
added gen num and ForEachObjectRef with range,
ForEachPage, barrier, card size and initialization fixes
This commit is contained in:
parent
01748e2d65
commit
c61cff6826
21 changed files with 515 additions and 132 deletions
|
@ -311,7 +311,7 @@ FORCEINLINE void InlinedMemmoveGCRefsHelper(void *dest, const void *src, size_t
|
|||
|
||||
if (len >= sizeof(size_t))
|
||||
{
|
||||
CheckEscapeSatoriRange(dest, (void*)src, len);
|
||||
CheckEscapeSatoriRange(dest, (size_t)src, len);
|
||||
}
|
||||
|
||||
// To be able to copy forwards, the destination buffer cannot start inside the source buffer
|
||||
|
|
24
src/coreclr/gc/env/gcenv.interlocked.inl
vendored
24
src/coreclr/gc/env/gcenv.interlocked.inl
vendored
|
@ -96,6 +96,30 @@ __forceinline T Interlocked::CompareExchange(T volatile *destination, T exchange
|
|||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
__forceinline size_t Interlocked::CompareExchange<size_t>(size_t volatile * destination, size_t exchange, size_t comparand)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _InterlockedCompareExchange64((volatile long long*)destination, exchange, comparand);
|
||||
#else
|
||||
T result = __sync_val_compare_and_swap(destination, comparand, exchange);
|
||||
ArmInterlockedOperationBarrier();
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
__forceinline uint8_t Interlocked::CompareExchange<uint8_t>(uint8_t volatile* destination, uint8_t exchange, uint8_t comparand)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _InterlockedCompareExchange8((char*)destination, exchange, comparand);
|
||||
#else
|
||||
T result = __sync_val_compare_and_swap(destination, comparand, exchange);
|
||||
ArmInterlockedOperationBarrier();
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Perform an atomic addition of two 32-bit values and return the original value of the addend.
|
||||
// Parameters:
|
||||
// addend - variable to be added to
|
||||
|
|
|
@ -161,13 +161,13 @@ SatoriObject* SatoriAllocator::AllocRegular(SatoriAllocationContext* context, si
|
|||
size_t allocRemaining = region->AllocRemaining();
|
||||
if (moreSpace <= allocRemaining)
|
||||
{
|
||||
bool isZeroing = true;
|
||||
if (isZeroing && moreSpace < Satori::MIN_REGULAR_ALLOC)
|
||||
bool zeroInitialize = !(flags & GC_ALLOC_ZEROING_OPTIONAL);
|
||||
if (zeroInitialize && moreSpace < Satori::MIN_REGULAR_ALLOC)
|
||||
{
|
||||
moreSpace = min(allocRemaining, Satori::MIN_REGULAR_ALLOC);
|
||||
}
|
||||
|
||||
if (region->Allocate(moreSpace, isZeroing))
|
||||
if (region->Allocate(moreSpace, zeroInitialize))
|
||||
{
|
||||
context->alloc_bytes += moreSpace;
|
||||
context->alloc_limit += moreSpace;
|
||||
|
@ -247,7 +247,8 @@ SatoriObject* SatoriAllocator::AllocLarge(SatoriAllocationContext* context, size
|
|||
size_t allocRemaining = region->AllocRemaining();
|
||||
if (allocRemaining >= size)
|
||||
{
|
||||
SatoriObject* result = SatoriObject::At(region->Allocate(size, true));
|
||||
bool zeroInitialize = !(flags & GC_ALLOC_ZEROING_OPTIONAL);
|
||||
SatoriObject* result = SatoriObject::At(region->Allocate(size, zeroInitialize));
|
||||
if (result)
|
||||
{
|
||||
result->CleanSyncBlock();
|
||||
|
@ -286,7 +287,6 @@ SatoriObject* SatoriAllocator::AllocLarge(SatoriAllocationContext* context, size
|
|||
}
|
||||
|
||||
_ASSERTE(region->NothingMarked());
|
||||
region->m_ownerThreadTag = SatoriUtil::GetCurrentThreadTag();
|
||||
context->LargeRegion() = region;
|
||||
}
|
||||
}
|
||||
|
@ -302,7 +302,8 @@ SatoriObject* SatoriAllocator::AllocHuge(SatoriAllocationContext* context, size_
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
SatoriObject* result = SatoriObject::At(region->AllocateHuge(size, true));
|
||||
bool zeroInitialize = !(flags & GC_ALLOC_ZEROING_OPTIONAL);
|
||||
SatoriObject* result = SatoriObject::At(region->AllocateHuge(size, zeroInitialize));
|
||||
if (result)
|
||||
{
|
||||
result->CleanSyncBlock();
|
||||
|
@ -318,8 +319,9 @@ SatoriObject* SatoriAllocator::AllocHuge(SatoriAllocationContext* context, size_
|
|||
|
||||
// we do not want to keep huge region in allocator for simplicity,
|
||||
// but can't drop it to recycler yet since the object has no MethodTable.
|
||||
// we will leave the region unowned and send it to recycler later in PublishObject.
|
||||
// we will make the region gen1 and send it to recycler later in PublishObject.
|
||||
region->StopAllocating(/* allocPtr */ 0);
|
||||
region->SetGeneration(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -345,7 +347,7 @@ bool SatoriAllocator::AddMoreMarkChunks()
|
|||
|
||||
while (true)
|
||||
{
|
||||
size_t mem = region->Allocate(Satori::MARK_CHUNK_SIZE, /*ensureZeroInited*/ false);
|
||||
size_t mem = region->Allocate(Satori::MARK_CHUNK_SIZE, /*zeroInitialize*/ false);
|
||||
if (!mem)
|
||||
{
|
||||
break;
|
||||
|
|
|
@ -127,9 +127,8 @@ int SatoriGC::WaitForFullGCComplete(int millisecondsTimeout)
|
|||
|
||||
unsigned SatoriGC::WhichGeneration(Object* obj)
|
||||
{
|
||||
//TODO: Satori update when have Gen1
|
||||
SatoriObject* so = (SatoriObject*)obj;
|
||||
return so->ContainingRegion()->IsThreadLocal() ? 0 : 2;
|
||||
return (unsigned)so->ContainingRegion()->Generation();
|
||||
}
|
||||
|
||||
int SatoriGC::CollectionCount(int generation, int get_bgc_fgc_coutn)
|
||||
|
@ -379,7 +378,7 @@ void SatoriGC::PublishObject(uint8_t* obj)
|
|||
// we do not retain huge regions in allocator,
|
||||
// but can't drop them in recycler until object has a MethodTable.
|
||||
// do that here.
|
||||
if (!region->IsThreadLocal())
|
||||
if (region->Generation() != 0)
|
||||
{
|
||||
_ASSERTE(region->Size() > Satori::REGION_SIZE_GRANULARITY);
|
||||
m_heap->Recycler()->AddRegion(region);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "SatoriRegion.h"
|
||||
#include "SatoriObject.h"
|
||||
#include "SatoriPage.h"
|
||||
#include "SatoriPage.inl"
|
||||
|
||||
void InitWriteBarrier(uint8_t* segmentTable, size_t highest_address)
|
||||
{
|
||||
|
@ -183,8 +184,9 @@ SatoriPage* SatoriHeap::AddLargePage(size_t minSize)
|
|||
m_pageMap[i] = 1;
|
||||
for (int j = 1; j < mapMarkCount; j++)
|
||||
{
|
||||
// TODO: VS skip-marks
|
||||
m_pageMap[i + j] = 2;
|
||||
DWORD log2;
|
||||
BitScanReverse(&log2, j);
|
||||
m_pageMap[i + j] = (uint8_t)(log2 + 2);
|
||||
}
|
||||
|
||||
// we also need to ensure that the other thread doing the barrier,
|
||||
|
@ -210,30 +212,6 @@ SatoriPage* SatoriHeap::AddLargePage(size_t minSize)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
//TODO: VS move into inl
|
||||
inline SatoriPage* SatoriHeap::PageForAddress(size_t address)
|
||||
{
|
||||
size_t mapIndex = address >> Satori::PAGE_BITS;
|
||||
while (m_pageMap[mapIndex] > 1)
|
||||
{
|
||||
mapIndex -= ((size_t)1 << (m_pageMap[mapIndex] - 2));
|
||||
}
|
||||
|
||||
return (SatoriPage *)(mapIndex << Satori::PAGE_BITS);
|
||||
}
|
||||
|
||||
//TODO: VS unused?
|
||||
SatoriRegion* SatoriHeap::RegionForAddress(size_t address)
|
||||
{
|
||||
if (IsHeapAddress(address))
|
||||
{
|
||||
return PageForAddress(address)->RegionForAddress(address);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//TODO: VS optimize this, move to inl
|
||||
SatoriObject* SatoriHeap::ObjectForAddress(size_t address)
|
||||
{
|
||||
if (IsHeapAddress(address))
|
||||
|
@ -243,9 +221,3 @@ SatoriObject* SatoriHeap::ObjectForAddress(size_t address)
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//TODO: VS move into inl
|
||||
void SatoriHeap::SetCardForAddress(size_t address)
|
||||
{
|
||||
PageForAddress(address)->SetCardForAddress(address);
|
||||
}
|
||||
|
|
|
@ -47,18 +47,45 @@ public:
|
|||
return &m_finalizationQueue;
|
||||
}
|
||||
|
||||
SatoriPage* PageForAddress(size_t address);
|
||||
SatoriRegion* RegionForAddress(size_t address);
|
||||
SatoriObject* ObjectForAddress(size_t address);
|
||||
void SetCardForAddress(size_t address);
|
||||
|
||||
bool IsHeapAddress(size_t address)
|
||||
{
|
||||
size_t mapIndex = address >> Satori::PAGE_BITS;
|
||||
return (unsigned int)mapIndex < (unsigned int)m_committedMapSize &&
|
||||
return (unsigned int)mapIndex < (unsigned int)m_committedMapSize&&
|
||||
m_pageMap[mapIndex] != 0;
|
||||
}
|
||||
|
||||
SatoriPage* PageForAddress(size_t address)
|
||||
{
|
||||
size_t mapIndex = address >> Satori::PAGE_BITS;
|
||||
while (m_pageMap[mapIndex] > 1)
|
||||
{
|
||||
mapIndex -= ((size_t)1 << (m_pageMap[mapIndex] - 2));
|
||||
}
|
||||
|
||||
return (SatoriPage*)(mapIndex << Satori::PAGE_BITS);
|
||||
}
|
||||
|
||||
SatoriObject* ObjectForAddress(size_t address);
|
||||
|
||||
template<typename F>
|
||||
void ForEachPage(F& lambda)
|
||||
{
|
||||
size_t mapIndex = m_nextPageIndex - 1;
|
||||
while (mapIndex > 0)
|
||||
{
|
||||
switch (m_pageMap[mapIndex])
|
||||
{
|
||||
case 1:
|
||||
lambda((SatoriPage*)(mapIndex << Satori::PAGE_BITS));
|
||||
case 0:
|
||||
mapIndex--;
|
||||
continue;
|
||||
default:
|
||||
mapIndex -= ((size_t)1 << (m_pageMap[mapIndex] - 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SatoriAllocator m_allocator;
|
||||
SatoriRecycler m_recycler;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "SatoriObject.inl"
|
||||
#include "SatoriRegion.h"
|
||||
#include "SatoriRegion.inl"
|
||||
#include "SatoriPage.h"
|
||||
#include "SatoriPage.inl"
|
||||
|
||||
MethodTable* SatoriObject::s_emptyObjectMt;
|
||||
|
||||
|
@ -80,6 +82,32 @@ SatoriObject* SatoriObject::FormatAsFreeAfterHuge(size_t location, size_t size)
|
|||
return obj;
|
||||
}
|
||||
|
||||
void SatoriObject::SetCardsForContent()
|
||||
{
|
||||
_ASSERTE(IsMarked());
|
||||
MethodTable* mt = RawGetMethodTable();
|
||||
if (mt->ContainsPointers())
|
||||
{
|
||||
SatoriPage* page = ContainingRegion()->m_containingPage;
|
||||
|
||||
// TODO: VS SetCardsForRange
|
||||
for (size_t i = Start(); i < End(); i++)
|
||||
{
|
||||
page->SetCardForAddress(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (mt->Collectible())
|
||||
{
|
||||
SatoriObject* o = (SatoriObject*)GCToEEInterface::GetLoaderAllocatorObjectForGC(this);
|
||||
if (!o->IsMarked())
|
||||
{
|
||||
o->SetMarked();
|
||||
o->SetCardsForContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SatoriObject::Validate()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
bool IsEscapedOrPinned();
|
||||
int MarkBitOffset(size_t* bitmapIndex);
|
||||
|
||||
void SetCardsForContent();
|
||||
|
||||
void EscapeCheck();
|
||||
|
||||
bool IsFinalizationSuppressed();
|
||||
|
@ -62,6 +64,9 @@ public:
|
|||
template<typename F>
|
||||
void ForEachObjectRef(F& lambda, bool includeCollectibleAllocator = false);
|
||||
|
||||
template<typename F>
|
||||
void ForEachObjectRef(F& lambda, size_t start, size_t end);
|
||||
|
||||
private:
|
||||
static MethodTable* s_emptyObjectMt;
|
||||
static void Initialize();
|
||||
|
|
|
@ -276,4 +276,105 @@ inline void SatoriObject::ForEachObjectRef(F& lambda, bool includeCollectibleAll
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void SatoriObject::ForEachObjectRef(F& lambda, size_t start, size_t end)
|
||||
{
|
||||
MethodTable* mt = RawGetMethodTable();
|
||||
if (!mt->ContainsPointers())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CGCDesc* map = CGCDesc::GetCGCDescFromMT(mt);
|
||||
CGCDescSeries* cur = map->GetHighestSeries();
|
||||
|
||||
// GetNumSeries is actually signed.
|
||||
// Negative value means the pattern repeats -cnt times such as in a case of arrays
|
||||
ptrdiff_t cnt = (ptrdiff_t)map->GetNumSeries();
|
||||
if (cnt >= 0)
|
||||
{
|
||||
CGCDescSeries* last = map->GetLowestSeries();
|
||||
|
||||
// series size is offset by the object size
|
||||
size_t size = mt->GetBaseSize();
|
||||
|
||||
// object arrays are handled here too, so need to compensate for that.
|
||||
if (mt->HasComponentSize())
|
||||
{
|
||||
size += (size_t)((ArrayBase*)this)->GetNumComponents() * sizeof(size_t);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
size_t refPtr = (size_t)this + cur->GetSeriesOffset();
|
||||
size_t refPtrStop = refPtr + size + cur->GetSeriesSize();
|
||||
|
||||
refPtr = max(refPtr, start);
|
||||
|
||||
// TODO: VS make ordinary while
|
||||
if (refPtr < refPtrStop)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (refPtr >= end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lambda((SatoriObject**)refPtr);
|
||||
refPtr += sizeof(size_t);
|
||||
} while (refPtr < refPtrStop);
|
||||
}
|
||||
|
||||
cur--;
|
||||
} while (cur >= last);
|
||||
}
|
||||
else
|
||||
{
|
||||
// repeating patern - an array of structs
|
||||
ptrdiff_t componentNum = ((ArrayBase*)this)->GetNumComponents();
|
||||
size_t elementSize = mt->RawGetComponentSize();
|
||||
size_t refPtr = (size_t)this + cur->GetSeriesOffset();
|
||||
|
||||
if (refPtr < start)
|
||||
{
|
||||
size_t skip = (start - refPtr) / elementSize;
|
||||
componentNum -= skip;
|
||||
refPtr += skip * elementSize;
|
||||
}
|
||||
|
||||
while (componentNum-- > 0)
|
||||
{
|
||||
for (ptrdiff_t i = 0; i > cnt; i--)
|
||||
{
|
||||
val_serie_item item = cur->val_serie[i];
|
||||
size_t refPtrStop = refPtr + item.nptrs * sizeof(size_t);
|
||||
|
||||
if (refPtrStop <= start)
|
||||
{
|
||||
// serie does not intersect with the range
|
||||
refPtr = refPtrStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
refPtr = max(refPtr, start);
|
||||
do
|
||||
{
|
||||
if (refPtr >= end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lambda((SatoriObject**)refPtr);
|
||||
refPtr += sizeof(size_t);
|
||||
} while (refPtr < refPtrStop);
|
||||
|
||||
}
|
||||
|
||||
refPtr += item.skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../env/gcenv.os.h"
|
||||
|
||||
#include "SatoriPage.h"
|
||||
#include "SatoriPage.inl"
|
||||
#include "SatoriRegion.h"
|
||||
#include "SatoriRegion.inl"
|
||||
|
||||
|
@ -24,10 +25,12 @@ SatoriPage* SatoriPage::InitializeAt(size_t address, size_t pageSize, SatoriHeap
|
|||
return result;
|
||||
}
|
||||
|
||||
// 128 bit/byte
|
||||
size_t cardTableBytes = pageSize / (128 * 8);
|
||||
size_t cardTableBytes = pageSize / Satori::BYTES_PER_CARD_BYTE;
|
||||
|
||||
// TODO: VS we do not need to commit the whole card table, we can wait until regions are used
|
||||
// and track commit via card groups.
|
||||
// commit size is the same as header size. We could commit more in the future.
|
||||
// or commit on demand as regions are committed.
|
||||
size_t commitSize = ALIGN_UP(cardTableBytes, Satori::CommitGranularity());
|
||||
if (!GCToOSInterface::VirtualCommit((void*)address, commitSize))
|
||||
{
|
||||
|
@ -41,15 +44,19 @@ SatoriPage* SatoriPage::InitializeAt(size_t address, size_t pageSize, SatoriHeap
|
|||
result->m_cardTableSize = (int)cardTableBytes / sizeof(size_t);
|
||||
|
||||
// conservatively assume the first useful card word to cover the start of the first region.
|
||||
size_t cardTableStart = (result->m_firstRegion - address) / (128 * 8 * sizeof(size_t));
|
||||
size_t cardTableStart = (result->m_firstRegion - address) / Satori::BYTES_PER_CARD_WORD;
|
||||
|
||||
// make sure the first useful card word is beyond the header.
|
||||
size_t regionMapSize = pageSize >> Satori::REGION_BITS;
|
||||
_ASSERTE(cardTableStart * sizeof(size_t) > offsetof(SatoriPage, m_regionMap) + regionMapSize);
|
||||
|
||||
result->m_cardTableStart = (int)cardTableStart;
|
||||
result->m_heap = heap;
|
||||
|
||||
// make sure offset of m_cardsStatus is 128.
|
||||
_ASSERTE(offsetof(SatoriPage, m_cardGroups) == 128);
|
||||
result->m_regionMap = (uint8_t*)(address + 128 + (pageSize >> Satori::REGION_BITS));
|
||||
|
||||
// make sure the first useful card word is beyond the header.
|
||||
_ASSERTE(result->Start() + cardTableStart * sizeof(size_t) > (size_t)(result->m_regionMap) + regionMapSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -68,8 +75,9 @@ void SatoriPage::RegionInitialized(SatoriRegion* region)
|
|||
RegionMap()[startIndex] = 1;
|
||||
for (int i = 1; i < mapCount; i++)
|
||||
{
|
||||
// TODO: VS skip-marks
|
||||
RegionMap()[startIndex + i] = 2;
|
||||
DWORD log2;
|
||||
BitScanReverse(&log2, i);
|
||||
RegionMap()[startIndex + i] = (uint8_t)(log2 + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,8 +88,9 @@ void SatoriPage::RegionDestroyed(SatoriRegion* region)
|
|||
size_t mapCount = region->Size() >> Satori::REGION_BITS;
|
||||
for (int i = 0; i < mapCount; i++)
|
||||
{
|
||||
// TODO: VS skip-marks
|
||||
RegionMap()[startIndex + i] = 0;
|
||||
DWORD log2;
|
||||
BitScanReverse(&log2, i);
|
||||
RegionMap()[startIndex + i] = (uint8_t)(log2 + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "../gc.h"
|
||||
#include "SatoriUtil.h"
|
||||
|
||||
class SatoriHeap;
|
||||
class SatoriRegion;
|
||||
|
@ -28,59 +29,76 @@ public:
|
|||
|
||||
SatoriRegion* RegionForAddress(size_t address);
|
||||
|
||||
size_t Start()
|
||||
size_t Start();
|
||||
size_t End();
|
||||
size_t RegionsStart();
|
||||
uint8_t* RegionMap();
|
||||
SatoriHeap* Heap();
|
||||
|
||||
void SetCardForAddress(size_t address);
|
||||
|
||||
bool IsClean()
|
||||
{
|
||||
return (size_t)this;
|
||||
return VolatileLoadWithoutBarrier(&m_cardState) == 0;
|
||||
}
|
||||
|
||||
size_t End()
|
||||
void SetProcessing()
|
||||
{
|
||||
return m_end;
|
||||
VolatileStoreWithoutBarrier(&m_cardState, 2);
|
||||
}
|
||||
|
||||
size_t RegionsStart()
|
||||
bool TrySetClean()
|
||||
{
|
||||
return m_firstRegion;
|
||||
_ASSERTE((m_cardState >= 0) && (m_cardState <= 2));
|
||||
return Interlocked::CompareExchange(&m_cardState, 0, 2) != 1;
|
||||
}
|
||||
|
||||
uint8_t* RegionMap()
|
||||
size_t CardGroupCount()
|
||||
{
|
||||
return m_regionMap;
|
||||
return (End() - Start()) >> Satori::REGION_BITS;
|
||||
}
|
||||
|
||||
SatoriHeap* Heap()
|
||||
Satori::CardGroupState CardGroupState(size_t i)
|
||||
{
|
||||
return m_heap;
|
||||
return (Satori::CardGroupState)m_cardGroups[i];
|
||||
}
|
||||
|
||||
void SetCardForAddress(size_t address)
|
||||
void CardGroupSetProcessing(size_t i)
|
||||
{
|
||||
size_t offset = address - Start();
|
||||
size_t cardByteOffset = offset / (128 * 8);
|
||||
m_cardGroups[i] = Satori::CardGroupState::processing;
|
||||
}
|
||||
|
||||
_ASSERTE(cardByteOffset / 8 > m_cardTableStart);
|
||||
_ASSERTE(cardByteOffset / 8 < m_cardTableSize);
|
||||
void CardGroupTrySetClean(size_t i)
|
||||
{
|
||||
Interlocked::CompareExchange<uint8_t>(&m_cardGroups[i], Satori::CardGroupState::clean, Satori::CardGroupState::processing);
|
||||
}
|
||||
|
||||
((uint8_t*)this)[cardByteOffset] = 0xFF;
|
||||
size_t* CardsForGroup(size_t i)
|
||||
{
|
||||
return &m_cardTable[i * Satori::CARD_WORDS_IN_CARD_GROUP];
|
||||
}
|
||||
|
||||
// TODO: VS dirty the region
|
||||
size_t LocationForCard(void* cardPtr)
|
||||
{
|
||||
return Start() + ((size_t)cardPtr - Start()) * Satori::BYTES_PER_CARD_BYTE;
|
||||
}
|
||||
|
||||
private:
|
||||
union
|
||||
{
|
||||
// 1bit - 128 bytes
|
||||
// 1byte - 1k
|
||||
// 2K - 2Mb (region granularity)
|
||||
// 1Mb - 1Gb
|
||||
// 1bit - 64 bytes
|
||||
// 1byte - 512 bytes i.e cards add ~ 0.002 overhead
|
||||
// 8byte - 4k
|
||||
// 4K - 2Mb (region granularity)
|
||||
// 2Mb - 1Gb (region granule can store cards for 1Gb page)
|
||||
// We can start card table at the beginning of the page for simplicity
|
||||
// The first 2K+ cover the header, which includes the region map and the table itself
|
||||
// so that space will be unused.
|
||||
// The first 4K cover the card itself, so that space will be unused and we can use it for other metadata.
|
||||
size_t m_cardTable[1];
|
||||
|
||||
// header (can be up to 2Kb for 1Gb page)
|
||||
struct
|
||||
{
|
||||
int32_t m_cardState;
|
||||
size_t m_end;
|
||||
size_t m_initialCommit;
|
||||
size_t m_firstRegion;
|
||||
|
@ -92,9 +110,19 @@ private:
|
|||
int m_cardTableSize;
|
||||
int m_cardTableStart;
|
||||
|
||||
// ----- we can have a few more fields above as long as m_cardsStatus starts at offset 128.
|
||||
// that can be adjusted if needed
|
||||
|
||||
// computed size,
|
||||
// 1byte per region
|
||||
// 512 bytes per 1Gb
|
||||
uint8_t m_regionMap[1];
|
||||
uint8_t* m_regionMap;
|
||||
|
||||
// computed size,
|
||||
// 1byte per region
|
||||
// 512 bytes per 1Gb
|
||||
DECLSPEC_ALIGN(128)
|
||||
uint8_t m_cardGroups[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
55
src/coreclr/src/gc/satori/SatoriPage.inl
Normal file
55
src/coreclr/src/gc/satori/SatoriPage.inl
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
//
|
||||
// SatoriPage.inl
|
||||
//
|
||||
|
||||
#ifndef __SATORI_PAGE_INL__
|
||||
#define __SATORI_PAGE_INL__
|
||||
|
||||
#include "SatoriUtil.h"
|
||||
#include "SatoriPage.h"
|
||||
|
||||
inline size_t SatoriPage::Start()
|
||||
{
|
||||
return (size_t)this;
|
||||
}
|
||||
|
||||
inline size_t SatoriPage::End()
|
||||
{
|
||||
return m_end;
|
||||
}
|
||||
|
||||
inline size_t SatoriPage::RegionsStart()
|
||||
{
|
||||
return m_firstRegion;
|
||||
}
|
||||
|
||||
inline uint8_t* SatoriPage::RegionMap()
|
||||
{
|
||||
return m_regionMap;
|
||||
}
|
||||
|
||||
inline SatoriHeap* SatoriPage::Heap()
|
||||
{
|
||||
return m_heap;
|
||||
}
|
||||
|
||||
inline void SatoriPage::SetCardForAddress(size_t address)
|
||||
{
|
||||
size_t offset = address - Start();
|
||||
size_t cardByteOffset = offset / Satori::BYTES_PER_CARD_BYTE;
|
||||
|
||||
_ASSERTE(cardByteOffset / 8 > m_cardTableStart);
|
||||
_ASSERTE(cardByteOffset / 8 < m_cardTableSize);
|
||||
|
||||
((uint8_t*)this)[cardByteOffset] = 0xFF;
|
||||
|
||||
size_t cardGroupOffset = offset / Satori::REGION_SIZE_GRANULARITY;
|
||||
this->m_cardGroups[cardGroupOffset] = Satori::CardGroupState::dirty;
|
||||
|
||||
this->m_cardState = 1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "SatoriHeap.h"
|
||||
#include "SatoriPage.h"
|
||||
#include "SatoriPage.inl"
|
||||
#include "SatoriRecycler.h"
|
||||
#include "SatoriObject.h"
|
||||
#include "SatoriObject.inl"
|
||||
|
@ -116,19 +117,19 @@ void SatoriRecycler::Collect(bool force)
|
|||
while (m_workList->Count() > 0)
|
||||
{
|
||||
DrainMarkQueues();
|
||||
//TODO: VS clean cards (could be due to overflow)
|
||||
}
|
||||
|
||||
// all strongly reachable objects are marked here
|
||||
// all strongly reachable objects are marked here
|
||||
AssertNoWork();
|
||||
|
||||
DependentHandlesInitialScan();
|
||||
while (m_workList->Count() > 0)
|
||||
{
|
||||
DrainMarkQueues();
|
||||
//TODO: VS clean cards (could be due to overflow)
|
||||
DependentHandlesRescan();
|
||||
}
|
||||
|
||||
AssertNoWork();
|
||||
// sync
|
||||
WeakPtrScan(/*isShort*/ true);
|
||||
// sync
|
||||
|
@ -138,10 +139,10 @@ void SatoriRecycler::Collect(bool force)
|
|||
while (m_workList->Count() > 0)
|
||||
{
|
||||
DrainMarkQueues();
|
||||
//TODO: VS clean cards (could be due to overflow)
|
||||
DependentHandlesRescan();
|
||||
}
|
||||
|
||||
AssertNoWork();
|
||||
// sync
|
||||
WeakPtrScan(/*isShort*/ false);
|
||||
WeakPtrScanBySingleThread();
|
||||
|
@ -202,6 +203,18 @@ void SatoriRecycler::Collect(bool force)
|
|||
m_gcInProgress = false;
|
||||
}
|
||||
|
||||
void SatoriRecycler::AssertNoWork()
|
||||
{
|
||||
_ASSERTE(m_workList->Count() == 0);
|
||||
|
||||
m_heap->ForEachPage(
|
||||
[&](SatoriPage* page)
|
||||
{
|
||||
_ASSERTE(page->IsClean());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void SatoriRecycler::DeactivateFn(gc_alloc_context* gcContext, void* param)
|
||||
{
|
||||
SatoriAllocationContext* context = (SatoriAllocationContext*)gcContext;
|
||||
|
@ -247,15 +260,20 @@ void SatoriRecycler::PushToMarkQueuesSlow(SatoriMarkChunk* ¤tMarkChunk, Sa
|
|||
m_workList->Push(currentMarkChunk);
|
||||
}
|
||||
|
||||
currentMarkChunk = m_heap->Allocator()->TryGetMarkChunk();
|
||||
//TODO: VS HACK HACK HACK, this is just to force overflows.(do this always in debug?)
|
||||
currentMarkChunk = nullptr;
|
||||
if (m_workList->Count() == 0)
|
||||
{
|
||||
currentMarkChunk = m_heap->Allocator()->TryGetMarkChunk();
|
||||
}
|
||||
|
||||
if (currentMarkChunk)
|
||||
{
|
||||
currentMarkChunk->Push(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: VS handle mark overflow.
|
||||
_ASSERTE(!"overflow");
|
||||
o->SetCardsForContent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,7 +306,7 @@ void SatoriRecycler::MarkFn(PTR_PTR_Object ppObject, ScanContext* sc, uint32_t f
|
|||
}
|
||||
}
|
||||
|
||||
if (o->ContainingRegion()->IsThreadLocal())
|
||||
if (o->ContainingRegion()->Generation() == 0)
|
||||
{
|
||||
// do not mark thread local regions.
|
||||
_ASSERTE(!"thread local region is unexpected");
|
||||
|
@ -303,9 +321,6 @@ void SatoriRecycler::MarkFn(PTR_PTR_Object ppObject, ScanContext* sc, uint32_t f
|
|||
MarkContext* context = (MarkContext*)sc->_unused1;
|
||||
// TODO: VS we do not need to push if card is marked, we will have to revisit anyways.
|
||||
|
||||
// TODO: VS test card setting. for now this is unused.
|
||||
// context->m_recycler->m_heap->SetCardForAddress(location);
|
||||
|
||||
context->PushToMarkQueues(o);
|
||||
}
|
||||
|
||||
|
@ -432,6 +447,91 @@ void SatoriRecycler::DrainMarkQueues()
|
|||
_ASSERTE(dstChunk->Count() == 0);
|
||||
m_heap->Allocator()->ReturnMarkChunk(dstChunk);
|
||||
}
|
||||
|
||||
CleanCards();
|
||||
}
|
||||
|
||||
void SatoriRecycler::CleanCards()
|
||||
{
|
||||
SatoriMarkChunk* dstChunk = nullptr;
|
||||
bool revisit = false;
|
||||
|
||||
do
|
||||
{
|
||||
m_heap->ForEachPage(
|
||||
[&](SatoriPage* page)
|
||||
{
|
||||
if (!page->IsClean())
|
||||
{
|
||||
page->SetProcessing();
|
||||
|
||||
size_t groupCount = page->CardGroupCount();
|
||||
for (size_t i = 0; i < groupCount; i++)
|
||||
{
|
||||
// TODO: VS when stealing is implemented we should start from a random location
|
||||
if (page->CardGroupState(i) == Satori::CardGroupState::dirty)
|
||||
{
|
||||
page->CardGroupSetProcessing(i);
|
||||
|
||||
size_t* cards = page->CardsForGroup(i);
|
||||
// TODO: VS page->RegionForCardGroup
|
||||
SatoriRegion* region = page->RegionForAddress(page->LocationForCard(cards));
|
||||
for (int j = 0; j < Satori::CARD_WORDS_IN_CARD_GROUP; j++)
|
||||
{
|
||||
// TODO: VS do one word at a time for now, scan for contiguous ranges later.
|
||||
size_t card = cards[j];
|
||||
if (!card)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cards[j] = 0;
|
||||
size_t start = page->LocationForCard(&cards[j]);
|
||||
size_t end = start + Satori::BYTES_PER_CARD_WORD;
|
||||
SatoriObject* o = region->FindObject(start);
|
||||
do
|
||||
{
|
||||
if (o->IsMarked())
|
||||
{
|
||||
o->ForEachObjectRef(
|
||||
[&](SatoriObject** ref)
|
||||
{
|
||||
// TODO: VS check that the ref is dirty in the card.
|
||||
|
||||
SatoriObject* child = *ref;
|
||||
if (child && !child->IsMarked())
|
||||
{
|
||||
child->SetMarked();
|
||||
child->Validate();
|
||||
if (!dstChunk || !dstChunk->TryPush(child))
|
||||
{
|
||||
this->PushToMarkQueuesSlow(dstChunk, child);
|
||||
}
|
||||
}
|
||||
},
|
||||
start,
|
||||
end
|
||||
);
|
||||
}
|
||||
o = o->Next();
|
||||
} while (o->Start() < end);
|
||||
}
|
||||
|
||||
page->CardGroupTrySetClean(i);
|
||||
}
|
||||
}
|
||||
|
||||
// record missed clean to revisit the whole deal.
|
||||
revisit = !page->TrySetClean();
|
||||
}
|
||||
}
|
||||
);
|
||||
} while (revisit);
|
||||
|
||||
if (dstChunk)
|
||||
{
|
||||
m_workList->Push(dstChunk);
|
||||
}
|
||||
}
|
||||
|
||||
void SatoriRecycler::MarkHandles()
|
||||
|
|
|
@ -30,6 +30,8 @@ public:
|
|||
|
||||
void Collect(bool force);
|
||||
|
||||
void AssertNoWork();
|
||||
|
||||
private:
|
||||
SatoriHeap* m_heap;
|
||||
|
||||
|
@ -65,6 +67,7 @@ private:
|
|||
void MarkOtherStacks();
|
||||
void IncrementScanCount();
|
||||
void DrainMarkQueues();
|
||||
void CleanCards();
|
||||
void MarkHandles();
|
||||
void WeakPtrScan(bool isShort);
|
||||
void WeakPtrScanBySingleThread();
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
#include "SatoriObject.inl"
|
||||
#include "SatoriRegion.h"
|
||||
#include "SatoriRegion.inl"
|
||||
#include "SatoriQueue.h"
|
||||
#include "SatoriPage.h"
|
||||
#include "SatoriPage.inl"
|
||||
#include "SatoriQueue.h"
|
||||
#include "SatoriMarkChunk.h"
|
||||
|
||||
#ifdef memcpy
|
||||
|
@ -83,6 +84,7 @@ void SatoriRegion::MakeBlank()
|
|||
{
|
||||
m_ownerThreadTag = 0;
|
||||
m_escapeFunc = EscapeFn;
|
||||
m_generation = 0;
|
||||
m_allocStart = (size_t)&m_firstObject;
|
||||
m_allocEnd = End();
|
||||
m_occupancy = 0;
|
||||
|
@ -99,7 +101,7 @@ void SatoriRegion::MakeBlank()
|
|||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
memset(&m_syncBlock, 0xFE, m_used - (size_t)&m_syncBlock);
|
||||
// memset(&m_syncBlock, 0xFE, m_used - (size_t)&m_syncBlock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -239,7 +241,7 @@ void SatoriRegion::Coalesce(SatoriRegion* next)
|
|||
m_containingPage->RegionInitialized(this);
|
||||
}
|
||||
|
||||
size_t SatoriRegion::Allocate(size_t size, bool ensureZeroInited)
|
||||
size_t SatoriRegion::Allocate(size_t size, bool zeroInitialize)
|
||||
{
|
||||
_ASSERTE(m_containingQueue == nullptr);
|
||||
|
||||
|
@ -260,13 +262,13 @@ size_t SatoriRegion::Allocate(size_t size, bool ensureZeroInited)
|
|||
m_committed = newComitted;
|
||||
}
|
||||
|
||||
if (ensureZeroInited)
|
||||
if (zeroInitialize)
|
||||
{
|
||||
size_t zeroUpTo = min(m_used, chunkEnd);
|
||||
ptrdiff_t zeroInitCount = zeroUpTo - chunkStart;
|
||||
if (zeroInitCount > 0)
|
||||
{
|
||||
ZeroMemory((void*)chunkStart, zeroInitCount);
|
||||
memset((void*)chunkStart, 0, zeroInitCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +280,7 @@ size_t SatoriRegion::Allocate(size_t size, bool ensureZeroInited)
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t SatoriRegion::AllocateHuge(size_t size, bool ensureZeroInited)
|
||||
size_t SatoriRegion::AllocateHuge(size_t size, bool zeroInitialize)
|
||||
{
|
||||
_ASSERTE(ValidateBlank());
|
||||
_ASSERTE(AllocRemaining() >= size);
|
||||
|
@ -300,6 +302,13 @@ size_t SatoriRegion::AllocateHuge(size_t size, bool ensureZeroInited)
|
|||
chunkStart = m_allocStart;
|
||||
}
|
||||
|
||||
// in rare cases the object does not cross into the last tile. (when free obj padding is on the edge).
|
||||
// in such case force the object to cross.
|
||||
if (End() - (chunkStart + size) >= Satori::REGION_SIZE_GRANULARITY)
|
||||
{
|
||||
chunkStart += Satori::LARGE_OBJECT_THRESHOLD + Satori::MIN_FREE_SIZE;
|
||||
}
|
||||
|
||||
chunkEnd = chunkStart + size;
|
||||
|
||||
// huge allocation should cross the end of the first tile, but have enough space between
|
||||
|
@ -319,14 +328,14 @@ size_t SatoriRegion::AllocateHuge(size_t size, bool ensureZeroInited)
|
|||
m_committed = newComitted;
|
||||
}
|
||||
|
||||
if (ensureZeroInited)
|
||||
if (zeroInitialize)
|
||||
{
|
||||
size_t zeroInitStart = chunkStart;
|
||||
size_t zeroUpTo = min(m_used, chunkEnd);
|
||||
ptrdiff_t zeroInitCount = zeroUpTo - zeroInitStart;
|
||||
if (zeroInitCount > 0)
|
||||
{
|
||||
ZeroMemory((void*)zeroInitStart, zeroInitCount);
|
||||
memset((void*)zeroInitStart, 0, zeroInitCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,9 +356,10 @@ inline int LocationToIndex(size_t location)
|
|||
return (location >> Satori::INDEX_GRANULARITY_BITS) % Satori::INDEX_LENGTH;
|
||||
}
|
||||
|
||||
//TODO: VS need FindObjectChecked when a real object must be found.
|
||||
SatoriObject* SatoriRegion::FindObject(size_t location)
|
||||
{
|
||||
_ASSERTE(location >= (size_t)FirstObject() && location <= End());
|
||||
_ASSERTE(location >= Start() && location <= End());
|
||||
|
||||
// start search from the first object or after unparseable alloc gap
|
||||
SatoriObject* obj = (IsAllocating() && (location >= m_allocEnd)) ?
|
||||
|
@ -389,7 +399,6 @@ SatoriObject* SatoriRegion::FindObject(size_t location)
|
|||
next = next->Next();
|
||||
}
|
||||
|
||||
_ASSERTE(!obj->IsFree());
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -485,6 +494,7 @@ void SatoriRegion::SetExposed(SatoriObject** location)
|
|||
void SatoriRegion::EscapeRecursively(SatoriObject* o)
|
||||
{
|
||||
_ASSERTE(this->OwnedByCurrentThread());
|
||||
_ASSERTE(o->ContainingRegion() == this);
|
||||
|
||||
if (o->IsEscaped())
|
||||
{
|
||||
|
@ -1163,7 +1173,7 @@ void SatoriRegion::CompactFinalizables()
|
|||
|
||||
void SatoriRegion::CleanMarks()
|
||||
{
|
||||
ZeroMemory(&m_bitmap[BITMAP_START], (BITMAP_LENGTH - BITMAP_START) * sizeof(size_t));
|
||||
memset(&m_bitmap[BITMAP_START], 0, (BITMAP_LENGTH - BITMAP_START) * sizeof(size_t));
|
||||
}
|
||||
|
||||
void SatoriRegion::Verify(bool allowMarked)
|
||||
|
|
|
@ -44,8 +44,8 @@ public:
|
|||
|
||||
size_t AllocStart();
|
||||
size_t AllocRemaining();
|
||||
size_t Allocate(size_t size, bool ensureZeroInited);
|
||||
size_t AllocateHuge(size_t size, bool ensureZeroInited);
|
||||
size_t Allocate(size_t size, bool zeroInitialize);
|
||||
size_t AllocateHuge(size_t size, bool zeroInitialize);
|
||||
void StopAllocating(size_t allocPtr);
|
||||
|
||||
bool IsAllocating();
|
||||
|
@ -53,6 +53,8 @@ public:
|
|||
|
||||
bool IsThreadLocal();
|
||||
bool OwnedByCurrentThread();
|
||||
size_t Generation();
|
||||
void SetGeneration(size_t generation);
|
||||
|
||||
size_t Start();
|
||||
size_t End();
|
||||
|
@ -106,6 +108,7 @@ private:
|
|||
// TEB address could be used on Windows, for example
|
||||
size_t m_ownerThreadTag;
|
||||
void (*m_escapeFunc)(SatoriObject**, SatoriObject*, SatoriRegion*);
|
||||
size_t m_generation;
|
||||
|
||||
size_t m_end;
|
||||
size_t m_committed;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "../env/gcenv.ee.h"
|
||||
#include "SatoriRegion.h"
|
||||
|
||||
//TODO: VS unused?
|
||||
inline bool SatoriRegion::IsThreadLocal()
|
||||
{
|
||||
return m_ownerThreadTag;
|
||||
|
@ -25,6 +26,16 @@ inline bool SatoriRegion::OwnedByCurrentThread()
|
|||
return m_ownerThreadTag == SatoriUtil::GetCurrentThreadTag();
|
||||
}
|
||||
|
||||
inline size_t SatoriRegion::Generation()
|
||||
{
|
||||
return m_generation;
|
||||
}
|
||||
|
||||
inline void SatoriRegion::SetGeneration(size_t generation)
|
||||
{
|
||||
m_generation = generation;
|
||||
}
|
||||
|
||||
inline bool SatoriRegion::IsAllocating()
|
||||
{
|
||||
return m_allocEnd != 0;
|
||||
|
@ -71,6 +82,7 @@ inline size_t SatoriRegion::Occupancy()
|
|||
inline void SatoriRegion::Publish()
|
||||
{
|
||||
m_ownerThreadTag = 0;
|
||||
m_generation = 1;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
|
|
|
@ -61,6 +61,18 @@ namespace Satori
|
|||
// TODO: VS this can be configured or computed at start up, but should not change dynamically.
|
||||
return 4096;
|
||||
}
|
||||
|
||||
static const int BYTES_PER_CARD_BYTE = 512;
|
||||
static const int BYTES_PER_CARD_WORD = BYTES_PER_CARD_BYTE * sizeof(size_t);
|
||||
static const int CARD_WORDS_IN_CARD_GROUP = Satori::REGION_SIZE_GRANULARITY / BYTES_PER_CARD_WORD;
|
||||
|
||||
enum CardGroupState : uint8_t
|
||||
{
|
||||
uncommitted = 0xFF,
|
||||
clean = 0,
|
||||
dirty = 1,
|
||||
processing = 2
|
||||
};
|
||||
}
|
||||
|
||||
class SatoriUtil
|
||||
|
|
|
@ -470,16 +470,16 @@ LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
|
|||
ret
|
||||
LEAF_END JIT_PatchedCodeLast, _TEXT
|
||||
|
||||
; Framed helper for a rare path to invoke recursive escape before doing assignment.
|
||||
; A helper for a rare path to invoke recursive escape before doing assignment.
|
||||
; rcx - dest (assumed to be in the heap)
|
||||
; rdx - src
|
||||
; r8 - source region
|
||||
;
|
||||
NESTED_ENTRY JIT_WriteBarrierHelper_SATORI, _TEXT
|
||||
push_vol_reg rcx
|
||||
push_vol_reg rdx
|
||||
alloc_stack 20h
|
||||
END_PROLOGUE
|
||||
LEAF_ENTRY JIT_WriteBarrierHelper_SATORI, _TEXT
|
||||
; save rcx and rdx and have enough stack for the callee
|
||||
push rcx
|
||||
push rdx
|
||||
sub rsp, 20h
|
||||
|
||||
; void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region)
|
||||
call qword ptr [r8 + 8]
|
||||
|
@ -487,10 +487,11 @@ NESTED_ENTRY JIT_WriteBarrierHelper_SATORI, _TEXT
|
|||
add rsp, 20h
|
||||
pop rdx
|
||||
pop rcx
|
||||
; the actual assignment. (AV here will be attributed to the caller)
|
||||
|
||||
; the actual assignment. (AV here will be attributed to the caller, unwinder knows this method)
|
||||
mov [rcx], rdx
|
||||
ret
|
||||
NESTED_END_MARKED JIT_WriteBarrierHelper_SATORI, _TEXT
|
||||
LEAF_END_MARKED JIT_WriteBarrierHelper_SATORI, _TEXT
|
||||
|
||||
; JIT_ByRefWriteBarrier has weird symantics, see usage in StubLinkerX86.cpp
|
||||
;
|
||||
|
|
|
@ -1311,20 +1311,22 @@ void CheckEscapeSatori(Object** dst, Object* ref)
|
|||
#endif
|
||||
}
|
||||
|
||||
void CheckEscapeSatoriRange(void* dst, void* src, size_t len)
|
||||
void CheckEscapeSatoriRange(void* dst, size_t src, size_t len)
|
||||
{
|
||||
#if FEATURE_SATORI_GC
|
||||
if (!IsInHeapSatori(src))
|
||||
if (!IsInHeapSatori((void*)src))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SatoriRegion* srcRegion = PageForAddressSatori(src)->RegionForAddress((size_t)src);
|
||||
SatoriRegion* srcRegion = PageForAddressSatori((void*)src)->RegionForAddress((size_t)src);
|
||||
if (!srcRegion->OwnedByCurrentThread())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: VS the following IsEscaped checks could be done faster by scanning bitmaps
|
||||
|
||||
// if move is within a region, check if the dest is escaped.
|
||||
if ((((size_t)dst ^ (size_t)src) >> 21) == 0)
|
||||
{
|
||||
|
@ -1344,24 +1346,14 @@ void CheckEscapeSatoriRange(void* dst, void* src, size_t len)
|
|||
containingSrcObj->ForEachObjectRef(
|
||||
[&](SatoriObject** ref)
|
||||
{
|
||||
// TODO: VS fold bounds checks into iterator
|
||||
if ((size_t)ref < (size_t)src)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = (size_t)ref - (size_t)src;
|
||||
if (offset >= len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SatoriObject* child = *ref;
|
||||
if (child->ContainingRegion() == srcRegion)
|
||||
{
|
||||
srcRegion->EscapeRecursively(child);
|
||||
}
|
||||
}
|
||||
},
|
||||
src,
|
||||
src + len
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ extern void ThrowOutOfMemoryDimensionsExceeded();
|
|||
void ErectWriteBarrier(OBJECTREF* dst, OBJECTREF ref);
|
||||
bool IsInHeapSatori(void* ptr);
|
||||
void CheckEscapeSatori(Object** dst, Object* ref);
|
||||
void CheckEscapeSatoriRange(void* dst, void* src, size_t len);
|
||||
void CheckEscapeSatoriRange(void* dst, size_t src, size_t len);
|
||||
|
||||
//void SetCardsAfterBulkCopy(Object **start, size_t len);
|
||||
#endif // _GCHELPERS_H_
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue