Bug 1602699 - Part 7: Scope PropagateForcedReturn to just Debugger.cpp. r=jimb
authorLogan Smyth <loganfsmyth@gmail.com>
Thu, 19 Dec 2019 01:11:59 +0000
changeset 507697 8ea0a6fda65d5599b5ed9badb50e59b018bc3898
parent 507696 46b011b3ac0f13e6f79fe7bcced67fee64abecac
child 507698 0141d065fe283afb395177b7097862b0bbf572b8
push id103601
push userloganfsmyth@gmail.com
push dateThu, 19 Dec 2019 02:01:57 +0000
treeherderautoland@cac7612e534b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1602699
milestone73.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 1602699 - Part 7: Scope PropagateForcedReturn to just Debugger.cpp. r=jimb Differential Revision: https://phabricator.services.mozilla.com/D57287
js/src/debugger/DebugAPI.h
js/src/debugger/Debugger.cpp
--- a/js/src/debugger/DebugAPI.h
+++ b/js/src/debugger/DebugAPI.h
@@ -317,22 +317,16 @@ class DebugAPI {
   // 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.
    *
--- a/js/src/debugger/Debugger.cpp
+++ b/js/src/debugger/Debugger.cpp
@@ -226,16 +226,31 @@ bool DebugAPI::slowPathCheckNoExecute(JS
 }
 
 static inline void NukeDebuggerWrapper(NativeObject* wrapper) {
   // In some OOM failure cases, we need to destroy the edge to the referent,
   // to avoid trying to trace it during untimely collections.
   wrapper->setPrivate(nullptr);
 }
 
+static void PropagateForcedReturn(JSContext* cx, AbstractFramePtr frame,
+                                  HandleValue rval) {
+  // The Debugger's hooks may return a value that affects the completion
+  // value of the given frame. For example, a hook may return `{ return: 42 }`
+  // to terminate the frame and return `42` as the final frame result.
+  // To accomplish this, the debugger treats these return values as if
+  // execution of the JS function has been terminated without a pending
+  // exception, but with a special flag. When the error is handled by the
+  // interpreter or JIT, the special flag and the error state will be cleared
+  // and execution will continue from the end of the frame.
+  MOZ_ASSERT(!cx->isExceptionPending());
+  cx->setPropagatingForcedReturn();
+  frame.setReturnValue(rval);
+}
+
 bool js::ValueToStableChars(JSContext* cx, const char* fnname,
                             HandleValue value,
                             AutoStableStringChars& stableChars) {
   if (!value.isString()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_NOT_EXPECTED_TYPE, fnname, "string",
                               InformalValueTypeName(value));
     return false;
@@ -733,17 +748,17 @@ bool DebugAPI::slowPathOnEnterFrame(JSCo
       cx->setPendingExceptionAndCaptureStack(rval);
       return false;
 
     case ResumeMode::Terminate:
       cx->clearPendingException();
       return false;
 
     case ResumeMode::Return:
-      DebugAPI::propagateForcedReturn(cx, frame, rval);
+      PropagateForcedReturn(cx, frame, rval);
       return false;
 
     default:
       MOZ_CRASH("bad Debugger::onEnterFrame resume mode");
   }
 
   return true;
 }
@@ -1051,17 +1066,17 @@ bool DebugAPI::slowPathOnDebuggerStateme
 
   switch (resumeMode) {
     case ResumeMode::Continue:
       break;
     case ResumeMode::Terminate:
       return false;
 
     case ResumeMode::Return:
-      DebugAPI::propagateForcedReturn(cx, frame, rval);
+      PropagateForcedReturn(cx, frame, rval);
       return false;
 
     case ResumeMode::Throw:
       cx->setPendingExceptionAndCaptureStack(rval);
       return false;
 
     default:
       MOZ_CRASH("Invalid onDebuggerStatement resume mode");
@@ -1103,17 +1118,17 @@ bool DebugAPI::slowPathOnExceptionUnwind
       return false;
 
     case ResumeMode::Terminate:
       cx->clearPendingException();
       return false;
 
     case ResumeMode::Return:
       cx->clearPendingException();
-      DebugAPI::propagateForcedReturn(cx, frame, rval);
+      PropagateForcedReturn(cx, frame, rval);
       return false;
 
     default:
       MOZ_CRASH("Invalid onExceptionUnwind resume mode");
   }
 
   return true;
 }
@@ -2480,17 +2495,17 @@ bool DebugAPI::onTrap(JSContext* cx) {
         ResumeMode resumeMode = dbg->processHandlerResult(
             ar, ok, rv, iter.abstractFramePtr(), iter.pc(), &rval);
         adjqi.runJobs();
 
         if (resumeMode != ResumeMode::Continue) {
           savedExc.drop();
 
           if (resumeMode == ResumeMode::Return) {
-            DebugAPI::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
+            PropagateForcedReturn(cx, iter.abstractFramePtr(), rval);
           } else if (resumeMode == ResumeMode::Throw) {
             cx->setPendingExceptionAndCaptureStack(rval);
           } else {
             MOZ_ASSERT(resumeMode == ResumeMode::Terminate);
           }
           return false;
         }
 
@@ -2611,17 +2626,17 @@ bool DebugAPI::onSingleStep(JSContext* c
       resumeMode = dbg->processParsedHandlerResult(
           ar, iter.abstractFramePtr(), iter.pc(), success, resumeMode, &rval);
       adjqi.runJobs();
 
       if (resumeMode != ResumeMode::Continue) {
         savedExc.drop();
 
         if (resumeMode == ResumeMode::Return) {
-          DebugAPI::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
+          PropagateForcedReturn(cx, iter.abstractFramePtr(), rval);
         } else if (resumeMode == ResumeMode::Throw) {
           cx->setPendingExceptionAndCaptureStack(rval);
         } else {
           MOZ_ASSERT(resumeMode == ResumeMode::Terminate);
         }
         return false;
       }
     }
@@ -6499,32 +6514,16 @@ bool DebugAPI::handleIonBailout(JSContex
 void DebugAPI::handleUnrecoverableIonBailoutError(
     JSContext* cx, jit::RematerializedFrame* frame) {
   // Ion bailout can fail due to overrecursion. In such cases we cannot
   // honor any further Debugger hooks on the frame, and need to ensure that
   // its Debugger.Frame entry is cleaned up.
   Debugger::removeFromFrameMapsAndClearBreakpointsIn(cx, frame);
 }
 
-/* static */
-void DebugAPI::propagateForcedReturn(JSContext* cx, AbstractFramePtr frame,
-                                     HandleValue rval) {
-  // The Debugger's hooks may return a value that affects the completion
-  // value of the given frame. For example, a hook may return `{ return: 42 }`
-  // to terminate the frame and return `42` as the final frame result.
-  // To accomplish this, the debugger treats these return values as if
-  // execution of the JS function has been terminated without a pending
-  // exception, but with a special flag. When the error is handled by the
-  // interpreter or JIT, the special flag and the error state will be cleared
-  // and execution will continue from the end of the frame.
-  MOZ_ASSERT(!cx->isExceptionPending());
-  cx->setPropagatingForcedReturn();
-  frame.setReturnValue(rval);
-}
-
 /*** JS::dbg::Builder *******************************************************/
 
 Builder::Builder(JSContext* cx, js::Debugger* debugger)
     : debuggerObject(cx, debugger->toJSObject().get()), debugger(debugger) {}
 
 #if DEBUG
 void Builder::assertBuilt(JSObject* obj) {
   // We can't use assertSameCompartment here, because that is always keyed to