Bug 1147665 - Replace value marking functions with TraceEdge; r=jonco
☠☠ backed out by 99415fbccf83 ☠ ☠
authorTerrence Cole <terrence@mozilla.com>
Thu, 26 Mar 2015 10:23:27 -0700
changeset 266635 ffe7f2e2a0f0099870373f80a102c11860d00c4e
parent 266634 37c42cff2c013c8451224b8ea9d6bd8d958d4fc8
child 266636 35ad82ff9ee770505514230b39864694cd045a75
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1147665
milestone39.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 1147665 - Replace value marking functions with TraceEdge; r=jonco
js/src/builtin/MapObject.cpp
js/src/builtin/TypedObject.cpp
js/src/gc/Barrier.h
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/gc/RootMarking.cpp
js/src/gc/StoreBuffer.cpp
js/src/gc/Tracer.cpp
js/src/jit/BaselineFrame.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/Ion.cpp
js/src/jit/JitFrames.cpp
js/src/jit/RematerializedFrame.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/shared/Assembler-x86-shared.cpp
js/src/jscntxt.cpp
js/src/jscompartment.cpp
js/src/jsfun.cpp
js/src/jsscript.cpp
js/src/proxy/Proxy.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/ArgumentsObject.h
js/src/vm/JSONParser.cpp
js/src/vm/PIC.cpp
js/src/vm/Stack.cpp
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -832,17 +832,17 @@ HashableValue::operator==(const Hashable
     return b;
 }
 
 HashableValue
 HashableValue::mark(JSTracer *trc) const
 {
     HashableValue hv(*this);
     trc->setTracingLocation((void *)this);
-    gc::MarkValue(trc, &hv.value, "key");
+    TraceEdge(trc, &hv.value, "key");
     return hv;
 }
 
 
 /*** MapIterator *********************************************************************************/
 
 namespace {
 
@@ -1101,17 +1101,17 @@ MarkKey(Range &r, const HashableValue &k
 }
 
 void
 MapObject::mark(JSTracer *trc, JSObject *obj)
 {
     if (ValueMap *map = obj->as<MapObject>().getData()) {
         for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
             MarkKey(r, r.front().key, trc);
-            gc::MarkValue(trc, &r.front().value, "value");
+            TraceEdge(trc, &r.front().value, "value");
         }
     }
 }
 
 struct UnbarrieredHashPolicy {
     typedef Value Lookup;
     static HashNumber hash(const Lookup &v) { return v.asRawBits(); }
     static bool match(const Value &k, const Lookup &l) { return k == l; }
@@ -1127,17 +1127,17 @@ class OrderedHashTableRef : public gc::B
 
   public:
     explicit OrderedHashTableRef(TableType *t, const Value &k) : table(t), key(k) {}
 
     void mark(JSTracer *trc) {
         MOZ_ASSERT(UnbarrieredHashPolicy::hash(key) ==
                    HashableValue::Hasher::hash(*reinterpret_cast<HashableValue*>(&key)));
         Value prior = key;
-        gc::MarkValueUnbarriered(trc, &key, "ordered hash table key");
+        TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key");
         table->rekeyOneEntry(prior, key);
     }
 };
 
 inline static void
 WriteBarrierPost(JSRuntime *rt, ValueMap *map, const Value &key)
 {
     typedef OrderedHashMap<Value, Value, UnbarrieredHashPolicy, RuntimeAllocPolicy> UnbarrieredMap;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2947,34 +2947,32 @@ class MemoryTracingVisitor {
 } // anonymous namespace
 
 void
 MemoryTracingVisitor::visitReference(ReferenceTypeDescr &descr, uint8_t *mem)
 {
     switch (descr.type()) {
       case ReferenceTypeDescr::TYPE_ANY:
       {
-        js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
-        gc::MarkValue(trace_, heapValue, "reference-val");
+        HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
+        TraceEdge(trace_, heapValue, "reference-val");
         return;
       }
 
       case ReferenceTypeDescr::TYPE_OBJECT:
       {
-        js::HeapPtrObject *objectPtr =
-            reinterpret_cast<js::HeapPtrObject *>(mem);
+        HeapPtrObject *objectPtr = reinterpret_cast<js::HeapPtrObject *>(mem);
         if (*objectPtr)
             gc::MarkObject(trace_, objectPtr, "reference-obj");
         return;
       }
 
       case ReferenceTypeDescr::TYPE_STRING:
       {
-        js::HeapPtrString *stringPtr =
-            reinterpret_cast<js::HeapPtrString *>(mem);
+        HeapPtrString *stringPtr = reinterpret_cast<js::HeapPtrString *>(mem);
         if (*stringPtr)
             gc::MarkString(trace_, stringPtr, "reference-str");
         return;
       }
     }
 
     MOZ_CRASH("Invalid kind");
 }
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -228,17 +228,17 @@ template <> struct MapTypeToTraceKind<Ac
 template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<SharedTypedArrayObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
 template <> struct MapTypeToTraceKind<jit::JitCode>     { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
 template <> struct MapTypeToTraceKind<ObjectGroup>      { static const JSGCTraceKind kind = JSTRACE_OBJECT_GROUP; };
 
 // Direct value access used by the write barriers and the jits.
 void
-MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+MarkValueForBarrier(JSTracer *trc, Value *v, const char *name);
 
 // These three declarations are also present in gc/Marking.h, via the DeclMarker
 // macro.  Not great, but hard to avoid.
 void
 MarkStringUnbarriered(JSTracer *trc, JSString **str, const char *name);
 void
 MarkSymbolUnbarriered(JSTracer *trc, JS::Symbol **sym, const char *name);
 
@@ -340,17 +340,17 @@ struct InternalGCMethods<Value>
     }
 
   private:
     static void preBarrierImpl(Zone *zone, Value v) {
         JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
         if (shadowZone->needsIncrementalBarrier()) {
             MOZ_ASSERT_IF(v.isMarkable(), shadowRuntimeFromMainThread(v)->needsIncrementalBarrier());
             Value tmp(v);
-            js::gc::MarkValueUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
+            js::gc::MarkValueForBarrier(shadowZone->barrierTracer(), &tmp, "write barrier");
             MOZ_ASSERT(tmp == v);
         }
     }
 
   public:
     static void postBarrier(Value *vp) {
         MOZ_ASSERT(!CurrentThreadIsIonCompiling());
         if (vp->isObject()) {
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1172,50 +1172,16 @@ MarkValueInternal(JSTracer *trc, Value *
                 v->setSymbol(sym);
         }
     } else {
         /* Unset realLocation manually if we do not call MarkInternal. */
         trc->unsetTracingLocation();
     }
 }
 
-void
-gc::MarkValue(JSTracer *trc, BarrieredBase<Value> *v, const char *name)
-{
-    trc->setTracingName(name);
-    MarkValueInternal(trc, v->unsafeGet());
-}
-
-void
-gc::MarkValueRoot(JSTracer *trc, Value *v, const char *name)
-{
-    JS_ROOT_MARKING_ASSERT(trc);
-    trc->setTracingName(name);
-    MarkValueInternal(trc, v);
-}
-
-void
-gc::MarkValueRange(JSTracer *trc, size_t len, BarrieredBase<Value> *vec, const char *name)
-{
-    for (size_t i = 0; i < len; ++i) {
-        trc->setTracingIndex(name, i);
-        MarkValueInternal(trc, vec[i].unsafeGet());
-    }
-}
-
-void
-gc::MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name)
-{
-    JS_ROOT_MARKING_ASSERT(trc);
-    for (size_t i = 0; i < len; ++i) {
-        trc->setTracingIndex(name, i);
-        MarkValueInternal(trc, &vec[i]);
-    }
-}
-
 bool
 gc::IsValueMarked(Value *v)
 {
     MOZ_ASSERT(v->isMarkable());
     bool rv;
     if (v->isString()) {
         JSString *str = (JSString *)v->toGCThing();
         rv = IsMarked<JSString>(&str);
@@ -1367,20 +1333,20 @@ static bool
 ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Value val)
 {
     return val.isMarkable() && ShouldMarkCrossCompartment(trc, src, (Cell *)val.toGCThing());
 }
 
 /*** Special Marking ***/
 
 void
-gc::MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
+gc::MarkValueForBarrier(JSTracer *trc, Value *v, const char *name)
 {
-    trc->setTracingName(name);
-    MarkValueInternal(trc, v);
+    MOZ_ASSERT(!trc->runtime()->isHeapBusy());
+    TraceManuallyBarrieredEdge(trc, v, name);
 }
 
 /*** Push Mark Stack ***/
 
 /*
  * PushMarkStack for BaseShape unpacks its children directly onto the mark
  * stack. For a pre-barrier between incremental slices, this may result in
  * objects in the nursery getting pushed onto the mark stack. It is safe to
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -223,43 +223,16 @@ MarkIdUnbarriered(JSTracer *trc, jsid *i
 void
 MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name);
 
 void
 MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
 
 /*** Value Marking ***/
 
-void
-MarkValue(JSTracer *trc, BarrieredBase<Value> *v, const char *name);
-
-void
-MarkValueRange(JSTracer *trc, size_t len, BarrieredBase<Value> *vec, const char *name);
-
-inline void
-MarkValueRange(JSTracer *trc, HeapValue *begin, HeapValue *end, const char *name)
-{
-    return MarkValueRange(trc, end - begin, begin, name);
-}
-
-void
-MarkValueRoot(JSTracer *trc, Value *v, const char *name);
-
-void
-MarkThingOrValueUnbarriered(JSTracer *trc, uintptr_t *word, const char *name);
-
-void
-MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name);
-
-inline void
-MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name)
-{
-    MarkValueRootRange(trc, end - begin, begin, name);
-}
-
 bool
 IsValueMarked(Value *v);
 
 bool
 IsValueAboutToBeFinalized(Value *v);
 
 bool
 IsValueAboutToBeFinalizedFromAnyThread(Value *v);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -100,17 +100,17 @@ MarkExactStackRootsAcrossTypes(T context
     MarkExactStackRootList<ObjectGroup *, MarkObjectGroupRoot>(
         trc, context, "exact-objectgroup");
     MarkExactStackRootList<JSString *, MarkStringRoot>(trc, context, "exact-string");
     MarkExactStackRootList<JS::Symbol *, MarkSymbolRoot>(trc, context, "exact-symbol");
     MarkExactStackRootList<jit::JitCode *, MarkJitCodeRoot>(trc, context, "exact-jitcode");
     MarkExactStackRootList<JSScript *, MarkScriptRoot>(trc, context, "exact-script");
     MarkExactStackRootList<LazyScript *, MarkLazyScriptRoot>(trc, context, "exact-lazy-script");
     MarkExactStackRootList<jsid, MarkIdRoot>(trc, context, "exact-id");
-    MarkExactStackRootList<Value, MarkValueRoot>(trc, context, "exact-value");
+    MarkExactStackRootList<Value, TraceRoot>(trc, context, "exact-value");
     MarkExactStackRootList<TypeSet::Type, TypeSet::MarkTypeRoot>(trc, context, "TypeSet::Type");
     MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
     MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
         trc, context, "JSPropertyDescriptor");
 }
 
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
@@ -146,31 +146,31 @@ AutoGCRooter::trace(JSTracer *trc)
             static_cast<AutoPropertyDescriptorVector *>(this)->vector;
         for (size_t i = 0, len = descriptors.length(); i < len; i++)
             descriptors[i].trace(trc);
         return;
       }
 
       case VALVECTOR: {
         AutoValueVector::VectorImpl &vector = static_cast<AutoValueVector *>(this)->vector;
-        MarkValueRootRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
+        TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
         return;
       }
 
       case IDVECTOR: {
         AutoIdVector::VectorImpl &vector = static_cast<AutoIdVector *>(this)->vector;
         MarkIdRootRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector");
         return;
       }
 
       case IDVALVECTOR: {
         AutoIdValueVector::VectorImpl &vector = static_cast<AutoIdValueVector *>(this)->vector;
         for (size_t i = 0; i < vector.length(); i++) {
             MarkIdRoot(trc, &vector[i].id, "js::AutoIdValueVector id");
-            MarkValueRoot(trc, &vector[i].value, "js::AutoIdValueVector value");
+            TraceRoot(trc, &vector[i].value, "js::AutoIdValueVector value");
         }
         return;
       }
 
       case SHAPEVECTOR: {
         AutoShapeVector::VectorImpl &vector = static_cast<js::AutoShapeVector *>(this)->vector;
         MarkShapeRootRange(trc, vector.length(), const_cast<Shape **>(vector.begin()),
                            "js::AutoShapeVector.vector");
@@ -202,17 +202,17 @@ AutoGCRooter::trace(JSTracer *trc)
       }
 
       case VALARRAY: {
         /*
          * We don't know the template size parameter, but we can safely treat it
          * as an AutoValueArray<1> because the length is stored separately.
          */
         AutoValueArray<1> *array = static_cast<AutoValueArray<1> *>(this);
-        MarkValueRootRange(trc, array->length(), array->begin(), "js::AutoValueArray");
+        TraceRootRange(trc, array->length(), array->begin(), "js::AutoValueArray");
         return;
       }
 
       case SCRIPTVECTOR: {
         AutoScriptVector::VectorImpl &vector = static_cast<AutoScriptVector *>(this)->vector;
         MarkScriptRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
         return;
       }
