Bug 1198861 - Improve aliasing information and type barrier handling for unboxed arrays, r=jandem.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 01 Sep 2015 13:04:26 -0600
changeset 260360 1530e404c8df70e2ddd214004f7aba31df043861
parent 260359 131e9ddc58bdfbc73fceb39768cb250675db8a36
child 260361 9c9f33fb94364ba69567ba9c42983ff9f09fdeeb
push id29307
push userryanvm@gmail.com
push dateWed, 02 Sep 2015 01:01:53 +0000
treeherdermozilla-central@e2eb0442ece9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1198861
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1198861 - Improve aliasing information and type barrier handling for unboxed arrays, r=jandem.
js/src/jit/MIR.cpp
js/src/jit/MIR.h
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4353,36 +4353,49 @@ MaybeUnwrapElements(const MDefinition* e
 
     // MTypedArrayElements and MTypedObjectElements aren't handled.
     if (!elementsOrObj->isElements())
         return nullptr;
 
     return elementsOrObj->toElements();
 }
 
+static inline const MDefinition*
+GetElementsObject(const MDefinition* elementsOrObj)
+{
+    if (elementsOrObj->type() == MIRType_Object)
+        return elementsOrObj;
+
+    const MDefinition* elements = MaybeUnwrapElements(elementsOrObj);
+    if (elements)
+        return elements->toElements()->input();
+
+    return nullptr;
+}
+
 // Gets the MDefinition of the target Object for the given store operation.
 static inline const MDefinition*
 GetStoreObject(const MDefinition* store)
 {
     switch (store->op()) {
-      case MDefinition::Op_StoreElement: {
-        const MDefinition* elementsOrObj = store->toStoreElement()->elements();
-        if (elementsOrObj->type() == MIRType_Object)
-            return elementsOrObj;
-
-        const MDefinition* elements = MaybeUnwrapElements(elementsOrObj);
-        if (elements)
-            return elements->toElements()->input();
-
-        return nullptr;
-      }
+      case MDefinition::Op_StoreElement:
+        return GetElementsObject(store->toStoreElement()->elements());
 
       case MDefinition::Op_StoreElementHole:
         return store->toStoreElementHole()->object();
 
+      case MDefinition::Op_StoreUnboxedObjectOrNull:
+        return GetElementsObject(store->toStoreUnboxedObjectOrNull()->elements());
+
+      case MDefinition::Op_StoreUnboxedString:
+        return GetElementsObject(store->toStoreUnboxedString()->elements());
+
+      case MDefinition::Op_StoreUnboxedScalar:
+        return GetElementsObject(store->toStoreUnboxedScalar()->elements());
+
       default:
         return nullptr;
     }
 }
 
 // Implements mightAlias() logic common to all load operations.
 static bool
 GenericLoadMightAlias(const MDefinition* elementsOrObj, const MDefinition* store)
@@ -4434,16 +4447,40 @@ MLoadElement::mightAlias(const MDefiniti
 
 bool
 MInitializedLength::mightAlias(const MDefinition* store) const
 {
     return GenericLoadMightAlias(elements(), store);
 }
 
 bool
+MLoadUnboxedObjectOrNull::mightAlias(const MDefinition* store) const
+{
+    return GenericLoadMightAlias(elements(), store);
+}
+
+bool
+MLoadUnboxedString::mightAlias(const MDefinition* store) const
+{
+    return GenericLoadMightAlias(elements(), store);
+}
+
+bool
+MLoadUnboxedScalar::mightAlias(const MDefinition* store) const
+{
+    return GenericLoadMightAlias(elements(), store);
+}
+
+bool
+MUnboxedArrayInitializedLength::mightAlias(const MDefinition* store) const
+{
+    return GenericLoadMightAlias(object(), store);
+}
+
+bool
 MGuardReceiverPolymorphic::congruentTo(const MDefinition* ins) const
 {
     if (!ins->isGuardReceiverPolymorphic())
         return false;
 
     const MGuardReceiverPolymorphic* other = ins->toGuardReceiverPolymorphic();
 
     if (numReceivers() != other->numReceivers())
@@ -4983,25 +5020,56 @@ PropertyReadNeedsTypeBarrier(CompilerCon
             return BarrierKind::TypeSet;
         }
     }
 
     property.freeze(constraints);
     return BarrierKind::NoBarrier;
 }
 
