Bug 569422 - Remove unions from GC (r=luke)

This commit is contained in:
Bill McCloskey 2011-03-23 11:57:27 -07:00
parent 9eb8ca7a24
commit cc5230b13c
4 changed files with 68 additions and 35 deletions

View File

@ -78,6 +78,10 @@ struct Cell {
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);
}
};
/* FreeCell has always size 8 */

View File

@ -169,15 +169,15 @@ Arena<T>::init(JSCompartment *compartment, unsigned thingKind)
{
aheader.compartment = compartment;
aheader.thingKind = thingKind;
aheader.freeList = &t.things[0].cell;
JS_ASSERT(sizeof(T) == sizeof(ThingOrCell<T>));
ThingOrCell<T> *thing = &t.things[0];
ThingOrCell<T> *last = &t.things[JS_ARRAY_LENGTH(t.things) - 1];
char *p = (char *)&t.things[0];
aheader.freeList = reinterpret_cast<FreeCell *>(p);
T *thing = &t.things[0];
T *last = &t.things[JS_ARRAY_LENGTH(t.things) - 1];
while (thing < last) {
thing->cell.link = &(thing + 1)->cell;
thing->asFreeCell()->link = (thing + 1)->asFreeCell();
++thing;
}
last->cell.link = NULL;
last->asFreeCell()->link = NULL;
#ifdef DEBUG
aheader.thingSize = sizeof(T);
aheader.isUsed = true;
@ -213,7 +213,7 @@ Arena<T>::mark(T *thing, JSTracer *trc)
{
T *alignedThing = getAlignedThing(thing);
if (alignedThing > &t.things[ThingsPerArena-1].t || alignedThing < &t.things[0].t)
if (alignedThing > &t.things[ThingsPerArena-1] || alignedThing < &t.things[0])
return CGCT_NOTARENA;
if (!aheader.compartment || inFreeList(alignedThing))
@ -1347,7 +1347,7 @@ void
Arena<T>::markDelayedChildren(JSTracer *trc)
{
T* thing = (T *)getMarkingDelay()->start;
T *thingsEnd = &t.things[ThingsPerArena-1].t;
T *thingsEnd = &t.things[ThingsPerArena-1];
JS_ASSERT(thing == getAlignedThing(thing));
while (thing <= thingsEnd) {
if (thing->isMarked())
@ -1838,8 +1838,8 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
FreeCell **tailp = &freeList;
bool allClear = true;
T *thingsEnd = &a->t.things[a->ThingsPerArena-1].t;
T *thing = &a->t.things[0].t;
T *thingsEnd = &a->t.things[a->ThingsPerArena-1];
T *thing = &a->t.things[0];
thingsEnd++;
if (!nextFree) {
@ -1896,14 +1896,14 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
* add the arena itself to the destroy list.
*/
JS_ASSERT(nfree == a->ThingsPerArena);
JS_ASSERT((T *)tailp == &a->t.things[a->ThingsPerArena-1].t);
JS_ASSERT((T *)tailp == &a->t.things[a->ThingsPerArena-1]);
*tailp = NULL;
header->freeList = freeList;
#ifdef DEBUG
header->hasFreeThings = true;
#endif
*ap = (header->next);
JS_ASSERT((T *)header->freeList == &a->t.things[0].t);
JS_ASSERT((T *)header->freeList == &a->t.things[0]);
a->chunk()->releaseArena(a);
METER(nkilledarenas++);
} else {

View File

@ -117,40 +117,67 @@ struct ArenaHeader {
#endif
};
template <typename T>
union ThingOrCell {
T t;
FreeCell cell;
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 R>
struct Things {
ThingOrCell<T> things[N];
char filler[R];
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> {
ThingOrCell<T> things[N];
struct Things<T, N, 0, 0> {
T things[N];
};
template <typename T>
struct Arena {
static const size_t ArenaSize = 4096;
struct AlignedArenaHeader {
T align[(sizeof(ArenaHeader) + sizeof(T) - 1) / sizeof(T)];
};
ArenaHeader aheader;
/* We want things in the arena to be aligned, so align the header. */
union {
ArenaHeader aheader;
AlignedArenaHeader align;
};
/*
* 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.
*
* +-------------+-----+----+----+-----+----+-----+
* | ArenaHeader | pad | T0 | T1 | ... | Tn | pad |
* +-------------+-----+----+----+-----+----+-----+
*
* <----------------------------------------------> = 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 ThingsPerArena = (ArenaSize - sizeof(AlignedArenaHeader)) / sizeof(T);
static const size_t FillerSize = ArenaSize - sizeof(AlignedArenaHeader) - sizeof(T) * ThingsPerArena;
Things<T, ThingsPerArena, FillerSize> t;
Things<T, ThingsPerArena, Filler1Size, Filler2Size> t;
static void staticAsserts() {
JS_STATIC_ASSERT(offsetof(Arena<T>, t.things) % sizeof(T) == 0);
JS_STATIC_ASSERT(sizeof(Arena<T>) == ArenaSize);
}
inline Chunk *chunk() const;
inline size_t arenaIndex() const;
@ -170,7 +197,6 @@ struct Arena {
void init(JSCompartment *compartment, unsigned thingKind);
};
JS_STATIC_ASSERT(sizeof(Arena<FreeCell>) == 4096);
/*
* Live objects are marked black. How many other additional colors are available
@ -392,7 +418,7 @@ STATIC_POSTCONDITION_ASSUME(return < ArenaBitmap::BitCount)
size_t
Cell::cellIndex() const
{
return reinterpret_cast<const FreeCell *>(this) - reinterpret_cast<FreeCell *>(&arena()->t);
return this->asFreeCell() - arena()->t.things[0].asFreeCell();
}
template <typename T>

View File

@ -175,6 +175,9 @@ template <> struct IsPodType<double> { static const bool result = true;
template <class T, size_t N> inline T *ArraySize(T (&)[N]) { return N; }
template <class T, size_t N> inline T *ArrayEnd(T (&arr)[N]) { return arr + N; }
template <bool cond, typename T, T v1, T v2> struct If { static const T result = v1; };
template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; };
} /* namespace tl */
/* Useful for implementing containers that assert non-reentrancy */