Bug 875872 - Add public Heap<T> class for implementing post-barriers in the browser r=terrence

This commit is contained in:
Jon Coppeard 2013-05-27 12:51:25 +01:00
parent a07d2309af
commit 18542d913b
6 changed files with 198 additions and 5 deletions

View File

@ -113,6 +113,9 @@ class HandleBase {};
template <typename T>
class MutableHandleBase {};
template <typename T>
class HeapBase {};
/*
* js::NullPtr acts like a NULL pointer in contexts that require a Handle.
*
@ -131,6 +134,10 @@ struct NullPtr
static void * const constNullValue;
};
namespace gc {
struct Cell;
} /* namespace gc */
} /* namespace js */
namespace JS {
@ -162,6 +169,69 @@ struct JS_PUBLIC_API(NullPtr)
static void * const constNullValue;
};
/*
* Encapsulated pointer class for use on the heap.
*
* Implements post barriers for heap-based GC thing pointers outside the engine.
*/
template <typename T>
class Heap : public js::HeapBase<T>
{
public:
Heap() { set(js::RootMethods<T>::initial()); }
explicit Heap(T p) { set(p); }
explicit Heap(const Heap<T> &p) { set(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; }
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; }
Heap<T> &operator=(T p) {
set(p);
return *this;
}
void set(T newPtr) {
JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr));
if (js::RootMethods<T>::needsPostBarrier(newPtr)) {
ptr = newPtr;
post();
} else if (js::RootMethods<T>::needsPostBarrier(ptr)) {
relocate(); /* Called before overwriting ptr. */
ptr = newPtr;
} else {
ptr = newPtr;
}
}
private:
void post() {
#ifdef JSGC_GENERATIONAL
JS_ASSERT(js::RootMethods<T>::needsPostBarrier(ptr));
js::RootMethods<T>::postBarrier(&ptr);
#endif
}
void relocate() {
#ifdef JSGC_GENERATIONAL
js::RootMethods<T>::relocate(&ptr);
#endif
}
T ptr;
};
/*
* Reference to a T that has been rooted elsewhere. This is most useful
* as a parameter type, which guarantees that the T lvalue is properly
@ -202,6 +272,10 @@ class MOZ_STACK_CLASS Handle : public js::HandleBase<T>
ptr = handle.address();
}
Handle(const Heap<T> &heapPtr) {
ptr = heapPtr.address();
}
/*
* This may be called only if the location of the T is guaranteed
* to be marked (for some reason other than being a Rooted),
@ -315,6 +389,11 @@ typedef MutableHandle<JSString*> MutableHandleString;
typedef MutableHandle<jsid> MutableHandleId;
typedef MutableHandle<Value> MutableHandleValue;
#ifdef JSGC_GENERATIONAL
JS_PUBLIC_API(void) HeapCellPostBarrier(js::gc::Cell **cellp);
JS_PUBLIC_API(void) HeapCellRelocate(js::gc::Cell **cellp);
#endif
} /* namespace JS */
namespace js {
@ -394,6 +473,15 @@ struct RootMethods<T *>
static T *initial() { return NULL; }
static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
static bool needsPostBarrier(T *v) { return v; }
#ifdef JSGC_GENERATIONAL
static void postBarrier(T **vp) {
JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
}
static void relocate(T **vp) {
JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp));
}
#endif
};
} /* namespace js */
@ -790,10 +878,6 @@ inline void MaybeCheckStackRoots(JSContext *cx)
#endif
}
namespace gc {
struct Cell;
} /* namespace gc */
/* Base class for automatic read-only object rooting during compilation. */
class CompilerRootNode
{

View File

@ -1393,6 +1393,13 @@ SameType(const Value &lhs, const Value &rhs)
/************************************************************************/
#ifdef JSGC_GENERATIONAL
namespace JS {
JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep);
JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep);
}
#endif
namespace js {
template <> struct RootMethods<const JS::Value>
@ -1407,6 +1414,11 @@ template <> struct RootMethods<JS::Value>
static JS::Value initial() { return JS::UndefinedValue(); }
static ThingRootKind kind() { return THING_ROOT_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 MutableValueOperations;
@ -1483,6 +1495,19 @@ class MutableValueOperations : public ValueOperations<Outer>
void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(arg); }
};
/*
* Augment the generic Heap<T> interface when T = Value with type-querying
* and value-extracting operations.
*/
template <>
class HeapBase<JS::Value> : public ValueOperations<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();
}
};
/*
* Augment the generic Handle<T> interface when T = Value with type-querying
* and value-extracting operations.

View File

@ -473,6 +473,40 @@ StoreBuffer::releaseVerificationData()
edgeSet.finish();
}
JS_PUBLIC_API(void)
JS::HeapCellPostBarrier(js::gc::Cell **cellp)
{
JS_ASSERT(*cellp);
JSRuntime *runtime = (*cellp)->runtime();
runtime->gcStoreBuffer.putRelocatableCell(cellp);
}
JS_PUBLIC_API(void)
JS::HeapCellRelocate(js::gc::Cell **cellp)
{
/* Called with old contents of *pp before overwriting. */
JS_ASSERT(*cellp);
JSRuntime *runtime = (*cellp)->runtime();
runtime->gcStoreBuffer.removeRelocatableCell(cellp);
}
JS_PUBLIC_API(void)
JS::HeapValuePostBarrier(JS::Value *valuep)
{
JS_ASSERT(JSVAL_IS_TRACEABLE(*valuep));
JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtime();
runtime->gcStoreBuffer.putRelocatableValue(valuep);
}
JS_PUBLIC_API(void)
JS::HeapValueRelocate(JS::Value *valuep)
{
/* Called with old contents of *valuep before overwriting. */
JS_ASSERT(JSVAL_IS_TRACEABLE(*valuep));
JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtime();
runtime->gcStoreBuffer.removeRelocatableValue(valuep);
}
template class StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
template class StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
template class StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotEdge>;

