mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset 869479a8d3c8 - patch for bug 656261 caused jsreftest failure on Windows in the browser.
This commit is contained in:
parent
8f8b62c845
commit
397237b2b1
@ -45,8 +45,11 @@ 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
|
||||
@ -55,8 +58,13 @@ struct Chunk;
|
||||
static const uint32 BLACK = 0;
|
||||
|
||||
/*
|
||||
* A GC cell is the base class for all GC things.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct Cell {
|
||||
static const size_t CellShift = 3;
|
||||
static const size_t CellSize = size_t(1) << CellShift;
|
||||
@ -72,11 +80,28 @@ 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 */
|
||||
|
||||
|
@ -118,7 +118,8 @@ JSCompartment::init()
|
||||
chunk = NULL;
|
||||
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
|
||||
arenas[i].init();
|
||||
freeLists.init();
|
||||
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
|
||||
freeLists.finalizables[i] = NULL;
|
||||
if (!crossCompartmentWrappers.init())
|
||||
return false;
|
||||
|
||||
|
221
js/src/jsgc.cpp
221
js/src/jsgc.cpp
@ -141,6 +141,7 @@ 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 */
|
||||
@ -161,59 +162,80 @@ const uint8 GCThingSizeMap[] = {
|
||||
#endif
|
||||
sizeof(JSShortString), /* FINALIZE_SHORT_STRING */
|
||||
sizeof(JSString), /* FINALIZE_STRING */
|
||||
sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */
|
||||
sizeof(JSString), /* 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::finalize(JSContext *cx)
|
||||
Arena<T>::finalize(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(aheader.compartment);
|
||||
JS_ASSERT(!aheader.getMarkingDelay()->link);
|
||||
|
||||
uintptr_t nextFree = reinterpret_cast<uintptr_t>(aheader.freeList);
|
||||
FreeCell *nextFree = aheader.freeList;
|
||||
FreeCell *freeList = NULL;
|
||||
FreeCell **tailp = &freeList;
|
||||
bool allClear = true;
|
||||
|
||||
uintptr_t thing = thingsStart(sizeof(T));
|
||||
uintptr_t end = thingsEnd();
|
||||
T *thingsEnd = &t.things[ThingsPerArena-1];
|
||||
T *thing = &t.things[0];
|
||||
thingsEnd++;
|
||||
|
||||
if (!nextFree) {
|
||||
nextFree = end;
|
||||
nextFree = thingsEnd->asFreeCell();
|
||||
} else {
|
||||
JS_ASSERT(thing <= nextFree);
|
||||
JS_ASSERT(nextFree < end);
|
||||
JS_ASSERT(thing->asFreeCell() <= nextFree);
|
||||
JS_ASSERT(nextFree < thingsEnd->asFreeCell());
|
||||
}
|
||||
|
||||
for (;; thing += sizeof(T)) {
|
||||
if (thing == nextFree) {
|
||||
if (thing == end)
|
||||
for (;; thing++) {
|
||||
if (thing->asFreeCell() == nextFree) {
|
||||
if (thing == thingsEnd)
|
||||
break;
|
||||
FreeCell *nextLink = reinterpret_cast<FreeCell *>(nextFree)->link;
|
||||
if (!nextLink) {
|
||||
nextFree = end;
|
||||
nextFree = nextFree->link;
|
||||
if (!nextFree) {
|
||||
nextFree = thingsEnd->asFreeCell();
|
||||
} else {
|
||||
nextFree = reinterpret_cast<uintptr_t>(nextLink);
|
||||
JS_ASSERT(thing < nextFree);
|
||||
JS_ASSERT(nextFree < end);
|
||||
JS_ASSERT(thing->asFreeCell() < nextFree);
|
||||
JS_ASSERT(nextFree < thingsEnd->asFreeCell());
|
||||
}
|
||||
} else if (thing->asFreeCell()->isMarked()) {
|
||||
allClear = false;
|
||||
continue;
|
||||
} else {
|
||||
T *t = reinterpret_cast<T *>(thing);
|
||||
if (t->isMarked()) {
|
||||
allClear = false;
|
||||
continue;
|
||||
}
|
||||
t->finalize(cx);
|
||||
thing->finalize(cx);
|
||||
#ifdef DEBUG
|
||||
memset(t, JS_FREE_PATTERN, sizeof(T));
|
||||
memset(thing, JS_FREE_PATTERN, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
FreeCell *freeCell = reinterpret_cast<FreeCell *>(thing);
|
||||
*tailp = freeCell;
|
||||
tailp = &freeCell->link;
|
||||
FreeCell *t = thing->asFreeCell();
|
||||
*tailp = t;
|
||||
tailp = &t->link;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -221,21 +243,21 @@ Arena::finalize(JSContext *cx)
|
||||
unsigned nfree = 0;
|
||||
if (freeList) {
|
||||
JS_ASSERT(tailp != &freeList);
|
||||
FreeCell *freeCell = freeList;
|
||||
FreeCell *t = freeList;
|
||||
for (;;) {
|
||||
++nfree;
|
||||
if (&freeCell->link == tailp)
|
||||
if (&t->link == tailp)
|
||||
break;
|
||||
JS_ASSERT(freeCell < freeCell->link);
|
||||
freeCell = freeCell->link;
|
||||
JS_ASSERT(t < t->link);
|
||||
t = t->link;
|
||||
}
|
||||
}
|
||||
if (allClear) {
|
||||
JS_ASSERT(nfree == Arena::thingsPerArena(sizeof(T)));
|
||||
JS_ASSERT(freeList->address() == thingsStart(sizeof(T)));
|
||||
JS_ASSERT(tailp == &reinterpret_cast<FreeCell *>(end - sizeof(T))->link);
|
||||
JS_ASSERT(nfree == ThingsPerArena);
|
||||
JS_ASSERT(freeList == static_cast<Cell *>(&t.things[0]));
|
||||
JS_ASSERT(tailp == &t.things[ThingsPerArena-1].asFreeCell()->link);
|
||||
} else {
|
||||
JS_ASSERT(nfree < Arena::thingsPerArena(sizeof(T)));
|
||||
JS_ASSERT(nfree < ThingsPerArena);
|
||||
}
|
||||
#endif
|
||||
*tailp = NULL;
|
||||
@ -253,7 +275,7 @@ FinalizeArenas(JSContext *cx, ArenaHeader **listHeadp)
|
||||
{
|
||||
ArenaHeader **ap = listHeadp;
|
||||
while (ArenaHeader *aheader = *ap) {
|
||||
bool allClear = aheader->getArena()->finalize<T>(cx);
|
||||
bool allClear = aheader->getArena<T>()->finalize(cx);
|
||||
if (allClear) {
|
||||
*ap = aheader->next;
|
||||
aheader->chunk()->releaseArena(aheader);
|
||||
@ -328,33 +350,7 @@ Chunk::withinArenasRange(Cell *cell)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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>
|
||||
template <typename T>
|
||||
ArenaHeader *
|
||||
Chunk::allocateArena(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
@ -363,7 +359,7 @@ Chunk::allocateArena(JSContext *cx, unsigned thingKind)
|
||||
ArenaHeader *aheader = info.emptyArenaLists.getTypedFreeList(thingKind);
|
||||
if (!aheader) {
|
||||
aheader = info.emptyArenaLists.getOtherArena();
|
||||
aheader->freeList = BuildFreeList<thingSize>(aheader);
|
||||
aheader->freeList = aheader->getArena<T>()->buildFreeList();
|
||||
}
|
||||
JS_ASSERT(!aheader->compartment);
|
||||
JS_ASSERT(!aheader->getMarkingDelay()->link);
|
||||
@ -640,12 +636,12 @@ MarkArenaPtrConservatively(JSTracer *trc, ArenaHeader *aheader, uintptr_t addr)
|
||||
JS_ASSERT(aheader->compartment);
|
||||
JS_ASSERT(sizeof(T) == aheader->getThingSize());
|
||||
|
||||
uintptr_t offset = addr & ArenaMask;
|
||||
if (offset < Arena::thingsStartOffset(sizeof(T)))
|
||||
uintptr_t offset = (addr & ArenaMask) - Arena<T>::FirstThingOffset;
|
||||
if (offset >= Arena<T>::ThingsSpan)
|
||||
return CGCT_NOTARENA;
|
||||
|
||||
/* addr can point inside the thing so we must align the address. */
|
||||
uintptr_t shift = (offset - Arena::thingsStartOffset(sizeof(T))) % sizeof(T);
|
||||
uintptr_t shift = offset % sizeof(T);
|
||||
T *thing = reinterpret_cast<T *>(addr - shift);
|
||||
|
||||
if (InFreeList(aheader, thing))
|
||||
@ -1103,6 +1099,22 @@ 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()
|
||||
{
|
||||
@ -1114,7 +1126,7 @@ ArenaList::searchForFreeArena()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <size_t thingSize>
|
||||
template <typename T>
|
||||
inline ArenaHeader *
|
||||
ArenaList::getArenaWithFreeList(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
@ -1180,7 +1192,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<thingSize>(cx, thingKind);
|
||||
ArenaHeader *aheader = chunk->allocateArena<T>(cx, thingKind);
|
||||
aheader->next = head;
|
||||
if (cursor == &head)
|
||||
cursor = &aheader->next;
|
||||
@ -1369,8 +1381,7 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind)
|
||||
if (Cell *thing = compartment->freeLists.getNext(thingKind))
|
||||
return thing;
|
||||
}
|
||||
ArenaHeader *aheader =
|
||||
compartment->arenas[thingKind].getArenaWithFreeList<sizeof(T)>(cx, thingKind);
|
||||
ArenaHeader *aheader = compartment->arenas[thingKind].getArenaWithFreeList<T>(cx, thingKind);
|
||||
if (aheader) {
|
||||
JS_ASSERT(sizeof(T) == aheader->getThingSize());
|
||||
return compartment->freeLists.populate(aheader, thingKind);
|
||||
@ -1534,19 +1545,15 @@ GCMarker::delayMarkingChildren(const void *thing)
|
||||
METER_UPDATE_MAX(cell->compartment()->rt->gcStats.maxunmarked, markLaterArenas);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader)
|
||||
MarkDelayedChilderen(JSTracer *trc, ArenaHeader *aheader)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1567,7 +1574,55 @@ GCMarker::markDelayedChildren()
|
||||
JS_ASSERT(markLaterArenas);
|
||||
markLaterArenas--;
|
||||
#endif
|
||||
MarkDelayedChildren(this, aheader);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
JS_ASSERT(!markLaterArenas);
|
||||
}
|
||||
|
169
js/src/jsgc.h
169
js/src/jsgc.h
@ -77,9 +77,6 @@ struct Shape;
|
||||
|
||||
namespace gc {
|
||||
|
||||
struct Arena;
|
||||
struct MarkingDelay;
|
||||
|
||||
/* The kind of GC thing with a finalizer. */
|
||||
enum FinalizeKind {
|
||||
FINALIZE_OBJECT0,
|
||||
@ -107,8 +104,6 @@ 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;
|
||||
@ -124,19 +119,7 @@ const size_t ArenaBitmapBits = ArenaCellCount;
|
||||
const size_t ArenaBitmapBytes = ArenaBitmapBits / 8;
|
||||
const size_t ArenaBitmapWords = ArenaBitmapBits / JS_BITS_PER_WORD;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
template <typename T> struct Arena;
|
||||
|
||||
/* Every arena has a header. */
|
||||
struct ArenaHeader {
|
||||
@ -151,8 +134,9 @@ struct ArenaHeader {
|
||||
inline uintptr_t address() const;
|
||||
inline Chunk *chunk() const;
|
||||
|
||||
Arena *getArena() {
|
||||
return reinterpret_cast<Arena *>(address());
|
||||
template <typename T>
|
||||
Arena<T> *getArena() {
|
||||
return reinterpret_cast<Arena<T> *>(address());
|
||||
}
|
||||
|
||||
unsigned getThingKind() const {
|
||||
@ -165,9 +149,9 @@ struct ArenaHeader {
|
||||
|
||||
inline MarkingDelay *getMarkingDelay() const;
|
||||
|
||||
size_t getThingSize() const {
|
||||
return GCThingSizeMap[getThingKind()];
|
||||
}
|
||||
#ifdef DEBUG
|
||||
JS_FRIEND_API(size_t) getThingSize() const;
|
||||
#endif
|
||||
|
||||
#if defined DEBUG || defined JS_GCMETER
|
||||
static size_t CountListLength(const ArenaHeader *aheader) {
|
||||
@ -179,50 +163,74 @@ 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 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.
|
||||
* 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.
|
||||
*
|
||||
* +-------------+-----+----+----+-----+----+
|
||||
* | ArenaHeader | pad | T0 | T1 | ... | Tn |
|
||||
* +-------------+-----+----+----+-----+----+
|
||||
* +-------------+-----+----+----+-----+----+-----+
|
||||
* | ArenaHeader | pad | T0 | T1 | ... | Tn | pad |
|
||||
* +-------------+-----+----+----+-----+----+-----+
|
||||
*
|
||||
* <----------------------------------------> = ArenaSize bytes
|
||||
* <-------------------> = thingsStartOffset
|
||||
* <----------------------------------------------> = 4096 bytes
|
||||
* <-----> = Filler1Size
|
||||
* <-------------------> = HeaderSize
|
||||
* <--------------------------> = SpaceAfterHeader
|
||||
* <-----> = Filler2Size
|
||||
*/
|
||||
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;
|
||||
uint8_t data[ArenaSize - sizeof(ArenaHeader)];
|
||||
Things<T, ThingsPerArena, Filler1Size, Filler2Size> t;
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(sizeof(Arena) == ArenaSize);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static size_t thingsPerArena(size_t thingSize) {
|
||||
JS_ASSERT(thingSize % Cell::CellSize == 0);
|
||||
return (ArenaSize - sizeof(ArenaHeader)) / thingSize;
|
||||
}
|
||||
inline FreeCell *buildFreeList();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
@ -234,7 +242,8 @@ struct Arena {
|
||||
struct MarkingDelay {
|
||||
ArenaHeader *link;
|
||||
|
||||
void init() {
|
||||
void init()
|
||||
{
|
||||
link = NULL;
|
||||
}
|
||||
|
||||
@ -242,7 +251,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 at the 0 address.
|
||||
* starting the 0 address.
|
||||
*/
|
||||
static ArenaHeader *stackBottom() {
|
||||
return reinterpret_cast<ArenaHeader *>(ArenaSize);
|
||||
@ -373,7 +382,7 @@ JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap));
|
||||
* marking state).
|
||||
*/
|
||||
struct Chunk {
|
||||
Arena arenas[ArenasPerChunk];
|
||||
Arena<FreeCell> arenas[ArenasPerChunk];
|
||||
ChunkBitmap bitmap;
|
||||
MarkingDelay markingDelay[ArenasPerChunk];
|
||||
ChunkInfo info;
|
||||
@ -398,7 +407,7 @@ struct Chunk {
|
||||
bool hasAvailableArenas();
|
||||
bool withinArenasRange(Cell *cell);
|
||||
|
||||
template <size_t thingSize>
|
||||
template <typename T>
|
||||
ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
|
||||
|
||||
void releaseArena(ArenaHeader *aheader);
|
||||
@ -438,8 +447,7 @@ Cell::chunk() const
|
||||
inline bool
|
||||
Cell::isAligned() const
|
||||
{
|
||||
/* Things ends at the arena end. */
|
||||
uintptr_t offset = ArenaSize - (address() & ArenaMask);
|
||||
uintptr_t offset = address() & ArenaMask;
|
||||
return offset % arenaHeader()->getThingSize() == 0;
|
||||
}
|
||||
#endif
|
||||
@ -571,7 +579,7 @@ GetGCThingTraceKind(const void *thing);
|
||||
static inline JSRuntime *
|
||||
GetGCThingRuntime(void *thing)
|
||||
{
|
||||
return reinterpret_cast<Cell *>(thing)->chunk()->info.runtime;
|
||||
return reinterpret_cast<FreeCell *>(thing)->chunk()->info.runtime;
|
||||
}
|
||||
|
||||
/* The arenas in a list have uniform kind. */
|
||||
@ -624,7 +632,7 @@ class ArenaList {
|
||||
|
||||
inline ArenaHeader *searchForFreeArena();
|
||||
|
||||
template <size_t thingSize>
|
||||
template <typename T>
|
||||
inline ArenaHeader *getArenaWithFreeList(JSContext *cx, unsigned thingKind);
|
||||
|
||||
template<typename T>
|
||||
@ -684,6 +692,17 @@ 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
|
||||
@ -698,29 +717,12 @@ class ArenaList {
|
||||
struct FreeLists {
|
||||
FreeCell *finalizables[FINALIZE_LIMIT];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
void purge();
|
||||
|
||||
FreeCell *getNext(unsigned kind) {
|
||||
FreeCell *top = finalizables[kind];
|
||||
if (top) {
|
||||
top->checkLink();
|
||||
CheckGCFreeListLink(top);
|
||||
finalizables[kind] = top->link;
|
||||
}
|
||||
return top;
|
||||
@ -728,7 +730,8 @@ struct FreeLists {
|
||||
|
||||
Cell *populate(ArenaHeader *aheader, uint32 thingKind) {
|
||||
FreeCell *cell = aheader->freeList;
|
||||
cell->checkLink();
|
||||
JS_ASSERT(cell);
|
||||
CheckGCFreeListLink(cell);
|
||||
aheader->freeList = NULL;
|
||||
finalizables[thingKind] = cell->link;
|
||||
return cell;
|
||||
|
@ -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->isAligned());
|
||||
JS_ASSERT(thing->asFreeCell()->isAligned());
|
||||
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
JS_ASSERT(thing->arenaHeader()->compartment);
|
||||
|
@ -147,6 +147,61 @@ 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)
|
||||
{
|
||||
@ -158,8 +213,8 @@ DumpArenaStats(JSGCArenaStats *stp, FILE *fp)
|
||||
JSGCArenaStats *st = &stp[i];
|
||||
if (st->maxarenas == 0)
|
||||
continue;
|
||||
size_t thingSize = GCThingSizeMap[i];
|
||||
size_t thingsPerArena = Arena::thingsPerArena(thingSize);
|
||||
size_t thingSize = 0, thingsPerArena = 0;
|
||||
GetSizeAndThingsPerArena(i, thingSize, thingsPerArena);
|
||||
|
||||
fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):\n",
|
||||
GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena));
|
||||
|
@ -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 Cell::CellSize. */
|
||||
/* This can be any value that is a multiple of sizeof(gc::FreeCell). */
|
||||
static const size_t INLINE_EXTENSION_CHARS = sizeof(JSString::Data) / sizeof(jschar);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % js::gc::Cell::CellSize == 0);
|
||||
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % sizeof(js::gc::FreeCell) == 0);
|
||||
JS_STATIC_ASSERT(MAX_SHORT_LENGTH + 1 ==
|
||||
(sizeof(JSShortString) -
|
||||
offsetof(JSShortString, d.inlineStorage)) / sizeof(jschar));
|
||||
|
Loading…
Reference in New Issue
Block a user