Backout 9a6b434b34be for mochitest-2 failures on a CLOSED TREE.
authorTerrence Cole <terrence@mozilla.com>
Thu, 01 May 2014 12:52:22 -0700
changeset 181237 e5a6e3bfa4be4139be832c70db3959b61819edbe
parent 181236 af1cebf017fc9c8ac78ea63213f13a9a3b9b237a
child 181238 e7217cdee50fdec067613b91a3cba0f047b76897
push id42994
push usertcole@mozilla.com
push dateThu, 01 May 2014 19:52:41 +0000
treeherdermozilla-inbound@e5a6e3bfa4be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
backs out9a6b434b34bec675539d12ce7566bc76f01ceaf1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout 9a6b434b34be for mochitest-2 failures on a CLOSED TREE.
js/public/HeapAPI.h
js/src/gc/Barrier.cpp
js/src/gc/Barrier.h
js/src/gc/Heap.h
js/src/gc/Nursery.h
js/src/gc/StoreBuffer.cpp
js/src/gc/StoreBuffer.h
js/src/jsgc.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/vm/ObjectImpl.cpp
js/src/vm/ObjectImpl.h
js/src/vm/Shape.h
js/src/vm/Stack.cpp
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -36,20 +36,20 @@ const size_t ChunkShift = 20;
 const size_t ChunkSize = size_t(1) << ChunkShift;
 const size_t ChunkMask = ChunkSize - 1;
 
 const size_t CellShift = 3;
 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 = 1032352;
+const size_t ChunkMarkBitmapOffset = 1032360;
 const size_t ChunkMarkBitmapBits = 129024;
 const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
-const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t);
+const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t);
 
 /*
  * Live objects are marked black. How many other additional colors are available
  * depends on the size of the GCThing. Objects marked gray are eligible for
  * cycle collection.
  */
 static const uint32_t BLACK = 0;
 static const uint32_t GRAY = 1;
--- a/js/src/gc/Barrier.cpp
+++ b/js/src/gc/Barrier.cpp
@@ -37,22 +37,22 @@ bool
 HeapSlot::preconditionForSet(Zone *zone, JSObject *owner, Kind kind, uint32_t slot)
 {
     bool ok = kind == Slot
             ? &owner->getSlotRef(slot) == this
             : &owner->getDenseElement(slot) == (const Value *)this;
     return ok && owner->zone() == zone;
 }
 
-bool
-HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target) const
+void
+HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target)
 {
-    return kind == Slot
-         ? obj->getSlotAddressUnchecked(slot)->get() == target
-         : static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target;
+    JS_ASSERT_IF(kind == Slot, obj->getSlotAddressUnchecked(slot)->get() == target);
+    JS_ASSERT_IF(kind == Element,
+                 static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target);
 }
 
 bool
 RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone *shadowZone)
 {
     return shadowZone->runtimeFromMainThread()->isHeapMajorCollecting();
 }
 #endif // DEBUG
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -228,19 +228,19 @@ class BarrieredCell : public gc::Cell
             MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
             T *tmp = thing;
             js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "write barrier");
             JS_ASSERT(tmp == thing);
         }
 #endif
     }
 
-    static void writeBarrierPost(T *thing, void *cellp) {}
-    static void writeBarrierPostRelocate(T *thing, void *cellp) {}
-    static void writeBarrierPostRemove(T *thing, void *cellp) {}
+    static void writeBarrierPost(T *thing, void *addr) {}
+    static void writeBarrierPostRelocate(T *thing, void *addr) {}
+    static void writeBarrierPostRemove(T *thing, void *addr) {}
 };
 
 } // namespace gc
 
 // Note: the following Zone-getting functions must be equivalent to the zone()
 // and shadowZone() functions implemented by the subclasses of BarrieredCell.
 
 JS::Zone *
@@ -334,58 +334,47 @@ struct InternalGCMethods<Value>
     static bool isMarkable(Value v) { return v.isMarkable(); }
 
     static void preBarrier(Value v) {
 #ifdef JSGC_INCREMENTAL
         if (v.isMarkable() && shadowRuntimeFromAnyThread(v)->needsBarrier())
             preBarrier(ZoneOfValueFromAnyThread(v), v);
 #endif
     }
-
     static void preBarrier(Zone *zone, Value v) {
 #ifdef JSGC_INCREMENTAL
         if (v.isString() && StringIsPermanentAtom(v.toString()))
             return;
         JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
         if (shadowZone->needsBarrier()) {
             JS_ASSERT_IF(v.isMarkable(), shadowRuntimeFromMainThread(v)->needsBarrier());
             Value tmp(v);
             js::gc::MarkValueUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
             JS_ASSERT(tmp == v);
         }
 #endif
     }
-
     static void postBarrier(Value *vp) {
 #ifdef JSGC_GENERATIONAL
-        if (vp->isObject()) {
-            gc::StoreBuffer *sb = reinterpret_cast<gc::Cell *>(&vp->toObject())->storeBuffer();
-            if (sb)
-                sb->putValueFromAnyThread(vp);
-        }
+        if (vp->isObject())
+            shadowRuntimeFromAnyThread(*vp)->gcStoreBufferPtr()->putValue(vp);
 #endif
     }
 
     static void postBarrierRelocate(Value *vp) {
 #ifdef JSGC_GENERATIONAL
-        if (vp->isObject()) {
-            gc::StoreBuffer *sb = reinterpret_cast<gc::Cell *>(&vp->toObject())->storeBuffer();
-            if (sb)
-                sb->putRelocatableValueFromAnyThread(vp);
-        }
+        shadowRuntimeFromAnyThread(*vp)->gcStoreBufferPtr()->putRelocatableValue(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()->removeRelocatableValueFromAnyThread(vp);
+        shadowRuntime->gcStoreBufferPtr()->removeRelocatableValue(vp);
 #endif
     }
 
     static void readBarrier(const Value &v) { ValueReadBarrier(v); }
 };
 
 template <>
 struct InternalGCMethods<jsid>
@@ -857,53 +846,74 @@ class HeapSlot : public BarrieredBase<Va
         pre();
     }
 
     void init(JSObject *owner, Kind kind, uint32_t slot, const Value &v) {
         value = v;
         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);
-    bool preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target) const;
+    static void preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot,
+                                                Value target);
 #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_ASSERT(!IsPoisonedValue(v));
+        JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
         pre(zone);
+        JS_ASSERT(!IsPoisonedValue(v));
         value = v;
-        post(owner, kind, slot, v);
+        post(shadowZone->runtimeFromAnyThread(), owner, kind, slot, v);
     }
 
-    /* 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);
+    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
     }
 
   private:
-    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
+    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);
     }
 };
 
 static inline const Value *
 Valueify(const BarrieredBase<Value> *array)
 {
     JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
     JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -106,18 +106,16 @@ struct Cell
     inline JS::Zone *tenuredZoneFromAnyThread() const;
     inline bool tenuredIsInsideZone(JS::Zone *zone) const;
 
     // Note: Unrestricted access to the runtime of a GC thing from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     inline JSRuntime *runtimeFromAnyThread() const;
     inline JS::shadow::Runtime *shadowRuntimeFromAnyThread() const;
 
-    inline StoreBuffer *storeBuffer() const;
-
 #ifdef DEBUG
     inline bool isAligned() const;
     inline bool isTenured() const;
 #endif
 
   protected:
     inline uintptr_t address() const;
     inline Chunk *chunk() const;
@@ -605,26 +603,25 @@ ArenaHeader::getThingSize() const
  * The tail of the chunk info is shared between all chunks in the system, both
  * nursery and tenured. This structure is locatable from any GC pointer by
  * aligning to 1MiB.
  */
 struct ChunkTrailer
 {
     /* The index the chunk in the nursery, or LocationTenuredHeap. */
     uint32_t        location;
+
+#if JS_BITS_PER_WORD == 64
     uint32_t        padding;
-
-    /* The store buffer for writes to things in this chunk or nullptr. */
-    StoreBuffer     *storeBuffer;
+#endif
 
     JSRuntime       *runtime;
 };
 
