Backed out 3 changesets (bug 1557343) for bustages on Debugger.h. CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 26 Jun 2019 22:05:21 +0300
changeset 543037 3c04e55d4acf82c328da941f0f4dc17592fcd45c
parent 543036 70040a80a4d720f327d1f2d6fa18e525f4bb6921
child 543038 219d38523a321229f7f48aca6592f76b993fb1aa
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1557343
milestone69.0a1
backs out70040a80a4d720f327d1f2d6fa18e525f4bb6921
a9de28d699a73c1a84e403f3db7c0cc22f44547c
1663fcb7bfd753ff1f52fe753db5f9bb9d766529
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
Backed out 3 changesets (bug 1557343) for bustages on Debugger.h. CLOSED TREE Backed out changeset 70040a80a4d7 (bug 1557343) Backed out changeset a9de28d699a7 (bug 1557343) Backed out changeset 1663fcb7bfd7 (bug 1557343)
js/src/jit-test/tests/debug/bug1557343.js
js/src/vm/Compartment.h
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/bug1557343.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// |jit-test| --no-ggc
-
-var g = newGlobal({ newCompartment: true });
-g.eval(`
-  function* g3() {
-    debugger;
-  }
-
-  function next() {
-    g3().next();
-  }
-
-  function ggg() {
-    gc(gc);
-  }
-`);
-
-var dbg = new Debugger(g);
-var frame;
-dbg.onDebuggerStatement = f => {
-  frame = f;
-};
-
-g.next();
-g.ggg();
--- a/js/src/vm/Compartment.h
+++ b/js/src/vm/Compartment.h
@@ -609,21 +609,16 @@ class JS::Compartment {
   js::WrapperMap::Ptr lookupWrapper(JSObject* obj) const {
     return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(obj));
   }
 
   void removeWrapper(js::WrapperMap::Ptr p) {
     crossCompartmentWrappers.remove(p);
   }
 
-  void removeWrapper(const js::CrossCompartmentKey& key) {
-    js::WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key);
-    crossCompartmentWrappers.remove(p);
-  }
-
   bool hasNurseryAllocatedWrapperEntries(const js::CompartmentFilter& f) {
     return crossCompartmentWrappers.hasNurseryAllocatedWrapperEntries(f);
   }
 
   struct WrapperEnum : public js::WrapperMap::Enum {
     explicit WrapperEnum(JS::Compartment* c)
         : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
   };
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -750,31 +750,63 @@ bool Debugger::getFrame(JSContext* cx, c
       if (!ensureExecutionObservabilityOfFrame(cx, referent)) {
         return false;
       }
 
       if (genObj) {
         if (!frame->setGenerator(cx, genObj)) {
           return false;
         }
+
+        DebuggerFrame* frameObj = frame;
+        if (!generatorFrames.relookupOrAdd(gp, genObj, frameObj)) {
+          frame->clearGenerator(cx->runtime()->defaultFreeOp());
+          ReportOutOfMemory(cx);
+          return false;
+        }
       }
     }
 
     if (!frames.add(p, referent, frame)) {
       NukeDebuggerWrapper(frame);
-      frame->clearGenerator(cx->runtime()->defaultFreeOp(), this);
+      if (genObj) {
+        generatorFrames.remove(genObj);
+        frame->clearGenerator(cx->runtime()->defaultFreeOp());
+      }
       ReportOutOfMemory(cx);
       return false;
     }
   }
 
   result.set(&p->value()->as<DebuggerFrame>());
   return true;
 }
 
