Bug 744579 - Implement a relocatable version of HeapPtr; r=billm
authorTerrence Cole <terrence@mozilla.com>
Tue, 15 May 2012 17:21:23 -0700
changeset 98477 21c6e51e2cb73a70f7ea85121d8e0cda0762aef7
parent 98476 b292b2847b7f1de280c57384a2426dd0e25455b3
child 98478 b03d90c2504efef092671d3e3f36ff411e8fa8f8
push idunknown
push userunknown
push dateunknown
reviewersbillm
bugs744579
milestone15.0a1
Bug 744579 - Implement a relocatable version of HeapPtr; r=billm We cannot store HeapPtrs in memory that may be realloced outside of the GC. Instead we should use the RelocatablePtr, which is more expensive, but is able to handle being moved, or EncapsulatedPtr which requires external barriers.
js/public/TemplateLib.h
js/public/Vector.h
js/src/gc/Barrier.h
--- a/js/public/TemplateLib.h
+++ b/js/public/TemplateLib.h
@@ -172,14 +172,14 @@ template <> struct IsPodType<wchar_t>   
 template <typename T> struct IsPodType<T *>         { static const bool result = true; };
 
 template <bool cond, typename T, T v1, T v2> struct If        { static const T result = v1; };
 template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; };
 
 /*
  * Traits class for identifying types that are implicitly barriered.
  */
-template <class T> struct IsPostBarrieredType { static const bool result = false; };
+template <class T> struct IsRelocatableHeapType { static const bool result = true; };
 
 } /* namespace tl */
 } /* namespace js */
 
 #endif  /* js_template_lib_h__ */
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -208,17 +208,17 @@ struct VectorImpl<T, N, AP, true>
  *  - see "Allocation policies" in jsalloc.h (default js::TempAllocPolicy)
  *
  * N.B: Vector is not reentrant: T member functions called during Vector member
  *      functions must not call back into the same object.
  */
 template <class T, size_t N, class AllocPolicy>
 class Vector : private AllocPolicy
 {
-    typedef typename tl::StaticAssert<!tl::IsPostBarrieredType<T>::result>::result _;
+    typedef typename tl::StaticAssert<tl::IsRelocatableHeapType<T>::result>::result _;
 
     /* utilities */
 
     static const bool sElemIsPod = tl::IsPodType<T>::result;
     typedef VectorImpl<T, N, AllocPolicy, sElemIsPod> Impl;
     friend struct VectorImpl<T, N, AllocPolicy, sElemIsPod>;
 
     bool calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap);
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -146,88 +146,149 @@
  * assigned for the first time.
  */
 
 struct JSXML;
 
 namespace js {
 
 template<class T, typename Unioned = uintptr_t>
-class HeapPtr
+class EncapsulatedPtr
 {
+  protected:
     union {
         T *value;
         Unioned other;
     };
 
   public:
-    HeapPtr() : value(NULL) {}
-    explicit HeapPtr(T *v) : value(v) { post(); }
-    explicit HeapPtr(const HeapPtr<T> &v) : value(v.value) { post(); }
-
-    ~HeapPtr() { pre(); }
+    EncapsulatedPtr() : value(NULL) {}
+    explicit EncapsulatedPtr(T *v) : value(v) {}
+    explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
 
-    /* Use this to install a ptr into a newly allocated object. */
-    void init(T *v) {
-        JS_ASSERT(!IsPoisonedPtr<T>(v));
-        value = v;
-        post();
-    }
+    ~EncapsulatedPtr() { pre(); }
 
     /* Use to set the pointer to NULL. */
     void clear() {
-	pre();
-	value = NULL;
+        pre();
+        value = NULL;
+    }
+
+    EncapsulatedPtr<T, Unioned> &operator=(T *v) {
+        pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v));
+        value = v;
+        return *this;
+    }
+
+    EncapsulatedPtr<T, Unioned> &operator=(const EncapsulatedPtr<T> &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v.value));
+        value = v.value;
+        return *this;
     }
 
     /* Use this if the automatic coercion to T* isn't working. */
     T *get() const { return value; }
 
     /*
      * Use these if you want to change the value without invoking the barrier.
      * Obviously this is dangerous unless you know the barrier is not needed.
      */
     T **unsafeGet() { return &value; }
     void unsafeSet(T *v) { value = v; }
 
     Unioned *unsafeGetUnioned() { return &other; }
 
+    T &operator*() const { return *value; }
+    T *operator->() const { return value; }
+
+    operator T*() const { return value; }
+
+  protected:
+    void pre() { T::writeBarrierPre(value); }
+};
+
+template <class T, class Unioned = uintptr_t>
+class HeapPtr : public EncapsulatedPtr<T, Unioned>
+{
+  public:
+    HeapPtr() : EncapsulatedPtr<T>(NULL) {}
+    explicit HeapPtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
+    explicit HeapPtr(const HeapPtr<T> &v)
+      : EncapsulatedPtr<T>(v) { post(); }
+
+    void init(T *v) {
+        JS_ASSERT(!IsPoisonedPtr<T>(v));
+        this->value = v;
+        post();
+    }
+
     HeapPtr<T, Unioned> &operator=(T *v) {
-        pre();
+        this->pre();
         JS_ASSERT(!IsPoisonedPtr<T>(v));
-        value = v;
+        this->value = v;
         post();
         return *this;
     }
 
     HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
-        pre();
+        this->pre();
         JS_ASSERT(!IsPoisonedPtr<T>(v.value));
-        value = v.value;
+        this->value = v.value;
         post();
         return *this;
     }
 
