mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 875872 - Add public Heap<T> class for implementing post-barriers in the browser r=terrence
This commit is contained in:
parent
a07d2309af
commit
18542d913b
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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>;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user