@@ -262,49 +262,49 @@ AutoGCRooter::trace(JSTracer *trc)
 
       case IONMASM: {
         static_cast<js::jit::MacroAssembler::AutoRooter *>(this)->masm()->trace(trc);
         return;
       }
 
       case WRAPPER: {
         /*
-         * We need to use MarkValueUnbarriered here because we mark wrapper
-         * roots in every slice. This is because of some rule-breaking in
-         * RemapAllWrappersForObject; see comment there.
+         * We need to use TraceManuallyBarrieredEdge here because we mark
+         * wrapper roots in every slice. This is because of some rule-breaking
+         * in RemapAllWrappersForObject; see comment there.
          */
-          MarkValueUnbarriered(trc, &static_cast<AutoWrapperRooter *>(this)->value.get(),
-                               "JS::AutoWrapperRooter.value");
+        TraceManuallyBarrieredEdge(trc, &static_cast<AutoWrapperRooter *>(this)->value.get(),
+                                   "JS::AutoWrapperRooter.value");
         return;
       }
 
       case WRAPVECTOR: {
         AutoWrapperVector::VectorImpl &vector = static_cast<AutoWrapperVector *>(this)->vector;
         /*
-         * We need to use MarkValueUnbarriered here because we mark wrapper
-         * roots in every slice. This is because of some rule-breaking in
-         * RemapAllWrappersForObject; see comment there.
+         * We need to use TraceManuallyBarrieredEdge here because we mark
+         * wrapper roots in every slice. This is because of some rule-breaking
+         * in RemapAllWrappersForObject; see comment there.
          */
         for (WrapperValue *p = vector.begin(); p < vector.end(); p++)
-            MarkValueUnbarriered(trc, &p->get(), "js::AutoWrapperVector.vector");
+            TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector");
         return;
       }
 
       case JSONPARSER:
         static_cast<js::JSONParserBase *>(this)->trace(trc);
         return;
 
       case CUSTOM:
         static_cast<JS::CustomAutoRooter *>(this)->trace(trc);
         return;
     }
 
     MOZ_ASSERT(tag_ >= 0);
     if (Value *vp = static_cast<AutoArrayRooter *>(this)->array)
