Bug 1244098 - Attempt to fold JSOP_IN to false in IonBuilder based on TI. r=bhackett

This commit is contained in:
Jan de Mooij 2016-02-08 15:41:42 +01:00
parent e0dba90fc3
commit 7ec509c581
3 changed files with 120 additions and 16 deletions

View File

@ -0,0 +1,32 @@
// Singleton
function f() {
var res = 0;
for (var i=0; i<500; i++)
res += ("abcd" in Math);
return res;
}
assertEq(f(), 0);
Math.abcd = 3;
assertEq(f(), 500);
delete Math.abcd;
assertEq(f(), 0);
// Non-singleton
function O(x) { if (x) this.x = 1; }
var arr = [];
for (var i=0; i<4; i++)
arr.push(new O(i % 2));
function g(arr) {
var res = 0;
for (var i=0; i<500; i++) {
var o = arr[i % arr.length];
res += "x" in o;
res += "abcd" in o;
}
return res;
}
assertEq(g(arr), 250);
arr[0].abcd = 3;
assertEq(g(arr), 375);

View File

@ -13319,21 +13319,13 @@ IonBuilder::jsop_in()
MDefinition* obj = convertUnboxedObjects(current->pop());
MDefinition* id = current->pop();
do {
if (shouldAbortOnPreliminaryGroups(obj))
break;
bool emitted = false;
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), obj, id))
break;
}
if (!inTryDense(&emitted, obj, id) || emitted)
return emitted;
if (ElementAccessHasExtraIndexedProperty(this, obj))
break;
return jsop_in_dense(obj, id, unboxedType);
} while (false);
if (!inTryFold(&emitted, obj, id) || emitted)
return emitted;
MIn* ins = MIn::New(alloc(), id, obj);
@ -13344,8 +13336,24 @@ IonBuilder::jsop_in()
}
bool
IonBuilder::jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType)
IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id)
{
MOZ_ASSERT(!*emitted);
if (shouldAbortOnPreliminaryGroups(obj))
return true;
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), obj, id))
return true;
}
if (ElementAccessHasExtraIndexedProperty(this, obj))
return true;
*emitted = true;
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
// Ensure id is an integer.
@ -13375,6 +13383,67 @@ IonBuilder::jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxed
return true;
}
bool
IonBuilder::inTryFold(bool* emitted, MDefinition* obj, MDefinition* id)
{
// Fold |id in obj| to |false|, if we know the object (or an object on its
// prototype chain) does not have this property.
MOZ_ASSERT(!*emitted);
jsid propId;
if (!id->isConstantValue() || !ValueToIdPure(id->constantValue(), &propId))
return true;
if (propId != IdToTypeId(propId))
return true;
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject())
return true;
for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
while (true) {
if (!key->hasStableClassAndProto(constraints()) || key->unknownProperties())
return true;
const Class* clasp = key->clasp();
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, propId))
return true;
// If the object is a singleton, we can do a lookup now to avoid
// unnecessary invalidations later on, in case the property types
// have not yet been instantiated.
if (key->isSingleton() &&
key->singleton()->is<NativeObject>() &&
key->singleton()->as<NativeObject>().lookupPure(propId))
{
return true;
}
HeapTypeSetKey property = key->property(propId);
if (property.isOwnProperty(constraints()))
return true;
JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
if (!proto)
break;
key = TypeSet::ObjectKey::get(proto);
}
}
*emitted = true;
pushConstant(BooleanValue(false));
obj->setImplicitlyUsedUnchecked();
id->setImplicitlyUsedUnchecked();
return true;
}
bool
IonBuilder::hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto)
{

View File

@ -502,13 +502,17 @@ class IonBuilder
// jsop_bitnot helpers.
bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
// jsop_compare helpes.
// jsop_compare helpers.
bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
// jsop_in helpers.
bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id);
bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id);
// binary data lookup helpers.
TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
@ -732,7 +736,6 @@ class IonBuilder
bool jsop_isnoiter();
bool jsop_iterend();
bool jsop_in();
bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType);
bool jsop_instanceof();
bool jsop_getaliasedvar(ScopeCoordinate sc);
bool jsop_setaliasedvar(ScopeCoordinate sc);