Bug 1281168 - Make hashing ObjectGroupCompartment::NewEntry fallible r=terrence a=sylvestre FIREFOX_49_0b3_BUILD1 FIREFOX_49_0b3_RELEASE
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 02 Aug 2016 10:26:25 +0100
changeset 340281 36af692196a1c92cc935cf6569e03fdf5dc5e426
parent 340280 971a19e5b78efd339687430321f42e1aa81b8062
child 340282 06619fe6e5052edaf48b94518f52e7cce35d0938
push id6285
push userjcoppeard@mozilla.com
push dateThu, 11 Aug 2016 10:16:31 +0000
treeherdermozilla-beta@36af692196a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence, sylvestre
bugs1281168
milestone49.0
Bug 1281168 - Make hashing ObjectGroupCompartment::NewEntry fallible r=terrence a=sylvestre
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
js/src/vm/TaggedProto.cpp
js/src/vm/TaggedProto.h
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -373,50 +373,91 @@ struct ObjectGroupCompartment::NewEntry
     JSObject* associated;
 
     NewEntry(ObjectGroup* group, JSObject* associated)
       : group(group), associated(associated)
     {}
 
     struct Lookup {
         const Class* clasp;
-        uint64_t protoUID;
-        uint64_t assocUID;
+        TaggedProto proto;
+        JSObject* associated;
 
         Lookup(const Class* clasp, TaggedProto proto, JSObject* associated)
-          : clasp(clasp),
-            protoUID(proto.uniqueId()),
-            assocUID(associated ? associated->zone()->getUniqueIdInfallible(associated) : 0)
+          : clasp(clasp), proto(proto), associated(associated)
         {}
+
+        bool hasAssocId() const {
+            return !associated || associated->zone()->hasUniqueId(associated);
+        }
+
+        bool ensureAssocId() const {
+            uint64_t unusedId;
+            return !associated ||
+                   associated->zoneFromAnyThread()->getUniqueId(associated, &unusedId);
+        }
+
+        uint64_t getAssocId() const {
+            return associated ? associated->zone()->getUniqueIdInfallible(associated) : 0;
+        }
     };
 
+    static bool hasHash(const Lookup& l) {
+        return l.proto.hasUniqueId() && l.hasAssocId();
+    }
+
+    static bool ensureHash(const Lookup& l) {
+        return l.proto.ensureUniqueId() && l.ensureAssocId();
+    }
+
     static inline HashNumber hash(const Lookup& lookup) {
+        MOZ_ASSERT(lookup.proto.hasUniqueId());
+        MOZ_ASSERT(lookup.hasAssocId());
         HashNumber hash = uintptr_t(lookup.clasp);
-        hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.protoUID);
-        hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.assocUID);
+        hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.proto.uniqueId());
+        hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.getAssocId());
         return hash;
     }
 
-    static inline bool match(const NewEntry& key, const Lookup& lookup) {
+    static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) {
+        TaggedProto proto = key.group.unbarrieredGet()->proto().unbarrieredGet();
+        JSObject* assoc = key.associated;
+        MOZ_ASSERT(proto.hasUniqueId());
+        MOZ_ASSERT_IF(assoc, assoc->zone()->hasUniqueId(assoc));
+        MOZ_ASSERT(lookup.proto.hasUniqueId());
+        MOZ_ASSERT(lookup.hasAssocId());
+
         if (lookup.clasp && key.group.unbarrieredGet()->clasp() != lookup.clasp)
             return false;
-        if (key.group.unbarrieredGet()->proto().unbarrieredGet().uniqueId() != lookup.protoUID)
+        if (proto.uniqueId() != lookup.proto.uniqueId())
             return false;
-        return !key.associated ||
-               key.associated->zone()->getUniqueIdInfallible(key.associated) == lookup.assocUID;
+        return !assoc || assoc->zone()->getUniqueIdInfallible(assoc) == lookup.getAssocId();
     }
 
     static void rekey(NewEntry& k, const NewEntry& newKey) { k = newKey; }
 
     bool needsSweep() {
         return (IsAboutToBeFinalized(&group) ||
                 (associated && IsAboutToBeFinalizedUnbarriered(&associated)));
     }
 };
 
