Bug 914032 (part 3) - Move a bunch more stuff out of -inl.h files. r=terrence.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 09 Sep 2013 15:50:19 -0700
changeset 146317 ea33604f6232a07d3e4be77718226d569490407f
parent 146316 ea1af870680c7ec875f0bce61c8541cc37a3b9d6
child 146318 25bfaa9538928bc70683aea449dc25b6ece6d4d1
child 146396 bd53e981282f9ed59ca35ce59776c2f94e9f6e7d
push id25251
push userMs2ger@gmail.com
push dateTue, 10 Sep 2013 08:13:39 +0000
treeherdermozilla-central@25bfaa953892 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs914032
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 914032 (part 3) - Move a bunch more stuff out of -inl.h files. r=terrence.
js/src/gc/Barrier-inl.h
js/src/gc/Barrier.h
js/src/gc/Marking.h
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/vm/Shape-inl.h
js/src/vm/Shape.h
js/src/vm/String-inl.h
js/src/vm/String.h
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -13,42 +13,16 @@
 
 #include "gc/Marking.h"
 #include "gc/StoreBuffer.h"
 
 #include "vm/String-inl.h"
 
 namespace js {
 
-template <typename T, typename Unioned>
-void
-EncapsulatedPtr<T, Unioned>::pre()
-{
-    T::writeBarrierPre(value);
-}
-
-template <typename T>
-inline void
-RelocatablePtr<T>::post()
-{
-#ifdef JSGC_GENERATIONAL
-    JS_ASSERT(this->value);
-    T::writeBarrierPostRelocate(this->value, &this->value);
-#endif
-}
-
-template <typename T>
-inline void
-RelocatablePtr<T>::relocate(JSRuntime *rt)
-{
-#ifdef JSGC_GENERATIONAL
-    T::writeBarrierPostRemove(this->value, &this->value);
-#endif
-}
-
 #ifdef JSGC_GENERATIONAL
 class DenseRangeRef : public gc::BufferableRef
 {
     JSObject *owner;
     uint32_t start;
     uint32_t end;
 
   public:
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -192,17 +192,17 @@ class EncapsulatedPtr
     Unioned *unsafeGetUnioned() { return &other; }
 
     T &operator*() const { return *value; }
     T *operator->() const { return value; }
 
     operator T*() const { return value; }
 
   protected:
-    void pre();
+    void pre() { T::writeBarrierPre(value); }
 };
 
 template <class T, class Unioned = uintptr_t>
 class HeapPtr : public EncapsulatedPtr<T, Unioned>
 {
   public:
     HeapPtr() : EncapsulatedPtr<T>(NULL) {}
     explicit HeapPtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
@@ -315,18 +315,28 @@ class RelocatablePtr : public Encapsulat
             JSRuntime *rt = this->value->runtimeFromMainThread();
             this->value = v;
             relocate(rt);
         }
         return *this;
     }
 
   protected:
-    inline void post();
-    inline void relocate(JSRuntime *rt);
+    void post() {
+#ifdef JSGC_GENERATIONAL
+        JS_ASSERT(this->value);
+        T::writeBarrierPostRelocate(this->value, &this->value);
+#endif
+    }
+
+    void relocate(JSRuntime *rt) {
+#ifdef JSGC_GENERATIONAL
+        T::writeBarrierPostRemove(this->value, &this->value);
+#endif
+    }
 };
 
 /*
  * This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
  * barriers with only one branch to check if we're in an incremental GC.
  */
 template<class T1, class T2>
 static inline void
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -3,17 +3,16 @@
  * 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/. */
 
 #ifndef gc_Marking_h
 #define gc_Marking_h
 
 #include "gc/Barrier.h"