-    T &operator*() const { return *value; }
-    T *operator->() const { return value; }
-
-    operator T*() const { return value; }
-
-  private:
-    void pre() { T::writeBarrierPre(value); }
-    void post() { T::writeBarrierPost(value, (void *)&value); }
+  protected:
+    void post() { T::writeBarrierPost(this->value, (void *)&this->value); }
 
     /* Make this friend so it can access pre() and post(). */
     template<class T1, class T2>
     friend inline void
     BarrieredSetPair(JSCompartment *comp,
                      HeapPtr<T1> &v1, T1 *val1,
                      HeapPtr<T2> &v2, T2 *val2);
 };
 
+template <class T>
+class RelocatablePtr : public EncapsulatedPtr<T>
+{
+  public:
+    RelocatablePtr() : EncapsulatedPtr<T>(NULL) {}
+    explicit RelocatablePtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
+    explicit RelocatablePtr(const RelocatablePtr<T> &v)
+      : EncapsulatedPtr<T>(v) { post(); }
+
+    ~RelocatablePtr() {
+        this->pre();
+        relocate();
+    }
+
+    RelocatablePtr<T> &operator=(T *v) {
+        this->pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v));
+        this->value = v;
+        post();
+        return *this;
+    }
+
+    RelocatablePtr<T> &operator=(const RelocatablePtr<T> &v) {
+        this->pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v.value));
+        this->value = v.value;
+        post();
+        return *this;
+    }
+
+  protected:
+    void post() { T::writeBarrierRelocPost(this->value, (void *)&this->value); }
+    void relocate() { T::writeBarrierRelocated(this->value, (void *)&this->value); }
+};
+
 /*
  * This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
  * barriers with only one branch to check if we're in an incremental GC.
  */
 template<class T1, class T2>
 static inline void
 BarrieredSetPair(JSCompartment *comp,
                  HeapPtr<T1> &v1, T1 *val1,
@@ -242,16 +303,19 @@ BarrieredSetPair(JSCompartment *comp,
     v1.post();
     v2.post();
 }
 
 struct Shape;
 class BaseShape;
 namespace types { struct TypeObject; }
 
+typedef RelocatablePtr<JSObject> RelocatablePtrObject;
+typedef RelocatablePtr<JSScript> RelocatablePtrScript;
+
 typedef HeapPtr<JSObject> HeapPtrObject;
 typedef HeapPtr<JSFunction> HeapPtrFunction;
 typedef HeapPtr<JSString> HeapPtrString;
 typedef HeapPtr<JSScript> HeapPtrScript;
 typedef HeapPtr<Shape> HeapPtrShape;
 typedef HeapPtr<BaseShape> HeapPtrBaseShape;
 typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
 typedef HeapPtr<JSXML> HeapPtrXML;
@@ -264,17 +328,17 @@ struct HeapPtrHasher
     typedef T *Lookup;
 
     static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
     static bool match(const Key &k, Lookup l) { return k.get() == l; }
 };
 
 /* Specialized hashing policy for HeapPtrs. */
 template <class T>
-struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { };
+struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
 
 class EncapsulatedValue
 {
   protected:
     Value value;
 
     /*
      * Ensure that EncapsulatedValue is not constructable, except by our
@@ -371,19 +435,16 @@ class RelocatableValue : public Encapsul
     explicit inline RelocatableValue();
     explicit inline RelocatableValue(const Value &v);
     explicit inline RelocatableValue(const RelocatableValue &v);
     inline ~RelocatableValue();
 
     inline RelocatableValue &operator=(const Value &v);
     inline RelocatableValue &operator=(const RelocatableValue &v);
 
-    static inline void writeBarrierPost(const Value &v, Value *addr);
-    static inline void writeBarrierPost(JSCompartment *comp, const Value &v, Value *addr);
-
   private:
     inline void post();
     inline void post(JSCompartment *comp);
     inline void relocate();
 };
 
 class HeapSlot : public EncapsulatedValue
 {
@@ -416,17 +477,17 @@ class HeapSlot : public EncapsulatedValu
 };
 
 /*
  * NOTE: This is a placeholder for bug 619558.
  *
  * Run a post write barrier that encompasses multiple contiguous slots in a
  * single step.
  */
-static inline void
+inline void
 SlotRangeWriteBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t start, uint32_t count)
 {
 }
 
 static inline const Value *
 Valueify(const EncapsulatedValue *array)
 {
     JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
@@ -551,18 +612,18 @@ class ReadBarrieredValue
     inline const Value &get() const;
     inline operator const Value &() const;
 
     inline JSObject &toObject() const;
 };
 
 namespace tl {
 
-template <class T> struct IsPostBarrieredType<HeapPtr<T> > {
-                                                    static const bool result = true; };
-template <> struct IsPostBarrieredType<HeapSlot>  { static const bool result = true; };
-template <> struct IsPostBarrieredType<HeapValue> { static const bool result = true; };
-template <> struct IsPostBarrieredType<HeapId>    { static const bool result = true; };
+template <class T> struct IsRelocatableHeapType<HeapPtr<T> >
+                                                    { static const bool result = false; };
+template <> struct IsRelocatableHeapType<HeapSlot>  { static const bool result = false; };
+template <> struct IsRelocatableHeapType<HeapValue> { static const bool result = false; };
+template <> struct IsRelocatableHeapType<HeapId>    { static const bool result = false; };
 
 } /* namespace tl */
 } /* namespace js */
 
 #endif /* jsgc_barrier_h___ */