mirror of
https://github.com/classilla/tenfourfox.git
synced 2025-01-01 06:33:22 +00:00
#529: jsop_in folding M1244098 M1041586 (partial)
This commit is contained in:
parent
c9ed275af7
commit
a8fa640688
@ -16,6 +16,7 @@ namespace JS {
|
||||
_(GetProp_ArgumentsCallee) \
|
||||
_(GetProp_InferredConstant) \
|
||||
_(GetProp_Constant) \
|
||||
_(GetProp_NotDefined) \
|
||||
_(GetProp_StaticName) \
|
||||
_(GetProp_SimdGetter) \
|
||||
_(GetProp_TypedObject) \
|
||||
@ -74,6 +75,7 @@ namespace JS {
|
||||
_(NotObject) \
|
||||
_(NotStruct) \
|
||||
_(NotUnboxed) \
|
||||
_(NotUndefined) \
|
||||
_(UnboxedConvertedToNative) \
|
||||
_(StructNoField) \
|
||||
_(InconsistentFieldType) \
|
||||
|
32
js/src/jit-test/tests/ion/fold-in.js
Normal file
32
js/src/jit-test/tests/ion/fold-in.js
Normal 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);
|
@ -135,9 +135,9 @@ function withinIf(i) {
|
||||
// Check case where one successor can have multiple times the same predecessor.
|
||||
function unknownLoad(i) {
|
||||
var obj = { foo: i };
|
||||
// Unknown properties are inlined as undefined.
|
||||
assertEq(obj.bar, undefined);
|
||||
// Unknown properties are using GetPropertyCache.
|
||||
assertRecoveredOnBailout(obj, false);
|
||||
assertRecoveredOnBailout(obj, true);
|
||||
}
|
||||
|
||||
// Check with dynamic slots.
|
||||
|
@ -7928,6 +7928,51 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::testNotDefinedProperty(MDefinition* obj, jsid id)
|
||||
{
|
||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType_Object)
|
||||
return false;
|
||||
|
||||
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 false;
|
||||
|
||||
const Class* clasp = key->clasp();
|
||||
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key,
|
||||
id))
|
||||
return false;
|
||||
|
||||
// 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(id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HeapTypeSetKey property = key->property(id);
|
||||
if (property.isOwnProperty(constraints()))
|
||||
return false;
|
||||
|
||||
JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
|
||||
if (!proto)
|
||||
break;
|
||||
key = TypeSet::ObjectKey::get(proto);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind)
|
||||
{
|
||||
@ -8931,6 +8976,13 @@ IonBuilder::getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* inde
|
||||
return *emitted;
|
||||
}
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_NotDefined);
|
||||
if (!getPropTryNotDefined(emitted, obj, id, types) || *emitted) {
|
||||
if (*emitted)
|
||||
index->setImplicitlyUsedUnchecked();
|
||||
return *emitted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -10966,6 +11018,11 @@ IonBuilder::jsop_getprop(PropertyName* name)
|
||||
if (!getPropTryConstant(&emitted, obj, NameToId(name), types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to hardcode known not-defined
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_NotDefined);
|
||||
if (!getPropTryNotDefined(&emitted, obj, NameToId(name), types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit SIMD getter loads
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_SimdGetter);
|
||||
if (!getPropTrySimdGetter(&emitted, obj, name) || emitted)
|
||||
@ -11212,6 +11269,30 @@ IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, Tempora
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
if (!types->mightBeMIRType(MIRType_Undefined)) {
|
||||
// Only optimize if we expect this property access to return undefined.
|
||||
trackOptimizationOutcome(TrackedOutcome::NotUndefined);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!testNotDefinedProperty(obj, id)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::GenericFailure);
|
||||
return true;
|
||||
}
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
pushConstant(UndefinedValue());
|
||||
|
||||
trackOptimizationSuccess();
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MIRType
|
||||
IonBuilder::SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
|
||||
{
|
||||
@ -13289,21 +13370,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);
|
||||
|
||||
@ -13314,8 +13387,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.
|
||||
@ -13345,6 +13434,32 @@ 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;
|
||||
|
||||
if (!testNotDefinedProperty(obj, propId))
|
||||
return true;
|
||||
|
||||
*emitted = true;
|
||||
|
||||
pushConstant(BooleanValue(false));
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
id->setImplicitlyUsedUnchecked();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto)
|
||||
{
|
||||
|
@ -431,6 +431,7 @@ class IonBuilder
|
||||
bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
|
||||
bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyName* name);
|
||||
bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
|
||||
bool getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
|
||||
bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
BarrierKind barrier, TemporaryTypeSet* types);
|
||||
bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
@ -503,13 +504,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 +737,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);
|
||||
@ -980,6 +984,8 @@ class IonBuilder
|
||||
JSObject* testSingletonProperty(JSObject* obj, jsid id);
|
||||
JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
|
||||
|
||||
bool testNotDefinedProperty(MDefinition* obj, jsid id);
|
||||
|
||||
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
|
||||
MDefinition* convertUnboxedObjects(MDefinition* obj);
|
||||
MDefinition* convertUnboxedObjects(MDefinition* obj,
|
||||
|
Loading…
Reference in New Issue
Block a user