зеркало из https://github.com/mozilla/gecko-dev.git
Bug 761864 - add write barrier on generator close (r=terrence)
--HG-- extra : rebase_source : 08ebe7de84c89ccc2e737ddcf472f59c8cb42b74
This commit is contained in:
Родитель
bff22f37e2
Коммит
9acb961a0b
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче