Bug 910771 (part 4) - Move all the methods of EncapsulatedValue, HeapValue, RelocatableValue, and HeapSlot from gc/Barrier-inl.h to gc/Barrier.h. r=terrence.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 04 Sep 2013 20:34:22 -0700
changeset 146167 17fcd21b3d3a84bc2982ac386df340a05594264a
parent 146166 f3bd74c444d99cda051343ccdbfc20966bca144c
child 146168 3e1dd474a575b5ced0bbf7ac4d7f15a8f51bf6b9
push id25244
push userryanvm@gmail.com
push dateMon, 09 Sep 2013 20:03:14 +0000
treeherdermozilla-central@f320b8c034bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs910771
milestone26.0a1
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
Bug 910771 (part 4) - Move all the methods of EncapsulatedValue, HeapValue, RelocatableValue, and HeapSlot from gc/Barrier-inl.h to gc/Barrier.h. r=terrence.
js/src/gc/Barrier-inl.h
js/src/gc/Barrier.cpp
js/src/gc/Barrier.h
js/src/gc/Marking.h
js/src/gc/Zone.cpp
js/src/moz.build
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -13,25 +13,16 @@
 
 #include "gc/Marking.h"
 #include "gc/StoreBuffer.h"
 
 #include "vm/String-inl.h"
 
 namespace js {
 
-JS_ALWAYS_INLINE JS::Zone *
-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();
-}
-
 template <typename T, typename Unioned>
 void
 EncapsulatedPtr<T, Unioned>::pre()
 {
     T::writeBarrierPre(value);
 }
 
 template <typename T>
@@ -48,363 +39,16 @@ template <typename T>
 inline void
 RelocatablePtr<T>::relocate(JSRuntime *rt)
 {
 #ifdef JSGC_GENERATIONAL
     T::writeBarrierPostRemove(this->value, &this->value);
 #endif
 }
 
-inline
-EncapsulatedValue::~EncapsulatedValue()
-{
-    pre();
-}
-
-inline EncapsulatedValue &
-EncapsulatedValue::operator=(const Value &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    return *this;
-}
-
-inline EncapsulatedValue &
-EncapsulatedValue::operator=(const EncapsulatedValue &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v.get();
-    return *this;
-}
-
-inline void
-EncapsulatedValue::writeBarrierPre(const Value &value)
-{
-#ifdef JSGC_INCREMENTAL
-    if (value.isMarkable() && runtimeFromAnyThread(value)->needsBarrier())
-        writeBarrierPre(ZoneOfValue(value), value);
-#endif
-}
-
-inline void
-EncapsulatedValue::writeBarrierPre(Zone *zone, const Value &value)
-{
-#ifdef JSGC_INCREMENTAL
-    if (zone->needsBarrier()) {
-        JS_ASSERT_IF(value.isMarkable(), runtimeFromMainThread(value)->needsBarrier());
-        Value tmp(value);
-        js::gc::MarkValueUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == value);
-    }
-#endif
-}
-
-inline void
-EncapsulatedValue::pre()
-{
-    writeBarrierPre(value);
-}
-
-inline void
-EncapsulatedValue::pre(Zone *zone)
-{
-    writeBarrierPre(zone, value);
-}
-
-inline
-HeapValue::HeapValue()
-    : EncapsulatedValue(UndefinedValue())
-{
-    post();
-}
-
-inline
-HeapValue::HeapValue(const Value &v)
-    : EncapsulatedValue(v)
-{
-    JS_ASSERT(!IsPoisonedValue(v));
-    post();
-}
-
-inline
-HeapValue::HeapValue(const HeapValue &v)
-    : EncapsulatedValue(v.value)
-{
-    JS_ASSERT(!IsPoisonedValue(v.value));
-    post();
-}
-
-inline
-HeapValue::~HeapValue()
-{
-    pre();
-}
-
-inline void
-HeapValue::init(const Value &v)
-{
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post();
-}
-
-inline void
-HeapValue::init(JSRuntime *rt, const Value &v)
-{
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post(rt);
-}
-
-inline HeapValue &
-HeapValue::operator=(const Value &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post();
-    return *this;
-}
-
-inline HeapValue &
-HeapValue::operator=(const HeapValue &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v.value));
-    value = v.value;
-    post();
-    return *this;
-}
-
-inline void
-HeapValue::set(Zone *zone, const Value &v)
-{
-#ifdef DEBUG
-    if (value.isMarkable()) {
-        JS_ASSERT(ZoneOfValue(value) == zone ||
-                  zone->runtimeFromAnyThread()->isAtomsZone(ZoneOfValue(value)));
-    }
-#endif
-
-    pre(zone);
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post(zone->runtimeFromAnyThread());
-}
-
-inline void
-HeapValue::writeBarrierPost(const Value &value, Value *addr)
-{
-#ifdef JSGC_GENERATIONAL
-    if (value.isMarkable())
-        runtimeFromMainThread(value)->gcStoreBuffer.putValue(addr);
-#endif
-}
-
-inline void
-HeapValue::writeBarrierPost(JSRuntime *rt, const Value &value, Value *addr)
-{
-#ifdef JSGC_GENERATIONAL
-    if (value.isMarkable())
-        rt->gcStoreBuffer.putValue(addr);
-#endif
-}
-
-inline void
-HeapValue::post()
-{
-    writeBarrierPost(value, &value);
-}
-
-inline void
-HeapValue::post(JSRuntime *rt)
-{
-    writeBarrierPost(rt, value, &value);
-}
-
-inline
-RelocatableValue::RelocatableValue()
-    : EncapsulatedValue(UndefinedValue())
-{
-}
-
-inline
-RelocatableValue::RelocatableValue(const Value &v)
-    : EncapsulatedValue(v)
-{
-    JS_ASSERT(!IsPoisonedValue(v));
-    if (v.isMarkable())
-        post();
-}
-
-inline
-RelocatableValue::RelocatableValue(const RelocatableValue &v)
-    : EncapsulatedValue(v.value)
-{
-    JS_ASSERT(!IsPoisonedValue(v.value));
-    if (v.value.isMarkable())
-        post();
-}
-
-inline
-RelocatableValue::~RelocatableValue()
-{
-    if (value.isMarkable())
-        relocate(runtimeFromMainThread(value));
-}
-
-inline RelocatableValue &
-RelocatableValue::operator=(const Value &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v));
-    if (v.isMarkable()) {
-        value = v;
-        post();
-    } else if (value.isMarkable()) {
-        JSRuntime *rt = runtimeFromMainThread(value);
-        relocate(rt);
-        value = v;
-    } else {
-        value = v;
-    }
-    return *this;
-}
-
-inline RelocatableValue &
-RelocatableValue::operator=(const RelocatableValue &v)
-{
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v.value));
-    if (v.value.isMarkable()) {
-        value = v.value;
-        post();
-    } else if (value.isMarkable()) {
-        JSRuntime *rt = runtimeFromMainThread(value);
-        relocate(rt);
-        value = v.value;
-    } else {
-        value = v.value;
-    }
-    return *this;
-}
-
-inline void
-RelocatableValue::post()
-{
-#ifdef JSGC_GENERATIONAL
-    JS_ASSERT(value.isMarkable());
-    runtimeFromMainThread(value)->gcStoreBuffer.putRelocatableValue(&value);
-#endif
-}
-
-inline void
-RelocatableValue::relocate(JSRuntime *rt)
-{
-#ifdef JSGC_GENERATIONAL
-    rt->gcStoreBuffer.removeRelocatableValue(&value);
-#endif
-}
-
-inline
-HeapSlot::HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-    : EncapsulatedValue(v)
-{
-    JS_ASSERT(!IsPoisonedValue(v));
-    post(obj, kind, slot, v);
-}
-
-inline
-HeapSlot::HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const HeapSlot &s)
-    : EncapsulatedValue(s.value)
-{
-    JS_ASSERT(!IsPoisonedValue(s.value));
-    post(obj, kind, slot, s);
-}
-
-inline
-HeapSlot::~HeapSlot()
-{
-    pre();
-}
-
-inline void
-HeapSlot::init(JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-{
-    value = v;
-    post(obj, kind, slot, v);
-}
-
-inline void
-HeapSlot::init(JSRuntime *rt, JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-{
-    value = v;
-    post(rt, obj, kind, slot, v);
-}
-
-inline void
-HeapSlot::set(JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-{
-    JS_ASSERT_IF(kind == Slot, &obj->getSlotRef(slot) == this);
-    JS_ASSERT_IF(kind == Element, &obj->getDenseElement(slot) == (const Value *)this);
-
-    pre();
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post(obj, kind, slot, v);
-}
-
-inline void
-HeapSlot::set(Zone *zone, JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-{
-    JS_ASSERT_IF(kind == Slot, &obj->getSlotRef(slot) == this);
-    JS_ASSERT_IF(kind == Element, &obj->getDenseElement(slot) == (const Value *)this);
-    JS_ASSERT(obj->zone() == zone);
-
-    pre(zone);
-    JS_ASSERT(!IsPoisonedValue(v));
-    value = v;
-    post(zone->runtimeFromAnyThread(), obj, kind, slot, v);
-}
-
-inline void
-HeapSlot::writeBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target)
-{
-#ifdef JSGC_GENERATIONAL
-    writeBarrierPost(obj->runtimeFromAnyThread(), obj, kind, slot, target);
-#endif
-}
-
-inline void
-HeapSlot::writeBarrierPost(JSRuntime *rt, JSObject *obj, Kind kind, uint32_t slot, Value target)
-{
-#ifdef JSGC_GENERATIONAL
-    JS_ASSERT_IF(kind == Slot, obj->getSlotAddressUnchecked(slot)->get() == target);
-    JS_ASSERT_IF(kind == Element,
-                 static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target);
-
-    if (target.isObject())
-        rt->gcStoreBuffer.putSlot(obj, kind, slot, &target.toObject());
-#endif
-}
-
-inline void
-HeapSlot::post(JSObject *owner, Kind kind, uint32_t slot, Value target)
-{
-    HeapSlot::writeBarrierPost(owner, kind, slot, target);
-}
-
-inline void
-HeapSlot::post(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, Value target)
-{
-    HeapSlot::writeBarrierPost(rt, owner, kind, slot, target);
-}
-
 #ifdef JSGC_GENERATIONAL
 class DenseRangeRef : public gc::BufferableRef
 {
     JSObject *owner;
     uint32_t start;
     uint32_t end;
 
   public:
@@ -444,17 +88,16 @@ inline void
 HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
 {
 #ifdef JSGC_GENERATIONAL
     if (key && IsInsideNursery(rt, key))
         rt->gcStoreBuffer.putGeneric(gc::HashKeyRef<Map, Key>(map, key));
 #endif
 }
 
-
 inline
 EncapsulatedId::~EncapsulatedId()
 {
     pre();
 }
 
 inline EncapsulatedId &
 EncapsulatedId::operator=(const EncapsulatedId &v)
new file mode 100644
--- /dev/null
+++ b/js/src/gc/Barrier.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gc/Barrier.h"
+
+#include "jsobj.h"
+
+#include "vm/ObjectImpl-inl.h"
+
+namespace js {
+
+#ifdef DEBUG
+
+bool
+HeapValue::preconditionForSet(Zone *zone)
+{
+    if (!value.isMarkable())
+        return true;
+
+    return ZoneOfValue(value) == zone ||
+           zone->runtimeFromAnyThread()->isAtomsZone(ZoneOfValue(value));
+}
+
+bool
+HeapSlot::preconditionForSet(JSObject *owner, Kind kind, uint32_t slot)
+{
+    return kind == Slot
+         ? &owner->getSlotRef(slot) == this
+         : &owner->getDenseElement(slot) == (const Value *)this;
+}
+
+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;
+}
+
+void
+HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target)
+{
+    JS_ASSERT_IF(kind == Slot, obj->getSlotAddressUnchecked(slot)->get() == target);
+    JS_ASSERT_IF(kind == Element,
+                 static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target);
+}
+
+#endif // DEBUG
+
+} // namespace js
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -115,16 +115,34 @@
  * the init naming idiom in many places to signify that a field is being
  * assigned for the first time.
  */
 
 namespace js {
 
 class PropertyName;
 
+namespace gc {
+// Direct value access used by the write barriers and the jits.
+void
+MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+}
+
+JS::Zone *
+ZoneOfObject(const JSObject &obj);
+
+JS_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();
+}
+
 template<class T, typename Unioned = uintptr_t>
 class EncapsulatedPtr
 {
   protected:
     union {
         T *value;
         Unioned other;
     };
@@ -388,47 +406,77 @@ class EncapsulatedValue : public ValueOp
 
   public:
     EncapsulatedValue(const Value &v) : value(v) {
         JS_ASSERT(!IsPoisonedValue(v));
     }
     EncapsulatedValue(const EncapsulatedValue &v) : value(v) {
         JS_ASSERT(!IsPoisonedValue(v));
     }
-    inline ~EncapsulatedValue();
+
+    ~EncapsulatedValue() {
+        pre();
+    }
 
     void init(const Value &v) {
         JS_ASSERT(!IsPoisonedValue(v));
         value = v;
     }
     void init(JSRuntime *rt, const Value &v) {
         JS_ASSERT(!IsPoisonedValue(v));
         value = v;
     }
 
-    inline EncapsulatedValue &operator=(const Value &v);
-    inline EncapsulatedValue &operator=(const EncapsulatedValue &v);
+    EncapsulatedValue &operator=(const Value &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        return *this;
+    }
+
+    EncapsulatedValue &operator=(const EncapsulatedValue &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v.get();
+        return *this;
+    }
 
     bool operator==(const EncapsulatedValue &v) const { return value == v.value; }
     bool operator!=(const EncapsulatedValue &v) const { return value != v.value; }
 
     const Value &get() const { return value; }
     Value *unsafeGet() { return &value; }
     operator const Value &() const { return value; }
 
     JSGCTraceKind gcKind() const { return value.gcKind(); }
 
     uint64_t asRawBits() const { return value.asRawBits(); }
 
-    static inline void writeBarrierPre(const Value &v);
-    static inline void writeBarrierPre(Zone *zone, const Value &v);
+    static void writeBarrierPre(const Value &v) {
+#ifdef JSGC_INCREMENTAL
+        if (v.isMarkable() && shadowRuntimeFromAnyThread(v)->needsBarrier())
+            writeBarrierPre(ZoneOfValue(v), v);
+#endif
+    }
+
+    static void writeBarrierPre(Zone *zone, const Value &v) {
+#ifdef JSGC_INCREMENTAL
+        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
+    }
 
   protected:
-    inline void pre();
-    inline void pre(Zone *zone);
+    void pre() { writeBarrierPre(value); }
+    void pre(Zone *zone) { writeBarrierPre(zone, value); }
 
     static JSRuntime *runtimeFromMainThread(const Value &v) {
         JS_ASSERT(v.isMarkable());
         return static_cast<js::gc::Cell *>(v.toGCThing())->runtimeFromMainThread();
     }
     static JSRuntime *runtimeFromAnyThread(const Value &v) {
         JS_ASSERT(v.isMarkable());
         return static_cast<js::gc::Cell *>(v.toGCThing())->runtimeFromAnyThread();
@@ -443,57 +491,188 @@ class EncapsulatedValue : public ValueOp
   private:
     friend class ValueOperations<EncapsulatedValue>;
     const Value * extract() const { return &value; }
 };
 
 class HeapValue : public EncapsulatedValue
 {
   public:
-    explicit inline HeapValue();
-    explicit inline HeapValue(const Value &v);
-    explicit inline HeapValue(const HeapValue &v);
-    inline ~HeapValue();
+    explicit HeapValue()
+      : EncapsulatedValue(UndefinedValue())
+    {
+        post();
+    }
+
+    explicit HeapValue(const Value &v)
+      : EncapsulatedValue(v)
+    {
+        JS_ASSERT(!IsPoisonedValue(v));
+        post();
+    }
+
+    explicit HeapValue(const HeapValue &v)
+      : EncapsulatedValue(v.value)
+    {
+        JS_ASSERT(!IsPoisonedValue(v.value));
+        post();
+    }
+
+    ~HeapValue() {
+        pre();
+    }
 
-    inline void init(const Value &v);
-    inline void init(JSRuntime *rt, const Value &v);
+    void init(const Value &v) {
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        post();
+    }
+
+    void init(JSRuntime *rt, const Value &v) {
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        post(rt);
+    }
 
-    inline HeapValue &operator=(const Value &v);
-    inline HeapValue &operator=(const HeapValue &v);
+    HeapValue &operator=(const Value &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        post();
+        return *this;
+    }
+
+    HeapValue &operator=(const HeapValue &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v.value));
+        value = v.value;
+        post();
+        return *this;
+    }
+
+#ifdef DEBUG
+    bool preconditionForSet(Zone *zone);
+#endif
 
     /*
      * This is a faster version of operator=. Normally, operator= has to
      * determine the compartment of the value before it can decide whether to do
      * the barrier. If you already know the compartment, it's faster to pass it
      * in.
      */
-    inline void set(Zone *zone, const Value &v);
+    void set(Zone *zone, const Value &v) {
+        JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
+        JS_ASSERT(preconditionForSet(zone));
+        pre(zone);
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        post(shadowZone->runtimeFromAnyThread());
+    }
 
-    static inline void writeBarrierPost(const Value &v, Value *addr);
-    static inline void writeBarrierPost(JSRuntime *rt, const Value &v, Value *addr);
+    static void writeBarrierPost(const Value &value, Value *addr) {
+#ifdef JSGC_GENERATIONAL
+        if (value.isMarkable())
+            shadowRuntimeFromMainThread(value)->gcStoreBufferPtr()->putValue(addr);
+#endif
+    }
+
+    static void writeBarrierPost(JSRuntime *rt, const Value &value, Value *addr) {
+#ifdef JSGC_GENERATIONAL
+        if (value.isMarkable()) {
+            JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+            shadowRuntime->gcStoreBufferPtr()->putValue(addr);
+        }
+#endif
+    }
 
   private:
-    inline void post();
-    inline void post(JSRuntime *rt);
+    void post() {
+        writeBarrierPost(value, &value);
+    }
+
+    void post(JSRuntime *rt) {
+        writeBarrierPost(rt, value, &value);
+    }
 };
 
 class RelocatableValue : public EncapsulatedValue
 {
   public:
-    explicit inline RelocatableValue();
-    explicit inline RelocatableValue(const Value &v);
-    inline RelocatableValue(const RelocatableValue &v);
-    inline ~RelocatableValue();
+    explicit RelocatableValue()
+      : EncapsulatedValue(UndefinedValue())
+    {}
+
+    explicit RelocatableValue(const Value &v)
+      : EncapsulatedValue(v)
+    {
+        JS_ASSERT(!IsPoisonedValue(v));
+        if (v.isMarkable())
+            post();
+    }
+
+    RelocatableValue(const RelocatableValue &v)
+      : EncapsulatedValue(v.value)
+    {
+        JS_ASSERT(!IsPoisonedValue(v.value));
+        if (v.value.isMarkable())
+            post();
+    }
+
+    ~RelocatableValue()
+    {
+        if (value.isMarkable())
+            relocate(runtimeFromMainThread(value));
+    }
 
-    inline RelocatableValue &operator=(const Value &v);
-    inline RelocatableValue &operator=(const RelocatableValue &v);
+    RelocatableValue &operator=(const Value &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        if (v.isMarkable()) {
+            value = v;
+            post();
+        } else if (value.isMarkable()) {
+            JSRuntime *rt = runtimeFromMainThread(value);
+            relocate(rt);
+            value = v;
+        } else {
+            value = v;
+        }
+        return *this;
+    }
+
+    RelocatableValue &operator=(const RelocatableValue &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v.value));
+        if (v.value.isMarkable()) {
+            value = v.value;
+            post();
+        } else if (value.isMarkable()) {
+            JSRuntime *rt = runtimeFromMainThread(value);
+            relocate(rt);
+            value = v.value;
+        } else {
+            value = v.value;
+        }
+        return *this;
+    }
 
   private:
-    inline void post();
-    inline void relocate(JSRuntime *rt);
+    void post() {
+#ifdef JSGC_GENERATIONAL
+        JS_ASSERT(value.isMarkable());
+        shadowRuntimeFromMainThread(value)->gcStoreBufferPtr()->putRelocatableValue(&value);
+#endif
+    }
+
+    void relocate(JSRuntime *rt) {
+#ifdef JSGC_GENERATIONAL
+        JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+        shadowRuntime->gcStoreBufferPtr()->removeRelocatableValue(&value);
+#endif
+    }
 };
 
 class HeapSlot : public EncapsulatedValue
 {
     /*
      * Operator= is not valid for HeapSlot because is must take the object and
      * slot offset to provide to the post/generational barrier.
      */
@@ -502,34 +681,100 @@ class HeapSlot : public EncapsulatedValu
     inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE;
 
   public:
     enum Kind {
         Slot,
         Element
     };
 
-    explicit inline HeapSlot() MOZ_DELETE;
-    explicit inline HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const Value &v);
-    explicit inline HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const HeapSlot &v);
-    inline ~HeapSlot();
+    explicit HeapSlot() MOZ_DELETE;
+
+    explicit HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const Value &v)
+      : EncapsulatedValue(v)
+    {
+        JS_ASSERT(!IsPoisonedValue(v));
+        post(obj, kind, slot, v);
+    }
+
+    explicit HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const HeapSlot &s)
+      : EncapsulatedValue(s.value)
+    {
+        JS_ASSERT(!IsPoisonedValue(s.value));
+        post(obj, kind, slot, s);
+    }
+
+    ~HeapSlot() {
+        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);
+    static void preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot,
+                                                Value target);
+#endif
 
-    inline void init(JSObject *owner, Kind kind, uint32_t slot, const Value &v);
-    inline void init(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, const Value &v);
+    void set(JSObject *owner, Kind kind, uint32_t slot, const Value &v) {
+        JS_ASSERT(preconditionForSet(owner, kind, slot));
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        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));
+        value = v;
+        post(shadowZone->runtimeFromAnyThread(), owner, kind, slot, v);
+    }
 
-    inline void set(JSObject *owner, Kind kind, uint32_t slot, const Value &v);
-    inline void set(Zone *zone, JSObject *owner, Kind kind, uint32_t slot, const Value &v);
+    static void writeBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target)
+    {
+#ifdef JSGC_GENERATIONAL
+        js::gc::Cell *cell = reinterpret_cast<js::gc::Cell*>(obj);
+        writeBarrierPost(cell->runtimeFromAnyThread(), obj, kind, slot, target);
+#endif
+    }
 
-    static inline void writeBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target);
-    static inline void writeBarrierPost(JSRuntime *rt, JSObject *obj, Kind kind, uint32_t slot,
-                                        Value target);
+    static void writeBarrierPost(JSRuntime *rt, JSObject *obj, Kind kind, uint32_t slot,
+                                 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, &target.toObject());
+        }
+#endif
+    }
 
   private:
