Bug 761864 - add write barrier on generator close (r=terrence)

--HG--
extra : rebase_source : 08ebe7de84c89ccc2e737ddcf472f59c8cb42b74
This commit is contained in:
Luke Wagner 2012-06-08 21:14:20 -07:00
Родитель bff22f37e2
Коммит 9acb961a0b
4 изменённых файлов: 111 добавлений и 33 удалений

Просмотреть файл

@ -0,0 +1,55 @@
function printStatus (msg) {
var lines = msg.split ("");
}
function printBugNumber (num) {
var digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
}
var lfcode = new Array();
lfcode.push("gczeal(4);");
lfcode.push("jsTestDriverEnd();");
lfcode.push("");
lfcode.push("var BUGNUMBER = \"(none)\";\
var summary = \"gen.close(); gen.throw(ex) throws ex forever\";\
var actual, expect;\
printBugNumber(BUGNUMBER);\
printStatus(summary);\
function gen() {\
var x = 5, y = 7;\
yield z;\
}\
var failed = false;\
var it = gen();\
try {\
it.close();\
var doThrow = true;\
var thrown = \"foobar\";\
try { } catch (e) { }\
try { } catch (e) { }\
throw \"it.throw(\\\"\" + thrown + \"\\\") failed\";\
var stopPassed = false;\
try { } catch (e) {\
if (\"1234\")\
stopPassed = true;\
}\
} catch (e) {}\
");
var lfRunTypeId = -1;
while (true) {
var file = lfcode.shift(); if (file == undefined) { break; }
if (file == "evaluate") {
} else {
loadFile(file);
}
}
function loadFile(lfVarx) {
try {
if (lfVarx.substr(-3) == ".js") {
} else {
switch (lfRunTypeId) {
default: evaluate(lfVarx);
}
}
} catch (lfVare) {
print(lfVare);
}
}

Просмотреть файл

