Bug 672112 - Fix PICTable bug in tracer (r=dmandelin)

This commit is contained in:
Bill McCloskey 2011-07-20 17:31:51 -07:00
parent 692bbd7e4c
commit 3eec196c84
2 changed files with 61 additions and 50 deletions

View File

@ -1662,6 +1662,7 @@ TreeFragment::initialize(JSContext* cx, SlotList *globalSlots, bool speculate)
this->shapes.clear();
this->unstableExits = NULL;
this->sideExits.clear();
this->picTables.clear();
/* Determine the native frame layout at the entry point. */
this->nativeStackBase = (nStackTypes - (cx->regs().sp - cx->fp()->base())) *
@ -2890,23 +2891,61 @@ HasUnreachableGCThings(JSContext *cx, TreeFragment *f)
*/
if (IsAboutToBeFinalized(cx, f->globalObj))
return true;
Value* vp = f->gcthings.data();
for (unsigned len = f->gcthings.length(); len; --len) {
Value &v = *vp++;
Value* vs = f->gcthings.data();
for (unsigned i = 0; i < f->gcthings.length(); ++i) {
Value &v = vs[i];
JS_ASSERT(v.isMarkable());
if (IsAboutToBeFinalized(cx, v.toGCThing()))
return true;
}
const Shape** shapep = f->shapes.data();
for (unsigned len = f->shapes.length(); len; --len) {
const Shape* shape = *shapep++;
if (IsAboutToBeFinalized(cx, shape))
const Shape** shapes = f->shapes.data();
for (unsigned i = 0; i < f->shapes.length(); ++i) {
if (IsAboutToBeFinalized(cx, shapes[i]))
return true;
}
return false;
}
static const size_t PIC_TABLE_ENTRY_COUNT = 32;
struct PICTableEntry
{
jsid id;
uint32 shape;
uint32 slot;
};
struct PICTable
{
PICTable() : entryCount(0) {}
PICTableEntry entries[PIC_TABLE_ENTRY_COUNT];
uint32 entryCount;
bool scan(uint32 shape, jsid id, uint32 *slotOut) {
for (size_t i = 0; i < entryCount; ++i) {
PICTableEntry &entry = entries[i];
if (entry.shape == shape && entry.id == id) {
*slotOut = entry.slot;
return true;
}
}
return false;
}
void update(uint32 shape, jsid id, uint32 slot) {
if (entryCount >= PIC_TABLE_ENTRY_COUNT)
return;
PICTableEntry &newEntry = entries[entryCount++];
newEntry.shape = shape;
newEntry.id = id;
newEntry.slot = slot;
}
void clear() { entryCount = 0; }
};
static bool
ContainsUnrechableGCThingImpl(JSContext *cx, TreeFragment *f)
{
@ -2975,7 +3014,7 @@ void
TraceMonitor::sweep(JSContext *cx)
{
JS_ASSERT(!ontrace());
debug_only_print0(LC_TMTracer, "Purging fragments with dead things");
debug_only_print0(LC_TMTracer, "Purging fragments with dead things\n");
bool shouldAbortRecording = false;
TreeFragment *recorderTree = NULL;
@ -2983,7 +3022,7 @@ TraceMonitor::sweep(JSContext *cx)
recorderTree = recorder->getTree();
shouldAbortRecording = HasUnreachableGCThings(cx, recorderTree);
}
for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
TreeFragment** fragp = &vmfragments[i];
while (TreeFragment* frag = *fragp) {
@ -2997,9 +3036,9 @@ TraceMonitor::sweep(JSContext *cx)
fragp = &frag->next;
continue;
}
debug_only_printf(LC_TMTracer,
"TreeFragment peer %p has dead gc thing."
"TreeFragment peer %p has dead gc thing. "
"Disconnecting tree %p with ip %p\n",
(void *) peer, (void *) frag, frag->ip);
JS_ASSERT(frag->root == frag);
@ -3014,17 +3053,21 @@ TraceMonitor::sweep(JSContext *cx)
}
}
#ifdef DEBUG
/* These tables contain GC things, so they must be cleared on GC. */
for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
for (TreeFragment* frag = vmfragments[i]; frag; frag = frag->next) {
TreeFragment* peer = frag;
do {
JS_ASSERT(!peer->visiting);
PICTable** tables = peer->picTables.data();
for (unsigned j = 0; j < peer->picTables.length(); ++j)
tables[j]->clear();
peer = peer->peer;
} while (peer);
}
}
#endif
if (shouldAbortRecording)
recorder->finishAbort("dead GC things");
@ -12562,43 +12605,6 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp)
return true;
}
static const size_t PIC_TABLE_ENTRY_COUNT = 32;
struct PICTableEntry
{
jsid id;
uint32 shape;
uint32 slot;
};
struct PICTable
{
PICTable() : entryCount(0) {}
PICTableEntry entries[PIC_TABLE_ENTRY_COUNT];
uint32 entryCount;
bool scan(uint32 shape, jsid id, uint32 *slotOut) {
for (size_t i = 0; i < entryCount; ++i) {
PICTableEntry &entry = entries[i];
if (entry.shape == shape && entry.id == id) {
*slotOut = entry.slot;
return true;
}
}
return false;
}
void update(uint32 shape, jsid id, uint32 slot) {
if (entryCount >= PIC_TABLE_ENTRY_COUNT)
return;
PICTableEntry &newEntry = entries[entryCount++];
newEntry.shape = shape;
newEntry.id = id;
newEntry.slot = slot;
}
};
static JSBool FASTCALL
GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, PICTable *picTable)
{
@ -12691,6 +12697,7 @@ TraceRecorder::getPropertyByName(LIns* obj_ins, Value* idvalp, Value* outp)
LIns* vp_ins = w.name(w.allocp(sizeof(Value)), "vp");
LIns* idvalp_ins = w.name(addr(idvalp), "idvalp");
PICTable *picTable = new (traceAlloc()) PICTable();
tree->picTables.add(picTable);
LIns* pic_ins = w.nameImmpNonGC(picTable);
LIns* args[] = {pic_ins, vp_ins, idvalp_ins, obj_ins, cx_ins};
LIns* ok_ins = w.call(&GetPropertyByName_ci, args);

View File

@ -539,6 +539,8 @@ struct LinkableFragment : public VMFragment
SlotList* globalSlots;
};
struct PICTable;
/*
* argc is cx->fp->argc at the trace loop header, i.e., the number of arguments
* pushed for the innermost JS frame. This is required as part of the fragment
@ -564,6 +566,7 @@ struct TreeFragment : public LinkableFragment
sideExits(alloc),
gcthings(alloc),
shapes(alloc),
picTables(alloc),
visiting(false)
{ }
@ -590,6 +593,7 @@ struct TreeFragment : public LinkableFragment
/* All embedded GC things are registered here so the GC can scan them. */
Queue<Value> gcthings;
Queue<const js::Shape*> shapes;
Queue<PICTable*> picTables;
unsigned maxNativeStackSlots;
/* Gives the number of times we have entered this trace. */
uintN execs;