-static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t) + sizeof(uint64_t),
-              "ChunkTrailer size is incorrect.");
+static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t), "ChunkTrailer size is incorrect.");
 
 /* The chunk header (located at the end of the chunk to preserve arena alignment). */
 struct ChunkInfo
 {
     Chunk           *next;
     Chunk           **prevp;
 
     /* Free arenas are linked together with aheader.next. */
@@ -863,23 +860,19 @@ struct Chunk
     inline void addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader);
 };
 
 static_assert(sizeof(Chunk) == ChunkSize,
               "Ensure the hardcoded chunk size definition actually matches the struct.");
 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
 {
     uintptr_t addr = reinterpret_cast<uintptr_t>(this);
     JS_ASSERT(!(addr & ArenaMask));
     JS_ASSERT(Chunk::withinArenasRange(addr));
     return addr;
@@ -1099,22 +1092,16 @@ Chunk *
 Cell::chunk() const
 {
     uintptr_t addr = uintptr_t(this);
     JS_ASSERT(addr % CellSize == 0);
     addr &= ~(ChunkSize - 1);
     return reinterpret_cast<Chunk *>(addr);
 }
 
-inline StoreBuffer *
-Cell::storeBuffer() const
-{
-    return chunk()->info.trailer.storeBuffer;
-}
-
 inline bool
 InFreeList(ArenaHeader *aheader, void *thing)
 {
     if (!aheader->hasFreeThings())
         return false;
 
     FreeSpan firstSpan(aheader->getFirstFreeSpan());
     uintptr_t addr = reinterpret_cast<uintptr_t>(thing);
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -198,17 +198,16 @@ class Nursery
     NurseryChunkLayout &chunk(int index) const {
         JS_ASSERT(index < NumNurseryChunks);
         JS_ASSERT(start());
         return reinterpret_cast<NurseryChunkLayout *>(start())[index];
     }
 
     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();
     }
 
     MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) {
         JS_ASSERT(chunkno < NumNurseryChunks);
         JS_ASSERT(chunkno < numActiveChunks_);
         currentChunk_ = chunkno;
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -330,55 +330,49 @@ StoreBuffer::addSizeOfExcludingThis(mozi
     sizes->storeBufferRelocVals  += bufferRelocVal.sizeOfExcludingThis(mallocSizeOf);
     sizes->storeBufferRelocCells += bufferRelocCell.sizeOfExcludingThis(mallocSizeOf);
     sizes->storeBufferGenerics   += bufferGeneric.sizeOfExcludingThis(mallocSizeOf);
 }
 
 JS_PUBLIC_API(void)
 JS::HeapCellPostBarrier(js::gc::Cell **cellp)
 {
-    JS_ASSERT(cellp);
     JS_ASSERT(*cellp);
-    StoreBuffer *storeBuffer = (*cellp)->storeBuffer();
-    if (storeBuffer)
-        storeBuffer->putRelocatableCellFromAnyThread(cellp);
+    JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
+    runtime->gc.storeBuffer.putRelocatableCell(cellp);
 }
 
 JS_PUBLIC_API(void)
 JS::HeapCellRelocate(js::gc::Cell **cellp)
 {
-    /* Called with old contents of *cellp before overwriting. */
-    JS_ASSERT(cellp);
+    /* Called with old contents of *pp before overwriting. */
     JS_ASSERT(*cellp);
     JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
-    runtime->gc.storeBuffer.removeRelocatableCellFromAnyThread(cellp);
+    runtime->gc.storeBuffer.removeRelocatableCell(cellp);
 }
 
 JS_PUBLIC_API(void)
 JS::HeapValuePostBarrier(JS::Value *valuep)
 {
-    JS_ASSERT(valuep);
     JS_ASSERT(valuep->isMarkable());
-    if (valuep->isObject()) {
-        StoreBuffer *storeBuffer = valuep->toObject().storeBuffer();
-        if (storeBuffer)
-            storeBuffer->putRelocatableValueFromAnyThread(valuep);
-    }
+    if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
+        return;
+    JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
+    runtime->gc.storeBuffer.putRelocatableValue(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() && valuep->toString()->isPermanentAtom())
+    if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
         return;
     JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
-    runtime->gc.storeBuffer.removeRelocatableValueFromAnyThread(valuep);
+    runtime->gc.storeBuffer.removeRelocatableValue(valuep);
 }
 
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeCellEdges>;
 template class StoreBuffer::RelocatableMonoTypeBuffer<StoreBuffer::ValueEdge>;
 template class StoreBuffer::RelocatableMonoTypeBuffer<StoreBuffer::CellPtrEdge>;
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -239,18 +239,17 @@ class StoreBuffer
     {
         Cell **edge;
 
         explicit CellPtrEdge(Cell **v) : edge(v) {}
         bool operator==(const CellPtrEdge &other) const { return edge == other.edge; }
         bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
 
         bool maybeInRememberedSet(const Nursery &nursery) const {
-            JS_ASSERT(nursery.isInside(*edge));
-            return !nursery.isInside(edge);
+            return !nursery.isInside(edge) && nursery.isInside(*edge);
         }
 
         void mark(JSTracer *trc);
 
         CellPtrEdge tagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) | 1)); }
         CellPtrEdge untagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