-#include "jit/IonCode.h"
 #include "js/TypeDecls.h"
 
 class JSAtom;
 class JSLinearString;
 
 namespace js {
 
 class ArgumentsObject;
@@ -25,16 +24,26 @@ struct GCMarker;
 class GlobalObject;
 class LazyScript;
 class ScopeObject;
 class Shape;
 class UnownedBaseShape;
 
 template<class, typename> class HeapPtr;
 
+namespace jit {
+class IonCode;
+class IonScript;
+class VMFunction;
+}
+
+namespace types {
+class Type;
+}
+
 namespace gc {
 
 /*** Object Marking ***/
 
 /*
  * These functions expose marking functionality for all of the different GC
  * thing kinds. For each GC thing, there are several variants. As an example,
  * these are the variants generated for JSObject. They are listed from most to
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -12,16 +12,17 @@
 #include "mozilla/MemoryReporting.h"
 
 #include "jsalloc.h"
 #include "jsfriendapi.h"
 
 #include "ds/IdValuePair.h"
 #include "ds/LifoAlloc.h"
 #include "gc/Barrier.h"
+#include "gc/Marking.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace js {
 
 class TypeRepresentation;
 
 class TaggedProto
@@ -880,17 +881,18 @@ struct TypeObjectAddendum
         return kind == TypedObject;
     }
 
     TypeTypedObject *asTypedObject() {
         JS_ASSERT(isTypedObject());
         return (TypeTypedObject*) this;
     }
 
-    static inline void writeBarrierPre(TypeObjectAddendum *newScript);
+    static inline void writeBarrierPre(TypeObjectAddendum *type);
+
     static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {}
 };
 
 /*
  * Information attached to a TypeObject if it is always constructed using 'new'
  * on a particular script. This is used to manage state related to the definite
  * properties on the type object: these definite properties depend on type
  * information which could change as the script executes (e.g. a scripted
@@ -1147,20 +1149,44 @@ struct TypeObject : gc::Cell
     /*
      * Type objects don't have explicit finalizers. Memory owned by a type
      * object pending deletion is released when weak references are sweeped
      * from all the compartment's type objects.
      */
     void finalize(FreeOp *fop) {}
 
     JS::Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
 
-    static inline void writeBarrierPre(TypeObject *type);
+    static void writeBarrierPre(TypeObject *type) {
+#ifdef JSGC_INCREMENTAL
+        if (!type || !type->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = type->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            TypeObject *tmp = type;
+            js::gc::MarkTypeObjectUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == type);
+        }
+#endif
+    }
+
     static void writeBarrierPost(TypeObject *type, void *addr) {}
-    static inline void readBarrier(TypeObject *type);
+
+    static void readBarrier(TypeObject *type) {
+#ifdef JSGC_INCREMENTAL
+        JS::shadow::Zone *shadowZone = type->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            TypeObject *tmp = type;
+            MarkTypeObjectUnbarriered(shadowZone->barrierTracer(), &tmp, "read barrier");
+            JS_ASSERT(tmp == type);
+        }
+#endif
+    }
 
     static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
 
   private:
     inline uint32_t basePropertyCount() const;
     inline void setBasePropertyCount(uint32_t count);
 
     static void staticAsserts() {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1566,45 +1566,16 @@ inline int
 TypeObject::getTypedArrayType()
 {
     if (IsTypedArrayClass(clasp))
         return clasp - &TypedArrayObject::classes[0];
     return ScalarTypeRepresentation::TYPE_MAX;
 }
 
 inline void
-TypeObject::writeBarrierPre(TypeObject *type)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!type || !type->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = type->zone();
-    if (zone->needsBarrier()) {
-        TypeObject *tmp = type;
-        MarkTypeObjectUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == type);
-    }
-#endif
-}
-
-inline void
-TypeObject::readBarrier(TypeObject *type)
-{
-#ifdef JSGC_INCREMENTAL
-    JS::Zone *zone = type->zone();
-    if (zone->needsBarrier()) {
-        TypeObject *tmp = type;
-        MarkTypeObjectUnbarriered(zone->barrierTracer(), &tmp, "read barrier");
-        JS_ASSERT(tmp == type);
-    }
-#endif
-}
-
-inline void
 TypeObjectAddendum::writeBarrierPre(TypeObjectAddendum *type)
 {
 #ifdef JSGC_INCREMENTAL
     if (!type)
         return;
 
     switch (type->kind) {
       case NewScript:
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -16,22 +16,22 @@
 #ifdef JS_THREADSAFE
 #include "jslock.h"
 #endif
 #include "jsobj.h"
 #include "jsopcode.h"
 
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
+#include "jit/IonCode.h"
 #include "vm/Shape.h"
 
 namespace js {
 
 namespace jit {
-    struct IonScript;
     struct BaselineScript;
     struct IonScriptCounts;
 }
 
 # define ION_DISABLED_SCRIPT ((js::jit::IonScript *)0x1)
 # define ION_COMPILING_SCRIPT ((js::jit::IonScript *)0x2)
 
 # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript *)0x1)
@@ -720,17 +720,22 @@ class JSScript : public js::gc::Cell
         return ion;
     }
     js::jit::IonScript *maybeIonScript() const {
         return ion;
     }
     js::jit::IonScript *const *addressOfIonScript() const {
         return &ion;
     }
-    inline void setIonScript(js::jit::IonScript *ionScript);
+    void setIonScript(js::jit::IonScript *ionScript) {
+        if (hasIonScript())
+            js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
+        ion = ionScript;
+        updateBaselineOrIonRaw();
+    }
 
     bool hasBaselineScript() const {
         return baseline && baseline != BASELINE_DISABLED_SCRIPT;
     }
     bool canBaselineCompile() const {
         return baseline != BASELINE_DISABLED_SCRIPT;
     }
     js::jit::BaselineScript *baselineScript() const {
@@ -755,17 +760,21 @@ class JSScript : public js::gc::Cell
 
     js::jit::IonScript *parallelIonScript() const {
         JS_ASSERT(hasParallelIonScript());
         return parallelIon;
     }
     js::jit::IonScript *maybeParallelIonScript() const {
         return parallelIon;
     }
-    inline void setParallelIonScript(js::jit::IonScript *ionScript);
+    void setParallelIonScript(js::jit::IonScript *ionScript) {
+        if (hasParallelIonScript())
+            js::jit::IonScript::writeBarrierPre(tenuredZone(), parallelIon);
+        parallelIon = ionScript;
+    }
 
     static size_t offsetOfBaselineScript() {
         return offsetof(JSScript, baseline);
     }
     static size_t offsetOfIonScript() {
         return offsetof(JSScript, ion);
     }
     static size_t offsetOfParallelIonScript() {
@@ -1049,18 +1058,33 @@ class JSScript : public js::gc::Cell
 
 #ifdef DEBUG
     uint32_t stepModeCount() { return hasDebugScript ? (debugScript()->stepMode & stepCountMask) : 0; }
 #endif
 
     void finalize(js::FreeOp *fop);
 
     JS::Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
 
-    static inline void writeBarrierPre(JSScript *script);
+    static void writeBarrierPre(JSScript *script) {
+#ifdef JSGC_INCREMENTAL
+        if (!script || !script->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = script->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            MOZ_ASSERT(!js::RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
+            JSScript *tmp = script;
+            js::gc::MarkScriptUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == script);
+        }
+#endif
+    }
+
     static void writeBarrierPost(JSScript *script, void *addr) {}
 
     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
 
     void markChildren(JSTracer *trc);
 };
 
 /* The array kind flags are stored in a 4-bit field; make sure they fit. */
@@ -1309,29 +1333,41 @@ class LazyScript : public js::gc::Cell
         return lineno_;
     }
     uint32_t column() const {
         return column_;
     }
 
     uint32_t staticLevel(JSContext *cx) const;
 
-    Zone *zone() const {
-        return Cell::tenuredZone();
-    }
+    Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
 
     void markChildren(JSTracer *trc);
     void finalize(js::FreeOp *fop);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
     {
         return mallocSizeOf(table_);
     }
 
-    static inline void writeBarrierPre(LazyScript *lazy);
+    static void writeBarrierPre(LazyScript *lazy) {
+#ifdef JSGC_INCREMENTAL
+        if (!lazy || !lazy->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = lazy->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            MOZ_ASSERT(!js::RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
+            js::LazyScript *tmp = lazy;
+            MarkLazyScriptUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == lazy);
+        }
+#endif
+    }
 };
 
 /* If this fails, add/remove padding within LazyScript. */
 JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
 
 /*
  * New-script-hook calling is factored from JSScript::fullyInitFromEmitter() so
  * that it and callers of XDRScript() can share this code.  In the case of
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -96,50 +96,16 @@ JSScript::global() const
 {
     /*
      * A JSScript always marks its compartment's global (via bindings) so we
      * can assert that maybeGlobal is non-null here.
      */
     return *compartment()->maybeGlobal();
 }
 