-        MarkValueRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
+        TraceRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
 }
 
 /* static */ void
 AutoGCRooter::traceAll(JSTracer *trc)
 {
     for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
         traceAllInContext(&*cx, trc);
 }
@@ -318,17 +318,17 @@ AutoGCRooter::traceAllWrappers(JSTracer 
                 gcr->trace(trc);
         }
     }
 }
 
 void
 AutoHashableValueRooter::trace(JSTracer *trc)
 {
-    MarkValueRoot(trc, reinterpret_cast<Value*>(&value), "AutoHashableValueRooter");
+    TraceRoot(trc, reinterpret_cast<Value*>(&value), "AutoHashableValueRooter");
 }
 
 void
 StackShape::trace(JSTracer *trc)
 {
     if (base)
         MarkBaseShapeRoot(trc, (BaseShape**) &base, "StackShape base");
 
@@ -341,17 +341,17 @@ StackShape::trace(JSTracer *trc)
         MarkObjectRoot(trc, (JSObject**)&rawSetter, "StackShape setter");
 }
 
 void
 JSPropertyDescriptor::trace(JSTracer *trc)
 {
     if (obj)
         MarkObjectRoot(trc, &obj, "Descriptor::obj");
-    MarkValueRoot(trc, &value, "Descriptor::value");
+    TraceRoot(trc, &value, "Descriptor::value");
     if ((attrs & JSPROP_GETTER) && getter) {
         JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, getter);
         MarkObjectRoot(trc, &tmp, "Descriptor::get");
         getter = JS_DATA_TO_FUNC_PTR(JSGetterOp, tmp);
     }
     if ((attrs & JSPROP_SETTER) && setter) {
         JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, setter);
         MarkObjectRoot(trc, &tmp, "Descriptor::set");