+bool Debugger::addGeneratorFrame(JSContext* cx,
+                                 Handle<AbstractGeneratorObject*> genObj,
+                                 HandleDebuggerFrame frameObj) {
+  GeneratorWeakMap::AddPtr p = generatorFrames.lookupForAdd(genObj);
+  if (p) {
+    MOZ_ASSERT(p->value() == frameObj);
+  } else {
+    {
+      AutoRealm ar(cx, frameObj);
+      if (!frameObj->setGenerator(cx, genObj)) {
+        return false;
+      }
+    }
+    if (!generatorFrames.relookupOrAdd(p, genObj, frameObj)) {
+      frameObj->clearGenerator(cx->runtime()->defaultFreeOp());
+      ReportOutOfMemory(cx);
+      return false;
+    }
+  }
+  return true;
+}
+
 /* static */
 bool Debugger::hasLiveHook(GlobalObject* global, Hook which) {
   if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
     for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
       Debugger* dbg = *p;
       if (dbg->enabled && dbg->getHook(which)) {
         return true;
       }
@@ -1133,27 +1165,24 @@ bool Debugger::slowPathOnNewGenerator(JS
   // created. It must be associated with any existing Debugger.Frames.
   bool ok = true;
   forEachDebuggerFrame(frame, [&](DebuggerFrame* frameObjPtr) {
     if (!ok) {
       return;
     }
 
     RootedDebuggerFrame frameObj(cx, frameObjPtr);
-    {
-      AutoRealm ar(cx, frameObj);
-
-      if (!frameObj->setGenerator(cx, genObj)) {
-        ReportOutOfMemory(cx);
-
-        // This leaves `genObj` and `frameObj` unassociated. It's OK
-        // because we won't pause again with this generator on the stack:
-        // the caller will immediately discard `genObj` and unwind `frame`.
-        ok = false;
-      }
+    Debugger* dbg = Debugger::fromChildJSObject(frameObj);
+    if (!dbg->addGeneratorFrame(cx, genObj, frameObj)) {
+      ReportOutOfMemory(cx);
+
+      // This leaves `genObj` and `frameObj` unassociated. It's OK
+      // because we won't pause again with this generator on the stack:
+      // the caller will immediately discard `genObj` and unwind `frame`.
+      ok = false;
     }
   });
   return ok;
 }
 
 /* static */
 ResumeMode Debugger::slowPathOnDebuggerStatement(JSContext* cx,
                                                  AbstractFramePtr frame) {
@@ -4490,23 +4519,25 @@ void Debugger::removeDebuggeeGlobal(Free
   // When called from script, it's okay to iterate over generatorFrames and
   // touch its keys and values (even when an incremental GC is in progress).
   // When called from GC, it's not okay; the keys and values may be dying. But
   // in that case, we can actually just skip the loop entirely! If the Debugger
   // is going away, it doesn't care about the state of its generatorFrames
   // table, and the Debugger.Frame finalizer will fix up the generator observer
   // counts.
   if (fromSweep == FromSweep::No) {
-    for (GeneratorWeakMap::Enum e(generatorFrames); !e.empty(); e.popFront()) {
-      auto& genObj = e.front().key()->as<AbstractGeneratorObject>();
-      auto& frameObj = e.front().value()->as<DebuggerFrame>();
+    generatorFrames.removeIf([global, fop](JSObject* key, JSObject* value) {
+      auto& genObj = key->as<AbstractGeneratorObject>();
+      auto& frameObj = value->as<DebuggerFrame>();
       if (genObj.isClosed() || &genObj.callee().global() == global) {
-        frameObj.clearGenerator(fop, this, &e);
-      }
-    }
+        frameObj.clearGenerator(fop);
+        return true;
+      }
+      return false;
+    });
   }
 
   auto* globalDebuggersVector = global->getDebuggers();
   auto* zoneDebuggersVector = global->zone()->getDebuggers();
 
   // The relation must be removed from up to three places:
   // globalDebuggersVector and debuggees for sure, and possibly the
   // compartment's debuggee set.
@@ -7807,17 +7838,18 @@ void Debugger::removeFromFrameMapsAndCle
       // generatorFrames. Such an entry exists if and only if the
       // Debugger.Frame's generator has been set.
       if (!suspending) {
         // Terminally exiting a generator.
         AbstractGeneratorObject& genObj = frameobj->unwrappedGenerator();
         GeneratorWeakMap::Ptr p = dbg->generatorFrames.lookup(&genObj);
         MOZ_ASSERT(p);
         MOZ_ASSERT(p->value() == frameobj);
-        frameobj->clearGenerator(fop, dbg);
+        dbg->generatorFrames.remove(p);
+        frameobj->clearGenerator(fop);
       }
     } else {
       frameobj->maybeDecrementFrameScriptStepperCount(fop, frame);
     }
   });
 
   // If this is an eval frame, then from the debugger's perspective the
   // script is about to be destroyed. Remove any breakpoints in it.
