Bug 1549950 - Remove TraceWeakEdge and associated machinery and sweep weak pointers in lazy scripts explicitly r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 May 2019 17:24:38 +0100
changeset 474730 4d7ef530fffba20a2b352cff9fa23438128105a7
parent 474729 f3fae269992d4984480f731765bd7040def16c60
child 474731 3c0f78074b727fbae112b6eda111d4c4d30cc3ec
push id36045
push userrmaries@mozilla.com
push dateTue, 21 May 2019 16:30:25 +0000
treeherdermozilla-central@3c0f78074b72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1549950
milestone69.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 1549950 - Remove TraceWeakEdge and associated machinery and sweep weak pointers in lazy scripts explicitly r=sfink Differential Revision: https://phabricator.services.mozilla.com/D31804
js/src/gc/GC.cpp
js/src/gc/GCMarker.h
js/src/gc/GenerateStatsPhases.py
js/src/gc/Marking.cpp
js/src/gc/Tracer.h
js/src/gc/Zone.cpp
js/src/gc/Zone.h
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testGCWeakRef.cpp
js/src/vm/JSScript.h
js/src/wasm/WasmInstance.cpp
js/src/wasm/WasmTable.cpp
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -5451,28 +5451,31 @@ static void SweepCompressionTasks(GCPara
   auto& pending = HelperThreadState().compressionPendingList(lock);
   for (size_t i = 0; i < pending.length(); i++) {
     if (pending[i]->shouldCancel()) {
       HelperThreadState().remove(pending, &i);
     }
   }
 }
 
