From cc5230b13c013eb580c492c3bddeb5a19af19cf9 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 23 Mar 2011 11:57:27 -0700 Subject: [PATCH] Bug 569422 - Remove unions from GC (r=luke) --- js/src/jscell.h | 4 +++ js/src/jsgc.cpp | 24 ++++++++--------- js/src/jsgc.h | 72 +++++++++++++++++++++++++++++++++---------------- js/src/jstl.h | 3 +++ 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/js/src/jscell.h b/js/src/jscell.h index 8abbd203e038..f85457c924e9 100644 --- a/js/src/jscell.h +++ b/js/src/jscell.h @@ -78,6 +78,10 @@ struct Cell { JS_ALWAYS_INLINE js::gc::FreeCell *asFreeCell() { return reinterpret_cast(this); } + + JS_ALWAYS_INLINE const js::gc::FreeCell *asFreeCell() const { + return reinterpret_cast(this); + } }; /* FreeCell has always size 8 */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 3eabd56a2f04..bb3c8de7ccb7 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -169,15 +169,15 @@ Arena::init(JSCompartment *compartment, unsigned thingKind) { aheader.compartment = compartment; aheader.thingKind = thingKind; - aheader.freeList = &t.things[0].cell; - JS_ASSERT(sizeof(T) == sizeof(ThingOrCell)); - ThingOrCell *thing = &t.things[0]; - ThingOrCell *last = &t.things[JS_ARRAY_LENGTH(t.things) - 1]; + char *p = (char *)&t.things[0]; + aheader.freeList = reinterpret_cast(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::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::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 { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 6247be0c9fb2..1f2dd4b222c1 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -117,40 +117,67 @@ struct ArenaHeader { #endif }; -template -union ThingOrCell { - T t; - FreeCell cell; +template +struct Things { + char filler1[R1]; + T things[N]; + char filler[R2]; }; -template -struct Things { - ThingOrCell things[N]; - char filler[R]; +template +struct Things { + char filler1[R1]; + T things[N]; +}; + +template +struct Things { + T things[N]; + char filler2[R2]; }; template -struct Things { - ThingOrCell things[N]; +struct Things { + T things[N]; }; template 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; + Things t; + + static void staticAsserts() { + JS_STATIC_ASSERT(offsetof(Arena, t.things) % sizeof(T) == 0); + JS_STATIC_ASSERT(sizeof(Arena) == 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) == 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(this) - reinterpret_cast(&arena()->t); + return this->asFreeCell() - arena()->t.things[0].asFreeCell(); } template diff --git a/js/src/jstl.h b/js/src/jstl.h index 31b1f03e0d09..33dcc9dcb9b2 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -175,6 +175,9 @@ template <> struct IsPodType { static const bool result = true; template inline T *ArraySize(T (&)[N]) { return N; } template inline T *ArrayEnd(T (&arr)[N]) { return arr + N; } +template struct If { static const T result = v1; }; +template struct If { static const T result = v2; }; + } /* namespace tl */ /* Useful for implementing containers that assert non-reentrancy */