@@ -9048,156 +9080,72 @@ class DebuggerFrame::GeneratorInfo {
 
   AbstractGeneratorObject& unwrappedGenerator() const {
     return unwrappedGenerator_.toObject().as<AbstractGeneratorObject>();
   }
 
   HeapPtr<JSScript*>& generatorScript() { return generatorScript_; }
 };
 
-js::AbstractGeneratorObject& js::DebuggerFrame::unwrappedGenerator() const {
-  return generatorInfo()->unwrappedGenerator();
-}
-
-bool DebuggerFrame::setGenerator(JSContext* cx,
-                                 Handle<AbstractGeneratorObject*> genObj) {
+bool DebuggerFrame::setGenerator(
+    JSContext* cx, Handle<AbstractGeneratorObject*> unwrappedGenObj) {
   cx->check(this);
 
-  Debugger::GeneratorWeakMap::AddPtr p =
-      owner()->generatorFrames.lookupForAdd(genObj);
-  if (p) {
-    MOZ_ASSERT(p->value() == this);
-    MOZ_ASSERT(&unwrappedGenerator() == genObj);
-    return true;
-  }
-
-  // There are five relations we must establish:
-  //
-  // 1) The DebuggerFrame must point to the AbstractGeneratorObject.
-  //
-  // 2) generatorFrames must map the AbstractGeneratorObject to the
-  //    DebuggerFrame.
-  //
-  // 3) The compartment's crossCompartmentWrappers map must map this Debugger
-  //    and the AbstractGeneratorObject to the DebuggerFrame.
-  //
-  // 4) The compartment's crossCompartmentWrappers map must map this Debugger
-  //    and the generator's JSScript to the DebuggerFrame.
-  //
-  // 5) The generator's script's observer count must be bumped.
-  RootedScript script(cx, genObj->callee().nonLazyScript());
-  auto* info = cx->new_<GeneratorInfo>(genObj, script);
-  if (!info) {
-    ReportOutOfMemory(cx);
-    return false;
-  }
-  auto infoGuard =
-      MakeScopeExit([&] { cx->runtime()->defaultFreeOp()->delete_(info); });
-
-  if (!owner()->generatorFrames.relookupOrAdd(p, genObj, this)) {
-    ReportOutOfMemory(cx);
-    return false;
-  }
-  auto generatorFramesGuard =
-      MakeScopeExit([&] { owner()->generatorFrames.remove(genObj); });
+  RootedNativeObject owner(cx, this->owner()->toJSObject());
+  RootedScript script(cx, unwrappedGenObj->callee().nonLazyScript());
 
   Rooted<CrossCompartmentKey> generatorKey(
-      cx, CrossCompartmentKey::DebuggeeFrameGenerator(owner()->toJSObject(),
-                                                      genObj));
+      cx, CrossCompartmentKey::DebuggeeFrameGenerator(owner, unwrappedGenObj));
   Rooted<CrossCompartmentKey> scriptKey(
-      cx, CrossCompartmentKey::DebuggeeFrameGeneratorScript(
-              owner()->toJSObject(), script));
+      cx, CrossCompartmentKey::DebuggeeFrameGeneratorScript(owner, script));
+
   if (!compartment()->putWrapper(cx, generatorKey, ObjectValue(*this)) ||
       !compartment()->putWrapper(cx, scriptKey, ObjectValue(*this))) {
     return false;
   }
-  auto crossCompartmentKeysGuard = MakeScopeExit([&] {
-    compartment()->removeWrapper(generatorKey);
-    compartment()->removeWrapper(scriptKey);
-  });
+
+  auto* info = cx->new_<GeneratorInfo>(unwrappedGenObj, script);
+  if (!info) {
+    JS_ReportOutOfMemory(cx);
+    return false;
+  }
 
   {
     AutoRealm ar(cx, script);
     if (!script->incrementGeneratorObserverCount(cx)) {
+      js_delete(info);
       return false;
     }
   }
 
   setReservedSlot(GENERATOR_INFO_SLOT, PrivateValue(info));
