bug 605029 - ArenaHeader versus Arena<FreeCell> and other cleanups. r=wmccloskey

This commit is contained in:
Igor Bukanov 2011-04-20 07:30:10 +02:00
parent a61c26e2c0
commit 8b0d367736
14 changed files with 500 additions and 724 deletions

View File

@ -652,7 +652,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
# We desire these numbers to go down, not up. See "User guide to memory
# management within SpiderMonkey" in jsutil.h.
$(srcdir)/config/check_source_count.py OffTheBooks:: 53 \
$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
# This should go to zero, if possible.
$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \

View File

@ -1064,7 +1064,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
/* Create a native scope. */
JSObject *arrayProto = getProto();
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arenaHeader()->getThingKind());
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
return false;

View File

@ -47,6 +47,7 @@ namespace gc {
template <typename T> struct Arena;
struct ArenaBitmap;
struct ArenaHeader;
struct MarkingDelay;
struct Chunk;
struct FreeCell;
@ -64,7 +65,8 @@ struct Cell {
static const size_t CellSize = size_t(1) << CellShift;
static const size_t CellMask = CellSize - 1;
inline Arena<Cell> *arena() const;
inline uintptr_t address() const;
inline ArenaHeader *arenaHeader() const;
inline Chunk *chunk() const;
inline ArenaBitmap *bitmap() const;
JS_ALWAYS_INLINE size_t cellIndex() const;
@ -82,9 +84,12 @@ struct Cell {
JS_ALWAYS_INLINE const js::gc::FreeCell *asFreeCell() const {
return reinterpret_cast<const FreeCell *>(this);
}
#ifdef DEBUG
inline bool isAligned() const;
#endif
};
/* FreeCell has always size 8 */
struct FreeCell : Cell {
union {
FreeCell *link;
@ -92,7 +97,7 @@ struct FreeCell : Cell {
};
};
JS_STATIC_ASSERT(sizeof(FreeCell) == 8);
JS_STATIC_ASSERT(sizeof(FreeCell) == Cell::CellSize);
} /* namespace gc */
} /* namespace js */

File diff suppressed because it is too large Load Diff

View File

@ -92,6 +92,7 @@ enum FinalizeKind {
FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_FUNCTION,
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
FINALIZE_SHAPE,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
@ -102,18 +103,43 @@ enum FinalizeKind {
FINALIZE_LIMIT
};
const uintN JS_FINALIZE_OBJECT_LIMIT = 12;
const size_t ArenaShift = 12;
const size_t ArenaSize = size_t(1) << ArenaShift;
const size_t ArenaMask = ArenaSize - 1;
template <typename T> struct Arena;
/* Every arena has a header. */
struct ArenaHeader {
JSCompartment *compartment;
Arena<FreeCell> *next;
ArenaHeader *next;
FreeCell *freeList;
private:
unsigned thingKind;
public:
inline uintptr_t address() const;
inline Chunk *chunk() const;
inline ArenaBitmap *bitmap() const;
template <typename T>
Arena<T> *getArena() {
return reinterpret_cast<Arena<T> *>(address());
}
unsigned getThingKind() const {
return thingKind;
}
void setThingKind(unsigned kind) {
thingKind = kind;
}
inline MarkingDelay *getMarkingDelay() const;
#ifdef DEBUG
size_t thingSize;
bool isUsed;
bool hasFreeThings;
JS_FRIEND_API(size_t) getThingSize() const;
#endif
};
@ -143,10 +169,6 @@ struct Things<T, N, 0, 0> {
template <typename T>
struct Arena {
static const size_t ArenaSize = 4096;
ArenaHeader aheader;
/*
* Layout of an arena:
* An arena is 4K. We want it to have a header followed by a list of T
@ -171,35 +193,28 @@ struct Arena {
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;
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);
}
inline Chunk *chunk() const;
inline size_t arenaIndex() const;
inline FreeCell *buildFreeList();
inline ArenaHeader *header() { return &aheader; };
inline MarkingDelay *getMarkingDelay() const;
inline ArenaBitmap *bitmap() const;
inline ConservativeGCTest mark(T *thing, JSTracer *trc);
void markDelayedChildren(JSTracer *trc);
inline bool inFreeList(void *thing) const;
inline T *getAlignedThing(const void *thing);
#ifdef DEBUG
inline bool assureThingIsAligned(void *thing);
#endif
void init(JSCompartment *compartment, unsigned thingKind);
bool finalize(JSContext *cx);
};
void FinalizeArena(Arena<FreeCell> *a);
void FinalizeArena(ArenaHeader *aheader);
/*
* Live objects are marked black. How many other additional colors are available
@ -209,7 +224,7 @@ static const uint32 BLACK = 0;
/* An arena bitmap contains enough mark bits for all the cells in an arena. */
struct ArenaBitmap {
static const size_t BitCount = Arena<FreeCell>::ArenaSize / Cell::CellSize;
static const size_t BitCount = ArenaSize / Cell::CellSize;
static const size_t BitWords = BitCount / JS_BITS_PER_WORD;
uintptr_t bitmap[BitWords];
@ -258,100 +273,76 @@ struct ArenaBitmap {
};
/* Ensure that bitmap covers the whole arena. */
JS_STATIC_ASSERT(Arena<FreeCell>::ArenaSize % Cell::CellSize == 0);
JS_STATIC_ASSERT(ArenaSize % Cell::CellSize == 0);
JS_STATIC_ASSERT(ArenaBitmap::BitCount % JS_BITS_PER_WORD == 0);
/* Marking delay is used to resume marking later when recursive marking uses too much stack. */
/*
* When recursive marking uses too much stack the marking is delayed and
* the corresponding arenas are put into a stack using a linked via the
* following per arena structure.
*/
struct MarkingDelay {
Arena<Cell> *link;
uintptr_t unmarkedChildren;
jsuword start;
ArenaHeader *link;
void init()
{
link = NULL;
unmarkedChildren = 0;
}
/*
* 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.
*/
static ArenaHeader *stackBottom() {
return reinterpret_cast<ArenaHeader *>(ArenaSize);
}
};
struct EmptyArenaLists {
/* Arenas with no internal freelist prepared. */
Arena<FreeCell> *cellFreeList;
ArenaHeader *cellFreeList;
/* Arenas with internal freelists prepared for a given finalize kind. */
Arena<FreeCell> *freeLists[FINALIZE_LIMIT];
ArenaHeader *freeLists[FINALIZE_LIMIT];
void init() {
PodZero(this);
}
Arena<FreeCell> *getOtherArena() {
Arena<FreeCell> *arena = cellFreeList;
if (arena) {
cellFreeList = arena->header()->next;
return arena;
ArenaHeader *getOtherArena() {
ArenaHeader *aheader = cellFreeList;
if (aheader) {
cellFreeList = aheader->next;
return aheader;
}
for (int i = 0; i < FINALIZE_LIMIT; i++) {
if ((arena = (Arena<FreeCell> *) freeLists[i])) {
freeLists[i] = freeLists[i]->header()->next;
return arena;
aheader = freeLists[i];
if (aheader) {
freeLists[i] = aheader->next;
return aheader;
}
}
JS_NOT_REACHED("No arena");
return NULL;
}
template <typename T>
inline Arena<T> *getTypedFreeList(unsigned thingKind);
ArenaHeader *getTypedFreeList(unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT);
ArenaHeader *aheader = freeLists[thingKind];
if (aheader)
freeLists[thingKind] = aheader->next;
return aheader;
}
template <typename T>
inline Arena<T> *getNext(JSCompartment *comp, unsigned thingKind);
template <typename T>
inline void insert(Arena<T> *arena);
void insert(ArenaHeader *aheader) {
unsigned thingKind = aheader->getThingKind();
aheader->next = freeLists[thingKind];
freeLists[thingKind] = aheader;
}
};
template <typename T>
inline Arena<T> *
EmptyArenaLists::getTypedFreeList(unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT);
Arena<T> *arena = (Arena<T>*) freeLists[thingKind];
if (arena) {
freeLists[thingKind] = freeLists[thingKind]->header()->next;
return arena;
}
return NULL;
}
template<typename T>
inline Arena<T> *
EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) {
Arena<T> *arena = getTypedFreeList<T>(thingKind);
if (arena) {
JS_ASSERT(arena->header()->isUsed == false);
JS_ASSERT(arena->header()->thingSize == sizeof(T));
#ifdef DEBUG
arena->header()->isUsed = true;
#endif
arena->header()->thingKind = thingKind;
arena->header()->compartment = comp;
return arena;
}
arena = (Arena<T> *)getOtherArena();
JS_ASSERT(arena->header()->isUsed == false);
arena->init(comp, thingKind);
return arena;
}
template <typename T>
inline void
EmptyArenaLists::insert(Arena<T> *arena) {
unsigned thingKind = arena->header()->thingKind;
JS_ASSERT(thingKind < FINALIZE_LIMIT);
arena->header()->next = freeLists[thingKind];
freeLists[thingKind] = (Arena<FreeCell> *) arena;
}
/* The chunk header (located at the end of the chunk to preserve arena alignment). */
struct ChunkInfo {
Chunk *link;
@ -366,9 +357,9 @@ struct ChunkInfo {
/* Chunks contain arenas and associated data structures (mark bitmap, delayed marking state). */
struct Chunk {
static const size_t BytesPerArena = sizeof(Arena<FreeCell>) +
static const size_t BytesPerArena = ArenaSize +
sizeof(ArenaBitmap) +
sizeof(MarkingDelay);
sizeof(sizeof(MarkingDelay));
static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena;
@ -378,6 +369,21 @@ struct Chunk {
ChunkInfo info;
static Chunk *fromAddress(uintptr_t addr) {
addr &= ~GC_CHUNK_MASK;
return reinterpret_cast<Chunk *>(addr);
}
static bool withinArenasRange(uintptr_t addr) {
uintptr_t offset = addr & GC_CHUNK_MASK;
return offset < ArenasPerChunk * ArenaSize;
}
static size_t arenaIndex(uintptr_t addr) {
JS_ASSERT(withinArenasRange(addr));
return (addr & GC_CHUNK_MASK) >> ArenaShift;
}
void clearMarkBitmap();
bool init(JSRuntime *rt);
@ -386,30 +392,37 @@ struct Chunk {
bool withinArenasRange(Cell *cell);
template <typename T>
Arena<T> *allocateArena(JSContext *cx, unsigned thingKind);
ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
template <typename T>
void releaseArena(Arena<T> *a);
void releaseArena(ArenaHeader *aheader);
JSRuntime *getRuntime();
};
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE);
Arena<Cell> *
Cell::arena() const
inline uintptr_t
Cell::address() const
{
uintptr_t addr = uintptr_t(this);
JS_ASSERT(addr % sizeof(FreeCell) == 0);
addr &= ~(Arena<FreeCell>::ArenaSize - 1);
return reinterpret_cast<Arena<Cell> *>(addr);
JS_ASSERT(addr % Cell::CellSize == 0);
JS_ASSERT(Chunk::withinArenasRange(addr));
return addr;
}
inline ArenaHeader *
Cell::arenaHeader() const
{
uintptr_t addr = address();
addr &= ~ArenaMask;
return reinterpret_cast<ArenaHeader *>(addr);
}
Chunk *
Cell::chunk() const
{
uintptr_t addr = uintptr_t(this);
JS_ASSERT(addr % sizeof(FreeCell) == 0);
JS_ASSERT(addr % Cell::CellSize == 0);
addr &= ~(GC_CHUNK_SIZE - 1);
return reinterpret_cast<Chunk *>(addr);
}
@ -417,70 +430,60 @@ Cell::chunk() const
ArenaBitmap *
Cell::bitmap() const
{
return &chunk()->bitmaps[arena()->arenaIndex()];
return &chunk()->bitmaps[Chunk::arenaIndex(address())];
}
STATIC_POSTCONDITION_ASSUME(return < ArenaBitmap::BitCount)
size_t
Cell::cellIndex() const
{
return this->asFreeCell() - arena()->t.things[0].asFreeCell();
}
template <typename T>
Chunk *
Arena<T>::chunk() const
{
uintptr_t addr = uintptr_t(this);
JS_ASSERT(addr % sizeof(FreeCell) == 0);
addr &= ~(GC_CHUNK_SIZE - 1);
return reinterpret_cast<Chunk *>(addr);
}
template <typename T>
size_t
Arena<T>::arenaIndex() const
{
return reinterpret_cast<const Arena<FreeCell> *>(this) - chunk()->arenas;
}
template <typename T>
MarkingDelay *
Arena<T>::getMarkingDelay() const
{
return &chunk()->markingDelay[arenaIndex()];
}
template <typename T>
ArenaBitmap *
Arena<T>::bitmap() const
{
return &chunk()->bitmaps[arenaIndex()];
}
template <typename T>
inline T *
Arena<T>::getAlignedThing(const void *thing)
{
jsuword start = reinterpret_cast<jsuword>(&t.things[0]);
jsuword offset = reinterpret_cast<jsuword>(thing) - start;
offset -= offset % sizeof(T);
return reinterpret_cast<T *>(start + offset);
uintptr_t addr = address();
return (addr & ArenaMask) >> Cell::CellShift;
}
#ifdef DEBUG
template <typename T>
inline bool
Arena<T>::assureThingIsAligned(void *thing)
Cell::isAligned() const
{
return (getAlignedThing(thing) == thing);
uintptr_t offset = address() & ArenaMask;
return offset % arenaHeader()->getThingSize() == 0;
}
#endif
inline uintptr_t
ArenaHeader::address() const
{
uintptr_t addr = reinterpret_cast<uintptr_t>(this);
JS_ASSERT(!(addr & ArenaMask));
JS_ASSERT(Chunk::withinArenasRange(addr));
return addr;
}
inline Chunk *
ArenaHeader::chunk() const
{
return Chunk::fromAddress(address());
}
inline ArenaBitmap *
ArenaHeader::bitmap() const
{
return &chunk()->bitmaps[Chunk::arenaIndex(address())];
}
inline MarkingDelay *
ArenaHeader::getMarkingDelay() const
{
return &chunk()->markingDelay[Chunk::arenaIndex(address())];
}
static void
AssertValidColor(const void *thing, uint32 color)
{
JS_ASSERT_IF(color, color < reinterpret_cast<const js::gc::FreeCell *>(thing)->arena()->header()->thingSize / sizeof(FreeCell));
#ifdef DEBUG
ArenaHeader *aheader = reinterpret_cast<const js::gc::Cell *>(thing)->arenaHeader();
JS_ASSERT_IF(color, color < aheader->getThingSize() / Cell::CellSize);
#endif
}
inline bool
@ -508,15 +511,7 @@ Cell::unmark(uint32 color) const
JSCompartment *
Cell::compartment() const
{
return arena()->header()->compartment;
}
template <typename T>
static inline
Arena<T> *
GetArena(Cell *cell)
{
return reinterpret_cast<Arena<T> *>(cell->arena());
return arenaHeader()->compartment;
}
#define JSTRACE_XML 3
@ -580,15 +575,10 @@ GetGCThingRuntime(void *thing)
return reinterpret_cast<FreeCell *>(thing)->chunk()->info.runtime;
}
#ifdef DEBUG
extern bool
checkArenaListsForThing(JSCompartment *comp, jsuword thing);
#endif
/* The arenas in a list have uniform kind. */
struct ArenaList {
Arena<FreeCell> *head; /* list start */
Arena<FreeCell> *cursor; /* arena with free things */
ArenaHeader *head; /* list start */
ArenaHeader *cursor; /* arena with free things */
volatile bool hasToBeFinalized;
inline void init() {
@ -597,47 +587,35 @@ struct ArenaList {
hasToBeFinalized = false;
}
inline Arena<FreeCell> *getNextWithFreeList(JSContext *cx) {
inline ArenaHeader *getNextWithFreeList() {
JS_ASSERT(!hasToBeFinalized);
Arena<FreeCell> *a;
while (cursor != NULL) {
ArenaHeader *aheader = cursor->header();
a = cursor;
while (cursor) {
ArenaHeader *aheader = cursor;
cursor = aheader->next;
if (aheader->freeList)
return a;
return aheader;
}
return NULL;
}
#ifdef DEBUG
template <typename T>
bool arenasContainThing(void *thing) {
for (Arena<T> *a = (Arena<T> *) head; a; a = (Arena<T> *) a->header()->next) {
JS_ASSERT(a->header()->isUsed);
if (thing >= &a->t.things[0] && thing < &a->t.things[a->ThingsPerArena])
return true;
}
return false;
}
bool markedThingsInArenaList() {
for (Arena<FreeCell> *a = (Arena<FreeCell> *) head; a; a = (Arena<FreeCell> *) a->header()->next) {
if (!a->bitmap()->noBitsSet())
for (ArenaHeader *aheader = head; aheader; aheader = aheader->next) {
if (!aheader->bitmap()->noBitsSet())
return true;
}
return false;
}
#endif
inline void insert(Arena<FreeCell> *a) {
a->header()->next = head;
head = a;
inline void insert(ArenaHeader *aheader) {
aheader->next = head;
head = aheader;
}
void releaseAll() {
void releaseAll(unsigned thingKind) {
while (head) {
Arena<FreeCell> *next = head->header()->next;
ArenaHeader *next = head->next;
head->chunk()->releaseArena(head);
head = next;
}
@ -646,7 +624,7 @@ struct ArenaList {
}
inline bool isEmpty() const {
return (head == NULL);
return !head;
}
};
@ -664,17 +642,12 @@ struct FreeLists {
} else {
finalizables[kind] = NULL;
}
#ifdef DEBUG
if (top && !top->link)
top->arena()->header()->hasFreeThings = false;
#endif
}
return top;
}
template <typename T>
inline void populate(Arena<T> *a, uint32 thingKind) {
finalizables[thingKind] = &a->header()->freeList;
void populate(ArenaHeader *aheader, uint32 thingKind) {
finalizables[thingKind] = &aheader->freeList;
}
#ifdef DEBUG
@ -744,9 +717,7 @@ CheckGCFreeListLink(js::gc::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->arena() ==
cell->link->arena());
JS_ASSERT_IF(cell->link, cell->arenaHeader() == cell->link->arenaHeader());
JS_ASSERT_IF(cell->link, cell < cell->link);
}
@ -885,7 +856,7 @@ extern void
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
extern void
FinalizeArenaList(JSContext *cx, js::gc::ArenaList *arenaList, js::gc::Arena<js::gc::FreeCell> *head);
FinalizeArenaList(JSContext *cx, js::gc::ArenaList *arenaList, js::gc::ArenaHeader *head);
namespace js {
@ -914,15 +885,18 @@ class GCHelperThread {
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
void **freeCursor;
void **freeCursorEnd;
Vector<void **, 16, js::SystemAllocPolicy> finalizeVector;
void **finalizeCursor;
void **finalizeCursorEnd;
struct FinalizeListAndHead {
js::gc::ArenaList *list;
js::gc::ArenaHeader *head;
};
Vector<FinalizeListAndHead, 64, js::SystemAllocPolicy> finalizeVector;
JS_FRIEND_API(void)
replenishAndFreeLater(void *ptr);
void replenishAndFinalizeLater(js::gc::ArenaList *list);
static void freeElementsAndArray(void **array, void **end) {
JS_ASSERT(array <= end);
for (void **p = array; p != end; ++p)
@ -930,17 +904,6 @@ class GCHelperThread {
js::Foreground::free_(array);
}
void finalizeElementsAndArray(void **array, void **end) {
JS_ASSERT(array <= end);
for (void **p = array; p != end; p += 2) {
js::gc::ArenaList *list = (js::gc::ArenaList *)*p;
js::gc::Arena<js::gc::FreeCell> *head = (js::gc::Arena<js::gc::FreeCell> *)*(p+1);
FinalizeArenaList(cx, list, head);
}
js::Foreground::free_(array);
}
static void threadMain(void* arg);
void threadLoop(JSRuntime *rt);
@ -954,8 +917,6 @@ class GCHelperThread {
shutdown(false),
freeCursor(NULL),
freeCursorEnd(NULL),
finalizeCursor(NULL),
finalizeCursorEnd(NULL),
sweeping(false) { }
volatile bool sweeping;
@ -976,19 +937,16 @@ class GCHelperThread {
replenishAndFreeLater(ptr);
}
void finalizeLater(js::gc::ArenaList *list) {
bool finalizeLater(js::gc::ArenaList *list) {
JS_ASSERT(!sweeping);
JS_ASSERT(!list->hasToBeFinalized);
if (!list->head)
return;
return true;
FinalizeListAndHead f = {list, list->head};
if (!finalizeVector.append(f))
return false;
list->hasToBeFinalized = true;
JS_ASSERT(!sweeping);
if (finalizeCursor + 1 < finalizeCursorEnd) {
*finalizeCursor++ = list;
*finalizeCursor++ = list->head;
} else {
replenishAndFinalizeLater(list);
}
return true;
}
void setContext(JSContext *context) { cx = context; }
@ -1119,9 +1077,9 @@ struct GCMarker : public JSTracer {
public:
/* See comments before delayMarkingChildren is jsgc.cpp. */
js::gc::Arena<js::gc::Cell> *unmarkedArenaStackTop;
js::gc::ArenaHeader *unmarkedArenaStackTop;
#ifdef DEBUG
size_t markLaterCount;
size_t markLaterArenas;
#endif
#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
@ -1129,8 +1087,7 @@ struct GCMarker : public JSTracer {
#endif
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
struct ConservativeRoot { void *thing; uint32 thingKind; };
Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
Vector<void *, 0, SystemAllocPolicy> conservativeRoots;
const char *conservativeDumpFileName;
void dumpConservativeRoots();

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
@ -114,7 +114,7 @@ GetGCThingTraceKind(const void *thing)
if (JSAtom::isStatic(thing))
return JSTRACE_STRING;
const Cell *cell = reinterpret_cast<const Cell *>(thing);
return GetFinalizableTraceKind(cell->arena()->header()->thingKind);
return GetFinalizableTraceKind(cell->arenaHeader()->getThingKind());
}
/* Capacity for slotsToThingKind */

View File

@ -77,14 +77,17 @@ Mark(JSTracer *trc, T *thing)
JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
/* Per-Compartment GC only with GCMarker and no custom JSTracer */
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
JS_ASSERT(!JSAtom::isStatic(thing));
JS_ASSERT(thing->asFreeCell()->isAligned());
JSRuntime *rt = trc->context->runtime;
JS_ASSERT(thing->arena()->header()->compartment);
JS_ASSERT(thing->arena()->header()->compartment->rt == rt);
JS_ASSERT(thing->arenaHeader()->compartment);
JS_ASSERT(thing->arenaHeader()->compartment->rt == rt);
/* Don't mark things outside a compartment if we are in a per-compartment GC */
/*
* Don't mark things outside a compartment if we are in a per-compartment
* GC.
*/
if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) {
if (IS_GC_MARKING_TRACER(trc))
PushMarkStack(static_cast<GCMarker *>(trc), thing);
@ -104,7 +107,6 @@ MarkString(JSTracer *trc, JSString *str)
JS_ASSERT(str);
if (str->isStaticAtom())
return;
JS_ASSERT(GetArena<JSString>((Cell *)str)->assureThingIsAligned((JSString *)str));
Mark(trc, str);
}
@ -122,13 +124,6 @@ MarkObject(JSTracer *trc, JSObject &obj, const char *name)
JS_ASSERT(trc);
JS_ASSERT(&obj);
JS_SET_TRACING_NAME(trc, name);
JS_ASSERT(GetArena<JSObject>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots2>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots4>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots8>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots12>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots16>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned(&obj));
Mark(trc, &obj);
}
@ -139,13 +134,6 @@ MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
JS_ASSERT(trc);
JS_ASSERT(&obj);
JS_SET_TRACING_DETAILS(trc, printer, arg, index);
JS_ASSERT(GetArena<JSObject>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots2>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots4>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots8>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots12>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots16>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned(&obj));
Mark(trc, &obj);
}
@ -155,19 +143,19 @@ MarkShape(JSTracer *trc, const Shape *shape, const char *name)
JS_ASSERT(trc);
JS_ASSERT(shape);
JS_SET_TRACING_NAME(trc, name);
JS_ASSERT(GetArena<Shape>((Cell *)shape)->assureThingIsAligned((void *)shape));
Mark(trc, shape);
}
#if JS_HAS_XML_SUPPORT
void
MarkXML(JSTracer *trc, JSXML *xml, const char *name)
{
JS_ASSERT(trc);
JS_ASSERT(xml);
JS_SET_TRACING_NAME(trc, name);
JS_ASSERT(GetArena<JSXML>(xml)->assureThingIsAligned(xml));
Mark(trc, xml);
}
#endif
void
PushMarkStack(GCMarker *gcmarker, JSXML *thing)

View File

@ -44,6 +44,8 @@
#include "jsbuiltins.h"
#include "jscompartment.h"
#include "jsgcinlines.h"
using namespace js;
using namespace js::gc;
@ -72,7 +74,7 @@ ConservativeGCStats::dump(FILE *fp)
fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(counter[CGCT_VALIDWITHOFFSET]));
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(unaligned));
#undef ULSTAT
}
#endif
@ -143,49 +145,6 @@ GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
thingsPerArena = Arena<T>::ThingsPerArena;
}
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
void *
GetAlignedThing(void *thing, int thingKind)
{
Cell *cell = (Cell *)thing;
switch (thingKind) {
case FINALIZE_OBJECT0:
case FINALIZE_OBJECT0_BACKGROUND:
return (void *)GetArena<JSObject>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT2:
case FINALIZE_OBJECT2_BACKGROUND:
return (void *)GetArena<JSObject_Slots2>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT4:
case FINALIZE_OBJECT4_BACKGROUND:
return (void *)GetArena<JSObject_Slots4>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT8:
case FINALIZE_OBJECT8_BACKGROUND:
return (void *)GetArena<JSObject_Slots8>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT12:
case FINALIZE_OBJECT12_BACKGROUND:
return (void *)GetArena<JSObject_Slots12>(cell)->getAlignedThing(thing);
case FINALIZE_OBJECT16:
case FINALIZE_OBJECT16_BACKGROUND:
return (void *)GetArena<JSObject_Slots16>(cell)->getAlignedThing(thing);
case FINALIZE_STRING:
return (void *)GetArena<JSString>(cell)->getAlignedThing(thing);
case FINALIZE_EXTERNAL_STRING:
return (void *)GetArena<JSExternalString>(cell)->getAlignedThing(thing);
case FINALIZE_SHORT_STRING:
return (void *)GetArena<JSShortString>(cell)->getAlignedThing(thing);
case FINALIZE_FUNCTION:
return (void *)GetArena<JSFunction>(cell)->getAlignedThing(thing);
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
return (void *)GetArena<JSXML>(cell)->getAlignedThing(thing);
#endif
default:
JS_NOT_REACHED("wrong kind");
return NULL;
}
}
#endif
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
{
switch (thingKind) {
@ -366,16 +325,16 @@ GCMarker::dumpConservativeRoots()
conservativeStats.dump(fp);
for (ConservativeRoot *i = conservativeRoots.begin();
i != conservativeRoots.end();
++i) {
fprintf(fp, " %p: ", i->thing);
switch (GetFinalizableTraceKind(i->thingKind)) {
for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) {
void *thing = thingp;
fprintf(fp, " %p: ", thing);
switch (GetGCThingTraceKind(thing)) {
default:
JS_NOT_REACHED("Unknown trace kind");
case JSTRACE_OBJECT: {
JSObject *obj = (JSObject *) i->thing;
JSObject *obj = (JSObject *) thing;
fprintf(fp, "object %s", obj->getClass()->name);
break;
}
@ -384,7 +343,7 @@ GCMarker::dumpConservativeRoots()
break;
}
case JSTRACE_STRING: {
JSString *str = (JSString *) i->thing;
JSString *str = (JSString *) thing;
if (str->isLinear()) {
char buf[50];
PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
@ -396,7 +355,7 @@ GCMarker::dumpConservativeRoots()
}
# if JS_HAS_XML_SUPPORT
case JSTRACE_XML: {
JSXML *xml = (JSXML *) i->thing;
JSXML *xml = (JSXML *) thing;
fprintf(fp, "xml %u", (unsigned)xml->xml_class);
break;
}

View File

@ -63,7 +63,6 @@ namespace gc {
*/
enum ConservativeGCTest {
CGCT_VALID,
CGCT_VALIDWITHOFFSET, /* points within an object */
CGCT_LOWBITSET, /* excluded because one of the low bits was set */
CGCT_NOTARENA, /* not within arena range in a chunk */
CGCT_NOTCHUNK, /* not within a valid chunk */
@ -75,7 +74,9 @@ enum ConservativeGCTest {
struct ConservativeGCStats {
uint32 counter[gc::CGCT_END]; /* ConservativeGCTest classification
counters */
counters */
uint32 unaligned; /* number of valid but not aligned on
thing start pointers */
void add(const ConservativeGCStats &another) {
for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i)
@ -129,10 +130,6 @@ UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearen
uint32 nkilledArenas, uint32 nthings);
#endif /* JS_GCMETER */
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
void *GetAlignedThing(void *thing, int thingKind);
#endif
} //gc
#ifdef MOZ_GCTIMER

View File

@ -327,7 +327,7 @@ JSObject::setPrimitiveThis(const js::Value &pthis)
inline /* gc::FinalizeKind */ unsigned
JSObject::finalizeKind() const
{
return js::gc::FinalizeKind(arena()->header()->thingKind);
return js::gc::FinalizeKind(arenaHeader()->getThingKind());
}
inline size_t

View File

@ -1406,7 +1406,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
* Make a blank object from the recipe fix provided to us. This must have
* number of fixed slots as the proxy so that we can swap their contents.
*/
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arena()->header()->thingKind);
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arenaHeader()->getThingKind());
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
if (!newborn)
return false;

View File

@ -73,7 +73,7 @@ JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
if (!emptyShapes) {
emptyShapes = (js::EmptyShape**)
cx->calloc_(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
cx->calloc_(sizeof(js::EmptyShape*) * js::gc::FINALIZE_FUNCTION_AND_OBJECT_LAST);
if (!emptyShapes)
return NULL;

View File

@ -91,7 +91,7 @@ using namespace js::gc;
bool
JSString::isShort() const
{
bool is_short = arena()->header()->thingKind == FINALIZE_SHORT_STRING;
bool is_short = arenaHeader()->getThingKind() == FINALIZE_SHORT_STRING;
JS_ASSERT_IF(is_short, isFlat());
return is_short;
}
@ -106,7 +106,7 @@ JSString::isFixed() const
bool
JSString::isExternal() const
{
bool is_external = arena()->header()->thingKind == FINALIZE_EXTERNAL_STRING;
bool is_external = arenaHeader()->getThingKind() == FINALIZE_EXTERNAL_STRING;
JS_ASSERT_IF(is_external, isFixed());
return is_external;
}

View File

@ -551,10 +551,10 @@ inline void
JSAtom::finalize(JSRuntime *rt)
{
JS_ASSERT(isAtom());
if (arena()->header()->thingKind == js::gc::FINALIZE_STRING)
if (arenaHeader()->getThingKind() == js::gc::FINALIZE_STRING)
asFlat().finalize(rt);
else
JS_ASSERT(arena()->header()->thingKind == js::gc::FINALIZE_SHORT_STRING);
JS_ASSERT(arenaHeader()->getThingKind() == js::gc::FINALIZE_SHORT_STRING);
}
inline void