Bug 1204073 - Optimize GETELEM with constant string-or-symbol index better in Ion. r=bhackett

This commit is contained in:
Jan de Mooij 2015-09-19 21:00:03 +02:00
Родитель 1e0c0f6319
Коммит 54366d34b4
3 изменённых файлов: 64 добавлений и 30 удалений

Просмотреть файл

@ -7587,21 +7587,21 @@ ClassHasEffectlessLookup(const Class* clasp)
// Return whether an object might have a property for name which is not
// accounted for by type information.
static bool
ObjectHasExtraOwnProperty(CompileCompartment* comp, TypeSet::ObjectKey* object, PropertyName* name)
ObjectHasExtraOwnProperty(CompileCompartment* comp, TypeSet::ObjectKey* object, jsid id)
{
// Some typed object properties are not reflected in type information.
if (object->isGroup() && object->group()->maybeTypeDescr())
return object->group()->typeDescr().hasProperty(comp->runtime()->names(), NameToId(name));
return object->group()->typeDescr().hasProperty(comp->runtime()->names(), id);
const Class* clasp = object->clasp();
// Array |length| properties are not reflected in type information.
if (clasp == &ArrayObject::class_)
return name == comp->runtime()->names().length;
return JSID_IS_ATOM(id, comp->runtime()->names().length);
// Resolve hooks can install new properties on objects on demand.
JSObject* singleton = object->isSingleton() ? object->singleton() : nullptr;
return ClassMayResolveId(comp->runtime()->names(), clasp, NameToId(name), singleton);
return ClassMayResolveId(comp->runtime()->names(), clasp, id, singleton);
}
void
@ -7629,7 +7629,7 @@ IonBuilder::insertRecompileCheck()
}
JSObject*
IonBuilder::testSingletonProperty(JSObject* obj, PropertyName* name)
IonBuilder::testSingletonProperty(JSObject* obj, jsid id)
{
// We would like to completely no-op property/global accesses which can
// produce only a particular JSObject. When indicating the access result is
@ -7651,19 +7651,19 @@ IonBuilder::testSingletonProperty(JSObject* obj, PropertyName* name)
TypeSet::ObjectKey* objKey = TypeSet::ObjectKey::get(obj);
if (analysisContext)
objKey->ensureTrackedProperty(analysisContext, NameToId(name));
objKey->ensureTrackedProperty(analysisContext, id);
if (objKey->unknownProperties())
return nullptr;
HeapTypeSetKey property = objKey->property(NameToId(name));
HeapTypeSetKey property = objKey->property(id);
if (property.isOwnProperty(constraints())) {
if (obj->isSingleton())
return property.singleton(constraints());
return nullptr;
}
if (ObjectHasExtraOwnProperty(compartment, objKey, name))
if (ObjectHasExtraOwnProperty(compartment, objKey, id))
return nullptr;
obj = checkNurseryObject(obj->getProto());
@ -7673,7 +7673,7 @@ IonBuilder::testSingletonProperty(JSObject* obj, PropertyName* name)
}
JSObject*
IonBuilder::testSingletonPropertyTypes(MDefinition* obj, PropertyName* name)
IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id)
{
// As for TestSingletonProperty, but the input is any value in a type set
// rather than a specific object.
@ -7684,7 +7684,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, PropertyName* name)
JSObject* objectSingleton = types ? types->maybeSingleton() : nullptr;
if (objectSingleton)
return testSingletonProperty(objectSingleton, name);
return testSingletonProperty(objectSingleton, id);
MIRType objType = obj->type();
if (objType == MIRType_Value && types)
@ -7722,20 +7722,20 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, PropertyName* name)
if (!key)
continue;
if (analysisContext)
key->ensureTrackedProperty(analysisContext, NameToId(name));
key->ensureTrackedProperty(analysisContext, id);
const Class* clasp = key->clasp();
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, name))
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, id))
return nullptr;
if (key->unknownProperties())
return nullptr;
HeapTypeSetKey property = key->property(NameToId(name));
HeapTypeSetKey property = key->property(id);
if (property.isOwnProperty(constraints()))
return nullptr;
if (JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull())) {
// Test this type.
JSObject* thisSingleton = testSingletonProperty(proto, name);
JSObject* thisSingleton = testSingletonProperty(proto, id);
if (!thisSingleton)
return nullptr;
if (singleton) {
@ -7757,7 +7757,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, PropertyName* name)
JSObject* proto = GetBuiltinPrototypePure(&script()->global(), key);
if (proto)
return testSingletonProperty(proto, name);
return testSingletonProperty(proto, id);
return nullptr;
}
@ -7986,7 +7986,7 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc
if (barrier == BarrierKind::NoBarrier) {
// Try to inline properties holding a known constant object.
if (singleton) {
if (testSingletonProperty(staticObject, name) == singleton)
if (testSingletonProperty(staticObject, id) == singleton)
return pushConstant(ObjectValue(*singleton));
}
@ -8221,6 +8221,11 @@ IonBuilder::jsop_getelem()
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
return emitted;
// Note: no trackOptimizationAttempt call is needed, getElemTryGetProp
// will call it.
if (!getElemTryGetProp(&emitted, obj, index) || emitted)
return emitted;
trackOptimizationAttempt(TrackedStrategy::GetElem_Dense);
if (!getElemTryDense(&emitted, obj, index) || emitted)
return emitted;
@ -8621,6 +8626,36 @@ IonBuilder::pushDerivedTypedObject(bool* emitted,
return true;
}
bool
IonBuilder::getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index)
{
// If index is a constant string or symbol, try to optimize this GETELEM
// as a GETPROP.
MOZ_ASSERT(*emitted == false);
if (!index->isConstantValue())
return true;
jsid id;
if (!ValueToIdPure(index->constantValue(), &id))
return true;
if (id != IdToTypeId(id))
return true;
TemporaryTypeSet* types = bytecodeTypes(pc);
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(emitted, obj, id, types) || *emitted) {
if (*emitted)
index->setImplicitlyUsedUnchecked();
return *emitted;
}
return true;
}
bool
IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
{
@ -10195,7 +10230,7 @@ IonBuilder::objectsHaveCommonPrototype(TemporaryTypeSet* types, PropertyName* na
if (!ClassHasEffectlessLookup(clasp))
return false;
JSObject* singleton = key->isSingleton() ? key->singleton() : nullptr;
if (ObjectHasExtraOwnProperty(compartment, key, name)) {
if (ObjectHasExtraOwnProperty(compartment, key, NameToId(name))) {
if (!singleton || !singleton->is<GlobalObject>())
return false;
*guardGlobal = true;
@ -10372,14 +10407,14 @@ IonBuilder::annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPro
JSObject* proto = checkNurseryObject(key->proto().toObject());
const Class* clasp = key->clasp();
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, name))
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, NameToId(name)))
continue;
HeapTypeSetKey ownTypes = key->property(NameToId(name));
if (ownTypes.isOwnProperty(constraints()))
continue;
JSObject* singleton = testSingletonProperty(proto, name);
JSObject* singleton = testSingletonProperty(proto, NameToId(name));
if (!singleton || !singleton->is<JSFunction>())
continue;
@ -10630,7 +10665,7 @@ IonBuilder::jsop_getprop(PropertyName* name)
// In this case we still need the getprop call so that the later
// analysis knows when the |this| value has been read from.
if (info().isAnalysis()) {
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
if (!getPropTryConstant(&emitted, obj, NameToId(name), types) || emitted)
return emitted;
}
@ -10649,7 +10684,7 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!forceInlineCaches()) {
// Try to hardcode known constants.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
if (!getPropTryConstant(&emitted, obj, NameToId(name), types) || emitted)
return emitted;
// Try to emit SIMD getter loads
@ -10861,8 +10896,7 @@ IonBuilder::getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyN
}
bool
IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, PropertyName* name,
TemporaryTypeSet* types)
IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types)
{
MOZ_ASSERT(*emitted == false);
@ -10873,7 +10907,7 @@ IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, PropertyName* na
return true;
}
JSObject* singleton = testSingletonPropertyTypes(obj, name);
JSObject* singleton = testSingletonPropertyTypes(obj, id);
if (!singleton) {
trackOptimizationOutcome(TrackedOutcome::NotSingleton);
return true;
@ -11692,7 +11726,7 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
// we'd produce here.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(emitted, inner, name, types) || *emitted)
if (!getPropTryConstant(emitted, inner, NameToId(name), types) || *emitted)
return *emitted;
trackOptimizationAttempt(TrackedStrategy::GetProp_StaticName);

Просмотреть файл

@ -425,8 +425,7 @@ class IonBuilder
TemporaryTypeSet* types);
bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyName* name);
bool getPropTryConstant(bool* emitted, MDefinition* obj, PropertyName* name,
TemporaryTypeSet* types);
bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types);
bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
@ -585,6 +584,7 @@ class IonBuilder
// jsop_getelem() helpers.
bool getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
bool getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index);
bool getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index);
bool getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index);
bool getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
@ -960,8 +960,8 @@ class IonBuilder
MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);
JSObject* testSingletonProperty(JSObject* obj, PropertyName* name);
JSObject* testSingletonPropertyTypes(MDefinition* obj, PropertyName* name);
JSObject* testSingletonProperty(JSObject* obj, jsid id);
JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);

Просмотреть файл

@ -795,7 +795,7 @@ class MDefinition : public MNode
MIR_OPCODE_LIST(OPCODE_CASTS)
# undef OPCODE_CASTS
bool isConstantValue() {
bool isConstantValue() const {
return isConstant() || (isBox() && getOperand(0)->isConstant());
}
const Value& constantValue();