-inline void
-JSScript::writeBarrierPre(JSScript *script)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!script || !script->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = script->zone();
-    if (zone->needsBarrier()) {
-        JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
-        JSScript *tmp = script;
-        MarkScriptUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == script);
-    }
-#endif
-}
-
-/* static */ inline void
-js::LazyScript::writeBarrierPre(js::LazyScript *lazy)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!lazy || !lazy->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = lazy->zone();
-    if (zone->needsBarrier()) {
-        JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
-        js::LazyScript *tmp = lazy;
-        MarkLazyScriptUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == lazy);
-    }
-#endif
-}
-
 inline JSPrincipals *
 JSScript::principals()
 {
     return compartment()->principals;
 }
 
 inline JSFunction *
 JSScript::originalFunction() const {
@@ -151,31 +117,16 @@ JSScript::originalFunction() const {
 inline void
 JSScript::setOriginalFunctionObject(JSObject *fun) {
     JS_ASSERT(isCallsiteClone);
     JS_ASSERT(fun->is<JSFunction>());
     enclosingScopeOrOriginalFunction_ = fun;
 }
 
 inline void
-JSScript::setIonScript(js::jit::IonScript *ionScript) {
-    if (hasIonScript())
-        js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
-    ion = ionScript;
-    updateBaselineOrIonRaw();
-}
-
-inline void
-JSScript::setParallelIonScript(js::jit::IonScript *ionScript) {
-    if (hasParallelIonScript())
-        js::jit::IonScript::writeBarrierPre(tenuredZone(), parallelIon);
-    parallelIon = ionScript;
-}
-
-inline void
 JSScript::setBaselineScript(js::jit::BaselineScript *baselineScript) {
 #ifdef JS_ION
     if (hasBaselineScript())
         js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
 #endif
     baseline = baselineScript;
     updateBaselineOrIonRaw();
 }
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -357,83 +357,25 @@ EmptyShape::EmptyShape(UnownedBaseShape 
   : js::Shape(base, nfixed)
 {
     /* Only empty shapes can be NON_NATIVE. */
     if (!getObjectClass()->isNative())
         flags |= NON_NATIVE;
 }
 
 inline void
-Shape::writeBarrierPre(Shape *shape)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!shape || !shape->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = shape->zone();
-    if (zone->needsBarrier()) {
-        Shape *tmp = shape;
-        MarkShapeUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == shape);
-    }
-#endif
-}
-
-inline void
-Shape::readBarrier(Shape *shape)
-{
-#ifdef JSGC_INCREMENTAL
-    JS::Zone *zone = shape->zone();
-    if (zone->needsBarrier()) {
-        Shape *tmp = shape;
-        MarkShapeUnbarriered(zone->barrierTracer(), &tmp, "read barrier");
-        JS_ASSERT(tmp == shape);
-    }
-#endif
-}
-
-inline void
 Shape::markChildren(JSTracer *trc)
 {
     MarkBaseShape(trc, &base_, "base");
     gc::MarkId(trc, &propidRef(), "propid");
     if (parent)
         MarkShape(trc, &parent, "parent");
 }
 
 inline void
-BaseShape::writeBarrierPre(BaseShape *base)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!base || !base->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = base->zone();
-    if (zone->needsBarrier()) {
-        BaseShape *tmp = base;
-        MarkBaseShapeUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == base);
-    }
-#endif
-}
-
-inline void
-BaseShape::readBarrier(BaseShape *base)
-{
-#ifdef JSGC_INCREMENTAL
-    JS::Zone *zone = base->zone();
-    if (zone->needsBarrier()) {
-        BaseShape *tmp = base;
-        MarkBaseShapeUnbarriered(zone->barrierTracer(), &tmp, "read barrier");
-        JS_ASSERT(tmp == base);
-    }
-#endif
-}
-
-inline void
 BaseShape::markChildren(JSTracer *trc)
 {
     if (hasGetterObject())
         MarkObjectUnbarriered(trc, &getterObj, "getter");
 
     if (hasSetterObject())
         MarkObjectUnbarriered(trc, &setterObj, "setter");
 
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -9,24 +9,25 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/TemplateLib.h"
 
 #include "jsapi.h"
+#include "jsfriendapi.h"
 #include "jsinfer.h"
-#include "jsfriendapi.h"
 #include "jspropertytree.h"
 #include "jstypes.h"
 #include "NamespaceImports.h"
 
 #include "gc/Barrier.h"
 #include "gc/Heap.h"
+#include "gc/Marking.h"
 #include "gc/Rooting.h"
 #include "js/HashTable.h"
 #include "js/RootingAPI.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4800)
 #pragma warning(push)
@@ -625,16 +626,17 @@ class BaseShape : public js::gc::Cell
     ShapeTable &table() const { JS_ASSERT(table_ && isOwned()); return *table_; }
     void setTable(ShapeTable *table) { JS_ASSERT(isOwned()); table_ = table; }
 
     uint32_t slotSpan() const { JS_ASSERT(isOwned()); return slotSpan_; }
     void setSlotSpan(uint32_t slotSpan) { JS_ASSERT(isOwned()); slotSpan_ = slotSpan; }
 
     JSCompartment *compartment() const { return compartment_; }
     JS::Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
 
     /* Lookup base shapes from the compartment's baseShapes table. */
     static UnownedBaseShape* getUnowned(ExclusiveContext *cx, const StackBaseShape &base);
 
     /* Get the canonical base shape. */
     inline UnownedBaseShape* unowned();
 
     /* Get the canonical base shape for an owned one. */
@@ -645,19 +647,42 @@ class BaseShape : public js::gc::Cell
 
     /* Check that an owned base shape is consistent with its unowned base. */
     inline void assertConsistency();
 
     /* For JIT usage */
     static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); }
     static inline size_t offsetOfFlags() { return offsetof(BaseShape, flags); }
 
