mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27: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);
|
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 {
|
bool isEmpty() const {
|
||||||
checkSpan();
|
checkSpan();
|
||||||
return first > last;
|
return first > last;
|
||||||
@ -246,16 +239,6 @@ struct FreeSpan
|
|||||||
return arenaAddressUnchecked();
|
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 {
|
bool isWithinArena(uintptr_t arenaAddr) const {
|
||||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||||
|
|
||||||
@ -272,61 +255,6 @@ struct FreeSpan
|
|||||||
return encodeOffsets(first - arenaAddr, last & ArenaMask);
|
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 {
|
void checkSpan() const {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* We do not allow spans at the end of the address space. */
|
/* We do not allow spans at the end of the address space. */
|
||||||
@ -388,7 +316,90 @@ struct FreeSpan
|
|||||||
}
|
}
|
||||||
#endif
|
#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. */
|
/* Every arena has a header. */
|
||||||
|
@ -463,9 +463,9 @@ MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKi
|
|||||||
|
|
||||||
CompileZone *zone = GetIonContext()->compartment->zone();
|
CompileZone *zone = GetIonContext()->compartment->zone();
|
||||||
|
|
||||||
// Inline FreeSpan::allocate.
|
// Inline FreeList::allocate.
|
||||||
// There is always exactly one FreeSpan per allocKind per JSCompartment.
|
// There is always exactly one FreeList per allocKind per JSCompartment.
|
||||||
// If a FreeSpan is replaced, its members are updated in the freeLists table,
|
// If a FreeList is replaced, its members are updated in the freeLists table,
|
||||||
// which the code below always re-reads.
|
// which the code below always re-reads.
|
||||||
loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
|
loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
|
||||||
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
|
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
|
||||||
@ -515,7 +515,7 @@ MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, R
|
|||||||
tempReg1);
|
tempReg1);
|
||||||
|
|
||||||
// Get a pointer to the relevant free list:
|
// 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) +
|
uint32_t offset = (offsetof(Allocator, arenas) +
|
||||||
js::gc::ArenaLists::getFreeListOffset(allocKind));
|
js::gc::ArenaLists::getFreeListOffset(allocKind));
|
||||||
addPtr(Imm32(offset), tempReg1);
|
addPtr(Imm32(offset), tempReg1);
|
||||||
|
@ -399,15 +399,15 @@ ArenaHeader::checkSynchronizedWithFreeList() const
|
|||||||
FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
||||||
if (firstSpan.isEmpty())
|
if (firstSpan.isEmpty())
|
||||||
return;
|
return;
|
||||||
const FreeSpan *list = zone->allocator.arenas.getFreeList(getAllocKind());
|
const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
|
||||||
if (list->isEmpty() || firstSpan.arenaAddress() != list->arenaAddress())
|
if (freeList->isEmpty() || firstSpan.arenaAddress() != freeList->arenaAddress())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here this arena has free things, FreeList::lists[thingKind] is not
|
* Here this arena has free things, FreeList::lists[thingKind] is not
|
||||||
* empty and also points to this arena. Thus they must the same.
|
* empty and also points to this arena. Thus they must the same.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(firstSpan.isSameNonEmptySpan(list));
|
JS_ASSERT(freeList->isSameNonEmptySpan(firstSpan));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1433,9 +1433,9 @@ inline void
|
|||||||
ArenaLists::prepareForIncrementalGC(JSRuntime *rt)
|
ArenaLists::prepareForIncrementalGC(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
|
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
|
||||||
FreeSpan *headSpan = &freeLists[i];
|
FreeList *freeList = &freeLists[i];
|
||||||
if (!headSpan->isEmpty()) {
|
if (!freeList->isEmpty()) {
|
||||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
ArenaHeader *aheader = freeList->arenaHeader();
|
||||||
aheader->allocatedDuringIncremental = true;
|
aheader->allocatedDuringIncremental = true;
|
||||||
rt->gc.marker.delayMarkingArena(aheader);
|
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
|
* Move the free span stored in the arena to the free list and
|
||||||
* allocate from it.
|
* allocate from it.
|
||||||
*/
|
*/
|
||||||
freeLists[thingKind] = aheader->getFirstFreeSpan();
|
FreeSpan firstFreeSpan = aheader->getFirstFreeSpan();
|
||||||
|
freeLists[thingKind].setHead(&firstFreeSpan);
|
||||||
aheader->setAsFullyUsed();
|
aheader->setAsFullyUsed();
|
||||||
if (MOZ_UNLIKELY(zone->wasGCStarted())) {
|
if (MOZ_UNLIKELY(zone->wasGCStarted())) {
|
||||||
if (zone->needsBarrier()) {
|
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
|
* 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.
|
* only for the arena that was not fully allocated.
|
||||||
*/
|
*/
|
||||||
FreeSpan freeLists[FINALIZE_LIMIT];
|
FreeList freeLists[FINALIZE_LIMIT];
|
||||||
|
|
||||||
ArenaList arenaLists[FINALIZE_LIMIT];
|
ArenaList arenaLists[FINALIZE_LIMIT];
|
||||||
|
|
||||||
@ -601,10 +601,10 @@ class ArenaLists
|
|||||||
|
|
||||||
static uintptr_t getFreeListOffset(AllocKind thingKind) {
|
static uintptr_t getFreeListOffset(AllocKind thingKind) {
|
||||||
uintptr_t offset = offsetof(ArenaLists, freeLists);
|
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];
|
return &freeLists[thingKind];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,11 +661,11 @@ class ArenaLists
|
|||||||
}
|
}
|
||||||
|
|
||||||
void purge(AllocKind i) {
|
void purge(AllocKind i) {
|
||||||
FreeSpan *headSpan = &freeLists[i];
|
FreeList *freeList = &freeLists[i];
|
||||||
if (!headSpan->isEmpty()) {
|
if (!freeList->isEmpty()) {
|
||||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
ArenaHeader *aheader = freeList->arenaHeader();
|
||||||
aheader->setFirstFreeSpan(headSpan);
|
aheader->setFirstFreeSpan(freeList);
|
||||||
headSpan->initAsEmpty();
|
freeList->initAsEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,11 +682,11 @@ class ArenaLists
|
|||||||
}
|
}
|
||||||
|
|
||||||
void copyFreeListToArena(AllocKind thingKind) {
|
void copyFreeListToArena(AllocKind thingKind) {
|
||||||
FreeSpan *headSpan = &freeLists[thingKind];
|
FreeList *freeList = &freeLists[thingKind];
|
||||||
if (!headSpan->isEmpty()) {
|
if (!freeList->isEmpty()) {
|
||||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
ArenaHeader *aheader = freeList->arenaHeader();
|
||||||
JS_ASSERT(!aheader->hasFreeThings());
|
JS_ASSERT(!aheader->hasFreeThings());
|
||||||
aheader->setFirstFreeSpan(headSpan);
|
aheader->setFirstFreeSpan(freeList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,10 +701,10 @@ class ArenaLists
|
|||||||
|
|
||||||
|
|
||||||
void clearFreeListInArena(AllocKind kind) {
|
void clearFreeListInArena(AllocKind kind) {
|
||||||
FreeSpan *headSpan = &freeLists[kind];
|
FreeList *freeList = &freeLists[kind];
|
||||||
if (!headSpan->isEmpty()) {
|
if (!freeList->isEmpty()) {
|
||||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
ArenaHeader *aheader = freeList->arenaHeader();
|
||||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
|
JS_ASSERT(freeList->isSameNonEmptySpan(aheader->getFirstFreeSpan()));
|
||||||
aheader->setAsFullyUsed();
|
aheader->setAsFullyUsed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,16 +714,16 @@ class ArenaLists
|
|||||||
* arena using copyToArena().
|
* arena using copyToArena().
|
||||||
*/
|
*/
|
||||||
bool isSynchronizedFreeList(AllocKind kind) {
|
bool isSynchronizedFreeList(AllocKind kind) {
|
||||||
FreeSpan *headSpan = &freeLists[kind];
|
FreeList *freeList = &freeLists[kind];
|
||||||
if (headSpan->isEmpty())
|
if (freeList->isEmpty())
|
||||||
return true;
|
return true;
|
||||||
ArenaHeader *aheader = headSpan->arenaHeader();
|
ArenaHeader *aheader = freeList->arenaHeader();
|
||||||
if (aheader->hasFreeThings()) {
|
if (aheader->hasFreeThings()) {
|
||||||
/*
|
/*
|
||||||
* If the arena has a free list, it must be the same as one in
|
* If the arena has a free list, it must be the same as one in
|
||||||
* lists.
|
* lists.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
|
JS_ASSERT(freeList->isSameNonEmptySpan(aheader->getFirstFreeSpan()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user