bug 656261 - better GC arena layout. r=wmccloskey

--HG--
extra : rebase_source : d6b63d38ef586c7e1d7141c8e0859fe026803a5d
This commit is contained in:
Igor Bukanov 2011-04-22 00:47:46 +02:00
parent 249a380f7b
commit 8f8b62c845
7 changed files with 174 additions and 313 deletions

View File

@ -45,11 +45,8 @@ struct JSCompartment;
namespace js {
namespace gc {
template <typename T> struct Arena;
struct ArenaHeader;
struct MarkingDelay;
struct Chunk;
struct FreeCell;
/*
* Live objects are marked black. How many other additional colors are available
@ -58,13 +55,8 @@ struct FreeCell;
static const uint32 BLACK = 0;
/*
* A GC cell is the base class for GC Things like JSObject, JSShortString,
* JSFunction, JSXML and for an empty cell called FreeCell. It helps avoiding
* casts from an Object to a Cell whenever we call GC related mark functions.
* Cell is not the base Class for JSString because static initialization
* (used for unitStringTables) does not work with inheritance.
* A GC cell is the base class for all GC things.
*/
struct Cell {
static const size_t CellShift = 3;
static const size_t CellSize = size_t(1) << CellShift;
@ -80,28 +72,11 @@ struct Cell {
inline JSCompartment *compartment() const;
JS_ALWAYS_INLINE js::gc::FreeCell *asFreeCell() {
return reinterpret_cast<FreeCell *>(this);
}
JS_ALWAYS_INLINE const js::gc::FreeCell *asFreeCell() const {
return reinterpret_cast<const FreeCell *>(this);
}
#ifdef DEBUG
inline bool isAligned() const;
#endif
};
struct FreeCell : Cell {
union {
FreeCell *link;
double data;
};
};
JS_STATIC_ASSERT(sizeof(FreeCell) == Cell::CellSize);
} /* namespace gc */
} /* namespace js */

View File

@ -118,8 +118,7 @@ JSCompartment::init()
chunk = NULL;
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
arenas[i].init();
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
freeLists.finalizables[i] = NULL;
freeLists.init();
if (!crossCompartmentWrappers.init())
return false;

View File

@ -141,7 +141,6 @@ FinalizeKind slotsToThingKind[] = {
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT);
#ifdef DEBUG
const uint8 GCThingSizeMap[] = {
sizeof(JSObject), /* FINALIZE_OBJECT0 */
sizeof(JSObject), /* FINALIZE_OBJECT0_BACKGROUND */
@ -162,80 +161,59 @@ const uint8 GCThingSizeMap[] = {
#endif
sizeof(JSShortString), /* FINALIZE_SHORT_STRING */
sizeof(JSString), /* FINALIZE_STRING */
sizeof(JSString), /* FINALIZE_EXTERNAL_STRING */
sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GCThingSizeMap) == FINALIZE_LIMIT);
JS_FRIEND_API(size_t)
ArenaHeader::getThingSize() const
{
return GCThingSizeMap[getThingKind()];
}
#endif
/* Initialize the arena and setup the free list. */
template<typename T>
inline FreeCell *
Arena<T>::buildFreeList()
{
T *first = &t.things[0];
T *last = &t.things[JS_ARRAY_LENGTH(t.things) - 1];
for (T *thing = first; thing != last;) {
T *following = thing + 1;
thing->asFreeCell()->link = following->asFreeCell();
thing = following;
}
last->asFreeCell()->link = NULL;
return first->asFreeCell();
}
template<typename T>
inline bool
Arena<T>::finalize(JSContext *cx)
Arena::finalize(JSContext *cx)
{
JS_ASSERT(aheader.compartment);
JS_ASSERT(!aheader.getMarkingDelay()->link);
FreeCell *nextFree = aheader.freeList;
uintptr_t nextFree = reinterpret_cast<uintptr_t>(aheader.freeList);
FreeCell *freeList = NULL;
FreeCell **tailp = &freeList;
bool allClear = true;
T *thingsEnd = &t.things[ThingsPerArena-1];
T *thing = &t.things[0];
thingsEnd++;
uintptr_t thing = thingsStart(sizeof(T));
uintptr_t end = thingsEnd();
if (!nextFree) {
nextFree = thingsEnd->asFreeCell();
nextFree = end;
} else {
JS_ASSERT(thing->asFreeCell() <= nextFree);
JS_ASSERT(nextFree < thingsEnd->asFreeCell());
JS_ASSERT(thing <= nextFree);
JS_ASSERT(nextFree < end);
}
for (;; thing++) {
if (thing->asFreeCell() == nextFree) {
if (thing == thingsEnd)
for (;; thing += sizeof(T)) {
if (thing == nextFree) {
if (thing == end)
break;
nextFree = nextFree->link;
if (!nextFree) {
nextFree = thingsEnd->asFreeCell();
FreeCell *nextLink = reinterpret_cast<FreeCell *>(nextFree)->link;
if (!nextLink) {
nextFree = end;
} else {
JS_ASSERT(thing->asFreeCell() < nextFree);
JS_ASSERT(nextFree < thingsEnd->asFreeCell());
nextFree = reinterpret_cast<uintptr_t>(nextLink);
JS_ASSERT(thing < nextFree);
JS_ASSERT(nextFree < end);
}
} else if (thing->asFreeCell()->isMarked()) {
allClear = false;
continue;
} else {
thing->finalize(cx);
T *t = reinterpret_cast<T *>(thing);
if (t->isMarked()) {
allClear = false;
continue;
}
t->finalize(cx);
#ifdef DEBUG
memset(thing, JS_FREE_PATTERN, sizeof(T));
memset(t, JS_FREE_PATTERN, sizeof(T));
#endif
}
FreeCell *t = thing->asFreeCell();
*tailp = t;
tailp = &t->link;
FreeCell *freeCell = reinterpret_cast<FreeCell *>(thing);
*tailp = freeCell;
tailp = &freeCell->link;
}
#ifdef DEBUG
@ -243,21 +221,21 @@ Arena<T>::finalize(JSContext *cx)
unsigned nfree = 0;
if (freeList) {
JS_ASSERT(tailp != &freeList);
FreeCell *t = freeList;
FreeCell *freeCell = freeList;
for (;;) {
++nfree;
if (&t->link == tailp)
if (&freeCell->link == tailp)
break;
JS_ASSERT(t < t->link);
t = t->link;
JS_ASSERT(freeCell < freeCell->link);
freeCell = freeCell->link;
}
}
if (allClear) {
JS_ASSERT(nfree == ThingsPerArena);
JS_ASSERT(freeList == static_cast<Cell *>(&t.things[0]));
JS_ASSERT(tailp == &t.things[ThingsPerArena-1].asFreeCell()->link);
JS_ASSERT(nfree == Arena::thingsPerArena(sizeof(T)));
JS_ASSERT(freeList->address() == thingsStart(sizeof(T)));
JS_ASSERT(tailp == &reinterpret_cast<FreeCell *>(end - sizeof(T))->link);
} else {
JS_ASSERT(nfree < ThingsPerArena);
JS_ASSERT(nfree < Arena::thingsPerArena(sizeof(T)));
}
#endif
*tailp = NULL;
@ -275,7 +253,7 @@ FinalizeArenas(JSContext *cx, ArenaHeader **listHeadp)
{
ArenaHeader **ap = listHeadp;
while (ArenaHeader *aheader = *ap) {
bool allClear = aheader->getArena<T>()->finalize(cx);
bool allClear = aheader->getArena()->finalize<T>(cx);
if (allClear) {
*ap = aheader->next;
aheader->chunk()->releaseArena(aheader);
@ -350,7 +328,33 @@ Chunk::withinArenasRange(Cell *cell)
return false;
}
template <typename T>
/* Turn arena cells into a free list starting from the first thing. */
template<size_t thingSize>
static inline FreeCell *
BuildFreeList(ArenaHeader *aheader)
{
uintptr_t thing = aheader->getArena()->thingsStart(thingSize);
uintptr_t end = aheader->getArena()->thingsEnd();
FreeCell *first = reinterpret_cast<FreeCell *>(thing);
FreeCell **prevp = &first->link;
for (thing += thingSize; thing != end; thing += thingSize) {
JS_ASSERT(thing < end);
FreeCell *cell = reinterpret_cast<FreeCell *>(thing);
/*
* Here prevp points to the link field of the previous cell in the
* list. Write the address of the following cell into it.
*/
*prevp = cell;
prevp = &cell->link;
}
*prevp = NULL;
return first;
}
template <size_t thingSize>
ArenaHeader *
Chunk::allocateArena(JSContext *cx, unsigned thingKind)
{
@ -359,7 +363,7 @@ Chunk::allocateArena(JSContext *cx, unsigned thingKind)
ArenaHeader *aheader = info.emptyArenaLists.getTypedFreeList(thingKind);
if (!aheader) {
aheader = info.emptyArenaLists.getOtherArena();
aheader->freeList = aheader->getArena<T>()->buildFreeList();
aheader->freeList = BuildFreeList<thingSize>(aheader);
}
JS_ASSERT(!aheader->compartment);
JS_ASSERT(!aheader->getMarkingDelay()->link);
@ -636,12 +640,12 @@ MarkArenaPtrConservatively(JSTracer *trc, ArenaHeader *aheader, uintptr_t addr)
JS_ASSERT(aheader->compartment);
JS_ASSERT(sizeof(T) == aheader->getThingSize());
uintptr_t offset = (addr & ArenaMask) - Arena<T>::FirstThingOffset;
if (offset >= Arena<T>::ThingsSpan)
uintptr_t offset = addr & ArenaMask;
if (offset < Arena::thingsStartOffset(sizeof(T)))
return CGCT_NOTARENA;
/* addr can point inside the thing so we must align the address. */
uintptr_t shift = offset % sizeof(T);
uintptr_t shift = (offset - Arena::thingsStartOffset(sizeof(T))) % sizeof(T);
T *thing = reinterpret_cast<T *>(addr - shift);
if (InFreeList(aheader, thing))
@ -1099,22 +1103,6 @@ JSCompartment::reduceGCTriggerBytes(uint32 amount) {
namespace js {
namespace gc {
void
FreeLists::purge()
{
/*
* Return the free list back to the arena so the GC finalization will not
* run the finalizers over unitialized bytes from free things.
*/
for (FreeCell **p = finalizables; p != JS_ARRAY_END(finalizables); ++p) {
if (FreeCell *thing = *p) {
JS_ASSERT(!thing->arenaHeader()->freeList);
thing->arenaHeader()->freeList = thing;
*p = NULL;
}
}
}
inline ArenaHeader *
ArenaList::searchForFreeArena()
{
@ -1126,7 +1114,7 @@ ArenaList::searchForFreeArena()
return NULL;
}
template <typename T>
template <size_t thingSize>
inline ArenaHeader *
ArenaList::getArenaWithFreeList(JSContext *cx, unsigned thingKind)
{
@ -1192,7 +1180,7 @@ ArenaList::getArenaWithFreeList(JSContext *cx, unsigned thingKind)
* to the head of the list before the cursor to prevent checking the arena
* for the free things.
*/
ArenaHeader *aheader = chunk->allocateArena<T>(cx, thingKind);
ArenaHeader *aheader = chunk->allocateArena<thingSize>(cx, thingKind);
aheader->next = head;
if (cursor == &head)
cursor = &aheader->next;
@ -1381,7 +1369,8 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind)
if (Cell *thing = compartment->freeLists.getNext(thingKind))
return thing;
}
ArenaHeader *aheader = compartment->arenas[thingKind].getArenaWithFreeList<T>(cx, thingKind);
ArenaHeader *aheader =
compartment->arenas[thingKind].getArenaWithFreeList<sizeof(T)>(cx, thingKind);
if (aheader) {
JS_ASSERT(sizeof(T) == aheader->getThingSize());
return compartment->freeLists.populate(aheader, thingKind);
@ -1545,15 +1534,19 @@ GCMarker::delayMarkingChildren(const void *thing)
METER_UPDATE_MAX(cell->compartment()->rt->gcStats.maxunmarked, markLaterArenas);
}
template<typename T>
static void
MarkDelayedChilderen(JSTracer *trc, ArenaHeader *aheader)
MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader)
{
Arena<T> *a = aheader->getArena<T>();
T *end = &a->t.things[Arena<T>::ThingsPerArena];
for (T* thing = &a->t.things[0]; thing != end; ++thing) {
if (thing->isMarked())
js::gc::MarkChildren(trc, thing);
unsigned traceKind = GetFinalizableTraceKind(aheader->getThingKind());
size_t thingSize = aheader->getThingSize();
Arena *a = aheader->getArena();
uintptr_t end = a->thingsEnd();
for (uintptr_t thing = a->thingsStart(thingSize); thing != end; thing += thingSize) {
Cell *t = reinterpret_cast<Cell *>(thing);
if (t->isMarked()) {
JS_SET_TRACING_NAME(trc, "delayed marking thing");
js::gc::MarkKind(trc, t, traceKind);
}
}
}
@ -1574,55 +1567,7 @@ GCMarker::markDelayedChildren()
JS_ASSERT(markLaterArenas);
markLaterArenas--;
#endif
switch (aheader->getThingKind()) {
case FINALIZE_OBJECT0:
case FINALIZE_OBJECT0_BACKGROUND:
MarkDelayedChilderen<JSObject>(this, aheader);
break;
case FINALIZE_OBJECT2:
case FINALIZE_OBJECT2_BACKGROUND:
MarkDelayedChilderen<JSObject_Slots2>(this, aheader);
break;
case FINALIZE_OBJECT4:
case FINALIZE_OBJECT4_BACKGROUND:
MarkDelayedChilderen<JSObject_Slots4>(this, aheader);
break;
case FINALIZE_OBJECT8:
case FINALIZE_OBJECT8_BACKGROUND:
MarkDelayedChilderen<JSObject_Slots8>(this, aheader);
break;
case FINALIZE_OBJECT12:
case FINALIZE_OBJECT12_BACKGROUND:
MarkDelayedChilderen<JSObject_Slots12>(this, aheader);
break;
case FINALIZE_OBJECT16:
case FINALIZE_OBJECT16_BACKGROUND:
MarkDelayedChilderen<JSObject_Slots16>(this, aheader);
break;
case FINALIZE_STRING:
MarkDelayedChilderen<JSString>(this, aheader);
break;
case FINALIZE_EXTERNAL_STRING:
MarkDelayedChilderen<JSExternalString>(this, aheader);
break;
case FINALIZE_SHORT_STRING:
JS_NOT_REACHED("no delayed marking");
break;
case FINALIZE_FUNCTION:
MarkDelayedChilderen<JSFunction>(this, aheader);
break;
case FINALIZE_SHAPE:
MarkDelayedChilderen<Shape>(this, aheader);
break;
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
MarkDelayedChilderen<JSXML>(this, aheader);
break;
#endif
default:
JS_NOT_REACHED("wrong thingkind");
}
MarkDelayedChildren(this, aheader);
}
JS_ASSERT(!markLaterArenas);
}

View File

@ -77,6 +77,9 @@ struct Shape;
namespace gc {
struct Arena;
struct MarkingDelay;
/* The kind of GC thing with a finalizer. */
enum FinalizeKind {
FINALIZE_OBJECT0,
@ -104,6 +107,8 @@ enum FinalizeKind {
FINALIZE_LIMIT
};
extern JS_FRIEND_DATA(const uint8) GCThingSizeMap[];
const size_t ArenaShift = 12;
const size_t ArenaSize = size_t(1) << ArenaShift;
const size_t ArenaMask = ArenaSize - 1;
@ -119,7 +124,19 @@ const size_t ArenaBitmapBits = ArenaCellCount;
const size_t ArenaBitmapBytes = ArenaBitmapBits / 8;
const size_t ArenaBitmapWords = ArenaBitmapBits / JS_BITS_PER_WORD;
template <typename T> struct Arena;
struct FreeCell : Cell {
FreeCell *link;
void checkLink() {
/*
* The GC things on the free lists come from one arena and the things
* on the free list are linked in ascending address order.
*/
JS_ASSERT_IF(link, arenaHeader() == link->arenaHeader());
JS_ASSERT_IF(link, this < link);
}
};
/* Every arena has a header. */
struct ArenaHeader {
@ -134,9 +151,8 @@ struct ArenaHeader {
inline uintptr_t address() const;
inline Chunk *chunk() const;
template <typename T>
Arena<T> *getArena() {
return reinterpret_cast<Arena<T> *>(address());
Arena *getArena() {
return reinterpret_cast<Arena *>(address());
}
unsigned getThingKind() const {
@ -149,9 +165,9 @@ struct ArenaHeader {
inline MarkingDelay *getMarkingDelay() const;
#ifdef DEBUG
JS_FRIEND_API(size_t) getThingSize() const;
#endif
size_t getThingSize() const {
return GCThingSizeMap[getThingKind()];
}
#if defined DEBUG || defined JS_GCMETER
static size_t CountListLength(const ArenaHeader *aheader) {
@ -163,74 +179,50 @@ struct ArenaHeader {
#endif
};
template <typename T, size_t N, size_t R1, size_t R2>
struct Things {
char filler1[R1];
T things[N];
char filler[R2];
};
template <typename T, size_t N, size_t R1>
struct Things<T, N, R1, 0> {
char filler1[R1];
T things[N];
};
template <typename T, size_t N, size_t R2>
struct Things<T, N, 0, R2> {
T things[N];
char filler2[R2];
};
template <typename T, size_t N>
struct Things<T, N, 0, 0> {
T things[N];
};
template <typename T>
struct Arena {
/*
* Layout of an arena:
* An arena is 4K. We want it to have a header followed by a list of T
* objects. However, each object should be aligned to a sizeof(T)-boundary.
* To achieve this, we pad before and after the object array.
* An arena is 4K in size and 4K-aligned. It starts with the ArenaHeader
* descriptor followed by some pad bytes. The remainder of the arena is
* filled with the array of T things. The pad bytes ensure that the thing
* array ends exactly at the end of the arena.
*
* +-------------+-----+----+----+-----+----+-----+
* | ArenaHeader | pad | T0 | T1 | ... | Tn | pad |
* +-------------+-----+----+----+-----+----+-----+
* +-------------+-----+----+----+-----+----+
* | ArenaHeader | pad | T0 | T1 | ... | Tn |
* +-------------+-----+----+----+-----+----+
*
* <----------------------------------------------> = 4096 bytes
* <-----> = Filler1Size
* <-------------------> = HeaderSize
* <--------------------------> = SpaceAfterHeader
* <-----> = Filler2Size
* <----------------------------------------> = ArenaSize bytes
* <-------------------> = thingsStartOffset
*/
static const size_t Filler1Size =
tl::If< sizeof(ArenaHeader) % sizeof(T) == 0, size_t,
0,
sizeof(T) - sizeof(ArenaHeader) % sizeof(T) >::result;
static const size_t HeaderSize = sizeof(ArenaHeader) + Filler1Size;
static const size_t SpaceAfterHeader = ArenaSize - HeaderSize;
static const size_t Filler2Size = SpaceAfterHeader % sizeof(T);
static const size_t ThingsPerArena = SpaceAfterHeader / sizeof(T);
static const size_t FirstThingOffset = HeaderSize;
static const size_t ThingsSpan = ThingsPerArena * sizeof(T);
ArenaHeader aheader;
Things<T, ThingsPerArena, Filler1Size, Filler2Size> t;
uint8_t data[ArenaSize - sizeof(ArenaHeader)];
static void staticAsserts() {
/*
* Everything we store in the heap must be a multiple of the cell
* size.
*/
JS_STATIC_ASSERT(sizeof(T) % Cell::CellSize == 0);
JS_STATIC_ASSERT(offsetof(Arena<T>, t.things) % sizeof(T) == 0);
JS_STATIC_ASSERT(sizeof(Arena<T>) == ArenaSize);
JS_STATIC_ASSERT(sizeof(Arena) == ArenaSize);
}
inline FreeCell *buildFreeList();
static size_t thingsPerArena(size_t thingSize) {
JS_ASSERT(thingSize % Cell::CellSize == 0);
return (ArenaSize - sizeof(ArenaHeader)) / thingSize;
}
static size_t thingsStartOffset(size_t thingSize) {
return ArenaSize - thingsPerArena(thingSize) * thingSize;
}
uintptr_t address() const {
return aheader.address();
}
uintptr_t thingsStart(size_t thingSize) {
return address() | thingsStartOffset(thingSize);
}
uintptr_t thingsEnd() {
return address() + ArenaSize;
}
template <typename T>
bool finalize(JSContext *cx);
};
@ -242,8 +234,7 @@ struct Arena {
struct MarkingDelay {
ArenaHeader *link;
void init()
{
void init() {
link = NULL;
}
@ -251,7 +242,7 @@ struct MarkingDelay {
* To separate arenas without things to mark later from the arena at the
* marked delay stack bottom we use for the latter a special sentinel
* value. We set it to the header for the second arena in the chunk
* starting the 0 address.
* starting at the 0 address.
*/
static ArenaHeader *stackBottom() {
return reinterpret_cast<ArenaHeader *>(ArenaSize);
@ -382,7 +373,7 @@ JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap));
* marking state).
*/
struct Chunk {
Arena<FreeCell> arenas[ArenasPerChunk];
Arena arenas[ArenasPerChunk];
ChunkBitmap bitmap;
MarkingDelay markingDelay[ArenasPerChunk];
ChunkInfo info;
@ -407,7 +398,7 @@ struct Chunk {
bool hasAvailableArenas();
bool withinArenasRange(Cell *cell);
template <typename T>
template <size_t thingSize>
ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
void releaseArena(ArenaHeader *aheader);
@ -447,7 +438,8 @@ Cell::chunk() const
inline bool
Cell::isAligned() const
{
uintptr_t offset = address() & ArenaMask;
/* Things ends at the arena end. */
uintptr_t offset = ArenaSize - (address() & ArenaMask);
return offset % arenaHeader()->getThingSize() == 0;
}
#endif
@ -579,7 +571,7 @@ GetGCThingTraceKind(const void *thing);
static inline JSRuntime *
GetGCThingRuntime(void *thing)
{
return reinterpret_cast<FreeCell *>(thing)->chunk()->info.runtime;
return reinterpret_cast<Cell *>(thing)->chunk()->info.runtime;
}
/* The arenas in a list have uniform kind. */
@ -632,7 +624,7 @@ class ArenaList {
inline ArenaHeader *searchForFreeArena();
template <typename T>
template <size_t thingSize>
inline ArenaHeader *getArenaWithFreeList(JSContext *cx, unsigned thingKind);
template<typename T>
@ -692,17 +684,6 @@ class ArenaList {
}
};
inline void
CheckGCFreeListLink(FreeCell *cell)
{
/*
* The GC things on the free lists come from one arena and the things on
* the free list are linked in ascending address order.
*/
JS_ASSERT_IF(cell->link, cell->arenaHeader() == cell->link->arenaHeader());
JS_ASSERT_IF(cell->link, cell < cell->link);
}
/*
* For a given arena, finalizables[thingKind] points to the next object to be
* allocated. It gets initialized, in RefillTypedFreeList, to the first free
@ -717,12 +698,29 @@ CheckGCFreeListLink(FreeCell *cell)
struct FreeLists {
FreeCell *finalizables[FINALIZE_LIMIT];
void purge();
void init() {
for (size_t i = 0; i < JS_ARRAY_LENGTH(finalizables); i++)
finalizables[i] = NULL;
}
void purge() {
/*
* Return the free list back to the arena so the GC finalization will
* not run the finalizers over unitialized bytes from free things.
*/
for (FreeCell **p = finalizables; p != JS_ARRAY_END(finalizables); ++p) {
if (FreeCell *thing = *p) {
JS_ASSERT(!thing->arenaHeader()->freeList);
thing->arenaHeader()->freeList = thing;
*p = NULL;
}
}
}
FreeCell *getNext(unsigned kind) {
FreeCell *top = finalizables[kind];
if (top) {
CheckGCFreeListLink(top);
top->checkLink();
finalizables[kind] = top->link;
}
return top;
@ -730,8 +728,7 @@ struct FreeLists {
Cell *populate(ArenaHeader *aheader, uint32 thingKind) {
FreeCell *cell = aheader->freeList;
JS_ASSERT(cell);
CheckGCFreeListLink(cell);
cell->checkLink();
aheader->freeList = NULL;
finalizables[thingKind] = cell->link;
return cell;

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -107,7 +107,7 @@ Mark(JSTracer *trc, T *thing)
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
JS_ASSERT(!JSAtom::isStatic(thing));
JS_ASSERT(thing->asFreeCell()->isAligned());
JS_ASSERT(thing->isAligned());
JSRuntime *rt = trc->context->runtime;
JS_ASSERT(thing->arenaHeader()->compartment);

View File

@ -147,61 +147,6 @@ static const char *const GC_ARENA_NAMES[] = {
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT);
template <typename T>
static inline void
GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
{
thingSize = sizeof(T);
thingsPerArena = Arena<T>::ThingsPerArena;
}
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
{
switch (thingKind) {
case FINALIZE_OBJECT0:
case FINALIZE_OBJECT0_BACKGROUND:
GetSizeAndThings<JSObject>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT2:
case FINALIZE_OBJECT2_BACKGROUND:
GetSizeAndThings<JSObject_Slots2>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT4:
case FINALIZE_OBJECT4_BACKGROUND:
GetSizeAndThings<JSObject_Slots4>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT8:
case FINALIZE_OBJECT8_BACKGROUND:
GetSizeAndThings<JSObject_Slots8>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT12:
case FINALIZE_OBJECT12_BACKGROUND:
GetSizeAndThings<JSObject_Slots12>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT16:
case FINALIZE_OBJECT16_BACKGROUND:
GetSizeAndThings<JSObject_Slots16>(thingSize, thingsPerArena);
break;
case FINALIZE_EXTERNAL_STRING:
case FINALIZE_STRING:
GetSizeAndThings<JSString>(thingSize, thingsPerArena);
break;
case FINALIZE_SHORT_STRING:
GetSizeAndThings<JSShortString>(thingSize, thingsPerArena);
break;
case FINALIZE_FUNCTION:
GetSizeAndThings<JSFunction>(thingSize, thingsPerArena);
break;
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
GetSizeAndThings<JSXML>(thingSize, thingsPerArena);
break;
#endif
default:
JS_NOT_REACHED("wrong kind");
}
}
void
DumpArenaStats(JSGCArenaStats *stp, FILE *fp)
{
@ -213,8 +158,8 @@ DumpArenaStats(JSGCArenaStats *stp, FILE *fp)
JSGCArenaStats *st = &stp[i];
if (st->maxarenas == 0)
continue;
size_t thingSize = 0, thingsPerArena = 0;
GetSizeAndThingsPerArena(i, thingSize, thingsPerArena);
size_t thingSize = GCThingSizeMap[i];
size_t thingsPerArena = Arena::thingsPerArena(thingSize);
fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):\n",
GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena));

View File

@ -516,11 +516,11 @@ JS_STATIC_ASSERT(sizeof(JSInlineString) == sizeof(JSString));
class JSShortString : public JSInlineString
{
/* This can be any value that is a multiple of sizeof(gc::FreeCell). */
/* This can be any value that is a multiple of Cell::CellSize. */
static const size_t INLINE_EXTENSION_CHARS = sizeof(JSString::Data) / sizeof(jschar);
static void staticAsserts() {
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % sizeof(js::gc::FreeCell) == 0);
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % js::gc::Cell::CellSize == 0);
JS_STATIC_ASSERT(MAX_SHORT_LENGTH + 1 ==
(sizeof(JSShortString) -
offsetof(JSShortString, d.inlineStorage)) / sizeof(jschar));