-    static inline void writeBarrierPre(BaseShape *shape);
-    static void writeBarrierPost(BaseShape *shape, void *addr) {}
-    static inline void readBarrier(BaseShape *shape);
+    static void writeBarrierPre(BaseShape *base) {
+#ifdef JSGC_INCREMENTAL
+        if (!base || !base->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = base->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            BaseShape *tmp = base;
+            js::gc::MarkBaseShapeUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == base);
+        }
+#endif
+    }
+
+    static void writeBarrierPost(BaseShape *base, void *addr) {}
+
+    static inline void readBarrier(BaseShape *base) {
+#ifdef JSGC_INCREMENTAL
+        JS::shadow::Zone *shadowZone = base->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            BaseShape *tmp = base;
+            js::gc::MarkBaseShapeUnbarriered(shadowZone->barrierTracer(), &tmp, "read barrier");
+            JS_ASSERT(tmp == base);
+        }
+#endif
+    }
 
     static inline ThingRootKind rootKind() { return THING_ROOT_BASE_SHAPE; }
 
     inline void markChildren(JSTracer *trc);
 
   private:
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(BaseShape, clasp) == offsetof(js::shadow::BaseShape, clasp));
@@ -1131,26 +1156,49 @@ class Shape : public js::gc::Cell
     void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
 #endif
 
     void sweep();
     void finalize(FreeOp *fop);
     void removeChild(Shape *child);
 
     JS::Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
 
