Bug 781393 - JS VM stack values shouldn't always be clobbered during marking (r=bhackett)

This commit is contained in:
Bill McCloskey 2012-08-15 10:33:12 -07:00
parent 2e2b4aca5e
commit ba92c54858
4 changed files with 54 additions and 25 deletions

View File

@ -0,0 +1,14 @@
gczeal(4,1);
function check(o)
{
print(o);
assertEq(o.b, 3);
}
function f()
{
for (var i=0; i<3; i++) {
var o = {b: 3};
check(o);
}
}
f();

View File

@ -486,6 +486,15 @@ JSCompartment::discardJitCode(FreeOp *fop)
#endif /* JS_METHODJIT */ #endif /* JS_METHODJIT */
} }
bool
JSCompartment::isDiscardingJitCode(JSTracer *trc)
{
if (!IS_GC_MARKING_TRACER(trc))
return false;
return !gcPreserveCode;
}
void void
JSCompartment::sweep(FreeOp *fop, bool releaseTypes) JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
{ {

View File

@ -325,6 +325,7 @@ struct JSCompartment
void markTypes(JSTracer *trc); void markTypes(JSTracer *trc);
void discardJitCode(js::FreeOp *fop); void discardJitCode(js::FreeOp *fop);
bool isDiscardingJitCode(JSTracer *trc);
void sweep(js::FreeOp *fop, bool releaseTypes); void sweep(js::FreeOp *fop, bool releaseTypes);
void sweepCrossCompartmentWrappers(); void sweepCrossCompartmentWrappers();
void purge(); void purge();

View File

@ -648,35 +648,40 @@ StackSpace::markFrameValues(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsby
for (Value *vp = slotsBegin; vp < fixedEnd; vp++) { for (Value *vp = slotsBegin; vp < fixedEnd; vp++) {
uint32_t slot = analyze::LocalSlot(script, vp - slotsBegin); uint32_t slot = analyze::LocalSlot(script, vp - slotsBegin);
/* /* Will this slot be synced by the JIT? */
* Will this slot be synced by the JIT? If not, replace with a dummy
* value with the same type tag.
*/
if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset)) { if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset)) {
gc::MarkValueRoot(trc, vp, "vm_stack"); gc::MarkValueRoot(trc, vp, "vm_stack");
} else if (vp->isDouble()) { } else if (script->compartment()->isDiscardingJitCode(trc)) {
*vp = DoubleValue(0.0);
} else {
/* /*
* It's possible that *vp may not be a valid Value. For example, it * If we're throwing away analysis information, we need to replace
* may be tagged as a NullValue but the low bits may be nonzero so * non-live Values with ones that can safely be marked in later
* that isNull() returns false. This can cause problems later on * collections.
* when marking the value. Extracting the type in this way and then
* overwriting the value circumvents the problem.
*/ */
JSValueType type = vp->extractNonDoubleType(); if (vp->isDouble()) {
if (type == JSVAL_TYPE_INT32) *vp = DoubleValue(0.0);
*vp = Int32Value(0); } else {
else if (type == JSVAL_TYPE_UNDEFINED) /*
*vp = UndefinedValue(); * It's possible that *vp may not be a valid Value. For example,
else if (type == JSVAL_TYPE_BOOLEAN) * it may be tagged as a NullValue but the low bits may be
*vp = BooleanValue(false); * nonzero so that isNull() returns false. This can cause
else if (type == JSVAL_TYPE_STRING) * problems later on when marking the value. Extracting the type
*vp = StringValue(trc->runtime->atomState.nullAtom); * in this way and then overwriting the value circumvents the
else if (type == JSVAL_TYPE_NULL) * problem.
*vp = NullValue(); */
else if (type == JSVAL_TYPE_OBJECT) JSValueType type = vp->extractNonDoubleType();
*vp = ObjectValue(fp->scopeChain()->global()); if (type == JSVAL_TYPE_INT32)
*vp = Int32Value(0);
else if (type == JSVAL_TYPE_UNDEFINED)
*vp = UndefinedValue();
else if (type == JSVAL_TYPE_BOOLEAN)
*vp = BooleanValue(false);
else if (type == JSVAL_TYPE_STRING)
*vp = StringValue(trc->runtime->atomState.nullAtom);
else if (type == JSVAL_TYPE_NULL)
*vp = NullValue();
else if (type == JSVAL_TYPE_OBJECT)
*vp = ObjectValue(fp->scopeChain()->global());
}
} }
} }