mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 989414 - Access the store buffer through the chunk trailer; r=jonco
This commit is contained in:
parent
45338123c5
commit
04457e91b1
@ -41,10 +41,10 @@ const size_t CellSize = size_t(1) << CellShift;
|
||||
const size_t CellMask = CellSize - 1;
|
||||
|
||||
/* These are magic constants derived from actual offsets in gc/Heap.h. */
|
||||
const size_t ChunkMarkBitmapOffset = 1032360;
|
||||
const size_t ChunkMarkBitmapOffset = 1032352;
|
||||
const size_t ChunkMarkBitmapBits = 129024;
|
||||
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
|
||||
const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t);
|
||||
const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t);
|
||||
|
||||
/*
|
||||
* Live objects are marked black. How many other additional colors are available
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
@ -665,7 +666,9 @@ struct GCMethods<JSObject *>
|
||||
static JSObject *initial() { return nullptr; }
|
||||
static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); }
|
||||
static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); }
|
||||
static bool needsPostBarrier(JSObject *v) { return v; }
|
||||
static bool needsPostBarrier(JSObject *v) {
|
||||
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell *>(v));
|
||||
}
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
static void postBarrier(JSObject **vp) {
|
||||
JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
|
||||
|
@ -1556,7 +1556,9 @@ template <> struct GCMethods<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(); }
|
||||
static bool needsPostBarrier(const JS::Value &v) {
|
||||
return v.isObject() && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(&v.toObject()));
|
||||
}
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); }
|
||||
static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); }
|
||||
|
@ -42,12 +42,12 @@ HeapSlot::preconditionForSet(Zone *zone, JSObject *owner, Kind kind, uint32_t sl
|
||||
return ok && owner->zone() == zone;
|
||||
}
|
||||
|
||||
void
|
||||
HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target)
|
||||
bool
|
||||
HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target) const
|
||||
{
|
||||
JS_ASSERT_IF(kind == Slot, obj->getSlotAddressUnchecked(slot)->get() == target);
|
||||
JS_ASSERT_IF(kind == Element,
|
||||
static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target);
|
||||
return kind == Slot
|
||||
? obj->getSlotAddressUnchecked(slot)->get() == target
|
||||
: static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -233,9 +233,9 @@ class BarrieredCell : public gc::Cell
|
||||
#endif
|
||||
}
|
||||
|
||||
static void writeBarrierPost(T *thing, void *addr) {}
|
||||
static void writeBarrierPostRelocate(T *thing, void *addr) {}
|
||||
static void writeBarrierPostRemove(T *thing, void *addr) {}
|
||||
static void writeBarrierPost(T *thing, void *cellp) {}
|
||||
static void writeBarrierPostRelocate(T *thing, void *cellp) {}
|
||||
static void writeBarrierPostRemove(T *thing, void *cellp) {}
|
||||
};
|
||||
|
||||
} // namespace gc
|
||||
@ -243,30 +243,12 @@ class BarrieredCell : public gc::Cell
|
||||
// Note: the following Zone-getting functions must be equivalent to the zone()
|
||||
// and shadowZone() functions implemented by the subclasses of BarrieredCell.
|
||||
|
||||
JS::Zone *
|
||||
ZoneOfObject(const JSObject &obj);
|
||||
|
||||
static inline JS::shadow::Zone *
|
||||
ShadowZoneOfObject(JSObject *obj)
|
||||
{
|
||||
return JS::shadow::Zone::asShadowZone(ZoneOfObject(*obj));
|
||||
}
|
||||
|
||||
static inline JS::shadow::Zone *
|
||||
ShadowZoneOfString(JSString *str)
|
||||
{
|
||||
return JS::shadow::Zone::asShadowZone(reinterpret_cast<const js::gc::Cell *>(str)->tenuredZone());
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JS::Zone *
|
||||
ZoneOfValue(const JS::Value &value)
|
||||
{
|
||||
JS_ASSERT(value.isMarkable());
|
||||
if (value.isObject())
|
||||
return ZoneOfObject(value.toObject());
|
||||
return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
|
||||
}
|
||||
|
||||
JS::Zone *
|
||||
ZoneOfObjectFromAnyThread(const JSObject &obj);
|
||||
|
||||
@ -339,6 +321,7 @@ struct InternalGCMethods<Value>
|
||||
preBarrier(ZoneOfValueFromAnyThread(v), v);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void preBarrier(Zone *zone, Value v) {
|
||||
#ifdef JSGC_INCREMENTAL
|
||||
if (v.isString() && StringIsPermanentAtom(v.toString()))
|
||||
@ -352,24 +335,34 @@ struct InternalGCMethods<Value>
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void postBarrier(Value *vp) {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (vp->isObject())
|
||||
shadowRuntimeFromAnyThread(*vp)->gcStoreBufferPtr()->putValue(vp);
|
||||
if (vp->isObject()) {
|
||||
gc::StoreBuffer *sb = reinterpret_cast<gc::Cell *>(&vp->toObject())->storeBuffer();
|
||||
if (sb)
|
||||
sb->putValueFromAnyThread(vp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void postBarrierRelocate(Value *vp) {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
shadowRuntimeFromAnyThread(*vp)->gcStoreBufferPtr()->putRelocatableValue(vp);
|
||||
if (vp->isObject()) {
|
||||
gc::StoreBuffer *sb = reinterpret_cast<gc::Cell *>(&vp->toObject())->storeBuffer();
|
||||
if (sb)
|
||||
sb->putRelocatableValueFromAnyThread(vp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void postBarrierRemove(Value *vp) {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS_ASSERT(vp);
|
||||
JS_ASSERT(vp->isMarkable());
|
||||
JSRuntime *rt = static_cast<js::gc::Cell *>(vp->toGCThing())->runtimeFromAnyThread();
|
||||
JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->removeRelocatableValue(vp);
|
||||
shadowRuntime->gcStoreBufferPtr()->removeRelocatableValueFromAnyThread(vp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -608,7 +601,7 @@ class RelocatablePtr : public BarrieredBase<T>
|
||||
public:
|
||||
RelocatablePtr() : BarrieredBase<T>(GCMethods<T>::initial()) {}
|
||||
explicit RelocatablePtr(T v) : BarrieredBase<T>(v) {
|
||||
if (isMarkable(v))
|
||||
if (GCMethods<T>::needsPostBarrier(v))
|
||||
post();
|
||||
}
|
||||
|
||||
@ -619,22 +612,22 @@ class RelocatablePtr : public BarrieredBase<T>
|
||||
* simply omit the rvalue variant.
|
||||
*/
|
||||
RelocatablePtr(const RelocatablePtr<T> &v) : BarrieredBase<T>(v) {
|
||||
if (isMarkable(this->value))
|
||||
if (GCMethods<T>::needsPostBarrier(this->value))
|
||||
post();
|
||||
}
|
||||
|
||||
~RelocatablePtr() {
|
||||
if (isMarkable(this->value))
|
||||
if (GCMethods<T>::needsPostBarrier(this->value))
|
||||
relocate();
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(T v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!GCMethods<T>::poisoned(v));
|
||||
if (isMarkable(v)) {
|
||||
if (GCMethods<T>::needsPostBarrier(v)) {
|
||||
this->value = v;
|
||||
post();
|
||||
} else if (isMarkable(this->value)) {
|
||||
} else if (GCMethods<T>::needsPostBarrier(this->value)) {
|
||||
relocate();
|
||||
this->value = v;
|
||||
} else {
|
||||
@ -646,10 +639,10 @@ class RelocatablePtr : public BarrieredBase<T>
|
||||
RelocatablePtr<T> &operator=(const RelocatablePtr<T> &v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!GCMethods<T>::poisoned(v.value));
|
||||
if (isMarkable(v.value)) {
|
||||
if (GCMethods<T>::needsPostBarrier(v.value)) {
|
||||
this->value = v.value;
|
||||
post();
|
||||
} else if (isMarkable(this->value)) {
|
||||
} else if (GCMethods<T>::needsPostBarrier(this->value)) {
|
||||
relocate();
|
||||
this->value = v;
|
||||
} else {
|
||||
@ -660,20 +653,16 @@ class RelocatablePtr : public BarrieredBase<T>
|
||||
}
|
||||
|
||||
protected:
|
||||
static bool isMarkable(const T &v) {
|
||||
return InternalGCMethods<T>::isMarkable(v);
|
||||
}
|
||||
|
||||
void post() {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS_ASSERT(isMarkable(this->value));
|
||||
JS_ASSERT(GCMethods<T>::needsPostBarrier(this->value));
|
||||
InternalGCMethods<T>::postBarrierRelocate(&this->value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void relocate() {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS_ASSERT(isMarkable(this->value));
|
||||
JS_ASSERT(GCMethods<T>::needsPostBarrier(this->value));
|
||||
InternalGCMethods<T>::postBarrierRemove(&this->value);
|
||||
#endif
|
||||
}
|
||||
@ -864,64 +853,43 @@ class HeapSlot : public BarrieredBase<Value>
|
||||
post(owner, kind, slot, v);
|
||||
}
|
||||
|
||||
void init(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, const Value &v) {
|
||||
value = v;
|
||||
post(rt, owner, kind, slot, v);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool preconditionForSet(JSObject *owner, Kind kind, uint32_t slot);
|
||||
bool preconditionForSet(Zone *zone, JSObject *owner, Kind kind, uint32_t slot);
|
||||
static void preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot,
|
||||
Value target);
|
||||
bool preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target) const;
|
||||
#endif
|
||||
|
||||
void set(JSObject *owner, Kind kind, uint32_t slot, const Value &v) {
|
||||
JS_ASSERT(preconditionForSet(owner, kind, slot));
|
||||
pre();
|
||||
JS_ASSERT(!IsPoisonedValue(v));
|
||||
pre();
|
||||
value = v;
|
||||
post(owner, kind, slot, v);
|
||||
}
|
||||
|
||||
void set(Zone *zone, JSObject *owner, Kind kind, uint32_t slot, const Value &v) {
|
||||
JS_ASSERT(preconditionForSet(zone, owner, kind, slot));
|
||||
JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
|
||||
pre(zone);
|
||||
JS_ASSERT(!IsPoisonedValue(v));
|
||||
pre(zone);
|
||||
value = v;
|
||||
post(shadowZone->runtimeFromAnyThread(), owner, kind, slot, v);
|
||||
post(owner, kind, slot, v);
|
||||
}
|
||||
|
||||
static void writeBarrierPost(JSObject *obj, Kind kind, uint32_t slot, const Value &target)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell*>(obj);
|
||||
writeBarrierPost(cell->runtimeFromAnyThread(), obj, kind, slot, target);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void writeBarrierPost(JSRuntime *rt, JSObject *obj, Kind kind, uint32_t slot,
|
||||
const Value &target)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
preconditionForWriteBarrierPost(obj, kind, slot, target);
|
||||
#endif
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (target.isObject()) {
|
||||
JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->putSlot(obj, kind, slot, 1);
|
||||
}
|
||||
#endif
|
||||
/* For users who need to manually barrier the raw types. */
|
||||
static void writeBarrierPost(JSObject *owner, Kind kind, uint32_t slot, const Value &target) {
|
||||
reinterpret_cast<HeapSlot *>(const_cast<Value *>(&target))->post(owner, kind, slot, target);
|
||||
}
|
||||
|
||||
private:
|
||||
void post(JSObject *owner, Kind kind, uint32_t slot, Value target) {
|
||||
HeapSlot::writeBarrierPost(owner, kind, slot, target);
|
||||
}
|
||||
|
||||
void post(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, Value target) {
|
||||
HeapSlot::writeBarrierPost(rt, owner, kind, slot, target);
|
||||
void post(JSObject *owner, Kind kind, uint32_t slot, const Value &target) {
|
||||
JS_ASSERT(preconditionForWriteBarrierPost(owner, kind, slot, target));
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (this->value.isObject()) {
|
||||
gc::Cell *cell = reinterpret_cast<gc::Cell *>(&this->value.toObject());
|
||||
if (cell->storeBuffer())
|
||||
cell->storeBuffer()->putSlotFromAnyThread(owner, kind, slot, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,8 @@ struct Cell
|
||||
inline JSRuntime *runtimeFromAnyThread() const;
|
||||
inline JS::shadow::Runtime *shadowRuntimeFromAnyThread() const;
|
||||
|
||||
inline StoreBuffer *storeBuffer() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
inline bool isAligned() const;
|
||||
inline bool isTenured() const;
|
||||
@ -608,15 +610,16 @@ struct ChunkTrailer
|
||||
{
|
||||
/* The index the chunk in the nursery, or LocationTenuredHeap. */
|
||||
uint32_t location;
|
||||
|
||||
#if JS_BITS_PER_WORD == 64
|
||||
uint32_t padding;
|
||||
#endif
|
||||
|
||||
/* The store buffer for writes to things in this chunk or nullptr. */
|
||||
StoreBuffer *storeBuffer;
|
||||
|
||||
JSRuntime *runtime;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t), "ChunkTrailer size is incorrect.");
|
||||
static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t) + sizeof(uint64_t),
|
||||
"ChunkTrailer size is incorrect.");
|
||||
|
||||
/* The chunk header (located at the end of the chunk to preserve arena alignment). */
|
||||
struct ChunkInfo
|
||||
@ -865,9 +868,13 @@ static_assert(sizeof(Chunk) == ChunkSize,
|
||||
static_assert(js::gc::ChunkMarkBitmapOffset == offsetof(Chunk, bitmap),
|
||||
"The hardcoded API bitmap offset must match the actual offset.");
|
||||
static_assert(js::gc::ChunkRuntimeOffset == offsetof(Chunk, info) +
|
||||
offsetof(ChunkInfo, trailer) +
|
||||
offsetof(ChunkTrailer, runtime),
|
||||
offsetof(ChunkInfo, trailer) +
|
||||
offsetof(ChunkTrailer, runtime),
|
||||
"The hardcoded API runtime offset must match the actual offset.");
|
||||
static_assert(js::gc::ChunkLocationOffset == offsetof(Chunk, info) +
|
||||
offsetof(ChunkInfo, trailer) +
|
||||
offsetof(ChunkTrailer, location),
|
||||
"The hardcoded API location offset must match the actual offset.");
|
||||
|
||||
inline uintptr_t
|
||||
ArenaHeader::address() const
|
||||
@ -1097,6 +1104,12 @@ Cell::chunk() const
|
||||
return reinterpret_cast<Chunk *>(addr);
|
||||
}
|
||||
|
||||
inline StoreBuffer *
|
||||
Cell::storeBuffer() const
|
||||
{
|
||||
return chunk()->info.trailer.storeBuffer;
|
||||
}
|
||||
|
||||
inline bool
|
||||
InFreeList(ArenaHeader *aheader, void *thing)
|
||||
{
|
||||
|
@ -203,6 +203,7 @@ class Nursery
|
||||
|
||||
MOZ_ALWAYS_INLINE void initChunk(int chunkno) {
|
||||
NurseryChunkLayout &c = chunk(chunkno);
|
||||
c.trailer.storeBuffer = JS::shadow::Runtime::asShadowRuntime(runtime())->gcStoreBufferPtr();
|
||||
c.trailer.location = gc::ChunkLocationNursery;
|
||||
c.trailer.runtime = runtime();
|
||||
}
|
||||
|
@ -335,39 +335,45 @@ StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSi
|
||||
JS_PUBLIC_API(void)
|
||||
JS::HeapCellPostBarrier(js::gc::Cell **cellp)
|
||||
{
|
||||
JS_ASSERT(cellp);
|
||||
JS_ASSERT(*cellp);
|
||||
JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
|
||||
runtime->gc.storeBuffer.putRelocatableCell(cellp);
|
||||
StoreBuffer *storeBuffer = (*cellp)->storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putRelocatableCellFromAnyThread(cellp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::HeapCellRelocate(js::gc::Cell **cellp)
|
||||
{
|
||||
/* Called with old contents of *pp before overwriting. */
|
||||
/* Called with old contents of *cellp before overwriting. */
|
||||
JS_ASSERT(cellp);
|
||||
JS_ASSERT(*cellp);
|
||||
JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
|
||||
runtime->gc.storeBuffer.removeRelocatableCell(cellp);
|
||||
runtime->gc.storeBuffer.removeRelocatableCellFromAnyThread(cellp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::HeapValuePostBarrier(JS::Value *valuep)
|
||||
{
|
||||
JS_ASSERT(valuep);
|
||||
JS_ASSERT(valuep->isMarkable());
|
||||
if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
|
||||
return;
|
||||
JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
|
||||
runtime->gc.storeBuffer.putRelocatableValue(valuep);
|
||||
if (valuep->isObject()) {
|
||||
StoreBuffer *storeBuffer = valuep->toObject().storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putRelocatableValueFromAnyThread(valuep);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::HeapValueRelocate(JS::Value *valuep)
|
||||
{
|
||||
/* Called with old contents of *valuep before overwriting. */
|
||||
JS_ASSERT(valuep);
|
||||
JS_ASSERT(valuep->isMarkable());
|
||||
if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
|
||||
if (valuep->isString() && valuep->toString()->isPermanentAtom())
|
||||
return;
|
||||
JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
|
||||
runtime->gc.storeBuffer.removeRelocatableValue(valuep);
|
||||
runtime->gc.storeBuffer.removeRelocatableValueFromAnyThread(valuep);
|
||||
}
|
||||
|
||||
template class StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
|
||||
|
@ -244,7 +244,8 @@ class StoreBuffer
|
||||
bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
|
||||
|
||||
bool maybeInRememberedSet(const Nursery &nursery) const {
|
||||
return !nursery.isInside(edge) && nursery.isInside(*edge);
|
||||
JS_ASSERT(nursery.isInside(*edge));
|
||||
return !nursery.isInside(edge);
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
@ -267,7 +268,8 @@ class StoreBuffer
|
||||
void *deref() const { return edge->isGCThing() ? edge->toGCThing() : nullptr; }
|
||||
|
||||
bool maybeInRememberedSet(const Nursery &nursery) const {
|
||||
return !nursery.isInside(edge) && nursery.isInside(deref());
|
||||
JS_ASSERT(nursery.isInside(deref()));
|
||||
return !nursery.isInside(edge);
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
@ -362,8 +364,7 @@ class StoreBuffer
|
||||
void *data;
|
||||
};
|
||||
|
||||
template <typename Edge>
|
||||
bool isOkayToUseBuffer(const Edge &edge) const {
|
||||
bool isOkayToUseBuffer() const {
|
||||
/*
|
||||
* Disabled store buffers may not have a valid state; e.g. when stored
|
||||
* inline in the ChunkTrailer.
|
||||
@ -382,8 +383,8 @@ class StoreBuffer
|
||||
}
|
||||
|
||||
template <typename Buffer, typename Edge>
|
||||
void put(Buffer &buffer, const Edge &edge) {
|
||||
if (!isOkayToUseBuffer(edge))
|
||||
void putFromAnyThread(Buffer &buffer, const Edge &edge) {
|
||||
if (!isOkayToUseBuffer())
|
||||
return;
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
if (edge.maybeInRememberedSet(nursery_))
|
||||
@ -391,8 +392,8 @@ class StoreBuffer
|
||||
}
|
||||
|
||||
template <typename Buffer, typename Edge>
|
||||
void unput(Buffer &buffer, const Edge &edge) {
|
||||
if (!isOkayToUseBuffer(edge))
|
||||
void unputFromAnyThread(Buffer &buffer, const Edge &edge) {
|
||||
if (!isOkayToUseBuffer())
|
||||
return;
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
buffer.unput(this, edge);
|
||||
@ -432,30 +433,38 @@ class StoreBuffer
|
||||
bool isAboutToOverflow() const { return aboutToOverflow_; }
|
||||
|
||||
/* Insert a single edge into the buffer/remembered set. */
|
||||
void putValue(JS::Value *valuep) { put(bufferVal, ValueEdge(valuep)); }
|
||||
void putCell(Cell **cellp) { put(bufferCell, CellPtrEdge(cellp)); }
|
||||
void putSlot(JSObject *obj, int kind, int32_t start, int32_t count) {
|
||||
put(bufferSlot, SlotsEdge(obj, kind, start, count));
|
||||
void putValueFromAnyThread(JS::Value *valuep) { putFromAnyThread(bufferVal, ValueEdge(valuep)); }
|
||||
void putCellFromAnyThread(Cell **cellp) { putFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
|
||||
void putSlotFromAnyThread(JSObject *obj, int kind, int32_t start, int32_t count) {
|
||||
putFromAnyThread(bufferSlot, SlotsEdge(obj, kind, start, count));
|
||||
}
|
||||
void putWholeCell(Cell *cell) {
|
||||
JS_ASSERT(cell->isTenured());
|
||||
put(bufferWholeCell, WholeCellEdges(cell));
|
||||
putFromAnyThread(bufferWholeCell, WholeCellEdges(cell));
|
||||
}
|
||||
|
||||
/* Insert or update a single edge in the Relocatable buffer. */
|
||||
void putRelocatableValue(JS::Value *valuep) { put(bufferRelocVal, ValueEdge(valuep)); }
|
||||
void putRelocatableCell(Cell **cellp) { put(bufferRelocCell, CellPtrEdge(cellp)); }
|
||||
void removeRelocatableValue(JS::Value *valuep) { unput(bufferRelocVal, ValueEdge(valuep)); }
|
||||
void removeRelocatableCell(Cell **cellp) { unput(bufferRelocCell, CellPtrEdge(cellp)); }
|
||||
void putRelocatableValueFromAnyThread(JS::Value *valuep) {
|
||||
putFromAnyThread(bufferRelocVal, ValueEdge(valuep));
|
||||
}
|
||||
void removeRelocatableValueFromAnyThread(JS::Value *valuep) {
|
||||
unputFromAnyThread(bufferRelocVal, ValueEdge(valuep));
|
||||
}
|
||||
void putRelocatableCellFromAnyThread(Cell **cellp) {
|
||||
putFromAnyThread(bufferRelocCell, CellPtrEdge(cellp));
|
||||
}
|
||||
void removeRelocatableCellFromAnyThread(Cell **cellp) {
|
||||
unputFromAnyThread(bufferRelocCell, CellPtrEdge(cellp));
|
||||
}
|
||||
|
||||
/* Insert an entry into the generic buffer. */
|
||||
template <typename T>
|
||||
void putGeneric(const T &t) { put(bufferGeneric, t);}
|
||||
void putGeneric(const T &t) { putFromAnyThread(bufferGeneric, t);}
|
||||
|
||||
/* Insert or update a callback entry. */
|
||||
template <typename Key>
|
||||
void putCallback(void (*callback)(JSTracer *trc, Key *key, void *data), Key *key, void *data) {
|
||||
put(bufferGeneric, CallbackRef<Key>(callback, key, data));
|
||||
putFromAnyThread(bufferGeneric, CallbackRef<Key>(callback, key, data));
|
||||
}
|
||||
|
||||
/* Methods to mark the source of all edges in the store buffer. */
|
||||
|
@ -247,12 +247,6 @@ Zone::createJitZone(JSContext *cx)
|
||||
}
|
||||
#endif
|
||||
|
||||
JS::Zone *
|
||||
js::ZoneOfObject(const JSObject &obj)
|
||||
{
|
||||
return obj.zone();
|
||||
}
|
||||
|
||||
JS::Zone *
|
||||
js::ZoneOfObjectFromAnyThread(const JSObject &obj)
|
||||
{
|
||||
@ -268,3 +262,12 @@ Zone::hasMarkedCompartments()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Zone *
|
||||
js::ZoneOfValue(const JS::Value &value)
|
||||
{
|
||||
JS_ASSERT(value.isMarkable());
|
||||
if (value.isObject())
|
||||
return value.toObject().zone();
|
||||
return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
|
||||
}
|
||||
|
@ -474,6 +474,10 @@ class CompartmentsIterT
|
||||
|
||||
typedef CompartmentsIterT<ZonesIter> CompartmentsIter;
|
||||
|
||||
/* Return the Zone* of a Value. Asserts if the Value is not a GC thing. */
|
||||
Zone *
|
||||
ZoneOfValue(const JS::Value &value);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* gc_Zone_h */
|
||||
|
@ -789,6 +789,7 @@ Chunk::init(JSRuntime *rt)
|
||||
|
||||
/* Initialize the chunk info. */
|
||||
info.age = 0;
|
||||
info.trailer.storeBuffer = nullptr;
|
||||
info.trailer.location = ChunkLocationTenuredHeap;
|
||||
info.trailer.runtime = rt;
|
||||
|
||||
|
@ -2293,8 +2293,8 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
||||
* below, in common with the other case.
|
||||
*/
|
||||
for (size_t i = 0; i < a->numFixedSlots(); ++i) {
|
||||
HeapSlot::writeBarrierPost(cx->runtime(), a, HeapSlot::Slot, i, a->getSlot(i));
|
||||
HeapSlot::writeBarrierPost(cx->runtime(), b, HeapSlot::Slot, i, b->getSlot(i));
|
||||
HeapSlot::writeBarrierPost(a, HeapSlot::Slot, i, a->getSlot(i));
|
||||
HeapSlot::writeBarrierPost(b, HeapSlot::Slot, i, b->getSlot(i));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
@ -187,7 +187,7 @@ DenseRangeWriteBarrierPost(JSRuntime *rt, JSObject *obj, uint32_t start, uint32_
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (count > 0) {
|
||||
JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->putSlot(obj, HeapSlot::Element, start, count);
|
||||
shadowRuntime->gcStoreBufferPtr()->putSlotFromAnyThread(obj, HeapSlot::Element, start, count);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -223,12 +223,13 @@ JSObject::ensureDenseInitializedLengthNoPackedCheck(js::ThreadSafeContext *cx, u
|
||||
uint32_t &initlen = getElementsHeader()->initializedLength;
|
||||
|
||||
if (initlen < index + extra) {
|
||||
JSRuntime *rt = runtimeFromAnyThread();
|
||||
size_t offset = initlen;
|
||||
for (js::HeapSlot *sp = elements + initlen;
|
||||
sp != elements + (index + extra);
|
||||
sp++, offset++)
|
||||
sp->init(rt, this, js::HeapSlot::Element, offset, js::MagicValue(JS_ELEMENTS_HOLE));
|
||||
{
|
||||
sp->init(this, js::HeapSlot::Element, offset, js::MagicValue(JS_ELEMENTS_HOLE));
|
||||
}
|
||||
initlen = index + extra;
|
||||
}
|
||||
}
|
||||
|
@ -264,24 +264,22 @@ js::ObjectImpl::initializeSlotRange(uint32_t start, uint32_t length)
|
||||
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
|
||||
getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
|
||||
|
||||
JSRuntime *rt = runtimeFromAnyThread();
|
||||
uint32_t offset = start;
|
||||
for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
|
||||
sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
|
||||
sp->init(this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
|
||||
for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
|
||||
sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
|
||||
sp->init(this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
|
||||
}
|
||||
|
||||
void
|
||||
js::ObjectImpl::initSlotRange(uint32_t start, const Value *vector, uint32_t length)
|
||||
{
|
||||
JSRuntime *rt = runtimeFromAnyThread();
|
||||
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
|
||||
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
|
||||
for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
|
||||
sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
|
||||
sp->init(this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
|
||||
for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
|
||||
sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
|
||||
sp->init(this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -840,7 +840,12 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
|
||||
|
||||
void privateWriteBarrierPost(void **pprivate) {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
|
||||
js::gc::Cell **cellp = reinterpret_cast<js::gc::Cell **>(pprivate);
|
||||
JS_ASSERT(cellp);
|
||||
JS_ASSERT(*cellp);
|
||||
js::gc::StoreBuffer *storeBuffer = (*cellp)->storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putCellFromAnyThread(cellp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -944,30 +949,43 @@ BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
|
||||
|
||||
template<>
|
||||
/* static */ inline void
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *addr)
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *cellp)
|
||||
{
|
||||
JS_ASSERT(cellp);
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (IsNullTaggedPointer(obj))
|
||||
return;
|
||||
obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell((Cell **)addr);
|
||||
JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
|
||||
gc::StoreBuffer *storeBuffer = obj->storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putCellFromAnyThread(static_cast<Cell **>(cellp));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
/* static */ inline void
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *addr)
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *cellp)
|
||||
{
|
||||
JS_ASSERT(cellp);
|
||||
JS_ASSERT(obj);
|
||||
JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putRelocatableCell((Cell **)addr);
|
||||
gc::StoreBuffer *storeBuffer = obj->storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putRelocatableCellFromAnyThread(static_cast<Cell **>(cellp));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
/* static */ inline void
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *addr)
|
||||
BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *cellp)
|
||||
{
|
||||
JS_ASSERT(cellp);
|
||||
JS_ASSERT(obj);
|
||||
JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCell((Cell **)addr);
|
||||
obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCellFromAnyThread(
|
||||
static_cast<Cell **>(cellp));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -525,8 +525,12 @@ static inline void
|
||||
GetterSetterWriteBarrierPost(JSRuntime *rt, JSObject **objp)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->putRelocatableCell(reinterpret_cast<gc::Cell **>(objp));
|
||||
JS_ASSERT(objp);
|
||||
JS_ASSERT(*objp);
|
||||
gc::Cell **cellp = reinterpret_cast<gc::Cell **>(objp);
|
||||
gc::StoreBuffer *storeBuffer = (*cellp)->storeBuffer();
|
||||
if (storeBuffer)
|
||||
storeBuffer->putRelocatableCellFromAnyThread(cellp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -535,7 +539,7 @@ GetterSetterWriteBarrierPostRemove(JSRuntime *rt, JSObject **objp)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->removeRelocatableCell(reinterpret_cast<gc::Cell **>(objp));
|
||||
shadowRuntime->gcStoreBufferPtr()->removeRelocatableCellFromAnyThread(reinterpret_cast<gc::Cell **>(objp));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -139,15 +139,15 @@ InterpreterFrame::writeBarrierPost()
|
||||
{
|
||||
/* This needs to follow the same rules as in InterpreterFrame::mark. */
|
||||
if (scopeChain_)
|
||||
JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
|
||||
JSObject::writeBarrierPost(scopeChain_, &scopeChain_);
|
||||
if (flags_ & HAS_ARGS_OBJ)
|
||||
JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
|
||||
JSObject::writeBarrierPost(argsObj_, &argsObj_);
|
||||
if (isFunctionFrame()) {
|
||||
JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
|
||||
JSFunction::writeBarrierPost(exec.fun, &exec.fun);
|
||||
if (isEvalFrame())
|
||||
JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
|
||||
JSScript::writeBarrierPost(u.evalScript, &u.evalScript);
|
||||
} else {
|
||||
JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
|
||||
JSScript::writeBarrierPost(exec.script, &exec.script);
|
||||
}
|
||||
if (hasReturnValue())
|
||||
HeapValue::writeBarrierPost(rval_, &rval_);
|
||||
|
Loading…
Reference in New Issue
Block a user