-    static inline void writeBarrierPre(Shape *shape);
+    static void writeBarrierPre(Shape *shape) {
+#ifdef JSGC_INCREMENTAL
+        if (!shape || !shape->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = shape->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            Shape *tmp = shape;
+            js::gc::MarkShapeUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == shape);
+        }
+#endif
+    }
+
     static void writeBarrierPost(Shape *shape, void *addr) {}
 
     /*
      * All weak references need a read barrier for incremental GC. This getter
      * method implements the read barrier. It's used to obtain initial shapes
      * from the compartment.
      */
-    static inline void readBarrier(Shape *shape);
+    static inline void readBarrier(Shape *shape) {
+#ifdef JSGC_INCREMENTAL
+        JS::shadow::Zone *shadowZone = shape->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            Shape *tmp = shape;
+            js::gc::MarkShapeUnbarriered(shadowZone->barrierTracer(), &tmp, "read barrier");
+            JS_ASSERT(tmp == shape);
+        }
+#endif
+    }
 
     static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
 
     inline void markChildren(JSTracer *trc);
 
     inline Shape *search(ExclusiveContext *cx, jsid id) {
         Shape **_;
         return search(cx, this, id, &_);
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -96,55 +96,16 @@ StringWriteBarrierPost(js::ThreadSafeCon
 
 static inline void
 StringWriteBarrierPostRemove(js::ThreadSafeContext *maybecx, JSString **strp)
 {
 }
 
 } /* namespace js */
 
-inline void
-JSString::writeBarrierPre(JSString *str)
-{
-#ifdef JSGC_INCREMENTAL
-    if (!str || !str->runtimeFromAnyThread()->needsBarrier())
-        return;
-
-    JS::Zone *zone = str->zone();
-    if (zone->needsBarrier()) {
-        JSString *tmp = str;
-        MarkStringUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == str);
-    }
-#endif
-}
-
-inline bool
-JSString::needWriteBarrierPre(JS::Zone *zone)
-{
-#ifdef JSGC_INCREMENTAL
-    return zone->needsBarrier();
-#else
-    return false;
-#endif
-}
-
-inline void
-JSString::readBarrier(JSString *str)
-{
-#ifdef JSGC_INCREMENTAL
-    JS::Zone *zone = str->zone();
-    if (zone->needsBarrier()) {
-        JSString *tmp = str;
-        MarkStringUnbarriered(zone->barrierTracer(), &tmp, "read barrier");
-        JS_ASSERT(tmp == str);
-    }
-#endif
-}
-
 JS_ALWAYS_INLINE bool
 JSString::validateLength(js::ThreadSafeContext *maybecx, size_t length)
 {
     if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) {
         js_ReportAllocationOverflow(maybecx);
         return false;
     }
 
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -11,16 +11,17 @@
 #include "mozilla/PodOperations.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsstr.h"
 
 #include "gc/Barrier.h"
 #include "gc/Heap.h"
