Bug 899139 - Part 3: Install SetElementIC for typed array writes. (r=bhackett)
authorShu-yu Guo <shu@rfrn.org>
Mon, 09 Sep 2013 18:55:52 -0700
changeset 146269 8c7d2ec92d8b0a691e92f8caac72d74d6b8c28b8
parent 146268 12657c2feb9c73ab8a0a8e3e75014c301b9ca4e2
child 146270 a3abf85dee117766589134c5ab61b66fde090b4a
push id33519
push usershu@rfrn.org
push dateTue, 10 Sep 2013 01:59:56 +0000
treeherdermozilla-inbound@a3abf85dee11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs899139
milestone26.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 899139 - Part 3: Install SetElementIC for typed array writes. (r=bhackett)
js/src/jit/BaselineInspector.cpp
js/src/jit/BaselineInspector.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/MIR.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -55,16 +55,30 @@ SetElemICInspector::sawDenseWrite() cons
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_DenseAdd() || stub->isSetElem_Dense())
             return true;
     }
     return false;
 }
 
 bool
+SetElemICInspector::sawTypedArrayWrite() const
+{
+    if (!icEntry_)
+        return false;
+
+    // Check for a SetElem_TypedArray stub.
+    for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
+        if (stub->isSetElem_TypedArray())
+            return true;
+    }
+    return false;
+}
+
+bool
 BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, Vector<Shape *> &shapes)
 {
     // Return a list of shapes seen by the baseline IC for the current op.
     // An empty list indicates no shapes are known, or there was an uncacheable
     // access.
     JS_ASSERT(shapes.empty());
 
     if (!hasBaselineScript())
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -35,16 +35,17 @@ class SetElemICInspector : public ICInsp
   public:
     SetElemICInspector(BaselineInspector *inspector, jsbytecode *pc, ICEntry *icEntry)
       : ICInspector(inspector, pc, icEntry)
     { }
 
     bool sawOOBDenseWrite() const;
     bool sawOOBTypedArrayWrite() const;
     bool sawDenseWrite() const;
+    bool sawTypedArrayWrite() const;
 };
 
 class BaselineInspector
 {
   private:
     RootedScript script;
     ICEntry *prevLookedUpEntry;
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7259,19 +7259,19 @@ IonBuilder::setElemTryCache(bool *emitte
     if (!object->mightBeType(MIRType_Object))
         return true;
 
     if (!index->mightBeType(MIRType_Int32) && !index->mightBeType(MIRType_String))
         return true;
 
     // TODO: Bug 876650: remove this check:
     // Temporary disable the cache if non dense native,
-    // untill the cache supports more ics
+    // until the cache supports more ics
     SetElemICInspector icInspect(inspector->setElemICInspector(pc));
-    if (!icInspect.sawDenseWrite())
+    if (!icInspect.sawDenseWrite() && !icInspect.sawTypedArrayWrite())
         return true;
 
     bool needsBarrier;
     if (PropertyWriteNeedsTypeBarrier(cx, current, &object, NULL, &value, /* canModify = */ true,
                                       &needsBarrier))
     {
         return false;
     }
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3362,22 +3362,20 @@ SetElementIC::attachDenseElement(JSConte
     attacher.jumpNextStub(masm);
 
     setHasDenseStub();
     return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
 }
 
 static bool
 GenerateSetTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
-                             TypedArrayObject *tarr, const Value &idval, Register object,
+                             TypedArrayObject *tarr, Register object,
                              ValueOperand indexVal, ConstantOrRegister value,
                              Register tempUnbox, Register temp, FloatRegister tempFloat)
 {
-    JS_ASSERT(SetElementIC::canAttachTypedArrayElement(tarr, idval));
-
     Label failures, done, popObjectAndFail;
 
     // Guard on the shape.
     Shape *shape = tarr->lastProperty();
     if (!shape)
         return false;
     masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
 
@@ -3439,28 +3437,29 @@ GenerateSetTypedArrayElement(JSContext *
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
     return true;
 }
 
 /* static */ bool
-SetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval)
+SetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value)
 {
-    return obj->is<TypedArrayObject>() && idval.isInt32();
+    // Don't bother attaching stubs for assigning strings and objects.
+    return (obj->is<TypedArrayObject>() && idval.isInt32() &&
+            !value.isString() && !value.isObject());
 }
 
 bool
-SetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion,
-                                      TypedArrayObject *tarr, const Value &idval)
+SetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr)
 {
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
-    if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr, idval,
+    if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
                                       object(), index(), value(),
                                       tempToUnboxIndex(), temp(), tempFloat()))
     {
         return false;
     }
 
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
 }
@@ -3474,19 +3473,19 @@ SetElementIC::update(JSContext *cx, size
 
     bool attachedStub = false;
     if (cache.canAttachStub()) {
         if (!cache.hasDenseStub() && IsElementSetInlineable(obj, idval)) {
             if (!cache.attachDenseElement(cx, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
-        if (!attachedStub && canAttachTypedArrayElement(obj, idval)) {
+        if (!attachedStub && canAttachTypedArrayElement(obj, idval, value)) {
             TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-            if (!cache.attachTypedArrayElement(cx, ion, tarr, idval))
+            if (!cache.attachTypedArrayElement(cx, ion, tarr))
                 return false;
         }
     }
 
     if (!SetObjectElement(cx, obj, idval, value, cache.strict()))
         return false;
     return true;
 }
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -844,21 +844,20 @@ class SetElementIC : public RepatchIonCa
     bool hasDenseStub() const {
         return hasDenseStub_;
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
         hasDenseStub_ = true;
     }
 
-    static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval);
+    static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value);
 
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
-    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
-                                 const Value &idval);
+    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            HandleValue value);
 };
 
 class BindNameIC : public RepatchIonCache
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3007,16 +3007,21 @@ jit::PropertyWriteNeedsTypeBarrier(JSCon
     for (size_t i = 0; i < types->getObjectCount(); i++) {
         types::TypeObject *object;
         if (!types->getTypeOrSingleObject(cx, i, &object))
             return false;
 
         if (!object || object->unknownProperties())
             continue;
 
+        // TI doesn't track TypedArray objects and should never insert a type
+        // barrier for them.
+        if (object->getTypedArrayType() < ScalarTypeRepresentation::TYPE_MAX)
+            continue;
+
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
         if (!property) {
             success = false;
             break;
         }
         if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
             // Either pobj or pvalue needs to be modified to filter out the
             // types which the value could have but are not in the property,
@@ -3046,16 +3051,18 @@ jit::PropertyWriteNeedsTypeBarrier(JSCon
     types::TypeObject *excluded = NULL;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
         types::TypeObject *object;
         if (!types->getTypeOrSingleObject(cx, i, &object))
             return false;
 
         if (!object || object->unknownProperties())
             continue;
+        if (object->getTypedArrayType() < ScalarTypeRepresentation::TYPE_MAX)
+            continue;
 
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
         if (!property) {
             *result = true;
             return true;
         }
 
         if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1104,16 +1104,19 @@ struct TypeObject : gc::Cell
     inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id, bool own);
 
     /* Get a property only if it already exists. */
     inline HeapTypeSet *maybeGetProperty(ExclusiveContext *cx, jsid id);
 
     inline unsigned getPropertyCount();
     inline Property *getProperty(unsigned i);
 
+    /* Get the typed array element type if clasp is a typed array. */
+    inline int getTypedArrayType();
+
     /*
      * Get the global object which all objects of this type are parented to,
      * or NULL if there is none known.
      */
     //inline JSObject *getGlobal();
 
     /* Helpers */
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1557,16 +1557,24 @@ TypeObject::getProperty(unsigned i)
     JS_ASSERT(i < getPropertyCount());
     if (basePropertyCount() == 1) {
         JS_ASSERT(i == 0);
         return (Property *) propertySet;
     }
     return propertySet[i];
 }
 
+inline int
+TypeObject::getTypedArrayType()
+{
+    if (IsTypedArrayClass(clasp))
+        return clasp - &TypedArrayObject::classes[0];
+    return ScalarTypeRepresentation::TYPE_MAX;
+}
+
 inline void
 TypeObject::writeBarrierPre(TypeObject *type)
 {
 #ifdef JSGC_INCREMENTAL
     if (!type || !type->runtimeFromAnyThread()->needsBarrier())
         return;
 
     JS::Zone *zone = type->zone();