-
-  crossCompartmentKeysGuard.release();
-  generatorFramesGuard.release();
-  infoGuard.release();
-
   return true;
 }
 
 void DebuggerFrame::clearGenerator(FreeOp* fop) {
   if (!hasGenerator()) {
     return;
   }
 
   GeneratorInfo* info = generatorInfo();
-
-  // 5) The generator's script's observer count must be dropped.
-  //
-  // For ordinary calls, Debugger.Frame objects drop the script's stepper count
-  // when the frame is popped, but for generators, they leave the stepper count
-  // incremented across suspensions. This means that, whereas ordinary calls
-  // never need to drop the stepper count from the D.F finalizer, generator
-  // calls may.
   HeapPtr<JSScript*>& generatorScript = info->generatorScript();
   if (!IsAboutToBeFinalized(&generatorScript)) {
     generatorScript->decrementGeneratorObserverCount(fop);
-
-    OnStepHandler* handler = onStepHandler();
-    if (handler) {
+    bool isStepper = !getReservedSlot(ONSTEP_HANDLER_SLOT).isUndefined();
+    if (isStepper) {
       generatorScript->decrementStepperCount(fop);
-      setReservedSlot(ONSTEP_HANDLER_SLOT, UndefinedValue());
-      fop->delete_(handler);
-    }
-  }
-
-  // 1) The DebuggerFrame must no longer point to the AbstractGeneratorObject.
-  setReservedSlot(GENERATOR_INFO_SLOT, UndefinedValue());
+    }
+  }
+
   fop->delete_(info);
-}
-
-void DebuggerFrame::clearGenerator(
-    FreeOp* fop, Debugger* owner,
-    Debugger::GeneratorWeakMap::Enum* maybeGeneratorFramesEnum) {
-  if (!hasGenerator()) {
-    return;
-  }
-
-  // 4) The compartment's crossCompartmentWrappers map must map this Debugger
-  //    and the generator's JSScript to the DebuggerFrame.
-  //
-  // 3) The compartment's crossCompartmentWrappers map must map this Debugger
-  //    and the AbstractGeneratorObject to the DebuggerFrame.
-  //
-  GeneratorInfo* info = generatorInfo();
-  HeapPtr<JSScript*>& generatorScript = info->generatorScript();
-  CrossCompartmentKey generatorKey(CrossCompartmentKey::DebuggeeFrameGenerator(
-      owner->object, &info->unwrappedGenerator()));
-  CrossCompartmentKey scriptKey(
-      CrossCompartmentKey::DebuggeeFrameGeneratorScript(owner->object,
-                                                        generatorScript));
-  compartment()->removeWrapper(generatorKey);
-  compartment()->removeWrapper(scriptKey);
-
-  // 2) generatorFrames must no longer map the AbstractGeneratorObject to the
-  // DebuggerFrame.
-  if (maybeGeneratorFramesEnum) {
-    maybeGeneratorFramesEnum->removeFront();
-  } else {
-    owner->generatorFrames.remove(&info->unwrappedGenerator());
-  }
-
-  clearGenerator(fop);
+  setReservedSlot(GENERATOR_INFO_SLOT, UndefinedValue());
+}
+
+js::AbstractGeneratorObject& js::DebuggerFrame::unwrappedGenerator() const {
+  return generatorInfo()->unwrappedGenerator();
 }
 
 /* static */
 bool DebuggerFrame::getCallee(JSContext* cx, HandleDebuggerFrame frame,
                               MutableHandleDebuggerObject result) {
   MOZ_ASSERT(frame->isLive());
 
   AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
@@ -9794,25 +9742,25 @@ void DebuggerFrame::maybeDecrementFrameS
   setReservedSlot(ONSTEP_HANDLER_SLOT, UndefinedValue());
 }
 
 /* static */
 void DebuggerFrame::finalize(FreeOp* fop, JSObject* obj) {
   MOZ_ASSERT(fop->onMainThread());
   DebuggerFrame& frameobj = obj->as<DebuggerFrame>();
   frameobj.freeFrameIterData(fop);
-  frameobj.clearGenerator(fop);
   OnStepHandler* onStepHandler = frameobj.onStepHandler();
   if (onStepHandler) {
     onStepHandler->drop();
   }
   OnPopHandler* onPopHandler = frameobj.onPopHandler();
   if (onPopHandler) {
     onPopHandler->drop();
   }
+  frameobj.clearGenerator(fop);
 }
 
 /* static */
 void DebuggerFrame::trace(JSTracer* trc, JSObject* obj) {
   OnStepHandler* onStepHandler = obj->as<DebuggerFrame>().onStepHandler();
   if (onStepHandler) {
     onStepHandler->trace(trc);
   }
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -148,47 +148,55 @@ class DebuggerWeakMap
  public:
   // Expose those parts of HashMap public interface that are used by Debugger
   // methods.
 
   using Entry = typename Base::Entry;
   using Ptr = typename Base::Ptr;
   using AddPtr = typename Base::AddPtr;
   using Range = typename Base::Range;
+  using Enum = typename Base::Enum;
   using Lookup = typename Base::Lookup;
 
   // Expose WeakMap public interface.
 
   using Base::all;
   using Base::has;
   using Base::lookup;
   using Base::lookupForAdd;
   using Base::remove;
   using Base::trace;
 
-  class Enum : public Base::Enum {
-   public:
-    Enum(DebuggerWeakMap& map) : Base::Enum(map) {}
-  };
-
   template <typename KeyInput, typename ValueInput>
   bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) {
     MOZ_ASSERT(v->compartment() == this->compartment);
 #ifdef DEBUG
     CheckDebuggeeThing(k, InvisibleKeysOk);
 #endif
     MOZ_ASSERT(!Base::has(k));
     bool ok = Base::relookupOrAdd(p, k, v);
     return ok;
   }
 
