Bug 1258314 - Use TraceNullableEdge where appropriate throughout the engine r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 23 Mar 2016 09:41:17 +0000
changeset 290013 9f7c4f40087a4391e68768c0f85bbe6881301a6c
parent 290012 f4b0e2f230e8c7658565676e5e00e0035e09a41f
child 290014 c539b5bbdb36e84e59846a8c5339e4fada2ce0ee
push id30112
push usercbook@mozilla.com
push dateWed, 23 Mar 2016 15:25:32 +0000
treeherdermozilla-central@6202ade0e6d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1258314
milestone48.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 1258314 - Use TraceNullableEdge where appropriate throughout the engine r=terrence
js/src/asmjs/WasmModule.cpp
js/src/builtin/TypedObject.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineJIT.cpp
js/src/jit/SharedIC.cpp
js/src/jsapi-tests/testGCExactRooting.cpp
js/src/jsfun.cpp
js/src/jsiter.cpp
js/src/jsscript.cpp
js/src/jsweakmap.cpp
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
js/src/vm/ReceiverGuard.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpStatics.h
js/src/vm/SavedStacks.h
js/src/vm/TypeInference.cpp
js/src/vm/UnboxedObject.cpp
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -903,23 +903,20 @@ Module::~Module()
         if (exit.baselineScript)
             exit.baselineScript->removeDependentWasmModule(*this, i);
     }
 }
 
 /* virtual */ void
 Module::trace(JSTracer* trc)
 {
-    for (const Import& import : imports()) {
-        if (importToExit(import).fun)
-            TraceEdge(trc, &importToExit(import).fun, "wasm function import");
-    }
+    for (const Import& import : imports())
+        TraceNullableEdge(trc, &importToExit(import).fun, "wasm function import");
 
-    if (heap_)
-        TraceEdge(trc, &heap_, "wasm buffer");
+    TraceNullableEdge(trc, &heap_, "wasm buffer");
 
     MOZ_ASSERT(ownerObject_);
     TraceEdge(trc, &ownerObject_, "wasm owner object");
 }
 
 /* virtual */ void
 Module::readBarrier()
 {
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2938,26 +2938,24 @@ MemoryTracingVisitor::visitReference(Ref
         HeapValue* heapValue = reinterpret_cast<js::HeapValue*>(mem);
         TraceEdge(trace_, heapValue, "reference-val");
         return;
       }
 
       case ReferenceTypeDescr::TYPE_OBJECT:
       {
         HeapPtrObject* objectPtr = reinterpret_cast<js::HeapPtrObject*>(mem);
-        if (*objectPtr)
-            TraceEdge(trace_, objectPtr, "reference-obj");
+        TraceNullableEdge(trace_, objectPtr, "reference-obj");
         return;
       }
 
       case ReferenceTypeDescr::TYPE_STRING:
       {
         HeapPtrString* stringPtr = reinterpret_cast<js::HeapPtrString*>(mem);
-        if (*stringPtr)
-            TraceEdge(trace_, stringPtr, "reference-str");
+        TraceNullableEdge(trace_, stringPtr, "reference-str");
         return;
       }
     }
 
     MOZ_CRASH("Invalid kind");
 }
 
 void
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1279,20 +1279,18 @@ class ICSetElem_DenseOrUnboxedArrayAddIm
     {
         MOZ_ASSERT(shapes.length() == NumShapes);
         for (size_t i = 0; i < NumShapes; i++)
             shapes_[i].init(shapes[i]);
     }
 
   public:
     void traceShapes(JSTracer* trc) {
-        for (size_t i = 0; i < NumShapes; i++) {
-            if (shapes_[i])
-                TraceEdge(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
-        }
+        for (size_t i = 0; i < NumShapes; i++)
+            TraceNullableEdge(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
     }
     Shape* shape(size_t i) const {
         MOZ_ASSERT(i < NumShapes);
         return shapes_[i];
     }
     static size_t offsetOfShape(size_t idx) {
         return offsetof(ICSetElem_DenseOrUnboxedArrayAddImpl, shapes_) + idx * sizeof(HeapPtrShape);
     }
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -451,18 +451,17 @@ BaselineScript::New(JSScript* jsscript, 
     MOZ_ASSERT(offsetCursor == sizeof(BaselineScript) + allocBytes);
     return script;
 }
 
 void
 BaselineScript::trace(JSTracer* trc)
 {
     TraceEdge(trc, &method_, "baseline-method");
-    if (templateScope_)
-        TraceEdge(trc, &templateScope_, "baseline-template-scope");
+    TraceNullableEdge(trc, &templateScope_, "baseline-template-scope");
 
     // Mark all IC stub codes hanging off the IC stub entries.
     for (size_t i = 0; i < numICEntries(); i++) {
         ICEntry& ent = icEntry(i);
         ent.trace(trc);
     }
 }
 
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -182,31 +182,28 @@ ICStub::trace(JSTracer* trc)
             iter->trace(trc);
         }
     }
 
     switch (kind()) {
       case ICStub::Call_Scripted: {
         ICCall_Scripted* callStub = toCall_Scripted();
         TraceEdge(trc, &callStub->callee(), "baseline-callscripted-callee");
-        if (callStub->templateObject())
-            TraceEdge(trc, &callStub->templateObject(), "baseline-callscripted-template");
+        TraceNullableEdge(trc, &callStub->templateObject(), "baseline-callscripted-template");
         break;
       }
       case ICStub::Call_Native: {
         ICCall_Native* callStub = toCall_Native();
         TraceEdge(trc, &callStub->callee(), "baseline-callnative-callee");
-        if (callStub->templateObject())
-            TraceEdge(trc, &callStub->templateObject(), "baseline-callnative-template");
+        TraceNullableEdge(trc, &callStub->templateObject(), "baseline-callnative-template");
         break;
       }
       case ICStub::Call_ClassHook: {
         ICCall_ClassHook* callStub = toCall_ClassHook();
-        if (callStub->templateObject())
-            TraceEdge(trc, &callStub->templateObject(), "baseline-callclasshook-template");
+        TraceNullableEdge(trc, &callStub->templateObject(), "baseline-callclasshook-template");
         break;
       }
       case ICStub::Call_StringSplit: {
         ICCall_StringSplit* callStub = toCall_StringSplit();
         TraceEdge(trc, &callStub->templateObject(), "baseline-callstringsplit-template");
         TraceEdge(trc, &callStub->expectedArg(), "baseline-callstringsplit-arg");
         TraceEdge(trc, &callStub->expectedThis(), "baseline-callstringsplit-this");
         break;
@@ -280,18 +277,17 @@ ICStub::trace(JSTracer* trc)
       }
       case ICStub::GetElem_TypedArray: {
         ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray();
         TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape");
         break;
       }
       case ICStub::SetElem_DenseOrUnboxedArray: {
         ICSetElem_DenseOrUnboxedArray* setElemStub = toSetElem_DenseOrUnboxedArray();
-        if (setElemStub->shape())
-            TraceEdge(trc, &setElemStub->shape(), "baseline-getelem-dense-shape");
+        TraceNullableEdge(trc, &setElemStub->shape(), "baseline-getelem-dense-shape");
         TraceEdge(trc, &setElemStub->group(), "baseline-setelem-dense-group");
         break;
       }
       case ICStub::SetElem_DenseOrUnboxedArrayAdd: {
         ICSetElem_DenseOrUnboxedArrayAdd* setElemStub = toSetElem_DenseOrUnboxedArrayAdd();
         TraceEdge(trc, &setElemStub->group(), "baseline-setelem-denseadd-group");
 
         JS_STATIC_ASSERT(ICSetElem_DenseOrUnboxedArrayAdd::MAX_PROTO_CHAIN_DEPTH == 4);
@@ -420,20 +416,18 @@ ICStub::trace(JSTracer* trc)
       case ICStub::GetProp_CallDOMProxyNative:
       case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
         ICGetPropCallDOMProxyNativeStub* propStub;
         if (kind() == ICStub::GetProp_CallDOMProxyNative)
             propStub = toGetProp_CallDOMProxyNative();
         else
             propStub = toGetProp_CallDOMProxyWithGenerationNative();
         propStub->receiverGuard().trace(trc);
-        if (propStub->expandoShape()) {
-            TraceEdge(trc, &propStub->expandoShape(),
-                      "baseline-getproplistbasenative-stub-expandoshape");
-        }
+        TraceNullableEdge(trc, &propStub->expandoShape(),
+                          "baseline-getproplistbasenative-stub-expandoshape");
         TraceEdge(trc, &propStub->holder(), "baseline-getproplistbasenative-stub-holder");
         TraceEdge(trc, &propStub->holderShape(), "baseline-getproplistbasenative-stub-holdershape");
         TraceEdge(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
         break;
       }
       case ICStub::GetProp_DOMProxyShadowed: {
         ICGetProp_DOMProxyShadowed* propStub = toGetProp_DOMProxyShadowed();
         TraceEdge(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
@@ -476,18 +470,17 @@ ICStub::trace(JSTracer* trc)
         TraceEdge(trc, &propStub->shape(), "baseline-setpropnative-stub-shape");
         TraceEdge(trc, &propStub->group(), "baseline-setpropnative-stub-group");
         break;
       }
       case ICStub::SetProp_NativeAdd: {
         ICSetProp_NativeAdd* propStub = toSetProp_NativeAdd();
         TraceEdge(trc, &propStub->group(), "baseline-setpropnativeadd-stub-group");
         TraceEdge(trc, &propStub->newShape(), "baseline-setpropnativeadd-stub-newshape");
-        if (propStub->newGroup())
-            TraceEdge(trc, &propStub->newGroup(), "baseline-setpropnativeadd-stub-new-group");
+        TraceNullableEdge(trc, &propStub->newGroup(), "baseline-setpropnativeadd-stub-new-group");
         JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
         switch (propStub->protoChainDepth()) {
           case 0: propStub->toImpl<0>()->traceShapes(trc); break;
           case 1: propStub->toImpl<1>()->traceShapes(trc); break;
           case 2: propStub->toImpl<2>()->traceShapes(trc); break;
           case 3: propStub->toImpl<3>()->traceShapes(trc); break;
           case 4: propStub->toImpl<4>()->traceShapes(trc); break;
           default: MOZ_CRASH("Invalid proto stub.");
@@ -524,25 +517,23 @@ ICStub::trace(JSTracer* trc)
       case ICStub::InstanceOf_Function: {
         ICInstanceOf_Function* instanceofStub = toInstanceOf_Function();
         TraceEdge(trc, &instanceofStub->shape(), "baseline-instanceof-fun-shape");
         TraceEdge(trc, &instanceofStub->prototypeObject(), "baseline-instanceof-fun-prototype");
         break;
       }
       case ICStub::NewArray_Fallback: {
         ICNewArray_Fallback* stub = toNewArray_Fallback();
-        if (stub->templateObject())
-            TraceEdge(trc, &stub->templateObject(), "baseline-newarray-template");
+        TraceNullableEdge(trc, &stub->templateObject(), "baseline-newarray-template");
         TraceEdge(trc, &stub->templateGroup(), "baseline-newarray-template-group");
         break;
       }
       case ICStub::NewObject_Fallback: {
         ICNewObject_Fallback* stub = toNewObject_Fallback();
-        if (stub->templateObject())
-            TraceEdge(trc, &stub->templateObject(), "baseline-newobject-template");
+        TraceNullableEdge(trc, &stub->templateObject(), "baseline-newobject-template");
         break;
       }
       case ICStub::Rest_Fallback: {
         ICRest_Fallback* stub = toRest_Fallback();
         TraceEdge(trc, &stub->templateObject(), "baseline-rest-template");
         break;
       }
       case ICStub::CacheIR_Monitored:
--- a/js/src/jsapi-tests/testGCExactRooting.cpp
+++ b/js/src/jsapi-tests/testGCExactRooting.cpp
@@ -46,20 +46,18 @@ END_TEST(testGCSuppressions)
 
 struct MyContainer
 {
     RelocatablePtrObject obj;
     RelocatablePtrString str;
 
     MyContainer() : obj(nullptr), str(nullptr) {}
     void trace(JSTracer* trc) {
-        if (obj)
-            js::TraceEdge(trc, &obj, "test container");
-        if (str)
-            js::TraceEdge(trc, &str, "test container");
+        js::TraceNullableEdge(trc, &obj, "test container");
+        js::TraceNullableEdge(trc, &str, "test container");
     }
 };
 
 namespace js {
 template <>
 struct RootedBase<MyContainer> {
     RelocatablePtrObject& obj() { return static_cast<Rooted<MyContainer>*>(this)->get().obj; }
     RelocatablePtrString& str() { return static_cast<Rooted<MyContainer>*>(this)->get().str; }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -695,18 +695,17 @@ fun_hasInstance(JSContext* cx, HandleObj
 inline void
 JSFunction::trace(JSTracer* trc)
 {
     if (isExtended()) {
         TraceRange(trc, ArrayLength(toExtended()->extendedSlots),
                    (HeapValue*)toExtended()->extendedSlots, "nativeReserved");
     }
 
-    if (atom_)
-        TraceEdge(trc, &atom_, "atom");
+    TraceNullableEdge(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
         // for self-hosted code.
         if (hasScript() && !hasUncompiledScript())
             TraceManuallyBarrieredEdge(trc, &u.i.s.script_, "script");
         else if (isInterpretedLazy() && u.i.s.lazy_)
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -52,18 +52,17 @@ typedef Rooted<PropertyIteratorObject*> 
 
 static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
 
 void
 NativeIterator::mark(JSTracer* trc)
 {
     for (HeapPtrFlatString* str = begin(); str < end(); str++)
         TraceEdge(trc, str, "prop");
-    if (obj)
-        TraceEdge(trc, &obj, "obj");
+    TraceNullableEdge(trc, &obj, "obj");
 
     for (size_t i = 0; i < guard_length; i++)
         guard_array[i].trace(trc);
 
     // The SuppressDeletedPropertyHelper loop can GC, so make sure that if the
     // GC removes any elements from the list, it won't remove this one.
     if (iterObj_)
         TraceManuallyBarrieredEdge(trc, &iterObj_, "iterObj");
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -341,18 +341,17 @@ Binding::trace(JSTracer* trc)
 {
     PropertyName* name = this->name();
     TraceManuallyBarrieredEdge(trc, &name, "binding");
 }
 
 void
 Bindings::trace(JSTracer* trc)
 {
-    if (callObjShape_)
-        TraceEdge(trc, &callObjShape_, "callObjShape");
+    TraceNullableEdge(trc, &callObjShape_, "callObjShape");
 
     /*
      * As the comment in Bindings explains, bindingsArray may point into freed
      * storage when bindingArrayUsingTemporaryStorage so we don't mark it.
      * Note: during compilation, atoms are already kept alive by gcKeepAtoms.
      */
     if (bindingArrayUsingTemporaryStorage())
         return;
@@ -3961,45 +3960,37 @@ JSScript::traceChildren(JSTracer* trc)
     // JSScript::Create(), but not yet finished initializing it with
     // fullyInitFromEmitter() or fullyInitTrivial().
 
     MOZ_ASSERT_IF(trc->isMarkingTracer() &&
                   static_cast<GCMarker*>(trc)->shouldCheckCompartments(),
                   zone()->isCollecting());
 
     if (atoms) {
-        for (uint32_t i = 0; i < natoms(); ++i) {
-            if (atoms[i])
-                TraceEdge(trc, &atoms[i], "atom");
-        }
+        for (uint32_t i = 0; i < natoms(); ++i)
+            TraceNullableEdge(trc, &atoms[i], "atom");
     }
 
     if (hasObjects()) {
         ObjectArray* objarray = objects();
         TraceRange(trc, objarray->length, objarray->vector, "objects");
     }
 
     if (hasConsts()) {
         ConstArray* constarray = consts();
         TraceRange(trc, constarray->length, constarray->vector, "consts");
     }
 
-    if (sourceObject()) {
-        MOZ_ASSERT(MaybeForwarded(sourceObject())->compartment() == compartment());
-        TraceEdge(trc, &sourceObject_, "sourceObject");
-    }
-
-    if (functionNonDelazifying())
-        TraceEdge(trc, &function_, "function");
-
-    if (module_)
-        TraceEdge(trc, &module_, "module");
-
-    if (enclosingStaticScope_)
-        TraceEdge(trc, &enclosingStaticScope_, "enclosingStaticScope");
+    MOZ_ASSERT_IF(sourceObject(), MaybeForwarded(sourceObject())->compartment() == compartment());
+    TraceNullableEdge(trc, &sourceObject_, "sourceObject");
+
+    TraceNullableEdge(trc, &function_, "function");
+    TraceNullableEdge(trc, &module_, "module");
+
+    TraceNullableEdge(trc, &enclosingStaticScope_, "enclosingStaticScope");
 
     if (maybeLazyScript())
         TraceManuallyBarrieredEdge(trc, &lazyScript, "lazyScript");
 
     if (trc->isMarkingTracer()) {
         compartment()->mark();
 
         if (code())
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -43,18 +43,17 @@ WeakMapBase::unmarkZone(JS::Zone* zone)
 }
 
 void
 WeakMapBase::markAll(JS::Zone* zone, JSTracer* tracer)
 {
     MOZ_ASSERT(tracer->weakMapAction() != DoNotTraceWeakMaps);
     for (WeakMapBase* m : zone->gcWeakMapList) {
         m->trace(tracer);
-        if (m->memberOf)
-            TraceEdge(tracer, &m->memberOf, "memberOf");
+        TraceNullableEdge(tracer, &m->memberOf, "memberOf");
     }
 }
 
 bool
 WeakMapBase::markZoneIteratively(JS::Zone* zone, JSTracer* tracer)
 {
     bool markedAny = false;
     for (WeakMapBase* m : zone->gcWeakMapList) {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2762,18 +2762,17 @@ Debugger::traceObject(JSTracer* trc, JSO
 {
     if (Debugger* dbg = Debugger::fromJSObject(obj))
         dbg->trace(trc);
 }
 
 void
 Debugger::trace(JSTracer* trc)
 {
-    if (uncaughtExceptionHook)
-        TraceEdge(trc, &uncaughtExceptionHook, "hooks");
+    TraceNullableEdge(trc, &uncaughtExceptionHook, "hooks");
 
     /*
      * Mark Debugger.Frame objects. These are all reachable from JS, because the
      * corresponding JS frames are still on the stack.
      *
      * (Once we support generator frames properly, we will need
      * weakly-referenced Debugger.Frame objects as well, for suspended generator
      * frames.)
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -333,20 +333,18 @@ class Debugger : private mozilla::Linked
         RelocatablePtrObject frame;
         double when;
         const char* className;
         RelocatablePtrAtom ctorName;
         size_t size;
         bool inNursery;
 
         void trace(JSTracer* trc) {
-            if (frame)
-                TraceEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame");
-            if (ctorName)
-                TraceEdge(trc, &ctorName, "Debugger::AllocationsLogEntry::ctorName");
+            TraceNullableEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame");
+            TraceNullableEdge(trc, &ctorName, "Debugger::AllocationsLogEntry::ctorName");
         }
     };
 
     // Barrier methods so we can have ReadBarriered<Debugger*>.
     static void readBarrier(Debugger* dbg) {
         InternalBarrierMethods<JSObject*>::readBarrier(dbg->object);
     }
     static void writeBarrierPost(Debugger** vp, Debugger* prev, Debugger* next) {}
--- a/js/src/vm/ReceiverGuard.cpp
+++ b/js/src/vm/ReceiverGuard.cpp
@@ -56,13 +56,11 @@ HeapReceiverGuard::keyBits(JSObject* obj
     }
     // Other objects only need the shape to be guarded.
     return 3;
 }
 
 void
 HeapReceiverGuard::trace(JSTracer* trc)
 {
-    if (shape_)
-        TraceEdge(trc, &shape_, "receiver_guard_shape");
-    if (group_)
-        TraceEdge(trc, &group_, "receiver_guard_group");
+    TraceNullableEdge(trc, &shape_, "receiver_guard_shape");
+    TraceNullableEdge(trc, &group_, "receiver_guard_group");
 }
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -493,23 +493,21 @@ RegExpShared::~RegExpShared()
 }
 
 void
 RegExpShared::trace(JSTracer* trc)
 {
     if (trc->isMarkingTracer())
         marked_ = true;
 
-    if (source)
-        TraceEdge(trc, &source, "RegExpShared source");
+    TraceNullableEdge(trc, &source, "RegExpShared source");
 
     for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
         RegExpCompilation& compilation = compilationArray[i];
-        if (compilation.jitCode)
-            TraceEdge(trc, &compilation.jitCode, "RegExpShared code");
+        TraceNullableEdge(trc, &compilation.jitCode, "RegExpShared code");
     }
 }
 
 bool
 RegExpShared::compile(JSContext* cx, HandleLinearString input,
                       CompilationMode mode, bool sticky, ForceByteCodeEnum force)
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
--- a/js/src/vm/RegExpStatics.h
+++ b/js/src/vm/RegExpStatics.h
@@ -88,22 +88,19 @@ class RegExpStatics
 
     JSString* getPendingInput() const { return pendingInput; }
 
     void mark(JSTracer* trc) {
         /*
          * Changes to this function must also be reflected in
          * RegExpStatics::AutoRooter::trace().
          */
-        if (matchesInput)
-            TraceEdge(trc, &matchesInput, "res->matchesInput");
-        if (lazySource)
-            TraceEdge(trc, &lazySource, "res->lazySource");
-        if (pendingInput)
-            TraceEdge(trc, &pendingInput, "res->pendingInput");
+        TraceNullableEdge(trc, &matchesInput, "res->matchesInput");
+        TraceNullableEdge(trc, &lazySource, "res->lazySource");
+        TraceNullableEdge(trc, &pendingInput, "res->pendingInput");
     }
 
     /* Value creators. */
 
     bool createPendingInput(JSContext* cx, MutableHandleValue out);
     bool createLastMatch(JSContext* cx, MutableHandleValue out);
     bool createLastParen(JSContext* cx, MutableHandleValue out);
     bool createParen(JSContext* cx, size_t pairNum, MutableHandleValue out);
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -230,18 +230,17 @@ class SavedStacks {
   public:
     struct LocationValue {
         LocationValue() : source(nullptr), line(0), column(0) { }
         LocationValue(JSAtom* source, size_t line, uint32_t column)
             : source(source), line(line), column(column)
         { }
 
         void trace(JSTracer* trc) {
-            if (source)
-                TraceEdge(trc, &source, "SavedStacks::LocationValue::source");
+            TraceNullableEdge(trc, &source, "SavedStacks::LocationValue::source");
         }
 
         bool needsSweep() {
             // LocationValue is always held strongly, but in a weak map.
             // Assert that it has been marked already, but allow it to be
             // ejected from the map when the key dies.
             MOZ_ASSERT(source);
             MOZ_ASSERT(!IsAboutToBeFinalized(&source));
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3415,18 +3415,17 @@ PreliminaryObjectArray::sweep()
             *ptr = nullptr;
         }
     }
 }
 
 void
 PreliminaryObjectArrayWithTemplate::trace(JSTracer* trc)
 {
-    if (shape_)
-        TraceEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
+    TraceNullableEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
 }
 
 /* static */ void
 PreliminaryObjectArrayWithTemplate::writeBarrierPre(PreliminaryObjectArrayWithTemplate* objects)
 {
     Shape* shape = objects->shape();
 
     if (!shape || shape->runtimeFromAnyThread()->isHeapBusy())
@@ -3976,25 +3975,19 @@ TypeNewScript::rollbackPartiallyInitiali
 
     return found;
 }
 
 void
 TypeNewScript::trace(JSTracer* trc)
 {
     TraceEdge(trc, &function_, "TypeNewScript_function");
-
-    if (templateObject_)
-        TraceEdge(trc, &templateObject_, "TypeNewScript_templateObject");
-
-    if (initializedShape_)
-        TraceEdge(trc, &initializedShape_, "TypeNewScript_initializedShape");
-
-    if (initializedGroup_)
-        TraceEdge(trc, &initializedGroup_, "TypeNewScript_initializedGroup");
+    TraceNullableEdge(trc, &templateObject_, "TypeNewScript_templateObject");
+    TraceNullableEdge(trc, &initializedShape_, "TypeNewScript_initializedShape");
+    TraceNullableEdge(trc, &initializedGroup_, "TypeNewScript_initializedGroup");
 }
 
 /* static */ void
 TypeNewScript::writeBarrierPre(TypeNewScript* newScript)
 {
     if (newScript->function()->runtimeFromAnyThread()->isHeapBusy())
         return;
 
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -30,30 +30,21 @@ void
 UnboxedLayout::trace(JSTracer* trc)
 {
     for (size_t i = 0; i < properties_.length(); i++)
         TraceManuallyBarrieredEdge(trc, &properties_[i].name, "unboxed_layout_name");
 
     if (newScript())
         newScript()->trace(trc);
 
-    if (nativeGroup_)
-        TraceEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup");
-
-    if (nativeShape_)
-        TraceEdge(trc, &nativeShape_, "unboxed_layout_nativeShape");
-
-    if (allocationScript_)
-        TraceEdge(trc, &allocationScript_, "unboxed_layout_allocationScript");
-
-    if (replacementGroup_)
-        TraceEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup");
-
-    if (constructorCode_)
-        TraceEdge(trc, &constructorCode_, "unboxed_layout_constructorCode");
+    TraceNullableEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup");
+    TraceNullableEdge(trc, &nativeShape_, "unboxed_layout_nativeShape");
+    TraceNullableEdge(trc, &allocationScript_, "unboxed_layout_allocationScript");
+    TraceNullableEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup");
+    TraceNullableEdge(trc, &constructorCode_, "unboxed_layout_constructorCode");
 }
 
 size_t
 UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return mallocSizeOf(this)
          + properties_.sizeOfExcludingThis(mallocSizeOf)
          + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0)
@@ -322,18 +313,17 @@ UnboxedPlainObject::trace(JSTracer* trc,
     while (*list != -1) {
         HeapPtrString* heap = reinterpret_cast<HeapPtrString*>(data + *list);
         TraceEdge(trc, heap, "unboxed_string");
         list++;
     }
     list++;
     while (*list != -1) {
         HeapPtrObject* heap = reinterpret_cast<HeapPtrObject*>(data + *list);
-        if (*heap)
-            TraceEdge(trc, heap, "unboxed_object");
+        TraceNullableEdge(trc, heap, "unboxed_object");
         list++;
     }
 
     // Unboxed objects don't have Values to trace.
     MOZ_ASSERT(*(list + 1) == -1);
 }
 
 /* static */ UnboxedExpandoObject*
@@ -1141,18 +1131,17 @@ UnboxedArrayObject::trace(JSTracer* trc,
     MOZ_ASSERT(obj->as<UnboxedArrayObject>().elementSize() == sizeof(uintptr_t));
     size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
     void** elements = reinterpret_cast<void**>(obj->as<UnboxedArrayObject>().elements());
 
     switch (type) {
       case JSVAL_TYPE_OBJECT:
         for (size_t i = 0; i < initlen; i++) {
             HeapPtrObject* heap = reinterpret_cast<HeapPtrObject*>(elements + i);
-            if (*heap)
-                TraceEdge(trc, heap, "unboxed_object");
+            TraceNullableEdge(trc, heap, "unboxed_object");
         }
         break;
 
       case JSVAL_TYPE_STRING:
         for (size_t i = 0; i < initlen; i++) {
             HeapPtrString* heap = reinterpret_cast<HeapPtrString*>(elements + i);
             TraceEdge(trc, heap, "unboxed_string");
         }