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
|
class FreeSpan
|
||||||
{
|
{
|
||||||
friend class FreeList;
|
|
||||||
friend class ArenaCellIterImpl;
|
friend class ArenaCellIterImpl;
|
||||||
|
friend class CompactFreeSpan;
|
||||||
|
friend class FreeList;
|
||||||
|
|
||||||
uintptr_t first;
|
uintptr_t first;
|
||||||
uintptr_t last;
|
uintptr_t last;
|
||||||
@ -188,37 +189,6 @@ class FreeSpan
|
|||||||
checkSpan(thingSize);
|
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 {
|
bool isEmpty() const {
|
||||||
checkSpan();
|
checkSpan();
|
||||||
return !first;
|
return !first;
|
||||||
@ -247,10 +217,6 @@ class FreeSpan
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t encodeAsOffsets() const {
|
|
||||||
return encodeOffsets(first & ArenaMask, last & ArenaMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t length(size_t thingSize) const {
|
size_t length(size_t thingSize) const {
|
||||||
checkSpan();
|
checkSpan();
|
||||||
JS_ASSERT((last - first) % thingSize == 0);
|
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
|
class FreeList
|
||||||
{
|
{
|
||||||
// Although |head| is private, it is exposed to the JITs via the
|
// Although |head| is private, it is exposed to the JITs via the
|
||||||
@ -395,11 +412,10 @@ struct ArenaHeader : public JS::shadow::ArenaHeader
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* The first span of free things in the arena. We encode it as the start
|
* The first span of free things in the arena. We encode it as a
|
||||||
* and end offsets within the arena, not as FreeSpan structure, to
|
* CompactFreeSpan rather than a FreeSpan to minimize the header size.
|
||||||
* minimize the header size.
|
|
||||||
*/
|
*/
|
||||||
size_t firstFreeSpanOffsets;
|
CompactFreeSpan firstFreeSpan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* One of AllocKind constants or FINALIZE_LIMIT when the arena does not
|
* 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.");
|
static_assert(FINALIZE_LIMIT <= 255, "We must be able to fit the allockind into uint8_t.");
|
||||||
allocKind = size_t(kind);
|
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() {
|
void setAsNotAllocated() {
|
||||||
@ -486,13 +505,13 @@ struct ArenaHeader : public JS::shadow::ArenaHeader
|
|||||||
inline size_t getThingSize() const;
|
inline size_t getThingSize() const;
|
||||||
|
|
||||||
bool hasFreeThings() const {
|
bool hasFreeThings() const {
|
||||||
return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets;
|
return !firstFreeSpan.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isEmpty() const;
|
inline bool isEmpty() const;
|
||||||
|
|
||||||
void setAsFullyUsed() {
|
void setAsFullyUsed() {
|
||||||
firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
|
firstFreeSpan.initAsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FreeSpan getFirstFreeSpan() const;
|
inline FreeSpan getFirstFreeSpan() const;
|
||||||
@ -900,7 +919,8 @@ ArenaHeader::isEmpty() const
|
|||||||
JS_ASSERT(allocated());
|
JS_ASSERT(allocated());
|
||||||
size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
|
size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
|
||||||
size_t lastThingOffset = ArenaSize - getThingSize();
|
size_t lastThingOffset = ArenaSize - getThingSize();
|
||||||
return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, lastThingOffset);
|
const CompactFreeSpan emptyCompactSpan(firstThingOffset, lastThingOffset);
|
||||||
|
return firstFreeSpan == emptyCompactSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeSpan
|
FreeSpan
|
||||||
@ -909,14 +929,14 @@ ArenaHeader::getFirstFreeSpan() const
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
checkSynchronizedWithFreeList();
|
checkSynchronizedWithFreeList();
|
||||||
#endif
|
#endif
|
||||||
return FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
return firstFreeSpan.decompact(arenaAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ArenaHeader::setFirstFreeSpan(const FreeSpan *span)
|
ArenaHeader::setFirstFreeSpan(const FreeSpan *span)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(!span->isEmpty(), span->isWithinArena(arenaAddress()));
|
JS_ASSERT_IF(!span->isEmpty(), span->isWithinArena(arenaAddress()));
|
||||||
firstFreeSpanOffsets = span->encodeAsOffsets();
|
firstFreeSpan.compact(*span);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ArenaHeader *
|
inline ArenaHeader *
|
||||||
|
@ -412,7 +412,7 @@ ArenaHeader::checkSynchronizedWithFreeList() const
|
|||||||
if (IsBackgroundFinalized(getAllocKind()) && zone->runtimeFromAnyThread()->gc.helperThread.onBackgroundThread())
|
if (IsBackgroundFinalized(getAllocKind()) && zone->runtimeFromAnyThread()->gc.helperThread.onBackgroundThread())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
|
FreeSpan firstSpan = firstFreeSpan.decompact(arenaAddress());
|
||||||
if (firstSpan.isEmpty())
|
if (firstSpan.isEmpty())
|
||||||
return;
|
return;
|
||||||
const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
|
const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
|
||||||
|
Loading…
Reference in New Issue
Block a user