+  // Remove all entries for which test(key, value) returns true.
+  template <typename Predicate>
+  void removeIf(Predicate test) {
+    for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
+      JSObject* key = e.front().key();
+      JSObject* value = e.front().value();
+      if (test(key, value)) {
+        e.removeFront();
+      }
+    }
+  }
+
  public:
   template <void(traceValueEdges)(JSTracer*, JSObject*)>
   void traceCrossCompartmentEdges(JSTracer* tracer) {
-    for (Enum e(*this); !e.empty(); e.popFront()) {
+    for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
       traceValueEdges(tracer, e.front().value());
       Key key = e.front().key();
       TraceEdge(tracer, &key, "Debugger WeakMap key");
       if (key != e.front().key()) {
         e.rekeyFront(key);
       }
       key.unsafeSet(nullptr);
     }
@@ -261,17 +269,16 @@ typedef mozilla::Variant<JSScript*, Lazy
 
 // Either a ScriptSourceObject, for ordinary JS, or a WasmInstanceObject,
 // denoting the synthesized source of a wasm module.
 typedef mozilla::Variant<ScriptSourceObject*, WasmInstanceObject*>
     DebuggerSourceReferent;
 
 class Debugger : private mozilla::LinkedListElement<Debugger> {
   friend class Breakpoint;
-  friend class DebuggerFrame;
   friend class DebuggerMemory;
   friend struct JSRuntime::GlobalObjectWatchersLinkAccess<Debugger>;
   friend class SavedStacks;
   friend class ScriptedOnStepHandler;
   friend class ScriptedOnPopHandler;
   friend class mozilla::LinkedListElement<Debugger>;
   friend class mozilla::LinkedList<Debugger>;
   friend bool(::JS_DefineDebuggerObject)(JSContext* cx, JS::HandleObject obj);
@@ -1215,16 +1222,33 @@ class Debugger : private mozilla::Linked
    * Return the Debugger.Source object for |wasmInstance| (the entire module),
    * synthesizing a new one if needed. The context |cx| must be in the
    * debugger compartment; |wasmInstance| must be a WasmInstanceObject in the
    * debuggee realm.
    */
   JSObject* wrapWasmSource(JSContext* cx,
                            Handle<WasmInstanceObject*> wasmInstance);
 
+  /*
+   * Add a link between the given generator object and a Debugger.Frame
+   * object.  This link is used to make sure the same Debugger.Frame stays
+   * associated with a given generator object (or async function activation),
+   * even while it is suspended and removed from the stack.
+   *
+   * The context `cx` and `frameObj` must be in the debugger realm, and
+   * `genObj` must be in a debuggee realm.
+   *
+   * `frameObj` must be this `Debugger`'s debug wrapper for the generator or
+   * async function call associated with `genObj`. This activation may
+   * or may not actually be on the stack right now.
+   */
+  MOZ_MUST_USE bool addGeneratorFrame(JSContext* cx,
+                                      Handle<AbstractGeneratorObject*> genObj,
+                                      HandleDebuggerFrame frameObj);
+
  private:
   Debugger(const Debugger&) = delete;
   Debugger& operator=(const Debugger&) = delete;
 };
 
 enum class DebuggerEnvironmentType { Declarative, With, Object };
 
 class DebuggerEnvironment : public NativeObject {
@@ -1494,63 +1518,26 @@ class DebuggerFrame : public NativeObjec
                                                const char* fnname,
                                                bool checkLive);
 
   bool isLive() const;
   OnStepHandler* onStepHandler() const;
   OnPopHandler* onPopHandler() const;
   void setOnPopHandler(OnPopHandler* handler);
 
+  bool setGenerator(JSContext* cx,
+                    Handle<AbstractGeneratorObject*> unwrappedGenObj);
   bool hasGenerator() const;
+  void clearGenerator(FreeOp* fop);
 
   // If hasGenerator(), return an direct cross-compartment reference to this
   // Debugger.Frame's generator object.
   AbstractGeneratorObject& unwrappedGenerator() const;
 
   /*
-   * Associate the generator object genObj with this Debugger.Frame. This
-   * association allows the Debugger.Frame to track the generator's execution
-   * across suspensions and resumptions, and to implement some methods even
-   * while the generator is suspended.
-   *
-   * The context `cx` must be in the Debugger.Frame's realm, and `genObj` must
-   * be in a debuggee realm.
-   *
-   * Technically, the generator activation need not actually be on the stack
-   * right now; it's okay to call this method on a Debugger.Frame that has no
-   * ScriptFrameIter::Data at present. However, this function has no way to
-   * verify that genObj really is the generator associated with the call for
-   * which this Debugger.Frame was originally created, so it's best to make the
-   * association while the call is on the stack, and the relationships are easy
-   * to discern.
-   */
-  MOZ_MUST_USE bool setGenerator(JSContext* cx,
-                                 Handle<AbstractGeneratorObject*> genObj);
-
-  /*
-   * Undo the effects of a prior call to setGenerator.
-   *
-   * If provided, owner must be the Debugger to which this Debugger.Frame
-   * belongs; remove this frame's entry from its generatorFrames map, and clean
-   * up its cross-compartment wrapper table entries. The owner must be passed
-   * unless this method is being called from the Debugger.Frame's finalizer. (In
-   * that case, the owner is not reliably available, and is not actually
-   * necessary.)
-   *
-   * If maybeGeneratorFramesEnum is non-null, use it to remove this frame's
-   * entry from the Debugger's generatorFrames weak map. In this case, this
-   * function will not otherwise disturb generatorFrames. Passing the enum
-   * allows this function to be used while iterating over generatorFrames.
-   */
-  void clearGenerator(FreeOp* fop);
-  void clearGenerator(
-      FreeOp* fop, Debugger* owner,
-      Debugger::GeneratorWeakMap::Enum* maybeGeneratorFramesEnum = nullptr);
-
-  /*
    * Called after a generator/async frame is resumed, before exposing this
    * Debugger.Frame object to any hooks.
    */
   bool resume(const FrameIter& iter);
 
   bool hasAnyLiveHooks() const;
 
  private:
@@ -1602,16 +1589,17 @@ class DebuggerFrame : public NativeObjec
   Debugger* owner() const;
 
  public:
   FrameIter::Data* frameIterData() const;
   void freeFrameIterData(FreeOp* fop);
   void maybeDecrementFrameScriptStepperCount(FreeOp* fop,
                                              AbstractFramePtr frame);
 
+ private:
   class GeneratorInfo;
   inline GeneratorInfo* generatorInfo() const;
 };
 
 class DebuggerObject : public NativeObject {
  public:
   static const Class class_;