@@ -263,18 +262,17 @@ class StoreBuffer
 
         explicit ValueEdge(JS::Value *v) : edge(v) {}
         bool operator==(const ValueEdge &other) const { return edge == other.edge; }
         bool operator!=(const ValueEdge &other) const { return edge != other.edge; }
 
         void *deref() const { return edge->isGCThing() ? edge->toGCThing() : nullptr; }
 
         bool maybeInRememberedSet(const Nursery &nursery) const {
-            JS_ASSERT(nursery.isInside(deref()));
-            return !nursery.isInside(edge);
+            return !nursery.isInside(edge) && nursery.isInside(deref());
         }
 
         void mark(JSTracer *trc);
 
         ValueEdge tagged() const { return ValueEdge((JS::Value *)(uintptr_t(edge) | 1)); }
         ValueEdge untagged() const { return ValueEdge((JS::Value *)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
@@ -359,17 +357,18 @@ class StoreBuffer
         }
 
       private:
         MarkCallback callback;
         Key *key;
         void *data;
     };
 
-    bool isOkayToUseBuffer() const {
+    template <typename Edge>
+    bool isOkayToUseBuffer(const Edge &edge) const {
         /*
          * Disabled store buffers may not have a valid state; e.g. when stored
          * inline in the ChunkTrailer.
          */
         if (!isEnabled())
             return false;
 
         /*
@@ -378,27 +377,27 @@ class StoreBuffer
          */
         if (!CurrentThreadCanAccessRuntime(runtime_))
             return false;
 
         return true;
     }
 
     template <typename Buffer, typename Edge>
-    void putFromAnyThread(Buffer &buffer, const Edge &edge) {
-        if (!isOkayToUseBuffer())
+    void put(Buffer &buffer, const Edge &edge) {
+        if (!isOkayToUseBuffer(edge))
             return;
         mozilla::ReentrancyGuard g(*this);
         if (edge.maybeInRememberedSet(nursery_))
             buffer.put(this, edge);
     }
 
     template <typename Buffer, typename Edge>
-    void unputFromAnyThread(Buffer &buffer, const Edge &edge) {
-        if (!isOkayToUseBuffer())
+    void unput(Buffer &buffer, const Edge &edge) {
+        if (!isOkayToUseBuffer(edge))
             return;
         mozilla::ReentrancyGuard g(*this);
         buffer.unput(this, edge);
     }
 
     MonoTypeBuffer<ValueEdge> bufferVal;
     MonoTypeBuffer<CellPtrEdge> bufferCell;
     MonoTypeBuffer<SlotsEdge> bufferSlot;
@@ -428,48 +427,40 @@ class StoreBuffer
     bool isEnabled() const { return enabled_; }
 
     bool clear();
 
     /* Get the overflowed status. */
     bool isAboutToOverflow() const { return aboutToOverflow_; }
 
     /* Insert a single edge into the buffer/remembered set. */
-    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 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 putWholeCell(Cell *cell) {
         JS_ASSERT(cell->isTenured());
-        putFromAnyThread(bufferWholeCell, WholeCellEdges(cell));
+        put(bufferWholeCell, WholeCellEdges(cell));
     }
 
     /* Insert or update a single edge in the Relocatable buffer. */
-    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));
-    }
+    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)); }
 
     /* Insert an entry into the generic buffer. */
     template <typename T>
