diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index f7f140f1828..76253e47610 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -6274,6 +6274,14 @@ IonBuilder::jsop_getelem_dense() MDefinition *obj = current->pop(); types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + + if (JSOp(*pc) == JSOP_CALLELEM && !id->mightBeType(MIRType_String) && types->noConstraints()) { + // Indexed call on an element of an array. Populate the observed types + // with any objects that could be in the array, to avoid extraneous + // type barriers. + AddObjectsForPropertyRead(cx, obj, NULL, types); + } + bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types); bool needsHoleCheck = !ElementAccessIsPacked(cx, obj); diff --git a/js/src/ion/MIR.cpp b/js/src/ion/MIR.cpp index a4f6587659c..7e48f08fce1 100644 --- a/js/src/ion/MIR.cpp +++ b/js/src/ion/MIR.cpp @@ -2413,10 +2413,7 @@ ion::DenseNativeElementType(JSContext *cx, MDefinition *obj) unsigned count = types->getObjectCount(); for (unsigned i = 0; i < count; i++) { - if (types->getSingleObject(i)) - return MIRType_None; - - if (types::TypeObject *object = types->getTypeObject(i)) { + if (types::TypeObject *object = types->getTypeOrSingleObject(cx, i)) { if (object->unknownProperties()) return MIRType_None; @@ -2518,17 +2515,8 @@ ion::PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName bool updateObserved = types->getObjectCount() == 1; for (size_t i = 0; i < types->getObjectCount(); i++) { - types::TypeObject *object = types->getTypeObject(i); - if (!object) { - JSObject *singleton = types->getSingleObject(i); - if (!singleton) - continue; - object = singleton->getType(cx); - if (!object) - return true; - } - - if (PropertyReadNeedsTypeBarrier(cx, object, name, observed, updateObserved)) + types::TypeObject *object = types->getTypeOrSingleObject(cx, i); + if (object && PropertyReadNeedsTypeBarrier(cx, object, name, observed, updateObserved)) return true; } @@ -2547,10 +2535,7 @@ ion::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *nam return false; for (size_t i = 0; i < types->getObjectCount(); i++) { - if (types->getSingleObject(i)) - return false; - - if (types::TypeObject *object = types->getTypeObject(i)) { + if (types::TypeObject *object = types->getTypeOrSingleObject(cx, i)) { if (object->unknownProperties()) return false; @@ -2564,6 +2549,48 @@ ion::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *nam return true; } +void +ion::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name, + types::StackTypeSet *observed) +{ + // Add objects to observed which *could* be observed by reading name from obj, + // to hopefully avoid unnecessary type barriers and code invalidations. + + JS_ASSERT(observed->noConstraints()); + + types::StackTypeSet *types = obj->resultTypeSet(); + if (!types || types->unknownObject()) { + observed->addType(cx, types::Type::AnyObjectType()); + return; + } + + jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID; + + for (size_t i = 0; i < types->getObjectCount(); i++) { + types::TypeObject *object = types->getTypeOrSingleObject(cx, i); + if (!object) + continue; + + if (object->unknownProperties()) { + observed->addType(cx, types::Type::AnyObjectType()); + return; + } + + types::HeapTypeSet *property = object->getProperty(cx, JSID_VOID, false); + if (property->unknownObject()) { + observed->addType(cx, types::Type::AnyObjectType()); + return; + } + + for (size_t i = 0; i < property->getObjectCount(); i++) { + if (types::TypeObject *object = property->getTypeObject(i)) + observed->addType(cx, types::Type::ObjectType(object)); + else if (JSObject *object = property->getSingleObject(i)) + observed->addType(cx, types::Type::ObjectType(object)); + } + } +} + static bool TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeSet *objTypes, jsid id, MDefinition **pvalue) @@ -2578,15 +2605,9 @@ TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeS types::HeapTypeSet *aggregateProperty = NULL; for (size_t i = 0; i < objTypes->getObjectCount(); i++) { - types::TypeObject *object = objTypes->getTypeObject(i); - if (!object) { - JSObject *singleton = objTypes->getSingleObject(i); - if (!singleton) - continue; - object = singleton->getType(cx); - if (!object) - return false; - } + types::TypeObject *object = objTypes->getTypeOrSingleObject(cx, i); + if (!object) + continue; if (object->unknownProperties()) return false; @@ -2683,19 +2704,8 @@ ion::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinit bool success = true; for (size_t i = 0; i < types->getObjectCount(); i++) { - types::TypeObject *object = types->getTypeObject(i); - if (!object) { - JSObject *singleton = types->getSingleObject(i); - if (!singleton) - continue; - object = singleton->getType(cx); - if (!object) { - success = false; - break; - } - } - - if (object->unknownProperties()) + types::TypeObject *object = types->getTypeOrSingleObject(cx, i); + if (!object || object->unknownProperties()) continue; types::HeapTypeSet *property = object->getProperty(cx, id, false); @@ -2727,13 +2737,8 @@ ion::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinit types::TypeObject *excluded = NULL; for (size_t i = 0; i < types->getObjectCount(); i++) { - types::TypeObject *object = types->getTypeObject(i); - if (!object) { - if (types->getSingleObject(i)) - return true; - continue; - } - if (object->unknownProperties()) + types::TypeObject *object = types->getTypeOrSingleObject(cx, i); + if (!object || object->unknownProperties()) continue; types::HeapTypeSet *property = object->getProperty(cx, id, false); diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index 3f8b61cc811..2efe8e345be 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -8112,6 +8112,8 @@ bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, Prop bool PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name, types::StackTypeSet *observed); bool PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name); +void AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name, + types::StackTypeSet *observed); bool PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj, PropertyName *name, MDefinition **pvalue, bool canModify = true); diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index af545b3e820..53e6a250a26 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -496,6 +496,7 @@ class TypeSet inline TypeObjectKey *getObject(unsigned i) const; inline JSObject *getSingleObject(unsigned i) const; inline TypeObject *getTypeObject(unsigned i) const; + inline TypeObject *getTypeOrSingleObject(JSContext *cx, unsigned i) const; void setOwnProperty(bool configurable) { flags |= TYPE_FLAG_OWN_PROPERTY; diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 19f332253e5..3b529376f22 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -1560,6 +1560,22 @@ TypeSet::getTypeObject(unsigned i) const return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL; } +inline TypeObject * +TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i) const +{ + JS_ASSERT(cx->compartment->activeAnalysis); + TypeObject *type = getTypeObject(i); + if (!type) { + JSObject *singleton = getSingleObject(i); + if (!singleton) + return NULL; + type = singleton->getType(cx); + if (!type) + cx->compartment->types.setPendingNukeTypes(cx); + } + return type; +} + ///////////////////////////////////////////////////////////////////// // TypeCallsite /////////////////////////////////////////////////////////////////////