-    inline void post(JSObject *owner, Kind kind, uint32_t slot, Value target);
-    inline void post(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, Value target);
+    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);
+    }
 };
 
 /*
  * NOTE: This is a placeholder for bug 619558.
  *
  * Run a post write barrier that encompasses multiple contiguous slots in a
  * single step.
  */
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -218,20 +218,16 @@ MarkCrossCompartmentSlot(JSTracer *trc, 
 
 /*
  * The unioned HeapPtr stored in script->globalObj needs special treatment to
  * typecheck correctly.
  */
 void
 MarkObject(JSTracer *trc, HeapPtr<GlobalObject, JSScript *> *thingp, const char *name);
 
-/* Direct value access used by the write barriers and the methodjit. */
-void
-MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
-
 /*
  * MarkChildren<JSObject> is exposed solely for preWriteBarrier on
  * JSObject::TradeGuts. It should not be considered external interface.
  */
 void
 MarkChildren(JSTracer *trc, JSObject *obj);
 
 /*
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -229,8 +229,16 @@ Zone::discardJitCode(FreeOp *fop, bool d
             if (comp->ionCompartment())
                 comp->ionCompartment()->optimizedStubSpace()->free();
 
             comp->types.sweepCompilerOutputs(fop, discardConstraints);
         }
     }
 #endif
 }
+
+JS::Zone *
+js::ZoneOfObject(const JSObject &obj)
+{
+    return obj.zone();
+}
+
+
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -74,17 +74,17 @@ EXPORTS.js += [
     '../public/TypeDecls.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
 ]
 
 CPP_SOURCES += [
     'ArgumentsObject.cpp',
-    'TypedObject.cpp',
+    'Barrier.cpp',
     'BytecodeCompiler.cpp',
     'BytecodeEmitter.cpp',
     'CallNonGenericMethod.cpp',
     'CharacterEncoding.cpp',
     'DateTime.cpp',
     'Debugger.cpp',
     'Eval.cpp',
     'ExecutableAllocator.cpp',
@@ -131,16 +131,17 @@ CPP_SOURCES += [
     'StringBuffer.cpp',
     'StructuredClone.cpp',
     'TestingFunctions.cpp',
     'ThreadPool.cpp',
     'TokenStream.cpp',
     'Tracer.cpp',
     'TypeRepresentation.cpp',
     'TypedArrayObject.cpp',
+    'TypedObject.cpp',
     'Unicode.cpp',
     'Value.cpp',
     'Verifier.cpp',
     'Xdr.cpp',
     'YarrCanonicalizeUCS2.cpp',
     'YarrInterpreter.cpp',
     'YarrPattern.cpp',
     'YarrSyntaxChecker.cpp',