Bug 1344198 - Inline various Shape search functions. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 07 Mar 2017 15:58:13 +0100
changeset 394483 a8d5f142c025a938b6af1656443b9eac20020e94
parent 394482 4e6fc030c70b70b13f0bd59dd43443bacbc43b21
child 394484 1a9059a55ce0d12376465994f43060cb7cc537a5
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1344198
milestone55.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 1344198 - Inline various Shape search functions. r=bhackett
js/src/vm/Shape-inl.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -37,17 +37,17 @@ AutoKeepShapeTables::~AutoKeepShapeTable
 }
 
 inline
 StackBaseShape::StackBaseShape(JSContext* cx, const Class* clasp, uint32_t objectFlags)
   : flags(objectFlags),
     clasp(clasp)
 {}
 
-inline Shape*
+MOZ_ALWAYS_INLINE Shape*
 Shape::search(JSContext* cx, jsid id)
 {
     return search(cx, this, id);
 }
 
 MOZ_ALWAYS_INLINE bool
 Shape::maybeCreateTableForLookup(JSContext* cx)
 {
@@ -80,17 +80,17 @@ Shape::search(JSContext* cx, Shape* star
     }
 
     *pentry = nullptr;
     *pshape = Shape::search<Adding>(cx, start, id);
     return true;
 }
 
 template<MaybeAdding Adding>
-/* static */ inline Shape*
+/* static */ MOZ_ALWAYS_INLINE Shape*
 Shape::search(JSContext* cx, Shape* start, jsid id)
 {
     if (start->maybeCreateTableForLookup(cx)) {
         JS::AutoCheckCannotGC nogc;
         if (ShapeTable* table = start->maybeTable(nogc)) {
             ShapeTable::Entry& entry = table->search<Adding>(id, nogc);
             return entry.shape();
         }
@@ -200,11 +200,138 @@ GetPropertyAttributes(JSObject* obj, Pro
         if (obj->is<TypedArrayObject>())
             return JSPROP_ENUMERATE | JSPROP_PERMANENT;
         return obj->as<NativeObject>().getElementsHeader()->elementAttributes();
     }
 
     return prop.shape()->attributes();
 }
 
+/*
+ * Double hashing needs the second hash code to be relatively prime to table
+ * size, so we simply make hash2 odd.
+ */
+MOZ_ALWAYS_INLINE HashNumber
+Hash1(HashNumber hash0, uint32_t shift)
+{
+    return hash0 >> shift;
+}
+
+MOZ_ALWAYS_INLINE HashNumber
+Hash2(HashNumber hash0, uint32_t log2, uint32_t shift)
+{
+    return ((hash0 << log2) >> shift) | 1;
+}
+
+template<MaybeAdding Adding>
+MOZ_ALWAYS_INLINE ShapeTable::Entry&
+ShapeTable::searchUnchecked(jsid id)
+{
+    MOZ_ASSERT(entries_);
+    MOZ_ASSERT(!JSID_IS_EMPTY(id));
+
+    /* Compute the primary hash address. */
+    HashNumber hash0 = HashId(id);
+    HashNumber hash1 = Hash1(hash0, hashShift_);
+    Entry* entry = &getEntry(hash1);
+
+    /* Miss: return space for a new entry. */
+    if (entry->isFree())
+        return *entry;
+
+    /* Hit: return entry. */
+    Shape* shape = entry->shape();
+    if (shape && shape->propidRaw() == id)
+        return *entry;
+
+    /* Collision: double hash. */
+    uint32_t sizeLog2 = HASH_BITS - hashShift_;
+    HashNumber hash2 = Hash2(hash0, sizeLog2, hashShift_);
+    uint32_t sizeMask = JS_BITMASK(sizeLog2);
+
+    /* Save the first removed entry pointer so we can recycle it if adding. */
+    Entry* firstRemoved;
+    if (Adding == MaybeAdding::Adding) {
+        if (entry->isRemoved()) {
+            firstRemoved = entry;
+        } else {
+            firstRemoved = nullptr;
+            if (!entry->hadCollision())
+                entry->flagCollision();
+        }
+    }
+
+#ifdef DEBUG
+    bool collisionFlag = true;
+    if (!entry->isRemoved())
+        collisionFlag = entry->hadCollision();
+#endif
+
+    while (true) {
+        hash1 -= hash2;
+        hash1 &= sizeMask;
+        entry = &getEntry(hash1);
+
+        if (entry->isFree())
+            return (Adding == MaybeAdding::Adding && firstRemoved) ? *firstRemoved : *entry;
+
+        shape = entry->shape();
+        if (shape && shape->propidRaw() == id) {
+            MOZ_ASSERT(collisionFlag);
+            return *entry;
+        }
+
+        if (Adding == MaybeAdding::Adding) {
+            if (entry->isRemoved()) {
+                if (!firstRemoved)
+                    firstRemoved = entry;
+            } else {
+                if (!entry->hadCollision())
+                    entry->flagCollision();
+            }
+        }
+
+#ifdef DEBUG
+        if (!entry->isRemoved())
+            collisionFlag &= entry->hadCollision();
+#endif
+    }
+
+    MOZ_CRASH("Shape::search failed to find an expected entry.");
+}
+
+template<MaybeAdding Adding>
+MOZ_ALWAYS_INLINE ShapeTable::Entry&
+ShapeTable::search(jsid id, const AutoKeepShapeTables&)
+{
+    return searchUnchecked<Adding>(id);
+}
+
+template<MaybeAdding Adding>
+MOZ_ALWAYS_INLINE ShapeTable::Entry&
+ShapeTable::search(jsid id, const JS::AutoCheckCannotGC&)
+{
+    return searchUnchecked<Adding>(id);
+}
+
+/*
+ * Keep this function in sync with search. It neither hashifies the start
+ * shape nor increments linear search count.
+ */
+MOZ_ALWAYS_INLINE Shape*
+Shape::searchNoHashify(Shape* start, jsid id)
+{
+    /*
+     * If we have a table, search in the shape table, else do a linear
+     * search. We never hashify into a table in parallel.
+     */
+    JS::AutoCheckCannotGC nogc;
+    if (ShapeTable* table = start->maybeTable(nogc)) {
+        ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(id, nogc);
+        return entry.shape();
+    }
+
+    return start->searchLinear(id);
+}
+
 } /* namespace js */
 
 #endif /* vm_Shape_inl_h */
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -166,112 +166,16 @@ Shape::hashify(JSContext* cx, Shape* sha
         js_free(table);
         return false;
     }
 
     shape->base()->setTable(table);
     return true;
 }
 