+namespace js {
+template <>
+struct FallibleHashMethods<ObjectGroupCompartment::NewEntry>
+{
+    template <typename Lookup> static bool hasHash(Lookup&& l) {
+        return ObjectGroupCompartment::NewEntry::hasHash(mozilla::Forward<Lookup>(l));
+    }
+    template <typename Lookup> static bool ensureHash(Lookup&& l) {
+        return ObjectGroupCompartment::NewEntry::ensureHash(mozilla::Forward<Lookup>(l));
+    }
+};
+} // namespace js
+
 class ObjectGroupCompartment::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry,
                                                                             SystemAllocPolicy>>
 {
     using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>;
     using Base = JS::WeakCache<Table>;
 
   public:
     explicit NewTable(Zone* zone) : Base(zone, Table()) {}
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -537,17 +537,16 @@ class ObjectGroup : public gc::TenuredCe
     static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
 };
 
 // Structure used to manage the groups in a compartment.
 class ObjectGroupCompartment
 {
     friend class ObjectGroup;
 
-    struct NewEntry;
     class NewTable;
 
     // Set of default 'new' or lazy groups in the compartment.
     NewTable* defaultNewTable;
     NewTable* lazyTable;
 
     struct ArrayObjectKey;
     using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
@@ -580,16 +579,18 @@ class ObjectGroupCompartment
 
     struct AllocationSiteKey;
     class AllocationSiteTable;
 
     // Table for referencing types of objects keyed to an allocation site.
     AllocationSiteTable* allocationSiteTable;
 
   public:
+    struct NewEntry;
+
     ObjectGroupCompartment();
     ~ObjectGroupCompartment();
 
     void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                     JSProtoKey kind, ObjectGroup* group);
 
     void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated);
     void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated,
--- a/js/src/vm/TaggedProto.cpp
+++ b/js/src/vm/TaggedProto.cpp
@@ -41,16 +41,35 @@ InternalBarrierMethods<TaggedProto>::rea
 } // namespace js
 
 js::HashNumber
 js::TaggedProto::hashCode() const
 {
     return Zone::UniqueIdToHash(uniqueId());
 }
 
+bool
+js::TaggedProto::hasUniqueId() const
+{
+    if (!isObject())
+        return true;
+    JSObject* obj = toObject();
+    return obj->zone()->hasUniqueId(obj);
+}
+
+bool
+js::TaggedProto::ensureUniqueId() const
+{
+    if (!isObject())
+        return true;
+    uint64_t unusedId;
+    JSObject* obj = toObject();
+    return obj->zone()->getUniqueId(obj, &unusedId);
+}
+
 uint64_t
 js::TaggedProto::uniqueId() const
 {
     if (isDynamic())
         return uint64_t(1);
     JSObject* obj = toObjectOrNull();
     if (!obj)
         return uint64_t(0);
--- a/js/src/vm/TaggedProto.h
+++ b/js/src/vm/TaggedProto.h
@@ -40,16 +40,19 @@ class TaggedProto
         return proto;
     }
     JSObject* raw() const { return proto; }
 
     bool operator ==(const TaggedProto& other) const { return proto == other.proto; }
     bool operator !=(const TaggedProto& other) const { return proto != other.proto; }
 
     HashNumber hashCode() const;
+
+    bool hasUniqueId() const;
+    bool ensureUniqueId() const;
     uint64_t uniqueId() const;
 
     void trace(JSTracer* trc) {
         if (isObject())
             TraceManuallyBarrieredEdge(trc, &proto, "TaggedProto");
     }
 
   private: