Bug 877762 - GC: Post-barrier cycle collector participants - 1 Fixes and updates to JS::Heap<T> r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 18 Jun 2013 11:00:37 +0100
changeset 146943 b2d1e90f21a2cd5108e511e82cf6232891d2d7af
parent 146942 e9e7d8066cb940fd97acd95a494f1d043c1bab57
child 146944 62da92d813c9bb3b0dc297606fd5afbc9eed9832
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs877762
milestone24.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 877762 - GC: Post-barrier cycle collector participants - 1 Fixes and updates to JS::Heap<T> r=terrence
js/public/RootingAPI.h
js/public/Value.h
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -176,28 +176,28 @@ struct JS_PUBLIC_API(NullPtr)
  */
 template <typename T>
 class Heap : public js::HeapBase<T>
 {
   public:
     Heap() {
         MOZ_STATIC_ASSERT(sizeof(T) == sizeof(Heap<T>),
                           "Heap<T> must be binary compatible with T.");
-        set(js::RootMethods<T>::initial());
+        init(js::RootMethods<T>::initial());
     }
-    explicit Heap(T p) { set(p); }
-    explicit Heap(const Heap<T> &p) { set(p.ptr); }
+    explicit Heap(T p) { init(p); }
+    explicit Heap(const Heap<T> &p) { init(p.ptr); }
 
     ~Heap() {
         if (js::RootMethods<T>::needsPostBarrier(ptr))
             relocate();
     }
 
-    bool operator!=(const T &other) { return *ptr != other; }
-    bool operator==(const T &other) { return *ptr == other; }
+    bool operator!=(const T &other) const { return ptr != other; }
+    bool operator==(const T &other) const { return ptr == other; }
 
     operator T() const { return ptr; }
     T operator->() const { return ptr; }
     const T *address() const { return &ptr; }
     const T &get() const { return ptr; }
 
     T *unsafeGet() { return &ptr; }
 
@@ -215,16 +215,23 @@ class Heap : public js::HeapBase<T>
             relocate();  /* Called before overwriting ptr. */
             ptr = newPtr;
         } else {
             ptr = newPtr;
         }
     }
 
   private:
+    void init(T newPtr) {
+        JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr));
+        ptr = newPtr;
+        if (js::RootMethods<T>::needsPostBarrier(ptr))
+            post();
+    }
+
     void post() {
 #ifdef JSGC_GENERATIONAL
         JS_ASSERT(js::RootMethods<T>::needsPostBarrier(ptr));
         js::RootMethods<T>::postBarrier(&ptr);
 #endif
     }
 
     void relocate() {
@@ -315,18 +322,18 @@ class MOZ_NONHEAP_CLASS Handle : public 
 
     /*
      * Return a reference so passing a Handle<T> to something that
      * takes a |const T&| is not a GC hazard.
      */
     operator const T&() const { return get(); }
     T operator->() const { return get(); }
 
-    bool operator!=(const T &other) { return *ptr != other; }
-    bool operator==(const T &other) { return *ptr == other; }
+    bool operator!=(const T &other) const { return *ptr != other; }
+    bool operator==(const T &other) const { return *ptr == other; }
 
   private:
     Handle() {}
 
     const T *ptr;
 
     template <typename S>
     void operator=(S v) MOZ_DELETE;
@@ -600,18 +607,18 @@ class MOZ_STACK_CLASS Rooted : public js
         return ptr;
     }
 
     void set(T value) {
         JS_ASSERT(!js::RootMethods<T>::poisoned(value));
         ptr = value;
     }
 
-    bool operator!=(const T &other) { return ptr != other; }
-    bool operator==(const T &other) { return ptr == other; }
+    bool operator!=(const T &other) const { return ptr != other; }
+    bool operator==(const T &other) const { return ptr == other; }
 
   private:
     void commonInit(Rooted<void*> **thingGCRooters) {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         js::ThingRootKind kind = js::RootMethods<T>::kind();
         this->stack = &thingGCRooters[kind];
         this->prev = *stack;
         *stack = reinterpret_cast<Rooted<void*>*>(this);
@@ -761,18 +768,18 @@ class FakeRooted : public RootedBase<T>
     const T &get() const { return ptr; }
 
     T &operator=(T value) {
         JS_ASSERT(!RootMethods<T>::poisoned(value));
         ptr = value;
         return ptr;
     }
 
-    bool operator!=(const T &other) { return ptr != other; }
-    bool operator==(const T &other) { return ptr == other; }
+    bool operator!=(const T &other) const { return ptr != other; }
+    bool operator==(const T &other) const { return ptr == other; }
 
   private:
     T ptr;
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     FakeRooted(const FakeRooted &) MOZ_DELETE;
 };
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1415,28 +1415,31 @@ template <> struct RootMethods<JS::Value
     static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
     static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); }
 #ifdef JSGC_GENERATIONAL
     static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); }
     static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); }
 #endif
 };
 
+template <class Outer> class UnbarrieredMutableValueOperations;
 template <class Outer> class MutableValueOperations;
 
 /*
  * A class designed for CRTP use in implementing the non-mutating parts of the
  * Value interface in Value-like classes.  Outer must be a class inheriting
  * ValueOperations<Outer> with a visible extract() method returning the
  * const Value* abstracted by Outer.
  */
 template <class Outer>
 class ValueOperations
 {
+    friend class UnbarrieredMutableValueOperations<Outer>;
     friend class MutableValueOperations<Outer>;
+
     const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); }
 
   public:
     bool isUndefined() const { return value()->isUndefined(); }
     bool isNull() const { return value()->isNull(); }
     bool isBoolean() const { return value()->isBoolean(); }
     bool isTrue() const { return value()->isTrue(); }
     bool isFalse() const { return value()->isFalse(); }
