Bug 1549950 - Remove TraceWeakEdge and associated machinery and sweep weak pointers in lazy scripts explicitly r=sfink default tip
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 May 2019 17:24:38 +0100
changeset 474684 4d7ef530fffba20a2b352cff9fa23438128105a7
parent 474683 f3fae269992d4984480f731765bd7040def16c60
push id113167
push userjcoppeard@mozilla.com
push dateTue, 21 May 2019 12:30:24 +0000
treeherdermozilla-inbound@4d7ef530fffb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1549950
milestone69.0a1
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++) {