Bug 1225821 - Add type write barrier to SetPropertyIC dense element stub. r=bhackett

This commit is contained in:
Jan de Mooij 2015-11-19 10:13:28 +01:00
parent ba8444d785
commit 2c74f213c1
3 changed files with 65 additions and 29 deletions

View File

@ -0,0 +1,22 @@
var arr = [];
for (var i=0; i<20; i++) {
arr.push(new Int32Array(2000));
}
arr.push([null, null]);
function test(o, x) {
assertEq(o[0], x);
}
function f() {
for (var i=0; i<3100; i++) {
var o = arr[i % arr.length];
if (o.length > 10 || i > 2000) {
var val = (i > 3000 ? 1 : null);
o[0] = val;
if (o.length < 5)
test(o, val);
}
}
}
f();

View File

@ -9863,17 +9863,11 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
bool barrier = true;
if (index->mightBeType(MIRType_Int32)) {
// Bail if we might have a barriered write to a dense element, as the
// dense element stub doesn't support this yet.
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&object, nullptr, &value, /* canModify = */ true))
{
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
return true;
}
if (index->type() == MIRType_Int32)
barrier = false;
if (index->type() == MIRType_Int32 &&
!PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&object, nullptr, &value, /* canModify = */ true))
{
barrier = false;
}
// We can avoid worrying about holes in the IC if we know a priori we are safe
@ -9890,7 +9884,7 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), object, value));
// Emit SetElementCache.
// Emit SetPropertyCache.
bool strict = JSOp(*pc) == JSOP_STRICTSETELEM;
MSetPropertyCache* ins =
MSetPropertyCache::New(alloc(), object, index, value, strict, barrier, guardHoles);

View File

@ -2251,8 +2251,8 @@ CheckTypeSetForWrite(MacroAssembler& masm, JSObject* obj, jsid id,
{
TypedOrValueRegister valReg = value.reg();
ObjectGroup* group = obj->group();
if (group->unknownProperties())
return;
MOZ_ASSERT(!group->unknownProperties());
HeapTypeSet* propTypes = group->maybeGetProperty(id);
MOZ_ASSERT(propTypes);
@ -2272,11 +2272,9 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
// Guard that the incoming value is in the type set for the property
// if a type barrier is required.
if (needsTypeBarrier) {
// We can't do anything that would change the HeapTypeSet, so
// just guard that it's already there.
if (checkTypeset)
CheckTypeSetForWrite(masm, obj, shape->propid(), tempReg, value, failures);
if (checkTypeset) {
MOZ_ASSERT(needsTypeBarrier);
CheckTypeSetForWrite(masm, obj, shape->propid(), tempReg, value, failures);
}
NativeObject::slotsSizeMustNotOverflow();
@ -3131,8 +3129,9 @@ IsPropertySetInlineable(NativeObject* obj, HandleId id, MutableHandleShape pshap
if (!pshape->writable())
return false;
if (needsTypeBarrier)
return CanInlineSetPropTypeCheck(obj, id, val, checkTypeset);
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
return true;
}
@ -3199,10 +3198,10 @@ IsPropertyAddInlineable(JSContext* cx, NativeObject* obj, HandleId id, ConstantO
if (obj->group()->newScript() && !obj->group()->newScript()->analyzed())
return false;
if (needsTypeBarrier)
return CanInlineSetPropTypeCheck(obj, id, val, checkTypeset);
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
return true;
}
@ -3289,6 +3288,7 @@ CanAttachSetUnboxed(JSContext* cx, HandleObject obj, HandleId id, ConstantOrRegi
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (property) {
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
*unboxedOffset = property->offset;
@ -3314,6 +3314,7 @@ CanAttachSetUnboxedExpando(JSContext* cx, HandleObject obj, HandleId id, Constan
if (!shape || !shape->hasDefaultSetter() || !shape->hasSlot() || !shape->writable())
return false;
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
@ -3342,6 +3343,7 @@ CanAttachAddUnboxedExpando(JSContext* cx, HandleObject obj, HandleShape oldShape
if (PrototypeChainShadowsPropertyAdd(cx, obj, id))
return false;
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
@ -3426,7 +3428,7 @@ SetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
RootedShape shape(cx);
RootedObject holder(cx);
bool checkTypeset;
bool checkTypeset = false;
NativeSetPropCacheability canCache = CanAttachNativeSetProp(cx, obj, id, value(), needsTypeBarrier(),
&holder, &shape, &checkTypeset);
switch (canCache) {
@ -4180,7 +4182,8 @@ GetPropertyIC::tryAttachArgumentsElement(JSContext* cx, HandleScript outerScript
}
static bool
IsDenseElementSetInlineable(JSObject* obj, const Value& idval)
IsDenseElementSetInlineable(JSObject* obj, const Value& idval, ConstantOrRegister val,
bool needsTypeBarrier, bool* checkTypeset)
{
if (!obj->is<ArrayObject>())
return false;
@ -4208,6 +4211,10 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval)
curObj = curObj->getProto();
}
*checkTypeset = false;
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, JSID_VOID, val, checkTypeset))
return false;
return true;
}
@ -4277,7 +4284,7 @@ static bool
GenerateSetDenseElement(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
JSObject* obj, const Value& idval, bool guardHoles, Register object,
TypedOrValueRegister index, ConstantOrRegister value, Register tempToUnboxIndex,
Register temp)
Register temp, bool needsTypeBarrier, bool checkTypeset)
{
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(idval.isInt32());
@ -4290,6 +4297,14 @@ GenerateSetDenseElement(JSContext* cx, MacroAssembler& masm, IonCache::StubAttac
return false;
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
// Guard that the incoming value is in the type set for the property
// if a type barrier is required.
if (needsTypeBarrier) {
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), &failures);
if (checkTypeset)
CheckTypeSetForWrite(masm, obj, JSID_VOID, temp, value, &failures);
}
// Ensure the index is an int32 value.
Register indexReg;
if (index.hasValue()) {
@ -4377,7 +4392,11 @@ SetPropertyIC::tryAttachDenseElement(JSContext* cx, HandleScript outerScript, Io
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(canAttachStub());
if (hasDenseStub() || !IsDenseElementSetInlineable(obj, idval))
if (hasDenseStub())
return true;
bool checkTypeset = false;
if (!IsDenseElementSetInlineable(obj, idval, value(), needsTypeBarrier(), &checkTypeset))
return true;
*emitted = true;
@ -4386,7 +4405,8 @@ SetPropertyIC::tryAttachDenseElement(JSContext* cx, HandleScript outerScript, Io
StubAttacher attacher(*this);
if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
guardHoles(), object(), id().reg(),
value(), tempToUnboxIndex(), temp()))
value(), tempToUnboxIndex(), temp(),
needsTypeBarrier(), checkTypeset))
{
return false;
}