+static bool
+ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
+{
+    if (first->isSingleton() ||
+        second->isSingleton() ||
+        first->clasp() != second->clasp() ||
+        first->unknownProperties() ||
+        second->unknownProperties())
+    {
+        return false;
+    }
+
+    if (first->clasp() == &ArrayObject::class_) {
+        HeapTypeSetKey firstElements = first->property(JSID_VOID);
+        HeapTypeSetKey secondElements = second->property(JSID_VOID);
+
+        return firstElements.maybeTypes() && secondElements.maybeTypes() &&
+               firstElements.maybeTypes()->equals(secondElements.maybeTypes());
+    }
+
+    if (first->clasp() == &UnboxedArrayObject::class_) {
+        return first->group()->unboxedLayout().elementType() ==
+               second->group()->unboxedLayout().elementType();
+    }
+
+    return false;
+}
+
 BarrierKind
 jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
                                   CompilerConstraintList* constraints,
                                   TypeSet::ObjectKey* key, PropertyName* name,
                                   TemporaryTypeSet* observed, bool updateObserved)
 {
+    if (!updateObserved)
+        return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
+
     // If this access has never executed, try to add types to the observed set
     // according to any property which exists on the object or its prototype.
-    if (updateObserved && observed->empty() && name) {
+    if (observed->empty() && name) {
         JSObject* obj;
         if (key->isSingleton())
             obj = key->singleton();
         else
             obj = key->proto().isLazy() ? nullptr : key->proto().toObjectOrNull();
 
         while (obj) {
             if (!obj->getClass()->isNative())
@@ -5024,16 +5092,40 @@ jit::PropertyReadNeedsTypeBarrier(JSCont
                     }
                 }
             }
 
             obj = obj->getProto();
         }
     }
 
+    // If any objects which could be observed are similar to ones that have
+    // already been observed, add them to the observed type set.
+    if (!key->unknownProperties()) {
+        HeapTypeSetKey property = key->property(name ? NameToId(name) : JSID_VOID);
+
+        if (property.maybeTypes() && !property.maybeTypes()->unknownObject()) {
+            for (size_t i = 0; i < property.maybeTypes()->getObjectCount(); i++) {
+                TypeSet::ObjectKey* key = property.maybeTypes()->getObject(i);
+                if (!key || observed->unknownObject())
+                    continue;
+
+                for (size_t j = 0; j < observed->getObjectCount(); j++) {
+                    TypeSet::ObjectKey* observedKey = observed->getObject(j);
+                    if (observedKey && ObjectSubsumes(observedKey, key)) {
+                        // Note: the return value here is ignored.
+                        observed->addType(TypeSet::ObjectType(key),
+                                          GetJitContext()->temp->lifoAlloc());
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
     return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
 }
 
 BarrierKind
 jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
                                   CompilerConstraintList* constraints,
                                   MDefinition* obj, PropertyName* name,
                                   TemporaryTypeSet* observed)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8003,16 +8003,17 @@ class MUnboxedArrayInitializedLength
         return getOperand(0);
     }
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
+    bool mightAlias(const MDefinition* store) const override;
 
     ALLOW_CLONE(MUnboxedArrayInitializedLength)
 };
 
 // Increment the initialized length of an unboxed array object.
 class MIncrementUnboxedArrayInitializedLength
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
@@ -8756,16 +8757,17 @@ class MLoadUnboxedObjectOrNull
             return false;
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Load(AliasSet::UnboxedElement);
     }
+    bool mightAlias(const MDefinition* store) const override;
 
     ALLOW_CLONE(MLoadUnboxedObjectOrNull)
 };
 
 class MLoadUnboxedString
   : public MBinaryInstruction,
     public SingleObjectPolicy::Data
 {
@@ -8805,16 +8807,17 @@ class MLoadUnboxedString
         const MLoadUnboxedString* other = ins->toLoadUnboxedString();
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Load(AliasSet::UnboxedElement);
     }
+    bool mightAlias(const MDefinition* store) const override;
 
     ALLOW_CLONE(MLoadUnboxedString)
 };
 
 class MStoreElementCommon
 {
     MIRType elementType_;
     bool needsBarrier_;
@@ -9457,16 +9460,17 @@ class MLoadUnboxedScalar
     }
     AliasSet getAliasSet() const override {
         // When a barrier is needed make the instruction effectful by
         // giving it a "store" effect.
         if (requiresBarrier_)
             return AliasSet::Store(AliasSet::UnboxedElement);
         return AliasSet::Load(AliasSet::UnboxedElement);
     }
+    bool mightAlias(const MDefinition* store) const override;
 
     bool congruentTo(const MDefinition* ins) const override {
         if (requiresBarrier_)
             return false;
         if (!ins->isLoadUnboxedScalar())
             return false;
         const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
         if (storageType_ != other->storageType_)
@@ -12895,17 +12899,17 @@ class MRecompileCheck : public MNullaryI
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
 // All barriered operations - MMemoryBarrier, MCompareExchangeTypedArrayElement,
 // MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as well as
-// MLoadUnboxedScalar and MStoreUnboxedSclaar when they are marked as requiring
+// MLoadUnboxedScalar and MStoreUnboxedScalar when they are marked as requiring
 // a memory barrer - have the following attributes:
 //
 // - Not movable
 // - Not removable
 // - Not congruent with any other instruction
 // - Effectful (they alias every TypedArray store)
 //
 // The intended effect of those constraints is to prevent all loads