-    void putGeneric(const T &t) { putFromAnyThread(bufferGeneric, t);}
+    void putGeneric(const T &t) { put(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) {
-        putFromAnyThread(bufferGeneric, CallbackRef<Key>(callback, key, data));
+        put(bufferGeneric, CallbackRef<Key>(callback, key, data));
     }
 
     /* Methods to mark the source of all edges in the store buffer. */
     void markAll(JSTracer *trc);
     void markValues(JSTracer *trc)            { bufferVal.mark(this, trc); }
     void markCells(JSTracer *trc)             { bufferCell.mark(this, trc); }
     void markSlots(JSTracer *trc)             { bufferSlot.mark(this, trc); }
     void markWholeCells(JSTracer *trc)        { bufferWholeCell.mark(this, trc); }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -784,17 +784,16 @@ Chunk::init(JSRuntime *rt)
     /*
      * Decommit the arenas. We do this after poisoning so that if the OS does
      * not have to recycle the pages, we still get the benefit of poisoning.
      */
     decommitAllArenas(rt);
 
     /* Initialize the chunk info. */
     info.age = 0;
-    info.trailer.storeBuffer = nullptr;
     info.trailer.location = ChunkLocationTenuredHeap;
     info.trailer.runtime = rt;
 
     /* The rest of info fields are initialized in PickChunk. */
 }
 
 static inline Chunk **
 GetAvailableChunkList(Zone *zone)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2288,18 +2288,18 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         js_memcpy(b, tmp, size);
 
 #ifdef JSGC_GENERATIONAL
         /*
          * Trigger post barriers for fixed slots. JSObject bits are barriered
          * below, in common with the other case.
          */
         for (size_t i = 0; i < a->numFixedSlots(); ++i) {
-            HeapSlot::writeBarrierPost(a, HeapSlot::Slot, i, a->getSlot(i));
-            HeapSlot::writeBarrierPost(b, HeapSlot::Slot, i, b->getSlot(i));
+            HeapSlot::writeBarrierPost(cx->runtime(), a, HeapSlot::Slot, i, a->getSlot(i));
+            HeapSlot::writeBarrierPost(cx->runtime(), b, HeapSlot::Slot, i, b->getSlot(i));
         }
 #endif
     } else {
         /*
          * If the objects are of differing sizes, use the space we reserved
          * earlier to save the slots from each object and then copy them into
          * the new layout for the other object.
          */
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -182,17 +182,17 @@ class StrictArgumentsObject;
  * single step.
  */
 inline void
 DenseRangeWriteBarrierPost(JSRuntime *rt, JSObject *obj, uint32_t start, uint32_t count)
 {
 #ifdef JSGC_GENERATIONAL
     if (count > 0) {
         JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
-        shadowRuntime->gcStoreBufferPtr()->putSlotFromAnyThread(obj, HeapSlot::Element, start, count);
+        shadowRuntime->gcStoreBufferPtr()->putSlot(obj, HeapSlot::Element, start, count);
     }
 #endif
 }
 
 }  /* namespace js */
 
 /*
  * The public interface for an object.
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -218,23 +218,22 @@ JSObject::ensureDenseInitializedLengthNo
      * Ensure that the array's contents have been initialized up to index, and
      * mark the elements through 'index + extra' as initialized in preparation
      * for a write.
      */
     JS_ASSERT(index + extra <= getDenseCapacity());
     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(this, js::HeapSlot::Element, offset, js::MagicValue(JS_ELEMENTS_HOLE));