+void js::gc::SweepLazyScripts(GCParallelTask* task) {
+  JSRuntime* runtime = task->runtime();
+  for (SweepGroupZonesIter zone(runtime); !zone.done(); zone.next()) {
+    for (auto i = zone->cellIter<LazyScript>(); !i.done(); i.next()) {
+      WeakHeapPtrScript* edge = &i.unbarrieredGet()->script_;
+      if (*edge && IsAboutToBeFinalized(edge)) {
+        *edge = nullptr;
+      }
+    }
+  }
+}
+
 static void SweepWeakMaps(GCParallelTask* task) {
   JSRuntime* runtime = task->runtime();
   for (SweepGroupZonesIter zone(runtime); !zone.done(); zone.next()) {
-    /* Clear all weakrefs that point to unmarked things. */
-    for (auto edge : zone->gcWeakRefs()) {
-      /* Edges may be present multiple times, so may already be nulled. */
-      if (*edge && IsAboutToBeFinalizedDuringSweep(**edge)) {
-        *edge = nullptr;
-      }
-    }
-    zone->gcWeakRefs().clear();
-
     /* No need to look up any more weakmap keys from this sweep group. */
     AutoEnterOOMUnsafeRegion oomUnsafe;
     if (!zone->gcWeakKeys().clear()) {
       oomUnsafe.crash("clearing weak keys in beginSweepingSweepGroup()");
     }
 
     zone->sweepWeakMaps();
   }
@@ -5720,16 +5723,18 @@ IncrementalProgress GCRuntime::beginSwee
 
     AutoRunParallelTask sweepCCWrappers(rt, SweepCCWrappers,
                                         PhaseKind::SWEEP_CC_WRAPPER, lock);
     AutoRunParallelTask sweepObjectGroups(rt, SweepObjectGroups,
                                           PhaseKind::SWEEP_TYPE_OBJECT, lock);
     AutoRunParallelTask sweepMisc(rt, SweepMisc, PhaseKind::SWEEP_MISC, lock);
     AutoRunParallelTask sweepCompTasks(rt, SweepCompressionTasks,
                                        PhaseKind::SWEEP_COMPRESSION, lock);
+    AutoRunParallelTask sweepLazyScripts(rt, SweepLazyScripts,
+                                         PhaseKind::SWEEP_LAZYSCRIPTS, lock);
     AutoRunParallelTask sweepWeakMaps(rt, SweepWeakMaps,
                                       PhaseKind::SWEEP_WEAKMAPS, lock);
     AutoRunParallelTask sweepUniqueIds(rt, SweepUniqueIds,
                                        PhaseKind::SWEEP_UNIQUEIDS, lock);
 
     WeakCacheTaskVector sweepCacheTasks;
     if (!PrepareWeakCacheTasks(rt, &sweepCacheTasks)) {
       SweepWeakCachesOnMainThread(rt);
--- a/js/src/gc/GCMarker.h
+++ b/js/src/gc/GCMarker.h
@@ -250,20 +250,16 @@ class GCMarker : public JSTracer {
   void traverseObjectEdge(S source, JSObject* target) {
     traverseEdge(source, target);
   }
   template <typename S>
   void traverseStringEdge(S source, JSString* target) {
     traverseEdge(source, target);
   }
 
-  // Notes a weak graph edge for later sweeping.
-  template <typename T>
-  void noteWeakEdge(T* edge);
-
   /*
    * Care must be taken changing the mark color from gray to black. The cycle
    * collector depends on the invariant that there are no black to gray edges
    * in the GC heap. This invariant lets the CC not trace through black
    * objects. If this invariant is violated, the cycle collector may free
    * objects that are still reachable.
    */
   void setMarkColorGray();
--- a/js/src/gc/GenerateStatsPhases.py
+++ b/js/src/gc/GenerateStatsPhases.py
@@ -123,16 +123,17 @@ PhaseKindGraphRoots = [
             PhaseKind("SWEEP_INNER_VIEWS", "Sweep Inner Views", 22),
             PhaseKind("SWEEP_CC_WRAPPER", "Sweep Cross Compartment Wrappers", 23),
             PhaseKind("SWEEP_BASE_SHAPE", "Sweep Base Shapes", 24),
             PhaseKind("SWEEP_INITIAL_SHAPE", "Sweep Initial Shapes", 25),
             PhaseKind("SWEEP_TYPE_OBJECT", "Sweep Type Objects", 26),
             PhaseKind("SWEEP_BREAKPOINT", "Sweep Breakpoints", 27),
             PhaseKind("SWEEP_REGEXP", "Sweep Regexps", 28),
             PhaseKind("SWEEP_COMPRESSION", "Sweep Compression Tasks", 62),
+            PhaseKind("SWEEP_LAZYSCRIPTS", "Sweep LazyScripts", 71),
             PhaseKind("SWEEP_WEAKMAPS", "Sweep WeakMaps", 63),
             PhaseKind("SWEEP_UNIQUEIDS", "Sweep Unique IDs", 64),
             PhaseKind("SWEEP_JIT_DATA", "Sweep JIT Data", 65),
             PhaseKind("SWEEP_WEAK_CACHES", "Sweep Weak Caches", 66),
             PhaseKind("SWEEP_MISC", "Sweep Miscellaneous", 29),
             PhaseKind("SWEEP_TYPES", "Sweep type information", 30, [
                 PhaseKind("SWEEP_TYPES_BEGIN", "Sweep type tables and compilations", 31),
                 PhaseKind("SWEEP_TYPES_END", "Free type arena", 32),
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -399,20 +399,16 @@ void js::gc::AssertRootMarkingPhase(JSTr
 template <typename T>
 T* DoCallback(JS::CallbackTracer* trc, T** thingp, const char* name);
 template <typename T>
 T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name);
 template <typename T>
 void DoMarking(GCMarker* gcmarker, T* thing);
 template <typename T>
 void DoMarking(GCMarker* gcmarker, const T& thing);
-template <typename T>
-void NoteWeakEdge(GCMarker* gcmarker, T** thingp);
-template <typename T>
-void NoteWeakEdge(GCMarker* gcmarker, T* thingp);
 
 template <typename T>
 JS_PUBLIC_API void js::gc::TraceExternalEdge(JSTracer* trc, T* thingp,
                                              const char* name) {
   MOZ_ASSERT(InternalBarrierMethods<T>::isMarkable(*thingp));
   TraceEdgeInternal(trc, ConvertToBase(thingp), name);
 }
 
@@ -442,17 +438,16 @@ FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTI
 FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
 #undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
 
 namespace js {
 namespace gc {
 
 #define INSTANTIATE_INTERNAL_TRACE_FUNCTIONS(type)                          \
   template void TraceEdgeInternal<type>(JSTracer*, type*, const char*);     \
-  template void TraceWeakEdgeInternal<type>(JSTracer*, type*, const char*); \
   template void TraceRangeInternal<type>(JSTracer*, size_t len, type*,      \
                                          const char*);
 
 #define INSTANTIATE_INTERNAL_TRACE_FUNCTIONS_FROM_TRACEKIND(_1, type, _2, _3) \
   INSTANTIATE_INTERNAL_TRACE_FUNCTIONS(type*)
 
 JS_FOR_EACH_TRACEKIND(INSTANTIATE_INTERNAL_TRACE_FUNCTIONS_FROM_TRACEKIND)
 FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_INTERNAL_TRACE_FUNCTIONS)
@@ -564,29 +559,16 @@ void js::gc::TraceEdgeInternal(JSTracer*
   if (trc->isTenuringTracer()) {
     return static_cast<TenuringTracer*>(trc)->traverse(thingp);
   }
   MOZ_ASSERT(trc->isCallbackTracer());
   DoCallback(trc->asCallbackTracer(), thingp, name);
 }
 
 template <typename T>
-void js::gc::TraceWeakEdgeInternal(JSTracer* trc, T* thingp, const char* name) {
-  if (!trc->isMarkingTracer()) {
-    // Non-marking tracers can select whether or not they see weak edges.
-    if (trc->traceWeakEdges()) {
-      TraceEdgeInternal(trc, thingp, name);
-    }
-    return;
-  }
-
-  NoteWeakEdge(GCMarker::fromTracer(trc), thingp);
-}
-
-template <typename T>
 void js::gc::TraceRangeInternal(JSTracer* trc, size_t len, T* vec,
                                 const char* name) {
   JS::AutoTracingIndex index(trc);
   for (auto i : IntegerRange(len)) {
     if (InternalBarrierMethods<T>::isMarkable(vec[i])) {
       TraceEdgeInternal(trc, &vec[i], name);
     }
     ++index;
@@ -733,54 +715,16 @@ void DoMarking(GCMarker* gcmarker, T* th
   SetMaybeAliveFlag(thing);
 }
 
 template <typename T>
 void DoMarking(GCMarker* gcmarker, const T& thing) {
   ApplyGCThingTyped(thing, [gcmarker](auto t) { DoMarking(gcmarker, t); });
 }
 
-template <typename T>
-void NoteWeakEdge(GCMarker* gcmarker, T** thingp) {
-  // Do per-type marking precondition checks.
-  if (!ShouldMark(gcmarker, *thingp)) {
-    return;
-  }
-
-  CheckTracedThing(gcmarker, *thingp);
-
-  // If the target is already marked, there's no need to store the edge.
-  if (IsMarkedUnbarriered(gcmarker->runtime(), thingp)) {
-    return;
-  }
-
-  gcmarker->noteWeakEdge(thingp);
-}
-
-template <typename T>
-void NoteWeakEdge(GCMarker* gcmarker, T* thingp) {
-  MOZ_CRASH("the gc does not support tagged pointers as weak edges");
-}
-
-template <typename T>
-void js::GCMarker::noteWeakEdge(T* edge) {
-  static_assert(IsBaseOf<Cell, typename mozilla::RemovePointer<T>::Type>::value,
-                "edge must point to a GC pointer");
-  MOZ_ASSERT((*edge)->isTenured());
-
-  // Note: we really want the *source* Zone here. The edge may start in a
-  // non-gc heap location, however, so we use the fact that cross-zone weak
-  // references are not allowed and use the *target's* zone.
-  JS::Zone::WeakEdges& weakRefs = (*edge)->asTenured().zone()->gcWeakRefs();
-  AutoEnterOOMUnsafeRegion oomUnsafe;
-  if (!weakRefs.append(reinterpret_cast<TenuredCell**>(edge))) {
-    oomUnsafe.crash("Failed to record a weak edge for sweeping.");
-  }
-}
-
 // The simplest traversal calls out to the fully generic traceChildren function
 // to visit the child edges. In the absence of other traversal mechanisms, this
 // function will rapidly grow the stack past its bounds and crash the process.
 // Thus, this generic tracing should only be used in cases where subsequent
 // tracing will not recurse.
 template <typename T>
 void js::GCMarker::markAndTraceChildren(T* thing) {
   if (ThingIsPermanentAtomOrWellKnownSymbol(thing)) {
@@ -962,18 +906,18 @@ bool js::GCMarker::mark(T* thing) {
 
 /*** Inline, Eager GC Marking ***********************************************/
 
 // Each of the eager, inline marking paths is directly preceeded by the
 // out-of-line, generic tracing code for comparison. Both paths must end up
 // traversing equivalent subgraphs.
 
 void LazyScript::traceChildren(JSTracer* trc) {
-  if (script_) {
-    TraceWeakEdge(trc, &script_, "script");
+  if (trc->traceWeakEdges()) {
+    TraceNullableEdge(trc, &script_, "script");
   }
 
   if (function_) {
     TraceEdge(trc, &function_, "function");
   }
 
   if (sourceObject_) {
     TraceEdge(trc, &sourceObject_, "sourceObject");
@@ -1000,19 +944,17 @@ void LazyScript::traceChildren(JSTracer*
     }
   }
 
   if (trc->isMarkingTracer()) {
     GCMarker::fromTracer(trc)->markImplicitEdges(this);
   }
 }
 inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
-  if (thing->script_) {
-    noteWeakEdge(thing->script_.unsafeUnbarrieredForTracing());
-  }
+  // script_ is weak so is not traced here.
 
   if (thing->function_) {
     traverseEdge(thing, static_cast<JSObject*>(thing->function_));
   }
 
   if (thing->sourceObject_) {
     traverseEdge(thing, static_cast<JSObject*>(thing->sourceObject_));
   }
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -89,31 +89,39 @@ template <typename T>
 typename PtrBaseGCType<T>::type* ConvertToBase(T* thingp) {
   return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
 }
 
 // Internal methods to trace edges.
 template <typename T>
 void TraceEdgeInternal(JSTracer* trc, T* thingp, const char* name);
 template <typename T>
-void TraceWeakEdgeInternal(JSTracer* trc, T* thingp, const char* name);
-template <typename T>
 void TraceRangeInternal(JSTracer* trc, size_t len, T* vec, const char* name);
 
 #ifdef DEBUG
 void AssertRootMarkingPhase(JSTracer* trc);
 #else
 inline void AssertRootMarkingPhase(JSTracer* trc) {}
 #endif
 
 }  // namespace gc
 
-// Trace through an edge in the live object graph on behalf of tracing. The
-// effect of tracing the edge depends on the JSTracer being used. For pointer
-// types, |*thingp| must not be null.
+// Trace through a strong edge in the live object graph on behalf of
+// tracing. The effect of tracing the edge depends on the JSTracer being
+// used. For pointer types, |*thingp| must not be null.
+//
+// Note that weak edges are handled separately. GC things with weak edges must
+// not trace those edges during marking tracing (which would keep the referent
+// alive) but instead arrange for the edge to be swept by calling
+// js::gc::IsAboutToBeFinalized during sweeping. For example, see the treatment
+// of the script_ edge in LazyScript::traceChildren and
+// js::gc::SweepLazyScripts.
+//
+// GC things that are weakly held in containers can use WeakMap or a container
+// wrapped in the WeakCache<> template to perform the appropriate sweeping.
 
 template <typename T>
 inline void TraceEdge(JSTracer* trc, WriteBarriered<T>* thingp,
                       const char* name) {
   gc::TraceEdgeInternal(
       trc, gc::ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
 }
 
@@ -180,26 +188,16 @@ inline void TraceNullableRoot(JSTracer* 
 // separate from TraceEdge to make accidental use of such edges more obvious.
 
 template <typename T>
 inline void TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp,
                                        const char* name) {
   gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
 }
 
-// Visits a WeakRef, but does not trace its referents. If *thingp is not marked
-// at the end of marking, it is replaced by nullptr. This method records
-// thingp, so the edge location must not change after this function is called.
-
-template <typename T>
-inline void TraceWeakEdge(JSTracer* trc, WeakHeapPtr<T>* thingp, const char* name) {
-  gc::TraceWeakEdgeInternal(
-      trc, gc::ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
-}
-
 // Trace all edges contained in the given array.
 
 template <typename T>
 void TraceRange(JSTracer* trc, size_t len, WriteBarriered<T>* vec,
                 const char* name) {
   gc::TraceRangeInternal(
       trc, len, gc::ConvertToBase(vec[0].unsafeUnbarrieredForTracing()), name);
 }
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -37,17 +37,16 @@ JS::Zone::Zone(JSRuntime* rt)
       uniqueIds_(this),
       suppressAllocationMetadataBuilder(this, false),
       arenas(this),
       tenuredAllocsSinceMinorGC_(0),
       types(this),
       gcWeakMapList_(this),
       compartments_(),
       gcGrayRoots_(this),
-      gcWeakRefs_(this),
       weakCaches_(this),
       gcWeakKeys_(this, SystemAllocPolicy(), rt->randomHashCodeScrambler()),
       typeDescrObjects_(this, this),
       markedAtoms_(this),
       atomCache_(this),
       externalStringCache_(this),
       functionToStringCache_(this),
       keepAtomsCount(this, 0),
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -384,26 +384,16 @@ class Zone : public JS::shadow::Zone,
                                js::SystemAllocPolicy>;
 
  private:
   js::ZoneOrGCTaskData<GrayRootVector> gcGrayRoots_;
 
  public:
   GrayRootVector& gcGrayRoots() { return gcGrayRoots_.ref(); }
 
-  // This zone's weak edges found via graph traversal during marking,
-  // preserved for re-scanning during sweeping.
-  using WeakEdges = js::Vector<js::gc::TenuredCell**, 0, js::SystemAllocPolicy>;
-
- private:
-  js::ZoneOrGCTaskData<WeakEdges> gcWeakRefs_;
-
- public:
-  WeakEdges& gcWeakRefs() { return gcWeakRefs_.ref(); }
-
  private:
   // List of non-ephemeron weak containers to sweep during
   // beginSweepingSweepGroup.
   js::ZoneOrGCTaskData<mozilla::LinkedList<detail::WeakCacheBase>> weakCaches_;
 
  public:
   mozilla::LinkedList<detail::WeakCacheBase>& weakCaches() {
     return weakCaches_.ref();
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -53,17 +53,16 @@ UNIFIED_SOURCES += [
     'testGCGrayMarking.cpp',
     'testGCHeapPostBarriers.cpp',
     'testGCHooks.cpp',
     'testGCMarking.cpp',
     'testGCOutOfMemory.cpp',
     'testGCStoreBufferRemoval.cpp',
     'testGCUniqueId.cpp',
     'testGCWeakCache.cpp',
-    'testGCWeakRef.cpp',
     'testGetPropertyDescriptor.cpp',
     'testHashTable.cpp',
     'testIndexToString.cpp',
     'testInformalValueTypeName.cpp',
     'testIntern.cpp',
     'testIntlAvailableLocales.cpp',
     'testIntString.cpp',
     'testIsInsideNursery.cpp',
deleted file mode 100644
--- a/js/src/jsapi-tests/testGCWeakRef.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gc/Barrier.h"
-#include "js/RootingAPI.h"
-
-#include "jsapi-tests/tests.h"
-
-struct MyHeap {
-  explicit MyHeap(JSObject* obj) : weak(obj) {}
-  js::WeakHeapPtrObject weak;
-
-  void trace(JSTracer* trc) { js::TraceWeakEdge(trc, &weak, "weak"); }
-};
-
-BEGIN_TEST(testGCWeakRef) {
-  // Create an object and add a property to it so that we can read the
-  // property back later to verify that object internals are not garbage.
-  JS::RootedObject obj(cx, JS_NewPlainObject(cx));
-  CHECK(obj);
-  CHECK(JS_DefineProperty(cx, obj, "x", 42, 0));
-
-  // Store the object behind a weak pointer and remove other references.
-  JS::Rooted<MyHeap> heap(cx, MyHeap(obj));
-  obj = nullptr;
-
-  cx->runtime()->gc.minorGC(JS::GCReason::API);
-
-  // The minor collection should have treated the weak ref as a strong ref,
-  // so the object should still be live, despite not having any other live
-  // references.
-  CHECK(heap.get().weak.unbarrieredGet() != nullptr);
-  obj = heap.get().weak;
-  JS::RootedValue v(cx);
-  CHECK(JS_GetProperty(cx, obj, "x", &v));
-  CHECK(v.isInt32());
-  CHECK(v.toInt32() == 42);
-
-  // A full collection with a second ref should keep the object as well.
-  CHECK(obj == heap.get().weak);
-  JS_GC(cx);
-  CHECK(obj == heap.get().weak);
-  v = JS::UndefinedValue();
-  CHECK(JS_GetProperty(cx, obj, "x", &v));
-  CHECK(v.isInt32());
-  CHECK(v.toInt32() == 42);
-
-  // A full collection after nulling the root should collect the object, or
-  // at least null out the weak reference before returning to the mutator.
-  obj = nullptr;
-  JS_GC(cx);
-  CHECK(heap.get().weak == nullptr);
-
-  return true;
-}
-END_TEST(testGCWeakRef)
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -64,29 +64,34 @@ struct IonScriptCounts;
 #define ION_PENDING_SCRIPT ((js::jit::IonScript*)0x3)
 
 #define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1)
 
 class AutoKeepTypeScripts;
 class AutoSweepTypeScript;
 class BreakpointSite;
 class Debugger;
+class GCParallelTask;
 class LazyScript;
 class ModuleObject;
 class RegExpObject;
 class SourceCompressionTask;
 class Shape;
 class TypeScript;
 
 namespace frontend {
 struct BytecodeEmitter;
 class FunctionBox;
 class ModuleSharedContext;
 }  // namespace frontend
 
+namespace gc {
+void SweepLazyScripts(GCParallelTask* task);
+} // namespace gc
+
 namespace detail {
 
 // Do not call this directly! It is exposed for the friend declarations in
 // this file.
 JSScript* CopyScript(JSContext* cx, HandleScript src,
                      HandleScriptSourceObject sourceObject,
                      MutableHandle<GCVector<Scope*>> scopes);
 
@@ -3020,16 +3025,17 @@ class alignas(uintptr_t) LazyScriptData 
 
 // Information about a script which may be (or has been) lazily compiled to
 // bytecode from its source.
 class LazyScript : public gc::TenuredCell {
   // If non-nullptr, the script has been compiled and this is a forwarding
   // pointer to the result. This is a weak pointer: after relazification, we
   // can collect the script if there are no other pointers to it.
   WeakHeapPtrScript script_;
+  friend void js::gc::SweepLazyScripts(GCParallelTask* task);
 
   // Original function with which the lazy script is associated.
   GCPtrFunction function_;
 
   // This field holds one of:
   //   * LazyScript in which the script is nested.  This case happens if the
   //     enclosing script is lazily parsed and have never been compiled.
   //
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -1407,18 +1407,17 @@ bool Instance::memoryAccessInBounds(uint
   }
 
   return true;
 }
 
 void Instance::tracePrivate(JSTracer* trc) {
   // This method is only called from WasmInstanceObject so the only reason why
   // TraceEdge is called is so that the pointer can be updated during a moving
-  // GC. TraceWeakEdge may sound better, but it is less efficient given that
-  // we know object_ is already marked.
+  // GC.
   MOZ_ASSERT(!gc::IsAboutToBeFinalized(&object_));
   TraceEdge(trc, &object_, "wasm instance object");
 
   // OK to just do one tier here; though the tiers have different funcImports
   // tables, they share the tls object.
   for (const FuncImport& fi : metadata(code().stableTier()).funcImports) {
     TraceNullableEdge(trc, &funcImportTls(fi).fun, "wasm import");
   }
--- a/js/src/wasm/WasmTable.cpp
+++ b/js/src/wasm/WasmTable.cpp
@@ -77,18 +77,17 @@ SharedTable Table::create(JSContext* cx,
       MOZ_CRASH();
   }
 }
 
 void Table::tracePrivate(JSTracer* trc) {
   // If this table has a WasmTableObject, then this method is only called by
   // WasmTableObject's trace hook so maybeObject_ must already be marked.
   // TraceEdge is called so that the pointer can be updated during a moving
-  // GC. TraceWeakEdge may sound better, but it is less efficient given that
-  // we know object_ is already marked.
+  // GC.
   if (maybeObject_) {
     MOZ_ASSERT(!gc::IsAboutToBeFinalized(&maybeObject_));
     TraceEdge(trc, &maybeObject_, "wasm table object");
   }
 
   switch (kind_) {
     case TableKind::FuncRef: {
       for (uint32_t i = 0; i < length_; i++) {