Bug 1569043 - Tidy up DebugAPI, r=jimb.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 25 Jul 2019 13:02:06 -1000
changeset 485008 d6714511c9c710e86a7b71f3552e5bed8c3a1102
parent 485007 9c55e0e26127dce7e5eec1b483f55da8348ad40f
child 485009 93d5840653ae6a81cacc964276f7597565772604
push id36357
push usernbeleuzu@mozilla.com
push dateSun, 28 Jul 2019 21:49:40 +0000
treeherdermozilla-central@be624f34dc4a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1569043
milestone70.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 1569043 - Tidy up DebugAPI, r=jimb. Differential Revision: https://phabricator.services.mozilla.com/D39423 MANUAL PUSH: Lando does not allow me to land these patches, and no one is in #lando to help diagnose why.
js/src/debugger/DebugAPI.h
js/src/debugger/Debugger.cpp
js/src/gc/GC.cpp
js/src/vm/Compartment.cpp
js/src/vm/Runtime.cpp
--- a/js/src/debugger/DebugAPI.h
+++ b/js/src/debugger/DebugAPI.h
@@ -80,58 +80,79 @@ class DebugAPI {
    *   * it is in the middle of dispatching an event (the event dispatching
    *     code roots it in this case); OR
    *   * it is enabled, and it is debugging at least one live compartment,
    *     and at least one of the following is true:
    *       - it has a debugger hook installed
    *       - it has a breakpoint set on a live script
    *       - it has a watchpoint set on a live object.
    *
-   * Debugger::markIteratively handles the last case. If it finds any Debugger
+   * DebugAPI::markIteratively handles the last case. If it finds any Debugger
    * objects that are definitely live but not yet marked, it marks them and
    * returns true. If not, it returns false.
    */
-  static void traceIncomingCrossCompartmentEdges(JSTracer* tracer);
   static MOZ_MUST_USE bool markIteratively(GCMarker* marker);
+
+  // Trace cross compartment edges in all debuggers relevant to the current GC.
+  static void traceCrossCompartmentEdges(JSTracer* tracer);
+
+  // Trace all debugger-owned GC things unconditionally, during a moving GC.
   static void traceAllForMovingGC(JSTracer* trc);
+
+  // Sweep dying debuggers, and detach edges to dying debuggees.
   static void sweepAll(FreeOp* fop);
+
+  // Add sweep group edges due to the presence of any debuggers.
   static MOZ_MUST_USE bool findSweepGroupEdges(JSRuntime* rt);
+
+  // Sweep breakpoints in a script associated with any debugger.
   static inline void sweepBreakpoints(FreeOp* fop, JSScript* script);
+
+  // Destroy the debugging information associated with a script.
   static void destroyDebugScript(FreeOp* fop, JSScript* script);
+
+  // Validate the debugging information in a script after a moving GC>
 #ifdef JSGC_HASH_TABLE_CHECKS
   static void checkDebugScriptAfterMovingGC(DebugScript* ds);
 #endif
 
   /*** Methods for querying script breakpoint state. **************************/
 
+  // Query information about whether any debuggers are observing a script.
   static inline bool stepModeEnabled(JSScript* script);
-
   static inline bool hasBreakpointsAt(JSScript* script, jsbytecode* pc);
-
   static inline bool hasAnyBreakpointsOrStepMode(JSScript* script);
 
-  /*** Methods for interacting with the runtime. ******************************/
+  /*** Methods for interacting with the JITs. *********************************/
 
+  // Update Debugger frames when an interpreter frame is replaced with a
+  // baseline frame.
   static MOZ_MUST_USE bool handleBaselineOsr(JSContext* cx,
                                              InterpreterFrame* from,
                                              jit::BaselineFrame* to);
 
+  // Update Debugger frames when an Ion frame bails out and is replaced with a
+  // baseline frame.
   static MOZ_MUST_USE bool handleIonBailout(JSContext* cx,
                                             jit::RematerializedFrame* from,
                                             jit::BaselineFrame* to);
 
+  // Detach any Debugger frames from an Ion frame after an error occurred while
+  // it bailed out.
   static void handleUnrecoverableIonBailoutError(
       JSContext* cx, jit::RematerializedFrame* frame);
 
-  static void propagateForcedReturn(JSContext* cx, AbstractFramePtr frame,
-                                    HandleValue rval);
-
+  // When doing on-stack-replacement of a debuggee interpreter frame with a
+  // baseline frame, ensure that the resulting frame can be observed by the
+  // debugger.
   static MOZ_MUST_USE bool ensureExecutionObservabilityOfOsrFrame(
       JSContext* cx, AbstractFramePtr osrSourceFrame);
 
+  // Describes a set of scripts or frames whose execution observability can
+  // change due to debugger activity.
   class ExecutionObservableSet {
    public:
     typedef HashSet<Zone*>::Range ZoneRange;
 
     virtual Zone* singleZone() const { return nullptr; }
     virtual JSScript* singleScriptForZoneInvalidation() const {
       return nullptr;
     }
@@ -140,21 +161,22 @@ class DebugAPI {
     virtual bool shouldRecompileOrInvalidate(JSScript* script) const = 0;
     virtual bool shouldMarkAsDebuggee(FrameIter& iter) const = 0;
   };
 
   // This enum is converted to and compare with bool values; NotObserving
   // must be 0 and Observing must be 1.
   enum IsObserving { NotObserving = 0, Observing = 1 };
 
-  // Checks if the current compartment is allowed to execute code.
-  static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx,
-                                                 HandleScript script);
+  /*** Methods for calling installed debugger handlers. ***********************/
 
+  // Called when a new script becomes accessible to debuggers.
   static inline void onNewScript(JSContext* cx, HandleScript script);
+
+  // Called when a new wasm instance becomes accessible to debuggers.
   static inline void onNewWasmInstance(
       JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
 
   /*
    * Announce to the debugger that the context has entered a new JavaScript
    * frame, |frame|. Call whatever hooks have been registered to observe new
    * frames.
    */
@@ -209,17 +231,20 @@ class DebugAPI {
    * cases where an onPop handler's resumption value changes a return to a
    * throw, or vice versa: we can redirect to a complete copy of the
    * alternative path, containing its own call to onLeaveFrame.)
    */
   static inline MOZ_MUST_USE bool onLeaveFrame(JSContext* cx,
                                                AbstractFramePtr frame,
                                                jsbytecode* pc, bool ok);
 
+  // Call any breakpoint handlers for the current scripted location.
   static ResumeMode onTrap(JSContext* cx, MutableHandleValue vp);
+
+  // Call any stepping handlers for the current scripted location.
   static ResumeMode onSingleStep(JSContext* cx, MutableHandleValue vp);
 
   // Notify any Debugger instances observing this promise's global that a new
   // promise was allocated.
   static inline void onNewPromise(JSContext* cx,
                                   Handle<PromiseObject*> promise);
 
   // Notify any Debugger instances observing this promise's global that the
@@ -228,71 +253,90 @@ class DebugAPI {
   // fate getting locked in) because you can resolve a promise with another
   // pending promise, in which case neither promise has settled yet.
   //
   // This should never be called on the same promise more than once, because a
   // promise can only make the transition from unsettled to settled once.
   static inline void onPromiseSettled(JSContext* cx,
                                       Handle<PromiseObject*> promise);
 
+  // Notify any Debugger instances that a new global object has been created.
+  static inline void onNewGlobalObject(JSContext* cx,
+                                       Handle<GlobalObject*> global);
+
+  /*** Methods for querying installed debugger handlers. **********************/
+
   // Whether any debugger is observing execution in a global.
   static bool debuggerObservesAllExecution(GlobalObject* global);
 
   // Whether any debugger is observing JS execution coverage in a global.
   static bool debuggerObservesCoverage(GlobalObject* global);
 
   // Whether any Debugger is observing asm.js execution in a global.
   static bool debuggerObservesAsmJS(GlobalObject* global);
 
   /*
+   * Return true if the given global is being observed by at least one
+   * Debugger that is tracking allocations.
+   */
+  static bool isObservedByDebuggerTrackingAllocations(
+      const GlobalObject& debuggee);
+
+  // If any debuggers are tracking allocations for a global, return the
+  // probability that a given allocation should be tracked. Nothing otherwise.
+  static mozilla::Maybe<double> allocationSamplingProbability(
+      GlobalObject* global);
+
+  // Whether any debugger is observing exception unwinds in a realm.
+  static bool hasExceptionUnwindHook(GlobalObject* global);
+
+  // Whether any debugger is observing debugger statements in a realm.
+  static bool hasDebuggerStatementHook(GlobalObject* global);
+
+  /*** Assorted methods for interacting with the runtime. *********************/
+
+  // When a step handler called during the interrupt callback forces the current
+  // frame to return, set state in the frame and context so that the exception
+  // handler will perform the forced return.
+  static void propagateForcedReturn(JSContext* cx, AbstractFramePtr frame,
+                                    HandleValue rval);
+
+  // Checks if the current compartment is allowed to execute code.
+  static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx,
+                                                 HandleScript script);
+
+  /*
    * Announce to the debugger that a generator object has been created,
    * via JSOP_GENERATOR.
    *
    * This does not fire user hooks, but it's needed for debugger bookkeeping.
    */
   static inline MOZ_MUST_USE bool onNewGenerator(
       JSContext* cx, AbstractFramePtr frame,
       Handle<AbstractGeneratorObject*> genObj);
 
+  // If necessary, record an object that was just allocated for any observing
+  // debuggers.
   static inline MOZ_MUST_USE bool onLogAllocationSite(JSContext* cx,
                                                       JSObject* obj,
                                                       HandleSavedFrame frame,
                                                       mozilla::TimeStamp when);
 
-  static inline void onNewGlobalObject(JSContext* cx,
-                                       Handle<GlobalObject*> global);
-
-  /*
-   * Return true if the given global is being observed by at least one
-   * Debugger that is tracking allocations.
-   */
-  static bool isObservedByDebuggerTrackingAllocations(
-      const GlobalObject& debuggee);
-
   // Announce to the debugger that a global object is being collected by the
   // specified major GC.
   static inline void notifyParticipatesInGC(GlobalObject* global,
                                             uint64_t majorGCNumber);
 
-  static mozilla::Maybe<double> allocationSamplingProbability(
-      GlobalObject* global);
-
   // Allocate an object which holds a GlobalObject::DebuggerVector.
   static JSObject* newGlobalDebuggersHolder(JSContext* cx);
 
   // Get the GlobalObject::DebuggerVector for an object allocated by
   // newGlobalDebuggersObject.
   static GlobalObject::DebuggerVector* getGlobalDebuggers(JSObject* holder);
 
-  // Whether any debugger is observing exception unwinds in a realm.
-  static bool hasExceptionUnwindHook(GlobalObject* global);
-
-  // Whether any debugger is observing debugger statements in a realm.
-  static bool hasDebuggerStatementHook(GlobalObject* global);
-
   /*
    * Get any instrumentation ID which has been associated with a script using
    * the specified debugger object.
    */
   static bool getScriptInstrumentationId(JSContext* cx,
                                          HandleObject dbgObject,
                                          HandleScript script,
                                          MutableHandleValue rval);
--- a/js/src/debugger/Debugger.cpp
+++ b/js/src/debugger/Debugger.cpp
@@ -3471,17 +3471,17 @@ void Debugger::traceCrossCompartmentEdge
  *
  * This happens during the initial mark phase, not iterative marking, because
  * all the edges being reported here are strong references.
  *
  * This method is also used during compacting GC to update cross compartment
  * pointers into zones that are being compacted.
  */
 /* static */
-void DebugAPI::traceIncomingCrossCompartmentEdges(JSTracer* trc) {
+void DebugAPI::traceCrossCompartmentEdges(JSTracer* trc) {
   JSRuntime* rt = trc->runtime();
   gc::State state = rt->gc.state();
   MOZ_ASSERT(state == gc::State::MarkRoots || state == gc::State::Compact);
 
   for (Debugger* dbg : rt->debuggerList()) {
     Zone* zone = MaybeForwarded(dbg->object.get())->zone();
     if (!zone->isCollecting() || state == gc::State::Compact) {
       dbg->traceCrossCompartmentEdges(trc);
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -3059,17 +3059,17 @@ void GCRuntime::updateRuntimePointersToR
   rt->geckoProfiler().fixupStringsMapAfterMovingGC();
 
   traceRuntimeForMajorGC(&trc, session);
 
   // Mark roots to update them.
   {
     gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::MARK_ROOTS);
     DebugAPI::traceAllForMovingGC(&trc);
-    DebugAPI::traceIncomingCrossCompartmentEdges(&trc);
+    DebugAPI::traceCrossCompartmentEdges(&trc);
 
     // Mark all gray roots, making sure we call the trace callback to get the
     // current set.
     if (JSTraceDataOp op = grayRootTracer.op) {
       (*op)(&trc, grayRootTracer.data);
     }
   }
 
--- a/js/src/vm/Compartment.cpp
+++ b/js/src/vm/Compartment.cpp
@@ -442,17 +442,17 @@ void Compartment::traceIncomingCrossComp
   gcstats::AutoPhase ap(trc->runtime()->gc.stats(),
                         gcstats::PhaseKind::MARK_CCWS);
   MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting());
   for (CompartmentsIter c(trc->runtime()); !c.done(); c.next()) {
     if (!c->zone()->isCollecting()) {
       c->traceOutgoingCrossCompartmentWrappers(trc);
     }
   }
-  DebugAPI::traceIncomingCrossCompartmentEdges(trc);
+  DebugAPI::traceCrossCompartmentEdges(trc);
 }
 
 void Compartment::sweepAfterMinorGC(JSTracer* trc) {
   crossCompartmentWrappers.sweepAfterMinorGC(trc);
 
   for (RealmsInCompartmentIter r(this); !r.done(); r.next()) {
     r->sweepAfterMinorGC();
   }
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -439,17 +439,17 @@ static bool HandleInterrupt(JSContext* c
         switch (DebugAPI::onSingleStep(cx, &rval)) {
           case ResumeMode::Terminate:
             mozilla::recordreplay::InvalidateRecording(
                 "Debugger single-step produced an error");
             return false;
           case ResumeMode::Continue:
             return true;
           case ResumeMode::Return:
-            // See note in Debugger::propagateForcedReturn.
+            // See note in DebugAPI::propagateForcedReturn.
             DebugAPI::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
             mozilla::recordreplay::InvalidateRecording(
                 "Debugger single-step forced return");
             return false;
           case ResumeMode::Throw:
             cx->setPendingExceptionAndCaptureStack(rval);
             mozilla::recordreplay::InvalidateRecording(
                 "Debugger single-step threw an exception");