View File

@ -2521,6 +2521,36 @@ JS_CallGenericTracer(JSTracer *trc, void *gcthingArg, const char *name)
JS_ASSERT(gcthing == gcthingArg);
}
JS_PUBLIC_API(void)
JS_CallHeapValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name)
{
MarkValueUnbarriered(trc, valuep->unsafeGet(), name);
}
JS_PUBLIC_API(void)
JS_CallHeapIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name)
{
MarkIdUnbarriered(trc, idp->unsafeGet(), name);
}
JS_PUBLIC_API(void)
JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name)
{
MarkObjectUnbarriered(trc, objp->unsafeGet(), name);
}
JS_PUBLIC_API(void)
JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name)
{
MarkStringUnbarriered(trc, strp->unsafeGet(), name);
}
JS_PUBLIC_API(void)
JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name)
{
MarkScriptUnbarriered(trc, scriptp->unsafeGet(), name);
}
JS_PUBLIC_API(void)
JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback)
{

View File

@ -1796,6 +1796,11 @@ template <> struct RootMethods<jsid>
static jsid initial() { return JSID_VOID; }
static ThingRootKind kind() { return THING_ROOT_ID; }
static bool poisoned(jsid id) { return JS::IsPoisonedId(id); }
static bool needsPostBarrier(jsid id) { return false; }
#ifdef JSGC_GENERATIONAL
static void postBarrier(jsid *idp) {}
static void relocate(jsid *idp) {}
#endif
};
} /* namespace js */
@ -2530,6 +2535,21 @@ JS_CallStringTracer(JSTracer *trc, JSString **strp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallGenericTracer(JSTracer *trc, void *gcthing, const char *name);

View File

@ -934,7 +934,7 @@ JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind)
JS_FRIEND_API(void)
JS::IncrementalValueBarrier(const Value &v)
{
HeapValue::writeBarrierPre(v);
js::HeapValue::writeBarrierPre(v);
}
JS_FRIEND_API(void)