@@ -403,18 +403,18 @@ js::gc::MarkPersistentRootedChains(JSTra
     PersistentRootedMarker<JSScript*>::markChainIfNotNull<MarkScriptRoot>(
         trc, rt->scriptPersistentRooteds, "PersistentRooted<JSScript *>");
     PersistentRootedMarker<JSString*>::markChainIfNotNull<MarkStringRoot>(
         trc, rt->stringPersistentRooteds, "PersistentRooted<JSString *>");
 
     // Mark the PersistentRooted chains of types that are never null.
     PersistentRootedMarker<jsid>::markChain<MarkIdRoot>(trc, rt->idPersistentRooteds,
                                                         "PersistentRooted<jsid>");
-    PersistentRootedMarker<Value>::markChain<MarkValueRoot>(trc, rt->valuePersistentRooteds,
-                                                            "PersistentRooted<Value>");
+    PersistentRootedMarker<Value>::markChain<TraceRoot>(trc, rt->valuePersistentRooteds,
+                                                        "PersistentRooted<Value>");
 }
 
 void
 js::gc::GCRuntime::markRuntime(JSTracer *trc,
                                TraceOrMarkRuntime traceOrMark,
                                TraceRootsOrUsedSaved rootsSource)
 {
     gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS);
@@ -441,17 +441,17 @@ js::gc::GCRuntime::markRuntime(JSTracer 
 
         if (!rt->isBeingDestroyed()) {
             MarkExactStackRoots(rt, trc);
             rt->markSelfHostingGlobal(trc);
         }
 
         for (RootRange r = rootsHash.all(); !r.empty(); r.popFront()) {
             const RootEntry &entry = r.front();
-            MarkValueRoot(trc, entry.key(), entry.value());
+            TraceRoot(trc, entry.key(), entry.value());
         }
 
         MarkPersistentRootedChains(trc);
     }
 
     if (rt->asyncStackForNewActivations)
         MarkObjectRoot(trc, &rt->asyncStackForNewActivations,
                        "asyncStackForNewActivations");
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -73,17 +73,17 @@ StoreBuffer::CellPtrEdge::mark(JSTracer 
 }
 
 void
 StoreBuffer::ValueEdge::mark(JSTracer *trc) const
 {
     if (!deref())
         return;
 
-    MarkValueRoot(trc, edge, "store buffer edge");
+    TraceRoot(trc, edge, "store buffer edge");
 }
 
 /*** MonoTypeBuffer ***/
 
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::mark(StoreBuffer *owner, JSTracer *trc)
 {
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -27,17 +27,17 @@
 
 using namespace js;
 using namespace js::gc;
 using mozilla::DebugOnly;
 
 JS_PUBLIC_API(void)
 JS_CallUnbarrieredValueTracer(JSTracer *trc, Value *valuep, const char *name)
 {
-    MarkValueUnbarriered(trc, valuep, name);
+    TraceManuallyBarrieredEdge(trc, valuep, name);
 }
 
 JS_PUBLIC_API(void)
 JS_CallUnbarrieredIdTracer(JSTracer *trc, jsid *idp, const char *name)
 {
     MarkIdUnbarriered(trc, idp, name);
 }
 
@@ -57,17 +57,17 @@ JS_PUBLIC_API(void)
 JS_CallUnbarrieredScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name)
 {
     MarkScriptUnbarriered(trc, scriptp, name);
 }
 
 JS_PUBLIC_API(void)
 JS_CallValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name)
 {
-    MarkValueUnbarriered(trc, valuep->unsafeGet(), name);
+    TraceManuallyBarrieredEdge(trc, valuep->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(void)
 JS_CallIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name)
 {
     MarkIdUnbarriered(trc, idp->unsafeGet(), name);
 }
 
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -18,40 +18,40 @@ using namespace js;
 using namespace js::jit;
 
 static void
 MarkLocals(BaselineFrame *frame, JSTracer *trc, unsigned start, unsigned end)
 {
     if (start < end) {
         // Stack grows down.
         Value *last = frame->valueSlot(end - 1);
-        gc::MarkValueRootRange(trc, end - start, last, "baseline-stack");
+        TraceRootRange(trc, end - start, last, "baseline-stack");
     }
 }
 
 void
 BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator)
 {
     replaceCalleeToken(MarkCalleeToken(trc, calleeToken()));
 
-    gc::MarkValueRoot(trc, &thisValue(), "baseline-this");
+    TraceRoot(trc, &thisValue(), "baseline-this");
 
     // Mark actual and formal args.
     if (isNonEvalFunctionFrame()) {
         unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
-        gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args");
+        TraceRootRange(trc, numArgs, argv(), "baseline-args");
     }
 
     // Mark scope chain, if it exists.
     if (scopeChain_)
         gc::MarkObjectRoot(trc, &scopeChain_, "baseline-scopechain");
 
     // Mark return value.
     if (hasReturnValue())
-        gc::MarkValueRoot(trc, returnValue().address(), "baseline-rval");
+        TraceRoot(trc, returnValue().address(), "baseline-rval");
 
     if (isEvalFrame())
         gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript");
 
     if (hasArgsObj())
         gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj");
 
     // Mark locals and stack values.
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -331,17 +331,17 @@ ICStub::trace(JSTracer *trc)
       case ICStub::GetName_Scope5:
         static_cast<ICGetName_Scope<5>*>(this)->traceScopes(trc);
         break;
       case ICStub::GetName_Scope6:
         static_cast<ICGetName_Scope<6>*>(this)->traceScopes(trc);
         break;
       case ICStub::GetIntrinsic_Constant: {
         ICGetIntrinsic_Constant *constantStub = toGetIntrinsic_Constant();
-        gc::MarkValue(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
+        TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
         break;
       }
       case ICStub::GetProp_Primitive: {
         ICGetProp_Primitive *propStub = toGetProp_Primitive();
         MarkShape(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape");
         break;
       }
       case ICStub::GetProp_Native: {
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -861,17 +861,17 @@ IonScript::trace(JSTracer *trc)
 {
     if (method_)
         MarkJitCode(trc, &method_, "method");
 
     if (deoptTable_)
         MarkJitCode(trc, &deoptTable_, "deoptimizationTable");
 
     for (size_t i = 0; i < numConstants(); i++)
-        gc::MarkValue(trc, &getConstant(i), "constant");
+        TraceEdge(trc, &getConstant(i), "constant");
 }
 
 /* static */ void
 IonScript::writeBarrierPre(Zone *zone, IonScript *ionScript)
 {
     if (zone->needsIncrementalBarrier())
         ionScript->trace(zone->barrierTracer());
 }
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1002,21 +1002,21 @@ MarkThisAndArguments(JSTracer *trc, JitF
     if (CalleeTokenIsFunction(layout->calleeToken())) {
         JSFunction *fun = CalleeTokenToFunction(layout->calleeToken());
         nformals = fun->nonLazyScript()->argumentsHasVarBinding() ? 0 : fun->nargs();
     }
 
     Value *argv = layout->argv();
 
     // Trace |this|.
-    gc::MarkValueRoot(trc, argv, "ion-thisv");
+    TraceRoot(trc, argv, "ion-thisv");
 
     // Trace actual arguments beyond the formals. Note + 1 for thisv.
     for (size_t i = nformals + 1; i < nargs + 1; i++)
-        gc::MarkValueRoot(trc, &argv[i], "ion-argv");
+        TraceRoot(trc, &argv[i], "ion-argv");
 }
 
 static void
 MarkThisAndArguments(JSTracer *trc, const JitFrameIterator &frame)
 {
     JitFrameLayout *layout = frame.jsFrame();
     MarkThisAndArguments(trc, layout);
 }
@@ -1063,39 +1063,39 @@ MarkIonJSFrame(JSTracer *trc, const JitF
 
     while (safepoint.getGcSlot(&entry)) {
         uintptr_t *ref = layout->slotRef(entry);
         gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(ref), "ion-gc-slot");
     }
 
     while (safepoint.getValueSlot(&entry)) {
         Value *v = (Value *)layout->slotRef(entry);
-        gc::MarkValueRoot(trc, v, "ion-gc-slot");
+        TraceRoot(trc, v, "ion-gc-slot");
     }
 
     uintptr_t *spill = frame.spillBase();
     GeneralRegisterSet gcRegs = safepoint.gcSpills();
     GeneralRegisterSet valueRegs = safepoint.valueSpills();
     for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
         --spill;
         if (gcRegs.has(*iter))
             gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill");
         else if (valueRegs.has(*iter))
-            gc::MarkValueRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill");
+            TraceRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill");
     }
 
 #ifdef JS_NUNBOX32
     LAllocation type, payload;
     while (safepoint.getNunboxSlot(&type, &payload)) {
         jsval_layout layout;
         layout.s.tag = (JSValueTag)ReadAllocation(frame, &type);
         layout.s.payload.uintptr = ReadAllocation(frame, &payload);
 
         Value v = IMPL_TO_JSVAL(layout);
-        gc::MarkValueRoot(trc, &v, "ion-torn-value");
+        TraceRoot(trc, &v, "ion-torn-value");
 
         if (v != IMPL_TO_JSVAL(layout)) {
             // GC moved the value, replace the stored payload.
             layout = JSVAL_TO_IMPL(v);
             WriteAllocation(frame, &payload, layout.s.payload.uintptr);
         }
     }
 #endif
@@ -1260,17 +1260,17 @@ MarkJitExitFrameCopiedArguments(JSTracer
     if (f->outParam == Type_Handle)
         doubleArgs -= sizeof(Value);
     doubleArgs -= f->doubleByRefArgs() * sizeof(double);
 
     for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
         if (f->argProperties(explicitArg) == VMFunction::DoubleByRef) {
             // Arguments with double size can only have RootValue type.
             if (f->argRootType(explicitArg) == VMFunction::RootValue)
-                gc::MarkValueRoot(trc, reinterpret_cast<Value*>(doubleArgs), "ion-vm-args");
+                TraceRoot(trc, reinterpret_cast<Value*>(doubleArgs), "ion-vm-args");
             else
                 MOZ_ASSERT(f->argRootType(explicitArg) == VMFunction::RootNone);
             doubleArgs += sizeof(double);
         }
     }
 }
 #else
 static void
@@ -1298,68 +1298,68 @@ MarkJitExitFrame(JSTracer *trc, const Ji
 
     // This correspond to the case where we have build a fake exit frame in
     // CodeGenerator.cpp which handle the case of a native function call. We
     // need to mark the argument vector of the function call.
     if (frame.isExitFrameLayout<NativeExitFrameLayout>()) {
         NativeExitFrameLayout *native = frame.exitFrame()->as<NativeExitFrameLayout>();
         size_t len = native->argc() + 2;
         Value *vp = native->vp();
-        gc::MarkValueRootRange(trc, len, vp, "ion-native-args");
+        TraceRootRange(trc, len, vp, "ion-native-args");
         return;
     }
 
     if (frame.isExitFrameLayout<IonOOLNativeExitFrameLayout>()) {
         IonOOLNativeExitFrameLayout *oolnative =
             frame.exitFrame()->as<IonOOLNativeExitFrameLayout>();
         gc::MarkJitCodeRoot(trc, oolnative->stubCode(), "ion-ool-native-code");
-        gc::MarkValueRoot(trc, oolnative->vp(), "iol-ool-native-vp");
+        TraceRoot(trc, oolnative->vp(), "iol-ool-native-vp");
         size_t len = oolnative->argc() + 1;
-        gc::MarkValueRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
+        TraceRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
         return;
     }
 
     if (frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>() ||
         frame.isExitFrameLayout<IonOOLSetterOpExitFrameLayout>())
     {
         // A SetterOp frame is a different size, but that's the only relevant
         // difference between the two. The fields that need marking are all in
         // the common base class.
         IonOOLPropertyOpExitFrameLayout *oolgetter =
             frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>()
             ? frame.exitFrame()->as<IonOOLPropertyOpExitFrameLayout>()
             : frame.exitFrame()->as<IonOOLSetterOpExitFrameLayout>();
         gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
-        gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
+        TraceRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
         gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");
         gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj");
         return;
     }
 
     if (frame.isExitFrameLayout<IonOOLProxyExitFrameLayout>()) {
         IonOOLProxyExitFrameLayout *oolproxy = frame.exitFrame()->as<IonOOLProxyExitFrameLayout>();
         gc::MarkJitCodeRoot(trc, oolproxy->stubCode(), "ion-ool-proxy-code");
-        gc::MarkValueRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
+        TraceRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
         gc::MarkIdRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
         gc::MarkObjectRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
         gc::MarkObjectRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
         return;
     }
 
     if (frame.isExitFrameLayout<IonDOMExitFrameLayout>()) {
         IonDOMExitFrameLayout *dom = frame.exitFrame()->as<IonDOMExitFrameLayout>();
         gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
         if (dom->isMethodFrame()) {
             IonDOMMethodExitFrameLayout *method =
                 reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom);
             size_t len = method->argc() + 2;
             Value *vp = method->vp();
-            gc::MarkValueRootRange(trc, len, vp, "ion-dom-args");
+            TraceRootRange(trc, len, vp, "ion-dom-args");
         } else {
-            gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args");
+            TraceRoot(trc, dom->vp(), "ion-dom-args");
         }
         return;
     }
 
     if (frame.isExitFrameLayout<LazyLinkExitFrameLayout>()) {
         LazyLinkExitFrameLayout *ll = frame.exitFrame()->as<LazyLinkExitFrameLayout>();
         JitFrameLayout *layout = ll->jsFrame();
 
@@ -1397,17 +1397,17 @@ MarkJitExitFrame(JSTracer *trc, const Ji
           case VMFunction::RootString:
           case VMFunction::RootPropertyName:
             gc::MarkStringRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
             break;
           case VMFunction::RootFunction:
             gc::MarkObjectRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
             break;
           case VMFunction::RootValue:
-            gc::MarkValueRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
+            TraceRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
             break;
           case VMFunction::RootCell:
             gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(argBase), "ion-vm-args");
             break;
         }
 
         switch (f->argProperties(explicitArg)) {
           case VMFunction::WordByValue:
@@ -1431,17 +1431,17 @@ MarkJitExitFrame(JSTracer *trc, const Ji
           case VMFunction::RootString:
           case VMFunction::RootPropertyName:
             gc::MarkStringRoot(trc, footer->outParam<JSString *>(), "ion-vm-out");
             break;
           case VMFunction::RootFunction:
             gc::MarkObjectRoot(trc, footer->outParam<JSFunction *>(), "ion-vm-out");
             break;
           case VMFunction::RootValue:
-            gc::MarkValueRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
+            TraceRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
             break;
           case VMFunction::RootCell:
             gc::MarkGCThingRoot(trc, footer->outParam<void *>(), "ion-vm-out");
             break;
         }
     }
 
     MarkJitExitFrameCopiedArguments(trc, f, footer);
@@ -1450,17 +1450,17 @@ MarkJitExitFrame(JSTracer *trc, const Ji
 static void
 MarkRectifierFrame(JSTracer *trc, const JitFrameIterator &frame)
 {
     // Mark thisv.
     //
     // Baseline JIT code generated as part of the ICCall_Fallback stub may use
     // it if we're calling a constructor that returns a primitive value.
     RectifierFrameLayout *layout = (RectifierFrameLayout *)frame.fp();
-    gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
+    TraceRoot(trc, &layout->argv()[0], "ion-thisv");
 }
 
 static void
 MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
 {
     JitActivation *activation = activations->asJit();
 
 #ifdef CHECK_OSIPOINT_REGISTERS
@@ -1700,17 +1700,17 @@ RInstructionResults::operator [](size_t 
     return (*results_)[index];
 }
 
 void
 RInstructionResults::trace(JSTracer *trc)
 {
     // Note: The vector necessary exists, otherwise this object would not have
     // been stored on the activation from where the trace function is called.
-    gc::MarkValueRange(trc, results_->length(), results_->begin(), "ion-recover-results");
+    TraceRange(trc, results_->length(), results_->begin(), "ion-recover-results");
 }
 
 
 SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
                                    JitFrameLayout *fp, const MachineState &machine)
   : snapshot_(ionScript->snapshots(),
               snapshotOffset,
               ionScript->snapshotsRVATableSize(),
@@ -2078,17 +2078,17 @@ SnapshotIterator::traceAllocation(JSTrac
     if (!allocationReadable(alloc, RM_AlwaysDefault))
         return;
 
     Value v = allocationValue(alloc, RM_AlwaysDefault);
     if (!v.isMarkable())
         return;
 
     Value copy = v;
-    gc::MarkValueRoot(trc, &v, "ion-typed-reg");
+    TraceRoot(trc, &v, "ion-typed-reg");
     if (v != copy) {
         MOZ_ASSERT(SameType(v, copy));
         writeAllocationValuePayload(alloc, v);
     }
 }
 
 const RResumePoint *
 SnapshotIterator::resumePoint() const
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -144,20 +144,19 @@ RematerializedFrame::initFunctionScopeOb
     return true;
 }
 
 void
 RematerializedFrame::mark(JSTracer *trc)
 {
     gc::MarkScriptRoot(trc, &script_, "remat ion frame script");
     gc::MarkObjectRoot(trc, &scopeChain_, "remat ion frame scope chain");
-    gc::MarkValueRoot(trc, &returnValue_, "remat ion frame return value");
-    gc::MarkValueRoot(trc, &thisValue_, "remat ion frame this");
-    gc::MarkValueRootRange(trc, slots_, slots_ + numActualArgs_ + script_->nfixed(),
-                           "remat ion frame stack");
+    TraceRoot(trc, &returnValue_, "remat ion frame return value");
+    TraceRoot(trc, &thisValue_, "remat ion frame this");
+    TraceRootRange(trc, numActualArgs_ + script_->nfixed(), slots_, "remat ion frame stack");
 }
 
 void
 RematerializedFrame::dump()
 {
     fprintf(stderr, " Rematerialized Ion Frame%s\n", inlined() ? " (inlined)" : "");
     if (isFunctionFrame()) {
         fprintf(stderr, "  callee fun: ");
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1238,17 +1238,17 @@ bool
 ObjectIsCallable(JSObject *obj)
 {
     return obj->isCallable();
 }
 
 void
 MarkValueFromIon(JSRuntime *rt, Value *vp)
 {
-    gc::MarkValueUnbarriered(&rt->gc.marker, vp, "write barrier");
+    TraceManuallyBarrieredEdge(&rt->gc.marker, vp, "write barrier");
 }
 
 void
 MarkStringFromIon(JSRuntime *rt, JSString **stringp)
 {
     if (*stringp)
         gc::MarkStringUnbarriered(&rt->gc.marker, stringp, "write barrier");
 }
--- a/js/src/jit/shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/shared/Assembler-x86-shared.cpp
@@ -56,17 +56,17 @@ TraceDataRelocations(JSTracer *trc, uint
 #ifdef JS_PUNBOX64
         // All pointers on x64 will have the top bits cleared. If those bits
         // are not cleared, this must be a Value.
         uintptr_t *word = reinterpret_cast<uintptr_t *>(ptr);
         if (*word >> JSVAL_TAG_SHIFT) {
             jsval_layout layout;
             layout.asBits = *word;
             Value v = IMPL_TO_JSVAL(layout);
-            gc::MarkValueUnbarriered(trc, &v, "ion-masm-value");
+            TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value");
             *word = JSVAL_TO_IMPL(v).asBits;
             continue;
         }
 #endif
 
         // The low bit shouldn't be set. If it is, we probably got a dummy
         // pointer inserted by CodeGenerator::visitNurseryObject, but we
         // shouldn't be able to trigger GC before those are patched to their
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1101,17 +1101,17 @@ JSContext::sizeOfIncludingThis(mozilla::
 
 void
 JSContext::mark(JSTracer *trc)
 {
     /* Stack frames and slots are traced by StackSpace::mark. */
 
     /* Mark other roots-by-definition in the JSContext. */
     if (isExceptionPending())
-        MarkValueRoot(trc, &unwrappedException_, "unwrapped exception");
+        TraceRoot(trc, &unwrappedException_, "unwrapped exception");
 
     TraceCycleDetectionSet(trc, cycleDetectorSet);
 
     if (compartment_)
         compartment_->mark();
 }
 
 void *
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -487,17 +487,17 @@ JSCompartment::markCrossCompartmentWrapp
         Value v = e.front().value();
         if (e.front().key().kind == CrossCompartmentKey::ObjectWrapper) {
             ProxyObject *wrapper = &v.toObject().as<ProxyObject>();
 
             /*
              * We have a cross-compartment wrapper. Its private pointer may
              * point into the compartment being collected, so we should mark it.
              */
-            MarkValue(trc, wrapper->slotOfPrivate(), "cross-compartment wrapper");
+            TraceEdge(trc, wrapper->slotOfPrivate(), "cross-compartment wrapper");
         }
     }
 }
 
 void
 JSCompartment::trace(JSTracer *trc)
 {
     savedStacks_.trace(trc);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -716,18 +716,18 @@ fun_hasInstance(JSContext *cx, HandleObj
     *bp = isDelegate;
     return true;
 }
 
 inline void
 JSFunction::trace(JSTracer *trc)
 {
     if (isExtended()) {
-        MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
-                       toExtended()->extendedSlots, "nativeReserved");
+        TraceRange(trc, ArrayLength(toExtended()->extendedSlots),
+                   (HeapValue *)toExtended()->extendedSlots, "nativeReserved");
     }
 
     if (atom_)
         MarkString(trc, &atom_, "atom");
 
     if (isInterpreted()) {
         // Functions can be be marked as interpreted despite having no script
         // yet at some points when parsing, and can be lazy with no lazy script
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3429,17 +3429,17 @@ JSScript::markChildren(JSTracer *trc)
 
     if (hasRegexps()) {
         ObjectArray *objarray = regexps();
         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
     }
 
     if (hasConsts()) {
         ConstArray *constarray = consts();
-        MarkValueRange(trc, constarray->length, constarray->vector, "consts");
+        TraceRange(trc, constarray->length, constarray->vector, "consts");
     }
 
     if (sourceObject()) {
         MOZ_ASSERT(MaybeForwarded(sourceObject())->compartment() == compartment());
         MarkObject(trc, &sourceObject_, "sourceObject");
     }
 
     if (functionNonDelazifying())
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -629,24 +629,24 @@ ProxyObject::trace(JSTracer *trc, JSObje
             MOZ_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
         }
     }
 #endif
 
     // Note: If you add new slots here, make sure to change
     // nuke() to cope.
     TraceCrossCompartmentEdge(trc, obj, proxy->slotOfPrivate(), "private");
-    MarkValue(trc, proxy->slotOfExtra(0), "extra0");
+    TraceEdge(trc, proxy->slotOfExtra(0), "extra0");
 
     /*
      * The GC can use the second reserved slot to link the cross compartment
      * wrappers into a linked list, in which case we don't want to trace it.
      */
     if (!proxy->is<CrossCompartmentWrapperObject>())
-        MarkValue(trc, proxy->slotOfExtra(1), "extra1");
+        TraceEdge(trc, proxy->slotOfExtra(1), "extra1");
 
     Proxy::trace(trc, obj);
 }
 
 JSObject *
 js::proxy_WeakmapKeyDelegate(JSObject *obj)
 {
     MOZ_ASSERT(obj->is<ProxyObject>());
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -538,18 +538,18 @@ ArgumentsObject::finalize(FreeOp *fop, J
     fop->free_(reinterpret_cast<void *>(obj->as<ArgumentsObject>().data()));
 }
 
 void
 ArgumentsObject::trace(JSTracer *trc, JSObject *obj)
 {
     ArgumentsObject &argsobj = obj->as<ArgumentsObject>();
     ArgumentsData *data = argsobj.data();
-    MarkValue(trc, &data->callee, js_callee_str);
-    MarkValueRange(trc, data->numArgs, data->args, js_arguments_str);
+    TraceEdge(trc, &data->callee, js_callee_str);
+    TraceRange(trc, data->numArgs, data->begin(), js_arguments_str);
     MarkScriptUnbarriered(trc, &data->script, "script");
 }
 
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
  * stack frame with their corresponding property values in the frame's
  * arguments object.
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -57,16 +57,22 @@ struct ArgumentsData
      * aliased by the CallObject. In such cases, the CallObject holds the
      * canonical value so any element access to the arguments object should load
      * the value out of the CallObject (which is pointed to by MAYBE_CALL_SLOT).
      */
     HeapValue   args[1];
 
     /* For jit use: */
     static ptrdiff_t offsetOfArgs() { return offsetof(ArgumentsData, args); }
+
+    /* Iterate args. */
+    HeapValue *begin() { return args; }
+    const HeapValue *begin() const { return args; }
+    HeapValue *end() { return args + numArgs; }
+    const HeapValue *end() const { return args + numArgs; }
 };
 
 // Maximum supported value of arguments.length. This bounds the maximum
 // number of arguments that can be supplied to Function.prototype.apply.
 // This value also bounds the number of elements parsed in an array
 // initialiser.
 static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
 
--- a/js/src/vm/JSONParser.cpp
+++ b/js/src/vm/JSONParser.cpp
@@ -42,21 +42,21 @@ JSONParserBase::~JSONParserBase()
 
 void
 JSONParserBase::trace(JSTracer *trc)
 {
     for (size_t i = 0; i < stack.length(); i++) {
         if (stack[i].state == FinishArrayElement) {
             ElementVector &elements = stack[i].elements();
             for (size_t j = 0; j < elements.length(); j++)
-                gc::MarkValueRoot(trc, &elements[j], "JSONParser element");
+                TraceRoot(trc, &elements[j], "JSONParser element");
         } else {
             PropertyVector &properties = stack[i].properties();
             for (size_t j = 0; j < properties.length(); j++) {
-                gc::MarkValueRoot(trc, &properties[j].value, "JSONParser property value");
+                TraceRoot(trc, &properties[j].value, "JSONParser property value");
                 gc::MarkIdRoot(trc, &properties[j].id, "JSONParser property id");
             }
         }
     }
 }
 
 template <typename CharT>
 void
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -255,18 +255,18 @@ js::ForOfPIC::Chain::mark(JSTracer *trc)
         return;
 
     gc::MarkObject(trc, &arrayProto_, "ForOfPIC Array.prototype.");
     gc::MarkObject(trc, &arrayIteratorProto_, "ForOfPIC ArrayIterator.prototype.");
 
     gc::MarkShape(trc, &arrayProtoShape_, "ForOfPIC Array.prototype shape.");
     gc::MarkShape(trc, &arrayIteratorProtoShape_, "ForOfPIC ArrayIterator.prototype shape.");
 
-    gc::MarkValue(trc, &canonicalIteratorFunc_, "ForOfPIC ArrayValues builtin.");
-    gc::MarkValue(trc, &canonicalNextFunc_, "ForOfPIC ArrayIterator.prototype.next builtin.");
+    TraceEdge(trc, &canonicalIteratorFunc_, "ForOfPIC ArrayValues builtin.");
+    TraceEdge(trc, &canonicalNextFunc_, "ForOfPIC ArrayIterator.prototype.next builtin.");
 
     // Free all the stubs in the chain.
     while (stubs_)
         removeStub(stubs_, nullptr);
 }
 
 void
 js::ForOfPIC::Chain::sweep(FreeOp *fop)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -340,24 +340,24 @@ InterpreterFrame::mark(JSTracer *trc)
         if (isEvalFrame())
             gc::MarkScriptUnbarriered(trc, &u.evalScript, "eval script");
     } else {
         gc::MarkScriptUnbarriered(trc, &exec.script, "script");
     }
     if (trc->isMarkingTracer())
         script()->compartment()->zone()->active = true;
     if (hasReturnValue())
-        gc::MarkValueUnbarriered(trc, &rval_, "rval");
+        TraceManuallyBarrieredEdge(trc, &rval_, "rval");
 }
 
 void
 InterpreterFrame::markValues(JSTracer *trc, unsigned start, unsigned end)
 {
     if (start < end)
-        gc::MarkValueRootRange(trc, end - start, slots() + start, "vm_stack");
+        TraceRootRange(trc, end - start, slots() + start, "vm_stack");
 }
 
 void
 InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
 {
     MOZ_ASSERT(sp >= slots());
 
     JSScript *script = this->script();
@@ -391,20 +391,20 @@ InterpreterFrame::markValues(JSTracer *t
 
         // Mark live locals.
         markValues(trc, 0, nlivefixed);
     }
 
     if (hasArgs()) {
         // Mark callee, |this| and arguments.
         unsigned argc = Max(numActualArgs(), numFormalArgs());
-        gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv");
+        TraceRootRange(trc, argc + 2, argv_ - 2, "fp argv");
     } else {
         // Mark callee and |this|
-        gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
+        TraceRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
     }
 }
 
 static void
 MarkInterpreterActivation(JSTracer *trc, InterpreterActivation *act)
 {
     for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
         InterpreterFrame *fp = frames.frame();