-/*
- * Double hashing needs the second hash code to be relatively prime to table
- * size, so we simply make hash2 odd.
- */
-static HashNumber
-Hash1(HashNumber hash0, uint32_t shift)
-{
-    return hash0 >> shift;
-}
-
-static HashNumber
-Hash2(HashNumber hash0, uint32_t log2, uint32_t shift)
-{
-    return ((hash0 << log2) >> shift) | 1;
-}
-
-template<MaybeAdding Adding>
-ShapeTable::Entry&
-ShapeTable::searchUnchecked(jsid id)
-{
-    MOZ_ASSERT(entries_);
-    MOZ_ASSERT(!JSID_IS_EMPTY(id));
-
-    /* Compute the primary hash address. */
-    HashNumber hash0 = HashId(id);
-    HashNumber hash1 = Hash1(hash0, hashShift_);
-    Entry* entry = &getEntry(hash1);
-
-    /* Miss: return space for a new entry. */
-    if (entry->isFree())
-        return *entry;
-
-    /* Hit: return entry. */
-    Shape* shape = entry->shape();
-    if (shape && shape->propidRaw() == id)
-        return *entry;
-
-    /* Collision: double hash. */
-    uint32_t sizeLog2 = HASH_BITS - hashShift_;
-    HashNumber hash2 = Hash2(hash0, sizeLog2, hashShift_);
-    uint32_t sizeMask = JS_BITMASK(sizeLog2);
-
-    /* Save the first removed entry pointer so we can recycle it if adding. */
-    Entry* firstRemoved;
-    if (Adding == MaybeAdding::Adding) {
-        if (entry->isRemoved()) {
-            firstRemoved = entry;
-        } else {
-            firstRemoved = nullptr;
-            if (!entry->hadCollision())
-                entry->flagCollision();
-        }
-    }
-
-#ifdef DEBUG
-    bool collisionFlag = true;
-    if (!entry->isRemoved())
-        collisionFlag = entry->hadCollision();
-#endif
-
-    while (true) {
-        hash1 -= hash2;
-        hash1 &= sizeMask;
-        entry = &getEntry(hash1);
-
-        if (entry->isFree())
-            return (Adding == MaybeAdding::Adding && firstRemoved) ? *firstRemoved : *entry;
-
-        shape = entry->shape();
-        if (shape && shape->propidRaw() == id) {
-            MOZ_ASSERT(collisionFlag);
-            return *entry;
-        }
-
-        if (Adding == MaybeAdding::Adding) {
-            if (entry->isRemoved()) {
-                if (!firstRemoved)
-                    firstRemoved = entry;
-            } else {
-                if (!entry->hadCollision())
-                    entry->flagCollision();
-            }
-        }
-
-#ifdef DEBUG
-        if (!entry->isRemoved())
-            collisionFlag &= entry->hadCollision();
-#endif
-    }
-
-    MOZ_CRASH("Shape::search failed to find an expected entry.");
-}
-
-template ShapeTable::Entry& ShapeTable::searchUnchecked<MaybeAdding::Adding>(jsid id);
-template ShapeTable::Entry& ShapeTable::searchUnchecked<MaybeAdding::NotAdding>(jsid id);
-
 bool
 ShapeTable::change(JSContext* cx, int log2Delta)
 {
     MOZ_ASSERT(entries_);
     MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
 
     /*
      * Grow, shrink, or compress by changing this->entries_.
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -196,17 +196,17 @@ class ShapeTable {
 
     uint32_t        freeList_;          /* SHAPE_INVALID_SLOT or head of slot
                                            freelist in owning dictionary-mode
                                            object */
 
     Entry*          entries_;          /* table of ptrs to shared tree nodes */
 
     template<MaybeAdding Adding>
-    Entry& searchUnchecked(jsid id);
+    MOZ_ALWAYS_INLINE Entry& searchUnchecked(jsid id);
 
   public:
     explicit ShapeTable(uint32_t nentries)
       : hashShift_(HASH_BITS - MIN_SIZE_LOG2),
         entryCount_(nentries),
         removedCount_(0),
         freeList_(SHAPE_INVALID_SLOT),
         entries_(nullptr)
@@ -233,24 +233,20 @@ class ShapeTable {
 
     // init() is fallible and reports OOM to the context.
     bool init(JSContext* cx, Shape* lastProp);
 
     // change() is fallible but does not report OOM.
     bool change(JSContext* cx, int log2Delta);
 
     template<MaybeAdding Adding>
-    MOZ_ALWAYS_INLINE Entry& search(jsid id, const AutoKeepShapeTables&) {
-        return searchUnchecked<Adding>(id);
-    }
+    MOZ_ALWAYS_INLINE Entry& search(jsid id, const AutoKeepShapeTables&);
 
     template<MaybeAdding Adding>
-    MOZ_ALWAYS_INLINE Entry& search(jsid id, const JS::AutoCheckCannotGC&) {
-        return searchUnchecked<Adding>(id);
-    }
+    MOZ_ALWAYS_INLINE Entry& search(jsid id, const JS::AutoCheckCannotGC&);
 
     void trace(JSTracer* trc);
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkAfterMovingGC();
 #endif
 
   private:
     Entry& getEntry(uint32_t i) const {
@@ -648,17 +644,17 @@ class Shape : public gc::TenuredCell
                                      to many-kids data structure */
         GCPtrShape* listp;        /* dictionary list starting at shape_
                                      has a double-indirect back pointer,
                                      either to the next shape's parent if not
                                      last, else to obj->shape_ */
     };
 
     template<MaybeAdding Adding = MaybeAdding::NotAdding>
-    static inline Shape* search(JSContext* cx, Shape* start, jsid id);
+    static MOZ_ALWAYS_INLINE Shape* search(JSContext* cx, Shape* start, jsid id);
 
     template<MaybeAdding Adding = MaybeAdding::NotAdding>
     static inline MOZ_MUST_USE bool search(JSContext* cx, Shape* start, jsid id,
                                            const AutoKeepShapeTables&,
                                            Shape** pshape, ShapeTable::Entry** pentry);
 
     static inline Shape* searchNoHashify(Shape* start, jsid id);
 
@@ -1041,17 +1037,17 @@ class Shape : public gc::TenuredCell
     void sweep();
     void finalize(FreeOp* fop);
     void removeChild(Shape* child);
 
     static const JS::TraceKind TraceKind = JS::TraceKind::Shape;
 
     void traceChildren(JSTracer* trc);
 
-    inline Shape* search(JSContext* cx, jsid id);
+    MOZ_ALWAYS_INLINE Shape* search(JSContext* cx, jsid id);
     MOZ_ALWAYS_INLINE Shape* searchLinear(jsid id);
 
     void fixupAfterMovingGC();
     void fixupGetterSetterForBarrier(JSTracer* trc);
     void updateBaseShapeAfterMovingGC();
 
     /* For JIT usage */
     static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
@@ -1512,36 +1508,16 @@ Shape::searchLinear(jsid id)
         if (shape->propidRef() == id)
             return shape;
         shape = shape->parent;
     }
 
     return nullptr;
 }
 
-/*
- * Keep this function in sync with search. It neither hashifies the start
- * shape nor increments linear search count.
- */
-inline Shape*
-Shape::searchNoHashify(Shape* start, jsid id)
-{
-    /*
-     * If we have a table, search in the shape table, else do a linear
-     * search. We never hashify into a table in parallel.
-     */
-    JS::AutoCheckCannotGC nogc;
-    if (ShapeTable* table = start->maybeTable(nogc)) {
-        ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(id, nogc);
-        return entry.shape();
-    }
-
-    return start->searchLinear(id);
-}
-
 inline bool
 Shape::matches(const StackShape& other) const
 {
     return propid_.get() == other.propid &&
            matchesParamsAfterId(other.base, other.slot_, other.attrs, other.flags,
                                 other.rawGetter, other.rawSetter);
 }