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.

--HG--
extra : rebase_source : 949c71cfdab8005339aea49437922f7f00a6f73a
This commit is contained in:
Terrence Cole 2012-05-15 17:21:23 -07:00
parent cbefc3395f
commit a3172ed2bc
3 changed files with 105 additions and 44 deletions

View File

@ -177,7 +177,7 @@ template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T r
/* /*
* Traits class for identifying types that are implicitly barriered. * 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 tl */
} /* namespace js */ } /* namespace js */

View File

@ -213,7 +213,7 @@ struct VectorImpl<T, N, AP, true>
template <class T, size_t N, class AllocPolicy> template <class T, size_t N, class AllocPolicy>
class Vector : private AllocPolicy class Vector : private AllocPolicy
{ {
typedef typename tl::StaticAssert<!tl::IsPostBarrieredType<T>::result>::result _; typedef typename tl::StaticAssert<tl::IsRelocatableHeapType<T>::result>::result _;
/* utilities */ /* utilities */

View File

@ -151,26 +151,20 @@ struct JSXML;
namespace js { namespace js {
template<class T, typename Unioned = uintptr_t> template<class T, typename Unioned = uintptr_t>
class HeapPtr class EncapsulatedPtr
{ {
protected:
union { union {
T *value; T *value;
Unioned other; Unioned other;
}; };
public: public:
HeapPtr() : value(NULL) {} EncapsulatedPtr() : value(NULL) {}
explicit HeapPtr(T *v) : value(v) { post(); } explicit EncapsulatedPtr(T *v) : value(v) {}
explicit HeapPtr(const HeapPtr<T> &v) : value(v.value) { post(); } explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
~HeapPtr() { pre(); } ~EncapsulatedPtr() { pre(); }
/* Use this to install a ptr into a newly allocated object. */
void init(T *v) {
JS_ASSERT(!IsPoisonedPtr<T>(v));
value = v;
post();
}
/* Use to set the pointer to NULL. */ /* Use to set the pointer to NULL. */
void clear() { void clear() {
@ -178,6 +172,20 @@ class HeapPtr
value = NULL; 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. */ /* Use this if the automatic coercion to T* isn't working. */
T *get() const { return value; } T *get() const { return value; }
@ -190,30 +198,48 @@ class HeapPtr
Unioned *unsafeGetUnioned() { return &other; } Unioned *unsafeGetUnioned() { return &other; }
HeapPtr<T, Unioned> &operator=(T *v) {
pre();
JS_ASSERT(!IsPoisonedPtr<T>(v));
value = v;
post();
return *this;
}
HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
pre();
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
value = v.value;
post();
return *this;
}
T &operator*() const { return *value; } T &operator*() const { return *value; }
T *operator->() const { return value; } T *operator->() const { return value; }
operator T*() const { return value; } operator T*() const { return value; }
private: protected:
void pre() { T::writeBarrierPre(value); } void pre() { T::writeBarrierPre(value); }
void post() { T::writeBarrierPost(value, (void *)&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) {
this->pre();
JS_ASSERT(!IsPoisonedPtr<T>(v));
this->value = v;
post();
return *this;
}
HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
this->pre();
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
this->value = v.value;
post();
return *this;
}
protected:
void post() { T::writeBarrierPost(this->value, (void *)&this->value); }
/* Make this friend so it can access pre() and post(). */ /* Make this friend so it can access pre() and post(). */
template<class T1, class T2> template<class T1, class T2>
@ -223,6 +249,41 @@ class HeapPtr
HeapPtr<T2> &v2, T2 *val2); 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 * 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. * barriers with only one branch to check if we're in an incremental GC.
@ -247,6 +308,9 @@ struct Shape;
class BaseShape; class BaseShape;
namespace types { struct TypeObject; } namespace types { struct TypeObject; }
typedef RelocatablePtr<JSObject> RelocatablePtrObject;
typedef RelocatablePtr<JSScript> RelocatablePtrScript;
typedef HeapPtr<JSObject> HeapPtrObject; typedef HeapPtr<JSObject> HeapPtrObject;
typedef HeapPtr<JSFunction> HeapPtrFunction; typedef HeapPtr<JSFunction> HeapPtrFunction;
typedef HeapPtr<JSString> HeapPtrString; typedef HeapPtr<JSString> HeapPtrString;
@ -269,7 +333,7 @@ struct HeapPtrHasher
/* Specialized hashing policy for HeapPtrs. */ /* Specialized hashing policy for HeapPtrs. */
template <class T> template <class T>
struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { }; struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
class EncapsulatedValue class EncapsulatedValue
{ {
@ -376,9 +440,6 @@ class RelocatableValue : public EncapsulatedValue
inline RelocatableValue &operator=(const Value &v); inline RelocatableValue &operator=(const Value &v);
inline RelocatableValue &operator=(const RelocatableValue &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: private:
inline void post(); inline void post();
inline void post(JSCompartment *comp); inline void post(JSCompartment *comp);
@ -421,7 +482,7 @@ class HeapSlot : public EncapsulatedValue
* Run a post write barrier that encompasses multiple contiguous slots in a * Run a post write barrier that encompasses multiple contiguous slots in a
* single step. * single step.
*/ */
static inline void inline void
SlotRangeWriteBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t start, uint32_t count) SlotRangeWriteBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t start, uint32_t count)
{ {
} }
@ -556,11 +617,11 @@ class ReadBarrieredValue
namespace tl { namespace tl {
template <class T> struct IsPostBarrieredType<HeapPtr<T> > { template <class T> struct IsRelocatableHeapType<HeapPtr<T> >
static const bool result = true; }; { static const bool result = false; };
template <> struct IsPostBarrieredType<HeapSlot> { static const bool result = true; }; template <> struct IsRelocatableHeapType<HeapSlot> { static const bool result = false; };
template <> struct IsPostBarrieredType<HeapValue> { static const bool result = true; }; template <> struct IsRelocatableHeapType<HeapValue> { static const bool result = false; };
template <> struct IsPostBarrieredType<HeapId> { static const bool result = true; }; template <> struct IsRelocatableHeapType<HeapId> { static const bool result = false; };
} /* namespace tl */ } /* namespace tl */
} /* namespace js */ } /* namespace js */