Bug 1266552 - Use WeakCache to automatically sweep AllocationSiteTable; r=sfink
--- 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();