-        }
+            sp->init(rt, this, js::HeapSlot::Element, offset, js::MagicValue(JS_ELEMENTS_HOLE));
         initlen = index + extra;
     }
 }
 
 inline void
 JSObject::ensureDenseInitializedLength(js::ExclusiveContext *cx, uint32_t index, uint32_t extra)
 {
     if (writeToIndexWouldMarkNotPacked(index))
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -259,32 +259,34 @@ js::ObjectImpl::initializeSlotRange(uint
 {
     /*
      * No bounds check, as this is used when the object's shape does not
      * reflect its allocated slots (updateSlotsForSpan).
      */
     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(this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
+        sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
     for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
-        sp->init(this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue());
+        sp->init(rt, 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(this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
+        sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
     for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
-        sp->init(this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
+        sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, start++, *vector++);
 }
 
 void
 js::ObjectImpl::copySlotRange(uint32_t start, const Value *vector, uint32_t length)
 {
     JS::Zone *zone = this->zone();
     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -835,22 +835,17 @@ class ObjectImpl : public gc::BarrieredC
 
     /* GC support. */
     static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
 
     inline void privateWriteBarrierPre(void **oldval);
 
     void privateWriteBarrierPost(void **pprivate) {
 #ifdef JSGC_GENERATIONAL
-        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);
+        shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
 #endif
     }
 
     void markChildren(JSTracer *trc);
 
     /* Private data accessors. */
 
     inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
@@ -944,53 +939,40 @@ template<>
 /* static */ inline bool
 BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
 {
     return IsNullTaggedPointer(obj);
 }
 
 template<>
 /* static */ inline void
-BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *cellp)
+BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *addr)
 {
-    JS_ASSERT(cellp);
 #ifdef JSGC_GENERATIONAL
     if (IsNullTaggedPointer(obj))
         return;
-    JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
-    gc::StoreBuffer *storeBuffer = obj->storeBuffer();
-    if (storeBuffer)
-        storeBuffer->putCellFromAnyThread(static_cast<Cell **>(cellp));
+    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell((Cell **)addr);
 #endif
 }
 
 template<>
 /* static */ inline void
-BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *cellp)
+BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *addr)
 {
-    JS_ASSERT(cellp);
-    JS_ASSERT(obj);
-    JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
 #ifdef JSGC_GENERATIONAL
-    gc::StoreBuffer *storeBuffer = obj->storeBuffer();
-    if (storeBuffer)
-        storeBuffer->putRelocatableCellFromAnyThread(static_cast<Cell **>(cellp));
+    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putRelocatableCell((Cell **)addr);
 #endif
 }
 
 template<>
 /* static */ inline void
-BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *cellp)
+BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *addr)
 {
-    JS_ASSERT(cellp);
-    JS_ASSERT(obj);
-    JS_ASSERT(obj == *static_cast<ObjectImpl **>(cellp));
 #ifdef JSGC_GENERATIONAL
-    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCellFromAnyThread(
-        static_cast<Cell **>(cellp));
+    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCell((Cell **)addr);
 #endif
 }
 
 } // namespace gc
 
 inline void
 ObjectImpl::privateWriteBarrierPre(void **oldval)
 {
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -520,31 +520,27 @@ struct StackBaseShape;
 namespace gc {
 void MergeCompartments(JSCompartment *source, JSCompartment *target);
 }
 
 static inline void
 GetterSetterWriteBarrierPost(JSRuntime *rt, JSObject **objp)
 {
 #ifdef JSGC_GENERATIONAL
-    JS_ASSERT(objp);
-    JS_ASSERT(*objp);
-    gc::Cell **cellp = reinterpret_cast<gc::Cell **>(objp);
-    gc::StoreBuffer *storeBuffer = (*cellp)->storeBuffer();
-    if (storeBuffer)
-        storeBuffer->putRelocatableCellFromAnyThread(cellp);
+    JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+    shadowRuntime->gcStoreBufferPtr()->putRelocatableCell(reinterpret_cast<gc::Cell **>(objp));
 #endif
 }
 
 static inline void
 GetterSetterWriteBarrierPostRemove(JSRuntime *rt, JSObject **objp)
 {
 #ifdef JSGC_GENERATIONAL
     JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
-    shadowRuntime->gcStoreBufferPtr()->removeRelocatableCellFromAnyThread(reinterpret_cast<gc::Cell **>(objp));
+    shadowRuntime->gcStoreBufferPtr()->removeRelocatableCell(reinterpret_cast<gc::Cell **>(objp));
 #endif
 }
 
 class BaseShape : public gc::BarrieredCell<BaseShape>
 {
   public:
     friend class Shape;
     friend struct StackBaseShape;
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -134,25 +134,25 @@ template
 void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>(
                                     JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
 
 void
 InterpreterFrame::writeBarrierPost()
 {
     /* This needs to follow the same rules as in InterpreterFrame::mark. */
     if (scopeChain_)
-        JSObject::writeBarrierPost(scopeChain_, &scopeChain_);
+        JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
     if (flags_ & HAS_ARGS_OBJ)
-        JSObject::writeBarrierPost(argsObj_, &argsObj_);
+        JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
     if (isFunctionFrame()) {
-        JSFunction::writeBarrierPost(exec.fun, &exec.fun);
+        JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
         if (isEvalFrame())
-            JSScript::writeBarrierPost(u.evalScript, &u.evalScript);
+            JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
     } else {
-        JSScript::writeBarrierPost(exec.script, &exec.script);
+        JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
     }
     if (hasReturnValue())
         HeapValue::writeBarrierPost(rval_, &rval_);
 }
 
 bool
 InterpreterFrame::copyRawFrameSlots(AutoValueVector *vec)
 {