Bug 1266552 - Use WeakCache to automatically sweep AllocationSiteTable; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Mon, 16 May 2016 15:08:18 -0700
changeset 374045 7195c2ccf18841f933bca6c6b825c4ceaafbf0d1
parent 374044 d9111a0d9a446c8c67eac75af4724b173e28ea01
child 374046 8a447cb4a8368283196efcf175bc77bf9aa27cb1
child 374053 622c7afef4ae38f9489e2269ebb3c61528edb5b5
child 374475 1fc5969348c9374b68f80f601692e3f10ece2c5a
child 374506 d9b3b1ddf10de64ede72b354c0692f871962d83c
child 380124 44d1d310745d9686e5b019b92d444809aa67bb6b
child 380817 309128b2a918c251e27d2d7ca0f3530790af54ac
push id19909
push userbmo:bennyjr169@gmail.com
push dateWed, 01 Jun 2016 18:15:58 +0000
reviewerssfink
bugs1266552
milestone49.0a1
Bug 1266552 - Use WeakCache to automatically sweep AllocationSiteTable; r=sfink
js/public/GCHashTable.h
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
--- a/js/public/GCHashTable.h
+++ b/js/public/GCHashTable.h
@@ -134,23 +134,23 @@ class GCRekeyableHashMap : public JS::GC
     }
 };
 
 template <typename Outer, typename... Args>
 class GCHashMapOperations
 {
     using Map = JS::GCHashMap<Args...>;
     using Lookup = typename Map::Lookup;
-    using Ptr = typename Map::Ptr;
-    using Range = typename Map::Range;
 
     const Map& map() const { return static_cast<const Outer*>(this)->get(); }
 
   public:
     using AddPtr = typename Map::AddPtr;
+    using Ptr = typename Map::Ptr;
+    using Range = typename Map::Range;
 
     bool initialized() const                   { return map().initialized(); }
     Ptr lookup(const Lookup& l) const          { return map().lookup(l); }
     AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); }
     Range all() const                          { return map().all(); }
     bool empty() const                         { return map().empty(); }
     uint32_t count() const                     { return map().count(); }
     size_t capacity() const                    { return map().capacity(); }
@@ -164,24 +164,24 @@ class GCHashMapOperations
 };
 
 template <typename Outer, typename... Args>
 class MutableGCHashMapOperations
   : public GCHashMapOperations<Outer, Args...>
 {
     using Map = JS::GCHashMap<Args...>;
     using Lookup = typename Map::Lookup;
-    using Ptr = typename Map::Ptr;
-    using Range = typename Map::Range;
 
     Map& map() { return static_cast<Outer*>(this)->get(); }
 
   public:
     using AddPtr = typename Map::AddPtr;
     struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} };
+    using Ptr = typename Map::Ptr;
+    using Range = typename Map::Range;
 
     bool init(uint32_t len = 16) { return map().init(len); }
     void clear()                 { map().clear(); }
     void finish()                { map().finish(); }
     void remove(Ptr p)           { map().remove(p); }
 
     template<typename KeyInput, typename ValueInput>
     bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
@@ -292,24 +292,24 @@ class GCHashSet : public js::HashSet<T, 
 
 namespace js {
 
 template <typename Outer, typename... Args>
 class GCHashSetOperations
 {
     using Set = JS::GCHashSet<Args...>;
     using Lookup = typename Set::Lookup;
-    using Ptr = typename Set::Ptr;
-    using Range = typename Set::Range;
 
     const Set& set() const { return static_cast<const Outer*>(this)->get(); }
 
   public:
     using AddPtr = typename Set::AddPtr;
     using Entry = typename Set::Entry;
+    using Ptr = typename Set::Ptr;
+    using Range = typename Set::Range;
 
     bool initialized() const                   { return set().initialized(); }
     Ptr lookup(const Lookup& l) const          { return set().lookup(l); }
     AddPtr lookupForAdd(const Lookup& l) const { return set().lookupForAdd(l); }
     Range all() const                          { return set().all(); }
     bool empty() const                         { return set().empty(); }
     uint32_t count() const                     { return set().count(); }
     size_t capacity() const                    { return set().capacity(); }
@@ -323,25 +323,25 @@ class GCHashSetOperations
 };
 
 template <typename Outer, typename... Args>
 class MutableGCHashSetOperations
   : public GCHashSetOperations<Outer, Args...>
 {
     using Set = JS::GCHashSet<Args...>;
     using Lookup = typename Set::Lookup;
-    using Ptr = typename Set::Ptr;
-    using Range = typename Set::Range;
 
     Set& set() { return static_cast<Outer*>(this)->get(); }
 
   public:
     using AddPtr = typename Set::AddPtr;
     using Entry = typename Set::Entry;
     struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} };
