Bug 1224050 - Use stable hashing for the IntialShapesTable; r=jonco

--HG--
extra : rebase_source : bb234ac7eac0503f8d7dec84ea8cf02894b3edf2
This commit is contained in:
Terrence Cole 2016-03-10 08:57:01 -08:00
Родитель 7b557b47a9
Коммит bd531e5bce
4 изменённых файлов: 26 добавлений и 83 удалений

Просмотреть файл

@ -1349,12 +1349,13 @@ BaseShape::finalize(FreeOp* fop)
} }
inline inline
InitialShapeEntry::InitialShapeEntry() : shape(nullptr), proto(nullptr) InitialShapeEntry::InitialShapeEntry() : shape(nullptr), proto(TaggedProto(nullptr))
{ {
} }
inline inline
InitialShapeEntry::InitialShapeEntry(const ReadBarrieredShape& shape, TaggedProto proto) InitialShapeEntry::InitialShapeEntry(const ReadBarriered<Shape*>& shape,
const ReadBarriered<TaggedProto>& proto)
: shape(shape), proto(proto) : shape(shape), proto(proto)
{ {
} }
@ -1368,73 +1369,20 @@ InitialShapeEntry::getLookup() const
/* static */ inline HashNumber /* static */ inline HashNumber
InitialShapeEntry::hash(const Lookup& lookup) InitialShapeEntry::hash(const Lookup& lookup)
{ {
HashNumber hash = uintptr_t(lookup.clasp) >> 3; return (RotateLeft(uintptr_t(lookup.clasp) >> 3, 4) ^ lookup.proto.hashCode()) +
hash = RotateLeft(hash, 4) ^ lookup.nfixed;
(uintptr_t(lookup.hashProto.toWord()) >> 3);
return hash + lookup.nfixed;
} }
/* static */ inline bool /* static */ inline bool
InitialShapeEntry::match(const InitialShapeEntry& key, const Lookup& lookup) InitialShapeEntry::match(const InitialShapeEntry& key, const Lookup& lookup)
{ {
const Shape* shape = *key.shape.unsafeGet(); const Shape* shape = key.shape.unbarrieredGet();
return lookup.clasp == shape->getObjectClass() return lookup.clasp == shape->getObjectClass()
&& lookup.matchProto.toWord() == key.proto.toWord()
&& lookup.nfixed == shape->numFixedSlots() && lookup.nfixed == shape->numFixedSlots()
&& lookup.baseFlags == shape->getObjectFlags(); && lookup.baseFlags == shape->getObjectFlags()
&& lookup.proto.uniqueId() == key.proto.unbarrieredGet().uniqueId();
} }
/*
* This class is used to add a post barrier on the initialShapes set, as the key
* is calculated based on objects which may be moved by generational GC.
*/
class InitialShapeSetRef : public BufferableRef
{
InitialShapeSet* set;
const Class* clasp;
TaggedProto proto;
size_t nfixed;
uint32_t objectFlags;
public:
InitialShapeSetRef(InitialShapeSet* set,
const Class* clasp,
TaggedProto proto,
size_t nfixed,
uint32_t objectFlags)
: set(set),
clasp(clasp),
proto(proto),
nfixed(nfixed),
objectFlags(objectFlags)
{}
void trace(JSTracer* trc) override {
TaggedProto priorProto = proto;
if (proto.isObject()) {
TraceManuallyBarrieredEdge(trc, reinterpret_cast<JSObject**>(&proto),
"initialShapes set proto");
}
if (proto == priorProto)
return;
/* Find the original entry, which must still be present. */
InitialShapeEntry::Lookup lookup(clasp, priorProto, nfixed, objectFlags);
InitialShapeSet::Ptr p = set->lookup(lookup);
MOZ_ASSERT(p);
/* Update the entry's possibly-moved proto, and ensure lookup will still match. */
InitialShapeEntry& entry = const_cast<InitialShapeEntry&>(*p);
entry.proto = proto;
lookup.matchProto = proto;
/* Rekey the entry. */
set->rekeyAs(lookup,
InitialShapeEntry::Lookup(clasp, proto, nfixed, objectFlags),
*p);
}
};
#ifdef JSGC_HASH_TABLE_CHECKS #ifdef JSGC_HASH_TABLE_CHECKS
void void
@ -1450,7 +1398,7 @@ JSCompartment::checkInitialShapesTableAfterMovingGC()
*/ */
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) { for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
InitialShapeEntry entry = e.front(); InitialShapeEntry entry = e.front();
TaggedProto proto = entry.proto; TaggedProto proto = entry.proto.unbarrieredGet();
Shape* shape = entry.shape.unbarrieredGet(); Shape* shape = entry.shape.unbarrieredGet();
if (proto.isObject()) if (proto.isObject())
@ -1511,15 +1459,9 @@ EmptyShape::getInitialShape(ExclusiveContext* cx, const Class* clasp, TaggedProt
return nullptr; return nullptr;
Lookup lookup(clasp, protoRoot, nfixed, objectFlags); Lookup lookup(clasp, protoRoot, nfixed, objectFlags);
if (!p.add(cx, table, lookup, InitialShapeEntry(ReadBarrieredShape(shape), protoRoot))) if (!p.add(cx, table, lookup, InitialShapeEntry(shape, protoRoot.get()))) {
ReportOutOfMemory(cx);
return nullptr; return nullptr;
// Post-barrier for the initial shape table update.
if (cx->isJSContext()) {
if (protoRoot.isObject() && IsInsideNursery(protoRoot.toObject())) {
InitialShapeSetRef ref(&table, clasp, protoRoot, nfixed, objectFlags);
cx->asJSContext()->runtime()->gc.storeBuffer.putGeneric(ref);
}
} }
return shape; return shape;

Просмотреть файл

@ -1079,31 +1079,29 @@ struct InitialShapeEntry
* certain classes (e.g. String, RegExp) which may add certain baked-in * certain classes (e.g. String, RegExp) which may add certain baked-in
* properties. * properties.
*/ */
ReadBarrieredShape shape; ReadBarriered<Shape*> shape;
/* /*
* Matching prototype for the entry. The shape of an object determines its * Matching prototype for the entry. The shape of an object determines its
* prototype, but the prototype cannot be determined from the shape itself. * prototype, but the prototype cannot be determined from the shape itself.
*/ */
TaggedProto proto; ReadBarriered<TaggedProto> proto;
/* State used to determine a match on an initial shape. */ /* State used to determine a match on an initial shape. */
struct Lookup { struct Lookup {
const Class* clasp; const Class* clasp;
TaggedProto hashProto; TaggedProto proto;
TaggedProto matchProto;
uint32_t nfixed; uint32_t nfixed;
uint32_t baseFlags; uint32_t baseFlags;
Lookup(const Class* clasp, TaggedProto proto, uint32_t nfixed, uint32_t baseFlags) Lookup(const Class* clasp, TaggedProto proto, uint32_t nfixed, uint32_t baseFlags)
: clasp(clasp), : clasp(clasp), proto(proto), nfixed(nfixed), baseFlags(baseFlags)
hashProto(proto), matchProto(proto),
nfixed(nfixed), baseFlags(baseFlags)
{} {}
}; };
inline InitialShapeEntry(); inline InitialShapeEntry();
inline InitialShapeEntry(const ReadBarrieredShape& shape, TaggedProto proto); inline InitialShapeEntry(const ReadBarriered<Shape*>& shape,
const ReadBarriered<TaggedProto>& proto);
inline Lookup getLookup() const; inline Lookup getLookup() const;

Просмотреть файл

@ -30,17 +30,18 @@ InternalBarrierMethods<TaggedProto>::postBarrier(TaggedProto* vp, TaggedProto pr
nextObj); nextObj);
} }
/* static */ void
InternalBarrierMethods<TaggedProto>::readBarrier(const TaggedProto& proto)
{
InternalBarrierMethods<JSObject*>::readBarrier(proto.toObjectOrNull());
}
} // namespace js } // namespace js
js::HashNumber js::HashNumber
js::TaggedProto::hashCode() const js::TaggedProto::hashCode() const
{ {
if (isLazy()) return Zone::UniqueIdToHash(uniqueId());
return HashNumber(1);
JSObject* obj = toObjectOrNull();
if (!obj)
return HashNumber(0);
return obj->zone()->getHashCodeInfallible(obj);
} }
uint64_t uint64_t

Просмотреть файл

@ -63,6 +63,8 @@ struct InternalBarrierMethods<TaggedProto>
static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next); static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
static void readBarrier(const TaggedProto& proto);
static bool isMarkableTaggedPointer(TaggedProto proto) { static bool isMarkableTaggedPointer(TaggedProto proto) {
return proto.isObject(); return proto.isObject();
} }