@ -1331,7 +1331,7 @@ generator_finalize(FreeOp *fop, JSObject *obj)
}
static void
MarkGenerator(JSTracer *trc, JSGenerator *gen)
MarkGeneratorFrame(JSTracer *trc, JSGenerator *gen)
{
MarkValueRange(trc,
HeapValueify(gen->fp->generatorArgsSnapshotBegin()),
@ -1349,7 +1349,31 @@ GeneratorWriteBarrierPre(JSContext *cx, JSGenerator *gen)
{
JSCompartment *comp = cx->compartment;
if (comp->needsBarrier())
MarkGenerator(comp->barrierTracer(), gen);
MarkGeneratorFrame(comp->barrierTracer(), gen);
}
/*
* Only mark generator frames/slots when the generator is not active on the
* stack or closed. Barriers when copying onto the stack or closing preserve
* gc invariants.
*/
static bool
GeneratorHasMarkableFrame(JSGenerator *gen)
{
return gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN;
}
/*
* When a generator is closed, the GC things reachable from the contained frame
* and slots become unreachable and thus require a write barrier.
*/
static void
SetGeneratorClosed(JSContext *cx, JSGenerator *gen)
{
JS_ASSERT(gen->state != JSGEN_CLOSED);
if (GeneratorHasMarkableFrame(gen))
GeneratorWriteBarrierPre(cx, gen);
gen->state = JSGEN_CLOSED;
}
static void
@ -1359,8 +1383,8 @@ generator_trace(JSTracer *trc, JSObject *obj)
if (!gen)
return;
if (gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN)
MarkGenerator(trc, gen);
if (GeneratorHasMarkableFrame(gen))
MarkGeneratorFrame(trc, gen);
}
Class js::GeneratorClass = {
@ -1444,12 +1468,15 @@ js_NewGenerator(JSContext *cx)
/* Copy from the stack to the generator's floating frame. */
gen->regs.rebaseFromTo(stackRegs, *genfp);
genfp->copyFrameAndValues<HeapValue, Value, StackFrame::DoPostBarrier>(
cx, genfp, genvp, stackfp, stackvp, stackRegs.sp);
cx, genvp, stackfp, stackvp, stackRegs.sp);
obj->setPrivate(gen);
return obj;
}
static void
SetGeneratorClosed(JSContext *cx, JSGenerator *gen);
typedef enum JSGeneratorOp {
JSGENOP_NEXT,
JSGENOP_SEND,
@ -1513,7 +1540,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
{
GeneratorFrameGuard gfg;
if (!cx->stack.pushGeneratorFrame(cx, gen, &gfg)) {
gen->state = JSGEN_CLOSED;
SetGeneratorClosed(cx, gen);
return JS_FALSE;
}
@ -1543,7 +1570,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
}
gen->fp->clearReturnValue();
gen->state = JSGEN_CLOSED;
SetGeneratorClosed(cx, gen);
if (ok) {
/* Returned, explicitly or by falling off the end. */
if (op == JSGENOP_CLOSE)
@ -1611,7 +1638,7 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned
default:
JS_ASSERT(op == JSGENOP_CLOSE);
gen->state = JSGEN_CLOSED;
SetGeneratorClosed(cx, gen);
args.rval().setUndefined();
return true;
}

Просмотреть файл

@ -95,14 +95,13 @@ StackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
template <class T, class U, StackFrame::TriggerPostBarriers doPostBarrier>
void
StackFrame::copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp,
StackFrame *otherfp, U *othervp, Value *othersp)
StackFrame::copyFrameAndValues(JSContext *cx, T *vp, StackFrame *otherfp, U *othervp, Value *othersp)
{
JS_ASSERT((U *)vp == (U *)this - ((U *)otherfp - othervp));
JS_ASSERT((Value *)othervp == otherfp->generatorArgsSnapshotBegin());
JS_ASSERT(othersp >= otherfp->slots());
JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots);
JS_ASSERT((T *)fp - vp == (U *)otherfp - othervp);
JS_ASSERT((T *)this - vp == (U *)otherfp - othervp);
/* Copy args, StackFrame, and slots. */
U *srcend = (U *)otherfp->generatorArgsSnapshotEnd();
@ -110,12 +109,12 @@ StackFrame::copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp,
for (U *src = othervp; src < srcend; src++, dst++)
*dst = *src;
*fp = *otherfp;
*this = *otherfp;
if (doPostBarrier)
fp->writeBarrierPost();
writeBarrierPost();
srcend = (U *)othersp;
dst = (T *)fp->slots();
dst = (T *)slots();
for (U *src = (U *)otherfp->slots(); src < srcend; src++, dst++)
*dst = *src;
@ -124,31 +123,29 @@ StackFrame::copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp,
}
/* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */
template void StackFrame::copyFrameAndValues<Value, HeapValue, StackFrame::NoPostBarrier>(
JSContext *, StackFrame *, Value *,
StackFrame *, HeapValue *, Value *);
template void StackFrame::copyFrameAndValues<HeapValue, Value, StackFrame::DoPostBarrier>(
JSContext *, StackFrame *, HeapValue *,
StackFrame *, Value *, Value *);
template
void StackFrame::copyFrameAndValues<Value, HeapValue, StackFrame::NoPostBarrier>(
JSContext *, Value *, StackFrame *, HeapValue *, Value *);
template
void StackFrame::copyFrameAndValues<HeapValue, Value, StackFrame::DoPostBarrier>(
JSContext *, HeapValue *, StackFrame *, Value *, Value *);
void
StackFrame::writeBarrierPost()
{
/* This needs to follow the same rules as in js_TraceStackFrame. */
/* This needs to follow the same rules as in StackFrame::mark. */
if (scopeChain_)
JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
if (isDummyFrame())
return;
if (flags_ & HAS_ARGS_OBJ)
JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
if (isScriptFrame()) {
if (isFunctionFrame()) {
JSFunction::writeBarrierPost((JSObject *)exec.fun, (void *)&exec.fun);
if (isEvalFrame())
JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
} else {
JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
}
if (isFunctionFrame()) {
JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
if (isEvalFrame())
JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
} else {
JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
}
if (hasReturnValue())
HeapValue::writeBarrierPost(rval_, &rval_);
@ -1043,7 +1040,7 @@ ContextStack::pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrame
/* Copy from the generator's floating frame to the stack. */
stackfp->copyFrameAndValues<Value, HeapValue, StackFrame::NoPostBarrier>(
cx, stackfp, stackvp, gen->fp, genvp, gen->regs.sp);
cx, stackvp, gen->fp, genvp, gen->regs.sp);
stackfp->resetGeneratorPrev(cx);
gfg->regs_.rebaseFromTo(gen->regs, *stackfp);
@ -1068,7 +1065,7 @@ ContextStack::popGeneratorFrame(const GeneratorFrameGuard &gfg)
if (stackfp->isYielding()) {
gen->regs.rebaseFromTo(stackRegs, *gen->fp);
gen->fp->copyFrameAndValues<HeapValue, Value, StackFrame::DoPostBarrier>(
cx_, gen->fp, genvp, stackfp, stackvp, stackRegs.sp);
cx_, genvp, stackfp, stackvp, stackRegs.sp);
}
/* ~FrameGuard/popFrame will finish the popping. */

Просмотреть файл

@ -979,8 +979,7 @@ class StackFrame
NoPostBarrier = false
};
template <class T, class U, TriggerPostBarriers doPostBarrier>
void copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp,
StackFrame *otherfp, U *othervp, Value *othersp);
void copyFrameAndValues(JSContext *cx, T *vp, StackFrame *otherfp, U *othervp, Value *othersp);
JSGenerator *maybeSuspendedGenerator(JSRuntime *rt);