+    using Ptr = typename Set::Ptr;
+    using Range = typename Set::Range;
 
     bool init(uint32_t len = 16) { return set().init(len); }
     void clear()                 { set().clear(); }
     void finish()                { set().finish(); }
     void remove(Ptr p)           { set().remove(p); }
     void remove(const Lookup& l) { set().remove(l); }
 
     template<typename TInput>
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1393,16 +1393,28 @@ struct ObjectGroupCompartment::Allocatio
     }
 
     bool needsSweep() {
         return IsAboutToBeFinalizedUnbarriered(script.unsafeGet()) ||
             (proto && IsAboutToBeFinalizedUnbarriered(proto.unsafeGet()));
     }
 };
 
+class ObjectGroupCompartment::AllocationSiteTable
+  : public JS::WeakCache<js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
+                                       AllocationSiteKey, SystemAllocPolicy>>
+{
+    using Table = js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
+                                AllocationSiteKey, SystemAllocPolicy>;
+    using Base = JS::WeakCache<Table>;
+
+  public:
+    explicit AllocationSiteTable(Zone* zone) : Base(zone, Table()) {}
+};
+
 /* static */ ObjectGroup*
 ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* pc,
                                  JSProtoKey kind, HandleObject protoArg /* = nullptr */)
 {
     MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
     MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
 
     uint32_t offset = scriptArg->pcToOffset(pc);
@@ -1412,17 +1424,17 @@ ObjectGroup::allocationSiteGroup(JSConte
             return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg));
         return defaultNewGroup(cx, kind);
     }
 
     ObjectGroupCompartment::AllocationSiteTable*& table =
         cx->compartment()->objectGroups.allocationSiteTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>();
+        table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>(cx->zone());
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
@@ -1483,17 +1495,17 @@ ObjectGroup::allocationSiteGroup(JSConte
 void
 ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                                    JSProtoKey kind, ObjectGroup* group)
 {
     AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
 
     AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
     MOZ_RELEASE_ASSERT(p);
-    allocationSiteTable->remove(p);
+    allocationSiteTable->get().remove(p);
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!allocationSiteTable->putNew(key, group))
             oomUnsafe.crash("Inconsistent object table");
     }
 }
 
 /* static */ ObjectGroup*
@@ -1744,18 +1756,16 @@ ObjectGroupCompartment::sweep(FreeOp* fo
      * Iterate through the array/object group tables and remove all entries
      * referencing collected data. These tables only hold weak references.
      */
 
     if (arrayObjectTable)
         arrayObjectTable->sweep();
     if (plainObjectTable)
         plainObjectTable->sweep();
-    if (allocationSiteTable)
-        allocationSiteTable->sweep();
 }
 
 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().
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -574,20 +574,17 @@ class ObjectGroupCompartment
     // All singleton/JSON arrays which have the same prototype, are homogenous
     // and of the same element type will share a group. All singleton/JSON
     // objects which have the same shape and property types will also share a
     // group. We don't try to collate arrays or objects with type mismatches.
     ArrayObjectTable* arrayObjectTable;
     PlainObjectTable* plainObjectTable;
 
     struct AllocationSiteKey;
-    using AllocationSiteTable = JS::GCHashMap<AllocationSiteKey,
-                                              ReadBarrieredObjectGroup,
-                                              AllocationSiteKey,
-                                              SystemAllocPolicy>;
+    class AllocationSiteTable;
 
     // Table for referencing types of objects keyed to an allocation site.
     AllocationSiteTable* allocationSiteTable;
 
   public:
     ObjectGroupCompartment();
     ~ObjectGroupCompartment();