Bug 1224038 - Use stable hashing in ObjectGroupCompartment::NewTable; r=jonco
☠☠ backed out by cfc8f256cea0 ☠ ☠
authorTerrence Cole <terrence@mozilla.com>
Tue, 17 Nov 2015 11:31:27 -0800
changeset 273034 f3d2ddb4979c9909e012adafd607fc4463e32e6b
parent 273033 a621c6d49da11548244ba40ba131db239195c43c
child 273035 02919b7d57d7f8206328f53ac0f7b2b9fe334c9b
push id29693
push usercbook@mozilla.com
push dateWed, 18 Nov 2015 13:50:33 +0000
treeherdermozilla-central@1d6155d7e6c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1224038
milestone45.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 1224038 - Use stable hashing in ObjectGroupCompartment::NewTable; r=jonco
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -361,110 +361,50 @@ JSObject::setNewGroupUnknown(JSContext* 
  * associated object may be a function (for types constructed with 'new') or a
  * type descriptor (for typed objects). These entries are also used for the set
  * of lazy groups in the compartment, which use a null associated object
  * (though there are only a few of these per compartment).
  */
 struct ObjectGroupCompartment::NewEntry
 {
     ReadBarrieredObjectGroup group;
-
-    // Note: This pointer is only used for equality and does not need a read barrier.
-    JSObject* associated;
+    ReadBarrieredObject associated;
 
     NewEntry(ObjectGroup* group, JSObject* associated)
       : group(group), associated(associated)
     {}
 
     struct Lookup {
         const Class* clasp;
-        TaggedProto hashProto;
-        TaggedProto matchProto;
+        TaggedProto proto;
         JSObject* associated;
 
         Lookup(const Class* clasp, TaggedProto proto, JSObject* associated)
-          : clasp(clasp), hashProto(proto), matchProto(proto), associated(associated)
-        {}
-
-        /*
-         * For use by generational post barriers only.  Look up an entry whose
-         * proto has been moved, but was hashed with the original value.
-         */
-        Lookup(const Class* clasp, TaggedProto hashProto, TaggedProto matchProto, JSObject* associated)
-            : clasp(clasp), hashProto(hashProto), matchProto(matchProto), associated(associated)
+          : clasp(clasp), proto(proto), associated(associated)
         {}
     };
 
     static inline HashNumber hash(const Lookup& lookup) {
-        return PointerHasher<JSObject*, 3>::hash(lookup.hashProto.raw()) ^
+        return lookup.proto.hashCode() ^
                PointerHasher<const Class*, 3>::hash(lookup.clasp) ^
-               PointerHasher<JSObject*, 3>::hash(lookup.associated);
+               MovableCellHasher<JSObject*>::hash(lookup.associated);
     }
 
     static inline bool match(const NewEntry& key, const Lookup& lookup) {
-        return key.group.unbarrieredGet()->proto() == lookup.matchProto &&
-               (!lookup.clasp || key.group.unbarrieredGet()->clasp() == lookup.clasp) &&
-               key.associated == lookup.associated;
+        TaggedProto keyProto = key.group.unbarrieredGet()->proto();
+        const Class* keyClasp = key.group.unbarrieredGet()->clasp();
+        JSObject* keyAssociated = key.associated.unbarrieredGet();
+        return keyProto.uniqueId() == lookup.proto.uniqueId() &&
+               (!lookup.clasp || PointerHasher<const Class*, 3>::match(keyClasp, lookup.clasp)) &&
+               MovableCellHasher<JSObject*>::match(keyAssociated, lookup.associated);
     }
 
     static void rekey(NewEntry& k, const NewEntry& newKey) { k = newKey; }
 };
 
-// This class is used to add a post barrier on a NewTable entry, as the key is
-// calculated from a prototype object which may be moved by generational GC.
-class ObjectGroupCompartment::NewTableRef : public gc::BufferableRef
-{
-    NewTable* table;
-    const Class* clasp;
-    JSObject* proto;
-    JSObject* associated;
-
-  public:
-    NewTableRef(NewTable* table, const Class* clasp, JSObject* proto, JSObject* associated)
-        : table(table), clasp(clasp), proto(proto), associated(associated)
-    {}
-
-    void trace(JSTracer* trc) override {
-        JSObject* prior = proto;
-        TraceManuallyBarrieredEdge(trc, &proto, "newObjectGroups set prototype");
-        if (prior == proto)
-            return;
-
-        NewTable::Ptr p = table->lookup(NewTable::Lookup(clasp, TaggedProto(prior),
-                                                         TaggedProto(proto),
-                                                         associated));
-        if (!p)
-            return;
-
-        table->rekeyAs(NewTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), associated),
-                       NewTable::Lookup(clasp, TaggedProto(proto), associated), *p);
-    }
-};
-
-/* static */ void
-ObjectGroupCompartment::newTablePostBarrier(ExclusiveContext* cx, NewTable* table,
-                                            const Class* clasp, TaggedProto proto,
-                                            JSObject* associated)
-{
-    MOZ_ASSERT_IF(associated, !IsInsideNursery(associated));
-
-    if (!proto.isObject())
-        return;
-
-    if (!cx->isJSContext()) {
-        MOZ_ASSERT(!IsInsideNursery(proto.toObject()));
-        return;
-    }
-
-    if (IsInsideNursery(proto.toObject())) {
-        gc::StoreBuffer& sb = cx->asJSContext()->runtime()->gc.storeBuffer;
-        sb.putGeneric(NewTableRef(table, clasp, proto.toObject(), associated));
-    }
-}
-
 /* static */ ObjectGroup*
 ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
                              TaggedProto proto, JSObject* associated)
 {
     MOZ_ASSERT_IF(associated, proto.isObject());
     MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
 
     // A null lookup clasp is used for 'new' groups with an associated
@@ -548,18 +488,16 @@ ObjectGroup::defaultNewGroup(ExclusiveCo
     if (!group)
         return nullptr;
 
     if (!table->add(p, ObjectGroupCompartment::NewEntry(group, associated))) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, associated);
-
     if (proto.isObject()) {
         RootedObject obj(cx, proto.toObject());
 
         if (associated) {
             if (associated->is<JSFunction>()) {
                 if (!TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>()))
                     return nullptr;
             } else {
@@ -634,18 +572,16 @@ ObjectGroup::lazySingletonGroup(Exclusiv
     if (!group)
         return nullptr;
 
     if (!table->add(p, ObjectGroupCompartment::NewEntry(group, nullptr))) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, nullptr);
-
     return group;
 }
 
 /* static */ void
 ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, const Class* clasp, HandleObject obj)
 {
     // If the object already has a new group, mark that group as unknown.
     ObjectGroupCompartment::NewTable* table = cx->compartment()->objectGroups.defaultNewTable;
@@ -1777,64 +1713,44 @@ ObjectGroupCompartment::sweep(FreeOp* fo
 
     sweepNewTable(defaultNewTable);
     sweepNewTable(lazyTable);
 }
 
 void
 ObjectGroupCompartment::sweepNewTable(NewTable* table)
 {
-    if (table && table->initialized()) {
-        for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
-            NewEntry entry = e.front();
-            if (IsAboutToBeFinalized(&entry.group) ||
-                (entry.associated && IsAboutToBeFinalizedUnbarriered(&entry.associated)))
-            {
-                e.removeFront();
-            } else {
-                /* Any rekeying necessary is handled by fixupNewObjectGroupTable() below. */
-                MOZ_ASSERT(entry.group.unbarrieredGet() == e.front().group.unbarrieredGet());
-                MOZ_ASSERT(entry.associated == e.front().associated);
-            }
+    if (!table || !table->initialized())
+        return;
+
+    for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
+        NewEntry entry = e.front();
+        if (IsAboutToBeFinalized(&entry.group) ||
+            (entry.associated && IsAboutToBeFinalized(&entry.associated)))
+        {
+            e.removeFront();
         }
     }
 }
 
 void
 ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable* table)
 {
     /*
      * Each entry's hash depends on the object's prototype and we can't tell
      * whether that has been moved or not in sweepNewObjectGroupTable().
      */
-    if (table && table->initialized()) {
-        for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
-            NewEntry entry = e.front();
-            bool needRekey = false;
-            if (IsForwarded(entry.group.unbarrieredGet())) {
-                entry.group.set(Forwarded(entry.group.unbarrieredGet()));
-                needRekey = true;
-            }
-            TaggedProto proto = entry.group.unbarrieredGet()->proto();
-            if (proto.isObject() && IsForwarded(proto.toObject())) {
-                proto = TaggedProto(Forwarded(proto.toObject()));
-                needRekey = true;
-            }
-            if (entry.associated && IsForwarded(entry.associated)) {
-                entry.associated = Forwarded(entry.associated);
-                needRekey = true;
-            }
-            if (needRekey) {
-                const Class* clasp = entry.group.unbarrieredGet()->clasp();
-                if (entry.associated && entry.associated->is<JSFunction>())
-                    clasp = nullptr;
-                NewEntry::Lookup lookup(clasp, proto, entry.associated);
-                e.rekeyFront(lookup, entry);
-            }
-        }
+    if (!table || !table->initialized())
+        return;
+
+    for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
+        if (IsForwarded(e.front().group.unbarrieredGet()))
+            e.mutableFront().group.set(Forwarded(e.front().group.unbarrieredGet()));
+        if (e.front().associated && IsForwarded(e.front().associated.unbarrieredGet()))
+            e.mutableFront().associated.set(Forwarded(e.front().associated.unbarrieredGet()));
     }
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
 {
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -534,17 +534,16 @@ class ObjectGroup : public gc::TenuredCe
 
 // Structure used to manage the groups in a compartment.
 class ObjectGroupCompartment
 {
     friend class ObjectGroup;
 
     struct NewEntry;
     typedef HashSet<NewEntry, NewEntry, SystemAllocPolicy> NewTable;
-    class NewTableRef;
 
     // Set of default 'new' or lazy groups in the compartment.
     NewTable* defaultNewTable;
     NewTable* lazyTable;
 
     struct ArrayObjectKey;
     typedef HashMap<ArrayObjectKey,
                     ReadBarrieredObjectGroup,
@@ -618,19 +617,16 @@ class ObjectGroupCompartment
 
   private:
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkNewTableAfterMovingGC(NewTable* table);
 #endif
 
     void sweepNewTable(NewTable* table);
     void fixupNewTableAfterMovingGC(NewTable* table);
-
-    static void newTablePostBarrier(ExclusiveContext* cx, NewTable* table,
-                                    const Class* clasp, TaggedProto proto, JSObject* associated);
 };
 
 PlainObject*
 NewPlainObjectWithProperties(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties,
                              NewObjectKind newKind);
 
 bool
 CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj,