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.
*/
template <class T> struct IsPostBarrieredType { static const bool result = false; };
template <class T> struct IsRelocatableHeapType { static const bool result = true; };
} /* namespace tl */
} /* namespace js */

View File

@ -213,7 +213,7 @@ struct VectorImpl<T, N, AP, true>
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 */

View File

@ -151,31 +151,39 @@ 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(); }
EncapsulatedPtr() : value(NULL) {}
explicit EncapsulatedPtr(T *v) : value(v) {}
explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
~HeapPtr() { pre(); }
/* 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. */
@ -190,30 +198,48 @@ class HeapPtr
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; }
operator T*() const { return value; }
private:
protected:
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(). */
template<class T1, class T2>
@ -223,6 +249,41 @@ class HeapPtr
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.
@ -247,6 +308,9 @@ 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;
@ -269,7 +333,7 @@ struct HeapPtrHasher
/* Specialized hashing policy for HeapPtrs. */
template <class T>
struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { };
struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
class EncapsulatedValue
{
@ -376,9 +440,6 @@ class RelocatableValue : public EncapsulatedValue
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);
@ -421,7 +482,7 @@ class HeapSlot : public EncapsulatedValue
* 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)
{
}
@ -556,11 +617,11 @@ class ReadBarrieredValue
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 */