mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1011355 (part 2) - Add a CompactFreeSpan class. r=billm.
--HG-- extra : rebase_source : 693f7ff5abb5e3335b62c790c997f713526027f0
This commit is contained in:
parent
55f51172ae
commit
75f2d0a39c
114
js/src/gc/Heap.h
114
js/src/gc/Heap.h
@ -148,8 +148,9 @@ const size_t ArenaBitmapWords = ArenaBitmapBits / JS_BITS_PER_WORD;
|
||||
*/
|
||||
class FreeSpan
|
||||
{
|
||||
friend class FreeList;
|
||||
friend class ArenaCellIterImpl;
|
||||
friend class CompactFreeSpan;
|
||||
friend class FreeList;
|
||||
|
||||
uintptr_t first;
|
||||
uintptr_t last;
|
||||
@ -188,37 +189,6 @@ class FreeSpan
|
||||
checkSpan(thingSize);
|
||||
}
|
||||
|
||||
/*
|
||||
* To minimize the size of the arena header the first span is encoded
|
||||
* there as offsets from the arena start.
|
||||
*/
|
||||
static size_t encodeOffsets(size_t firstOffset, size_t lastOffset) {
|
||||
static_assert(ArenaShift < 16, "Check that we can pack offsets into uint16_t.");
|
||||
JS_ASSERT(firstOffset <= lastOffset);
|
||||
JS_ASSERT(lastOffset < ArenaSize);
|
||||
return firstOffset | (lastOffset << 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encoded offsets for a full arena, i.e. one with an empty FreeSpan.
|
||||
*/
|
||||
static const size_t FullArenaOffsets = 0;
|
||||
|
||||
static FreeSpan decodeOffsets(uintptr_t arenaAddr, size_t offsets) {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
FreeSpan decodedSpan;
|
||||
if (offsets == FullArenaOffsets) {
|
||||
decodedSpan.initAsEmpty();
|
||||
} else {
|
||||
size_t firstOffset = offsets & 0xFFFF;
|
||||
size_t lastOffset = offsets >> 16;
|
||||
JS_ASSERT(firstOffset <= lastOffset);
|
||||
JS_ASSERT(lastOffset < ArenaSize);
|
||||
decodedSpan.initBounds(arenaAddr + firstOffset, arenaAddr + lastOffset);
|
||||
}
|
||||
return decodedSpan;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
checkSpan();
|
||||
return !first;
|
||||
@ -247,10 +217,6 @@ class FreeSpan
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t encodeAsOffsets() const {
|
||||
return encodeOffsets(first & ArenaMask, last & ArenaMask);
|
||||
}
|
||||
|
||||
size_t length(size_t thingSize) const {
|
||||
checkSpan();
|
||||
JS_ASSERT((last - first) % thingSize == 0);
|
||||
@ -300,6 +266,57 @@ class FreeSpan
|
||||
}
|
||||
};
|
||||
|
||||
class CompactFreeSpan
|
||||
{
|
||||
uint16_t firstOffset_;
|
||||
uint16_t lastOffset_;
|
||||
|
||||
public:
|
||||
CompactFreeSpan(size_t firstOffset, size_t lastOffset)
|
||||
: firstOffset_(firstOffset)
|
||||
, lastOffset_(lastOffset)
|
||||
{}
|
||||
|
||||
void initAsEmpty() {
|
||||
firstOffset_ = 0;
|
||||
lastOffset_ = 0;
|
||||
}
|
||||
|
||||
bool operator==(const CompactFreeSpan &other) const {
|
||||
return firstOffset_ == other.firstOffset_ &&
|
||||
lastOffset_ == other.lastOffset_;
|
||||
}
|
||||
|
||||
void compact(FreeSpan span) {
|
||||
if (span.isEmpty()) {
|
||||
initAsEmpty();
|
||||
} else {
|
||||
static_assert(ArenaShift < 16, "Check that we can pack offsets into uint16_t.");
|
||||
uintptr_t arenaAddr = span.arenaAddress();
|
||||
firstOffset_ = span.first - arenaAddr;
|
||||
lastOffset_ = span.last - arenaAddr;
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
JS_ASSERT(!!firstOffset_ == !!lastOffset_);
|
||||
return !firstOffset_;
|
||||
}
|
||||
|
||||
FreeSpan decompact(uintptr_t arenaAddr) const {
|
||||
JS_ASSERT(!(arenaAddr & ArenaMask));
|
||||
FreeSpan decodedSpan;
|
||||
if (isEmpty()) {
|
||||
decodedSpan.initAsEmpty();
|
||||
} else {
|
||||
JS_ASSERT(firstOffset_ <= lastOffset_);
|
||||
JS_ASSERT(lastOffset_ < ArenaSize);
|
||||
decodedSpan.initBounds(arenaAddr + firstOffset_, arenaAddr + lastOffset_);
|
||||
}
|
||||
return decodedSpan;
|
||||
}
|
||||
};
|
||||
|
||||
class FreeList
|
||||
{
|
||||
// Although |head| is private, it is exposed to the JITs via the
|
||||
@ -395,11 +412,10 @@ struct ArenaHeader : public JS::shadow::ArenaHeader
|
||||
|
||||
private:
|
||||
/*
|
||||
* The first span of free things in the arena. We encode it as the start
|
||||
* and end offsets within the arena, not as FreeSpan structure, to
|
||||
* minimize the header size.
|
||||
* The first span of free things in the arena. We encode it as a
|
||||
* CompactFreeSpan rather than a FreeSpan to minimize the header size.
|
||||
*/
|
||||
size_t firstFreeSpanOffsets;
|
||||
CompactFreeSpan firstFreeSpan;
|
||||
|
||||
/*
|
||||
* One of AllocKind constants or FINALIZE_LIMIT when the arena does not
|
||||
@ -463,8 +479,11 @@ struct ArenaHeader : public JS::shadow::ArenaHeader
|
||||
static_assert(FINALIZE_LIMIT <= 255, "We must be able to fit the allockind into uint8_t.");
|
||||
allocKind = size_t(kind);
|
||||
|
||||
/* The arena is initially marked as full; see allocateFromArenaInline(). */
|
||||
firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
|
||||
/*
|
||||
* The firstFreeSpan is initially marked as empty (and thus the arena
|
||||
* is marked as full). See allocateFromArenaInline().
|
||||
*/
|
||||
firstFreeSpan.initAsEmpty();
|
||||
}
|
||||
|
||||
void setAsNotAllocated() {
|
||||
@ -486,13 +505,13 @@ struct ArenaHeader : public JS::shadow::ArenaHeader
|
||||
inline size_t getThingSize() const;
|
||||
|
||||
bool hasFreeThings() const {
|
||||
return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets;
|
||||
return !firstFreeSpan.isEmpty();
|
||||
}
|
||||
|
||||
inline bool isEmpty() const;
|
||||
|
||||
void setAsFullyUsed() {
|
||||
firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
|
||||
firstFreeSpan.initAsEmpty();
|
||||
}
|
||||
|
||||
inline FreeSpan getFirstFreeSpan() const;
|
||||
@ -900,7 +919,8 @@ ArenaHeader::isEmpty() const
|
||||
JS_ASSERT(allocated());
|
||||
size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
|
||||
size_t lastThingOffset = ArenaSize - getThingSize();
|
||||
return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, lastThingOffset);
|
||||
const CompactFreeSpan emptyCompactSpan(firstThingOffset, lastThingOffset);
|
||||
return firstFreeSpan == emptyCompactSpan;
|
||||
}
|
||||
|
||||
FreeSpan
|
||||
@ -909,14 +929,14 @@ ArenaHeader::getFirstFreeSpan() const
|
||||
#ifdef DEBUG
|
||||
checkSynchronizedWithFreeList();
|
||||
#endif
|
||||
return FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
||||
return firstFreeSpan.decompact(arenaAddress());
|
||||
}
|
||||
|
||||
void
|
||||
ArenaHeader::setFirstFreeSpan(const FreeSpan *span)
|
||||
{
|
||||
JS_ASSERT_IF(!span->isEmpty(), span->isWithinArena(arenaAddress()));
|
||||
firstFreeSpanOffsets = span->encodeAsOffsets();
|
||||
firstFreeSpan.compact(*span);
|
||||
}
|
||||
|
||||
inline ArenaHeader *
|
||||
|
@ -412,7 +412,7 @@ ArenaHeader::checkSynchronizedWithFreeList() const
|
||||
if (IsBackgroundFinalized(getAllocKind()) && zone->runtimeFromAnyThread()->gc.helperThread.onBackgroundThread())
|
||||
return;
|
||||
|
||||
FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
||||
FreeSpan firstSpan = firstFreeSpan.decompact(arenaAddress());
|
||||
if (firstSpan.isEmpty())
|
||||
return;
|
||||
const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
|
||||
|
Loading…
Reference in New Issue
Block a user