Bug 1236523 part 2 - Cache isBigEnoughForAShapeTable on the Shape. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 07 Jan 2016 10:17:32 +0100
changeset 278870 f8817ab2f74500c71ec2f51eb38a315af871e6c6
parent 278869 fe453285a5939636c10e0c270d056a5786430b5b
child 278871 cb2aea4df00597cc86ea1bc998f3f52c155879f5
push id69919
push userjandemooij@gmail.com
push dateThu, 07 Jan 2016 09:20:07 +0000
treeherdermozilla-inbound@cb2aea4df005 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1236523
milestone46.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 1236523 part 2 - Cache isBigEnoughForAShapeTable on the Shape. r=bhackett
js/src/vm/Shape.h
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -710,17 +710,19 @@ class Shape : public gc::TenuredCell
         OVERWRITTEN     = 0x02,
 
         /*
          * This shape is an AccessorShape, a fat Shape that can store
          * getter/setter information.
          */
         ACCESSOR_SHAPE  = 0x04,
 
-        UNUSED_BITS     = 0x3C
+        /* Flags used to speed up isBigEnoughForAShapeTable(). */
+        HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x08,
+        CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x10,
     };
 
     /* Get a shape identical to this one, without parent/kids information. */
     inline Shape(const StackShape& other, uint32_t nfixed);
 
     /* Used by EmptyShape (see jsscopeinlines.h). */
     inline Shape(UnownedBaseShape* base, uint32_t nfixed);
 
@@ -894,28 +896,50 @@ class Shape : public gc::TenuredCell
         if (hasTable())
             return table().entryCount();
         uint32_t count = 0;
         for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
             ++count;
         return count;
     }
 
-    bool isBigEnoughForAShapeTable() {
-        MOZ_ASSERT(!hasTable());
-        Shape* shape = this;
+  private:
+    bool isBigEnoughForAShapeTableSlow() {
         uint32_t count = 0;
-        for (Shape::Range<NoGC> r(shape); !r.empty(); r.popFront()) {
+        for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront()) {
             ++count;
             if (count >= ShapeTable::MIN_ENTRIES)
                 return true;
         }
         return false;
     }
 
+  public:
+    bool isBigEnoughForAShapeTable() {
+        MOZ_ASSERT(!inDictionary());
+        MOZ_ASSERT(!hasTable());
+
+        // isBigEnoughForAShapeTableSlow is pretty inefficient so we only call
+        // it once and cache the result.
+
+        if (flags & HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE) {
+            bool res = flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+            MOZ_ASSERT(res == isBigEnoughForAShapeTableSlow());
+            return res;
+        }
+
+        MOZ_ASSERT(!(flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE));
+
+        bool res = isBigEnoughForAShapeTableSlow();
+        if (res)
+            flags |= CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+        flags |= HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+        return res;
+    }
+
 #ifdef DEBUG
     void dump(JSContext* cx, FILE* fp) const;
     void dumpSubtree(JSContext* cx, int level, FILE* fp) const;
 #endif
 
     void sweep();
     void finalize(FreeOp* fop);
     void removeChild(Shape* child);