Bug 912567 - Add post barrier for newTypeObjects r=bhackett
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 24 Sep 2013 10:03:57 +0100
changeset 148426 104bd5bd8154492238c47adb676ed662e378ef9d
parent 148425 58de1d903b6fdbc565e62f692d5c70fa1660939a
child 148427 6d6942eeef1a162aeda1adc9fa01e8e445caa967
push id25343
push userkwierso@gmail.com
push dateWed, 25 Sep 2013 02:43:37 +0000
treeherdermozilla-central@ce5bc913350a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs912567
milestone27.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 912567 - Add post barrier for newTypeObjects r=bhackett
js/src/jsinfer.cpp
js/src/jsinfer.h
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3482,24 +3482,24 @@ JSObject::makeLazyType(JSContext *cx, Ha
     obj->type_ = type;
 
     return type;
 }
 
 /* static */ inline HashNumber
 TypeObjectEntry::hash(const Lookup &lookup)
 {
-    return PointerHasher<JSObject *, 3>::hash(lookup.proto.raw()) ^
+    return PointerHasher<JSObject *, 3>::hash(lookup.hashProto.raw()) ^
            PointerHasher<const Class *, 3>::hash(lookup.clasp);
 }
 
 /* static */ inline bool
 TypeObjectEntry::match(TypeObject *key, const Lookup &lookup)
 {
-    return key->proto == lookup.proto.raw() && key->clasp == lookup.clasp;
+    return key->proto == lookup.matchProto.raw() && key->clasp == lookup.clasp;
 }
 
 #ifdef DEBUG
 bool
 JSObject::hasNewType(const Class *clasp, TypeObject *type)
 {
     TypeObjectSet &table = compartment()->newTypeObjects;
 
@@ -3526,32 +3526,67 @@ JSObject::setNewTypeUnknown(JSContext *c
     if (table.initialized()) {
         if (TypeObjectSet::Ptr p = table.lookup(TypeObjectSet::Lookup(clasp, obj.get())))
             MarkTypeObjectUnknownProperties(cx, *p);
     }
 
     return true;
 }
 
+#ifdef JSGC_GENERATIONAL
+/*
+ * This class is used to add a post barrier on the newTypeObjects set, as the
+ * key is calculated from a prototype object which may be moved by generational
+ * GC.
+ */
+class NewTypeObjectsSetRef : public BufferableRef
+{
+    TypeObjectSet *set;
+    TypeObject    *typeObject;
+    JSObject      *proto;
+
+  public:
+    NewTypeObjectsSetRef(TypeObjectSet *s, TypeObject *t, JSObject *p)
+      : set(s), typeObject(t), proto(p) {}
+
+    void mark(JSTracer *trc) {
+        const Class *clasp = typeObject->clasp;
+        JSObject *prior = proto;
+        JS_SET_TRACING_LOCATION(trc, (void*)&*prior);
+        Mark(trc, &proto, "newTypeObjects set prototype");
+        if (prior == proto)
+            return;
+
+        TypeObjectSet::Ptr p = set->lookup(TypeObjectSet::Lookup(clasp, prior, proto));
+        JS_ASSERT(p);  // newTypeObjects set must still contain original entry.
+
+        set->rekeyAs(TypeObjectSet::Lookup(clasp, prior, proto),
+                     TypeObjectSet::Lookup(clasp, proto), typeObject);
+    }
+};
+#endif
+
 TypeObject *
 ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto_, JSFunction *fun_)
 {
     JS_ASSERT_IF(fun_, proto_.isObject());
     JS_ASSERT_IF(proto_.isObject(), isInsideCurrentCompartment(proto_.toObject()));
 
     TypeObjectSet &newTypeObjects = compartment_->newTypeObjects;
 
     if (!newTypeObjects.initialized() && !newTypeObjects.init())
         return NULL;
 
     TypeObjectSet::AddPtr p = newTypeObjects.lookupForAdd(TypeObjectSet::Lookup(clasp, proto_));
     SkipRoot skipHash(this, &p); /* Prevent the hash from being poisoned. */
     uint64_t originalGcNumber = gcNumber();
     if (p) {
         TypeObject *type = *p;
+        JS_ASSERT(type->clasp == clasp);
+        JS_ASSERT(type->proto.get() == proto_.raw());
 
         /*
          * If set, the type's newScript indicates the script used to create
          * all objects in existence which have this type. If there are objects
          * in existence which are not created by calling 'new' on newScript,
          * we must clear the new script information from the type and will not
          * be able to assume any definite properties for instances of the type.
          * This case is rare, but can happen if, for example, two scripted
@@ -3586,16 +3621,23 @@ ExclusiveContext::getNewType(const Class
      */
     bool gcHappened = gcNumber() != originalGcNumber;
     bool added =
         gcHappened ? newTypeObjects.putNew(TypeObjectSet::Lookup(clasp, proto), type.get())
                    : newTypeObjects.relookupOrAdd(p, TypeObjectSet::Lookup(clasp, proto), type.get());
     if (!added)
         return NULL;
 
+#ifdef JSGC_GENERATIONAL
+    if (proto.isObject() && hasNursery() && nursery().isInside(proto.toObject())) {
+        asJSContext()->runtime()->gcStoreBuffer.putGeneric(
+            NewTypeObjectsSetRef(&newTypeObjects, type.get(), proto.toObject()));
+    }
+#endif
+
     if (!typeInferenceEnabled())
         return type;
 
     AutoEnterAnalysis enter(this);
 
     /*
      * Set the special equality flag for types whose prototype also has the
      * flag set. This is a hack, :XXX: need a real correspondence between
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1201,19 +1201,30 @@ struct TypeObject : gc::BarrieredCell<Ty
 /*
  * Entries for the per-compartment set of type objects which are the default
  * 'new' or the lazy types of some prototype.
  */
 struct TypeObjectEntry : DefaultHasher<ReadBarriered<TypeObject> >
 {
     struct Lookup {
         const Class *clasp;
-        TaggedProto proto;
+        TaggedProto hashProto;
+        TaggedProto matchProto;
+
+        Lookup(const Class *clasp, TaggedProto proto)
+          : clasp(clasp), hashProto(proto), matchProto(proto) {}
 
-        Lookup(const Class *clasp, TaggedProto proto) : clasp(clasp), proto(proto) {}
+#ifdef JSGC_GENERATIONAL
+        /*
+         * 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)
+          : clasp(clasp), hashProto(hashProto), matchProto(matchProto) {}
+#endif
     };
 
     static inline HashNumber hash(const Lookup &lookup);
     static inline bool match(TypeObject *key, const Lookup &lookup);
 };
 typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
 
 /* Whether to use a new type object when calling 'new' at script/pc. */