mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
Bug 1004790 (part 1) - Split off a new class FreeList from FreeSpan. r=billm.
This commit is contained in:
parent
43d93ff145
commit
48deef3163
155
js/src/gc/Heap.h
155
js/src/gc/Heap.h
@ -206,13 +206,6 @@ struct FreeSpan
|
||||
return FreeSpan(arenaAddr + firstOffset, arenaAddr | lastOffset);
|
||||
}
|
||||
|
||||
void initAsEmpty(uintptr_t arenaAddr = 0) {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
first = arenaAddr + ArenaSize;
|
||||
last = arenaAddr | (ArenaSize - 1);
|
||||
JS_ASSERT(isEmpty());
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
checkSpan();
|
||||
return first > last;
|
||||
@ -246,16 +239,6 @@ struct FreeSpan
|
||||
return arenaAddressUnchecked();
|
||||
}
|
||||
|
||||
ArenaHeader *arenaHeader() const {
|
||||
return reinterpret_cast<ArenaHeader *>(arenaAddress());
|
||||
}
|
||||
|
||||
bool isSameNonEmptySpan(const FreeSpan *another) const {
|
||||
JS_ASSERT(!isEmpty());
|
||||
JS_ASSERT(!another->isEmpty());
|
||||
return first == another->first && last == another->last;
|
||||
}
|
||||
|
||||
bool isWithinArena(uintptr_t arenaAddr) const {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
|
||||
@ -272,61 +255,6 @@ struct FreeSpan
|
||||
return encodeOffsets(first - arenaAddr, last & ArenaMask);
|
||||
}
|
||||
|
||||
/* See comments before FreeSpan for details. */
|
||||
MOZ_ALWAYS_INLINE void *allocate(size_t thingSize) {
|
||||
JS_ASSERT(thingSize % CellSize == 0);
|
||||
checkSpan();
|
||||
uintptr_t thing = first;
|
||||
if (thing < last) {
|
||||
/* Bump-allocate from the current span. */
|
||||
first = thing + thingSize;
|
||||
} else if (MOZ_LIKELY(thing == last)) {
|
||||
/*
|
||||
* Move to the next span. We use MOZ_LIKELY as without PGO
|
||||
* compilers mis-predict == here as unlikely to succeed.
|
||||
*/
|
||||
*this = *reinterpret_cast<FreeSpan *>(thing);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
|
||||
/* A version of allocate when we know that the span is not empty. */
|
||||
MOZ_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) {
|
||||
JS_ASSERT(thingSize % CellSize == 0);
|
||||
checkSpan();
|
||||
uintptr_t thing = first;
|
||||
if (thing < last) {
|
||||
first = thing + thingSize;
|
||||
} else {
|
||||
JS_ASSERT(thing == last);
|
||||
*this = *reinterpret_cast<FreeSpan *>(thing);
|
||||
}
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate from a newly allocated arena. We do not move the free list
|
||||
* from the arena. Rather we set the arena up as fully used during the
|
||||
* initialization so to allocate we simply return the first thing in the
|
||||
* arena and set the free list to point to the second.
|
||||
*/
|
||||
MOZ_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset,
|
||||
size_t thingSize) {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
uintptr_t thing = arenaAddr | firstThingOffset;
|
||||
first = thing + thingSize;
|
||||
last = arenaAddr | ArenaMask;
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
|
||||
void checkSpan() const {
|
||||
#ifdef DEBUG
|
||||
/* We do not allow spans at the end of the address space. */
|
||||
@ -388,7 +316,90 @@ struct FreeSpan
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct FreeList : public FreeSpan
|
||||
{
|
||||
FreeList() {}
|
||||
|
||||
void initAsEmpty(uintptr_t arenaAddr = 0) {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
first = arenaAddr + ArenaSize;
|
||||
last = arenaAddr | (ArenaSize - 1);
|
||||
JS_ASSERT(isEmpty());
|
||||
}
|
||||
|
||||
void setHead(FreeSpan *span) {
|
||||
first = span->first;
|
||||
last = span->last;
|
||||
}
|
||||
|
||||
ArenaHeader *arenaHeader() const {
|
||||
return reinterpret_cast<ArenaHeader *>(arenaAddress());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isSameNonEmptySpan(const FreeSpan &another) const {
|
||||
JS_ASSERT(!isEmpty());
|
||||
JS_ASSERT(!another.isEmpty());
|
||||
return first == another.first && last == another.last;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See comments before FreeSpan for details. */
|
||||
MOZ_ALWAYS_INLINE void *allocate(size_t thingSize) {
|
||||
JS_ASSERT(thingSize % CellSize == 0);
|
||||
checkSpan();
|
||||
uintptr_t thing = first;
|
||||
if (thing < last) {
|
||||
/* Bump-allocate from the current span. */
|
||||
first = thing + thingSize;
|
||||
} else if (MOZ_LIKELY(thing == last)) {
|
||||
/*
|
||||
* Move to the next span. We use MOZ_LIKELY as without PGO
|
||||
* compilers mis-predict == here as unlikely to succeed.
|
||||
*/
|
||||
setHead(reinterpret_cast<FreeSpan *>(thing));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
|
||||
/* A version of allocate when we know that the span is not empty. */
|
||||
MOZ_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) {
|
||||
JS_ASSERT(thingSize % CellSize == 0);
|
||||
checkSpan();
|
||||
uintptr_t thing = first;
|
||||
if (thing < last) {
|
||||
first = thing + thingSize;
|
||||
} else {
|
||||
JS_ASSERT(thing == last);
|
||||
setHead(reinterpret_cast<FreeSpan *>(thing));
|
||||
}
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate from a newly allocated arena. We do not move the free list
|
||||
* from the arena. Rather we set the arena up as fully used during the
|
||||
* initialization so to allocate we simply return the first thing in the
|
||||
* arena and set the free list to point to the second.
|
||||
*/
|
||||
MOZ_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset,
|
||||
size_t thingSize) {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
uintptr_t thing = arenaAddr | firstThingOffset;
|
||||
first = thing + thingSize;
|
||||
last = arenaAddr | ArenaMask;
|
||||
checkSpan();
|
||||
JS_EXTRA_POISON(reinterpret_cast<void *>(thing), JS_ALLOCATED_TENURED_PATTERN, thingSize);
|
||||
return reinterpret_cast<void *>(thing);
|
||||
}
|
||||
};
|
||||
|
||||
/* Every arena has a header. */
|
||||
|
@ -463,9 +463,9 @@ MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKi
|
||||
|
||||
CompileZone *zone = GetIonContext()->compartment->zone();
|
||||
|
||||
// Inline FreeSpan::allocate.
|
||||
// There is always exactly one FreeSpan per allocKind per JSCompartment.
|
||||
// If a FreeSpan is replaced, its members are updated in the freeLists table,
|
||||
// Inline FreeList::allocate.
|
||||
// There is always exactly one FreeList per allocKind per JSCompartment.
|
||||
// If a FreeList is replaced, its members are updated in the freeLists table,
|
||||
// which the code below always re-reads.
|
||||
loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
|
||||
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
|
||||
@ -515,7 +515,7 @@ MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, R
|
||||
tempReg1);
|
||||
|
||||
// Get a pointer to the relevant free list:
|
||||
// tempReg1 = (FreeSpan*) &tempReg1->arenas.freeLists[(allocKind)]
|
||||
// tempReg1 = (FreeList*) &tempReg1->arenas.freeLists[(allocKind)]
|
||||
uint32_t offset = (offsetof(Allocator, arenas) +
|
||||
js::gc::ArenaLists::getFreeListOffset(allocKind));
|
||||
addPtr(Imm32(offset), tempReg1);
|
||||
|
@ -399,15 +399,15 @@ ArenaHeader::checkSynchronizedWithFreeList() const
|
||||
FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
||||
if (firstSpan.isEmpty())
|
||||
return;
|
||||
const FreeSpan *list = zone->allocator.arenas.getFreeList(getAllocKind());
|
||||
if (list->isEmpty() || firstSpan.arenaAddress() != list->arenaAddress())
|
||||
const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
|
||||
if (freeList->isEmpty() || firstSpan.arenaAddress() != freeList->arenaAddress())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Here this arena has free things, FreeList::lists[thingKind] is not
|
||||
* empty and also points to this arena. Thus they must the same.
|
||||
*/
|
||||
JS_ASSERT(firstSpan.isSameNonEmptySpan(list));
|
||||
JS_ASSERT(freeList->isSameNonEmptySpan(firstSpan));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1433,9 +1433,9 @@ inline void
|
||||
ArenaLists::prepareForIncrementalGC(JSRuntime *rt)
|
||||
{
|
||||
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
|
||||
FreeSpan *headSpan = &freeLists[i];
|
||||
if (!headSpan->isEmpty()) {
|
||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
||||
FreeList *freeList = &freeLists[i];
|
||||
if (!freeList->isEmpty()) {
|
||||
ArenaHeader *aheader = freeList->arenaHeader();
|
||||
aheader->allocatedDuringIncremental = true;
|
||||
rt->gc.marker.delayMarkingArena(aheader);
|
||||
}
|
||||
@ -1511,7 +1511,8 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
* Move the free span stored in the arena to the free list and
|
||||
* allocate from it.
|
||||
*/
|
||||
freeLists[thingKind] = aheader->getFirstFreeSpan();
|
||||
FreeSpan firstFreeSpan = aheader->getFirstFreeSpan();
|
||||
freeLists[thingKind].setHead(&firstFreeSpan);
|
||||
aheader->setAsFullyUsed();
|
||||
if (MOZ_UNLIKELY(zone->wasGCStarted())) {
|
||||
if (zone->needsBarrier()) {
|
||||
|
@ -537,7 +537,7 @@ class ArenaLists
|
||||
* GC we only move the head of the of the list of spans back to the arena
|
||||
* only for the arena that was not fully allocated.
|
||||
*/
|
||||
FreeSpan freeLists[FINALIZE_LIMIT];
|
||||
FreeList freeLists[FINALIZE_LIMIT];
|
||||
|
||||
ArenaList arenaLists[FINALIZE_LIMIT];
|
||||
|
||||
@ -601,10 +601,10 @@ class ArenaLists
|
||||
|
||||
static uintptr_t getFreeListOffset(AllocKind thingKind) {
|
||||
uintptr_t offset = offsetof(ArenaLists, freeLists);
|
||||
return offset + thingKind * sizeof(FreeSpan);
|
||||
return offset + thingKind * sizeof(FreeList);
|
||||
}
|
||||
|
||||
const FreeSpan *getFreeList(AllocKind thingKind) const {
|
||||
const FreeList *getFreeList(AllocKind thingKind) const {
|
||||
return &freeLists[thingKind];
|
||||
}
|
||||
|
||||
@ -661,11 +661,11 @@ class ArenaLists
|
||||
}
|
||||
|
||||
void purge(AllocKind i) {
|
||||
FreeSpan *headSpan = &freeLists[i];
|
||||
if (!headSpan->isEmpty()) {
|
||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
||||
aheader->setFirstFreeSpan(headSpan);
|
||||
headSpan->initAsEmpty();
|
||||
FreeList *freeList = &freeLists[i];
|
||||
if (!freeList->isEmpty()) {
|
||||
ArenaHeader *aheader = freeList->arenaHeader();
|
||||
aheader->setFirstFreeSpan(freeList);
|
||||
freeList->initAsEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,11 +682,11 @@ class ArenaLists
|
||||
}
|
||||
|
||||
void copyFreeListToArena(AllocKind thingKind) {
|
||||
FreeSpan *headSpan = &freeLists[thingKind];
|
||||
if (!headSpan->isEmpty()) {
|
||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
||||
FreeList *freeList = &freeLists[thingKind];
|
||||
if (!freeList->isEmpty()) {
|
||||
ArenaHeader *aheader = freeList->arenaHeader();
|
||||
JS_ASSERT(!aheader->hasFreeThings());
|
||||
aheader->setFirstFreeSpan(headSpan);
|
||||
aheader->setFirstFreeSpan(freeList);
|
||||
}
|
||||
}
|
||||
|
||||
@ -701,10 +701,10 @@ class ArenaLists
|
||||
|
||||
|
||||
void clearFreeListInArena(AllocKind kind) {
|
||||
FreeSpan *headSpan = &freeLists[kind];
|
||||
if (!headSpan->isEmpty()) {
|
||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
|
||||
FreeList *freeList = &freeLists[kind];
|
||||
if (!freeList->isEmpty()) {
|
||||
ArenaHeader *aheader = freeList->arenaHeader();
|
||||
JS_ASSERT(freeList->isSameNonEmptySpan(aheader->getFirstFreeSpan()));
|
||||
aheader->setAsFullyUsed();
|
||||
}
|
||||
}
|
||||
@ -714,16 +714,16 @@ class ArenaLists
|
||||
* arena using copyToArena().
|
||||
*/
|
||||
bool isSynchronizedFreeList(AllocKind kind) {
|
||||
FreeSpan *headSpan = &freeLists[kind];
|
||||
if (headSpan->isEmpty())
|
||||
FreeList *freeList = &freeLists[kind];
|
||||
if (freeList->isEmpty())
|
||||
return true;
|
||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
||||
ArenaHeader *aheader = freeList->arenaHeader();
|
||||
if (aheader->hasFreeThings()) {
|
||||
/*
|
||||
* If the arena has a free list, it must be the same as one in
|
||||
* lists.
|
||||
*/
|
||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
|
||||
JS_ASSERT(freeList->isSameNonEmptySpan(aheader->getFirstFreeSpan()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user