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->shapes.clear();
this->unstableExits = NULL; this->unstableExits = NULL;
this->sideExits.clear(); this->sideExits.clear();
this->picTables.clear();
/* Determine the native frame layout at the entry point. */ /* Determine the native frame layout at the entry point. */
this->nativeStackBase = (nStackTypes - (cx->regs().sp - cx->fp()->base())) * this->nativeStackBase = (nStackTypes - (cx->regs().sp - cx->fp()->base())) *
@ -2890,23 +2891,61 @@ HasUnreachableGCThings(JSContext *cx, TreeFragment *f)
*/ */
if (IsAboutToBeFinalized(cx, f->globalObj)) if (IsAboutToBeFinalized(cx, f->globalObj))
return true; return true;
Value* vp = f->gcthings.data(); Value* vs = f->gcthings.data();
for (unsigned len = f->gcthings.length(); len; --len) { for (unsigned i = 0; i < f->gcthings.length(); ++i) {
Value &v = *vp++; Value &v = vs[i];
JS_ASSERT(v.isMarkable()); JS_ASSERT(v.isMarkable());
if (IsAboutToBeFinalized(cx, v.toGCThing())) if (IsAboutToBeFinalized(cx, v.toGCThing()))
return true; return true;
} }
const Shape** shapep = f->shapes.data(); const Shape** shapes = f->shapes.data();
for (unsigned len = f->shapes.length(); len; --len) { for (unsigned i = 0; i < f->shapes.length(); ++i) {
const Shape* shape = *shapep++; if (IsAboutToBeFinalized(cx, shapes[i]))
if (IsAboutToBeFinalized(cx, shape))
return true; return true;
} }
return false; 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 static bool
ContainsUnrechableGCThingImpl(JSContext *cx, TreeFragment *f) ContainsUnrechableGCThingImpl(JSContext *cx, TreeFragment *f)
{ {
@ -2975,7 +3014,7 @@ void
TraceMonitor::sweep(JSContext *cx) TraceMonitor::sweep(JSContext *cx)
{ {
JS_ASSERT(!ontrace()); 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; bool shouldAbortRecording = false;
TreeFragment *recorderTree = NULL; TreeFragment *recorderTree = NULL;
@ -2999,7 +3038,7 @@ TraceMonitor::sweep(JSContext *cx)
} }
debug_only_printf(LC_TMTracer, 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", "Disconnecting tree %p with ip %p\n",
(void *) peer, (void *) frag, frag->ip); (void *) peer, (void *) frag, frag->ip);
JS_ASSERT(frag->root == frag); 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 (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
for (TreeFragment* frag = vmfragments[i]; frag; frag = frag->next) { for (TreeFragment* frag = vmfragments[i]; frag; frag = frag->next) {
TreeFragment* peer = frag; TreeFragment* peer = frag;
do { do {
JS_ASSERT(!peer->visiting); JS_ASSERT(!peer->visiting);
PICTable** tables = peer->picTables.data();
for (unsigned j = 0; j < peer->picTables.length(); ++j)
tables[j]->clear();
peer = peer->peer; peer = peer->peer;
} while (peer); } while (peer);
} }
} }
#endif
if (shouldAbortRecording) if (shouldAbortRecording)
recorder->finishAbort("dead GC things"); recorder->finishAbort("dead GC things");
@ -12562,43 +12605,6 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp)
return true; 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 static JSBool FASTCALL
GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, PICTable *picTable) 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* vp_ins = w.name(w.allocp(sizeof(Value)), "vp");
LIns* idvalp_ins = w.name(addr(idvalp), "idvalp"); LIns* idvalp_ins = w.name(addr(idvalp), "idvalp");
PICTable *picTable = new (traceAlloc()) PICTable(); PICTable *picTable = new (traceAlloc()) PICTable();
tree->picTables.add(picTable);
LIns* pic_ins = w.nameImmpNonGC(picTable); LIns* pic_ins = w.nameImmpNonGC(picTable);
LIns* args[] = {pic_ins, vp_ins, idvalp_ins, obj_ins, cx_ins}; LIns* args[] = {pic_ins, vp_ins, idvalp_ins, obj_ins, cx_ins};
LIns* ok_ins = w.call(&GetPropertyByName_ci, args); LIns* ok_ins = w.call(&GetPropertyByName_ci, args);

View File

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