@@ -1464,51 +1467,92 @@ class ValueOperations
     void *toGCThing() const { return value()->toGCThing(); }
 
     JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); }
 
     JSWhyMagic whyMagic() const { return value()->whyMagic(); }
 };
 
 /*
- * A class designed for CRTP use in implementing the mutating parts of the
- * Value interface in Value-like classes.  Outer must be a class inheriting
- * MutableValueOperations<Outer> with visible extractMutable() and extract()
- * methods returning the const Value* and Value* abstracted by Outer.
+ * A class designed for CRTP use in implementing the mutating parts of the Value
+ * interface in Value-like classes that don't need post barriers.  Outer must be
+ * a class inheriting UnbarrieredMutableValueOperations<Outer> with visible
+ * extractMutable() and extract() methods returning the const Value* and Value*
+ * abstracted by Outer.
  */
 template <class Outer>
-class MutableValueOperations : public ValueOperations<Outer>
+class UnbarrieredMutableValueOperations : public ValueOperations<Outer>
 {
+    friend class MutableValueOperations<Outer>;
     JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); }
 
   public:
     void setNull() { value()->setNull(); }
     void setUndefined() { value()->setUndefined(); }
     void setInt32(int32_t i) { value()->setInt32(i); }
     void setDouble(double d) { value()->setDouble(d); }
-    void setString(JSString *str) { value()->setString(str); }
-    void setString(const JS::Anchor<JSString *> &str) { value()->setString(str); }
-    void setObject(JSObject &obj) { value()->setObject(obj); }
     void setBoolean(bool b) { value()->setBoolean(b); }
     void setMagic(JSWhyMagic why) { value()->setMagic(why); }
     bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
     bool setNumber(double d) { return value()->setNumber(d); }
-    void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(arg); }
+};
+
+/*
+ * A class designed for CRTP use in implementing all the mutating parts of the
+ * Value interface in Value-like classes.  Outer must be a class inheriting
+ * MutableValueOperations<Outer> with visible extractMutable() and extract()
+ * methods returning the const Value* and Value* abstracted by Outer.
+ */
+template <class Outer>
+class MutableValueOperations : public UnbarrieredMutableValueOperations<Outer>
+{
+  public:
+    void setString(JSString *str) { this->value()->setString(str); }
+    void setString(const JS::Anchor<JSString *> &str) { this->value()->setString(str); }
+    void setObject(JSObject &obj) { this->value()->setObject(obj); }
+    void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); }
 };
 
 /*
- * Augment the generic Heap<T> interface when T = Value with type-querying
- * and value-extracting operations.
+ * Augment the generic Heap<T> interface when T = Value with
+ * type-querying, value-extracting, and mutating operations.
  */
 template <>
-class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
+class HeapBase<JS::Value> : public UnbarrieredMutableValueOperations<JS::Heap<JS::Value> >
 {
-    friend class ValueOperations<JS::Heap<JS::Value> >;
-    const JS::Value * extract() const {
-        return static_cast<const JS::Heap<JS::Value>*>(this)->address();
+    typedef JS::Heap<JS::Value> Outer;
+
+    friend class ValueOperations<Outer>;
+    friend class UnbarrieredMutableValueOperations<Outer>;
+
+    const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); }
+    JS::Value * extractMutable() { return static_cast<Outer*>(this)->unsafeGet(); }
+
+    /*
+     * Setters that potentially change the value to a GC thing from a non-GC
+     * thing must call JS::Heap::set() to trigger the post barrier.
+     *
+     * Changing from a GC thing to a non-GC thing value will leave the heap
+     * value in the store buffer, but it will be ingored so this is not a
+     * problem.
+     */
+    void setBarriered(const JS::Value &v) {
+        static_cast<JS::Heap<JS::Value> *>(this)->set(v);
+    }
+
+  public:
+    void setString(JSString *str) { setBarriered(JS::StringValue(str)); }
+    void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); }
+    void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); }
+
+    void setObjectOrNull(JSObject *arg) {
+        if (arg)
+            setObject(*arg);
+        else
+            setNull();
     }
 };
 
 /*
  * Augment the generic Handle<T> interface when T = Value with type-querying
  * and value-extracting operations.
  */
 template <>
@@ -1527,16 +1571,17 @@ class HandleBase<JS::Value> : public Val
 template <>
 class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
 {
     friend class ValueOperations<JS::MutableHandle<JS::Value> >;
     const JS::Value * extract() const {
         return static_cast<const JS::MutableHandle<JS::Value>*>(this)->address();
     }
 
+    friend class UnbarrieredMutableValueOperations<JS::MutableHandle<JS::Value> >;
     friend class MutableValueOperations<JS::MutableHandle<JS::Value> >;
     JS::Value * extractMutable() {
         return static_cast<JS::MutableHandle<JS::Value>*>(this)->address();
     }
 };
 
 /*
  * Augment the generic Rooted<T> interface when T = Value with type-querying,
@@ -1545,16 +1590,17 @@ class MutableHandleBase<JS::Value> : pub
 template <>
 class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
 {
     friend class ValueOperations<JS::Rooted<JS::Value> >;
     const JS::Value * extract() const {
         return static_cast<const JS::Rooted<JS::Value>*>(this)->address();
     }
 
+    friend class UnbarrieredMutableValueOperations<JS::Rooted<JS::Value> >;
     friend class MutableValueOperations<JS::Rooted<JS::Value> >;
     JS::Value * extractMutable() {
         return static_cast<JS::Rooted<JS::Value>*>(this)->address();
     }
 };
 
 } // namespace js