+#include "gc/Marking.h"
 #include "gc/Rooting.h"
 #include "js/CharacterEncoding.h"
 #include "js/RootingAPI.h"
 
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSInlineString;
@@ -422,25 +423,57 @@ class JSString : public js::gc::Cell
         return offsetof(JSString, d.lengthAndFlags);
     }
 
     static size_t offsetOfChars() {
         return offsetof(JSString, d.u1.chars);
     }
 
     JS::Zone *zone() const { return tenuredZone(); }
+    JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
+
     bool isInsideZone(JS::Zone *zone_) { return tenuredIsInsideZone(zone_); }
     js::gc::AllocKind getAllocKind() const { return tenuredGetAllocKind(); }
 
-    static inline void writeBarrierPre(JSString *str);
+    static void writeBarrierPre(JSString *str) {
+#ifdef JSGC_INCREMENTAL
+        if (!str || !str->shadowRuntimeFromAnyThread()->needsBarrier())
+            return;
+
+        JS::shadow::Zone *shadowZone = str->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            JSString *tmp = str;
+            js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            JS_ASSERT(tmp == str);
+        }
+#endif
+    }
+
     static void writeBarrierPost(JSString *str, void *addr) {}
     static void writeBarrierPostRelocate(JSString *str, void *addr) {}
     static void writeBarrierPostRemove(JSString *str, void *addr) {}
-    static inline bool needWriteBarrierPre(JS::Zone *zone);
-    static inline void readBarrier(JSString *str);
+
+    static bool needWriteBarrierPre(JS::Zone *zone) {
+#ifdef JSGC_INCREMENTAL
+        return JS::shadow::Zone::asShadowZone(zone)->needsBarrier();
+#else
+        return false;
+#endif
+    }
+
+    static void readBarrier(JSString *str) {
+#ifdef JSGC_INCREMENTAL
+        JS::shadow::Zone *shadowZone = str->shadowZone();
+        if (shadowZone->needsBarrier()) {
+            JSString *tmp = str;
+            js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &tmp, "read barrier");
+            JS_ASSERT(tmp == str);
+        }
+#endif
+    }
 
     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_STRING; }
 
 #ifdef DEBUG
     void dump();
     static void dumpChars(const jschar *s, size_t len);
     bool equals(const char *s);
 #endif