Bug 979730 part 1 - Remove frame iterator SavedOption. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 27 May 2016 17:57:14 +0200
changeset 338355 d2f18efe44a37ee8746041c3f4aaa59bfef217c8
parent 338354 a87537ed67915d13f1ecabf2e9723fa96e8d94e0
child 338356 d835e1ad42221c0d52aa434c8efdcc06d17813cd
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs979730
milestone49.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 979730 part 1 - Remove frame iterator SavedOption. r=luke
js/src/builtin/Eval.cpp
js/src/builtin/TestingFunctions.cpp
js/src/frontend/TokenStream.cpp
js/src/jit/Ion.cpp
js/src/jit/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/Runtime.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/TypeInference.cpp
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -433,17 +433,17 @@ js::IndirectEval(JSContext* cx, unsigned
     return EvalKernel(cx, args.get(0), INDIRECT_EVAL, NullFramePtr(), globalLexical, nullptr,
                       args.rval());
 }
 
 bool
 js::DirectEval(JSContext* cx, HandleValue v, MutableHandleValue vp)
 {
     // Direct eval can assume it was called from an interpreted or baseline frame.
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     AbstractFramePtr caller = iter.abstractFramePtr();
 
     MOZ_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL ||
                JSOp(*iter.pc()) == JSOP_STRICTEVAL ||
                JSOp(*iter.pc()) == JSOP_SPREADEVAL ||
                JSOp(*iter.pc()) == JSOP_STRICTSPREADEVAL);
     MOZ_ASSERT(caller.compartment() == caller.script()->compartment());
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1745,17 +1745,17 @@ ShellAllocationMetadataBuilder::build(JS
                            JS_STUBGETTER, JS_STUBSETTER))
     {
         oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
     }
 
     int stackIndex = 0;
     RootedId id(cx);
     RootedValue callee(cx);
-    for (NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED); !iter.done(); ++iter) {
+    for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) {
         if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) {
             id = INT_TO_JSID(stackIndex);
             RootedObject callee(cx, iter.callee(cx));
             if (!JS_DefinePropertyById(cx, stack, id, callee, 0,
                                        JS_STUBGETTER, JS_STUBSETTER))
             {
                 oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
             }
@@ -1856,17 +1856,17 @@ testingFunc_inIon(JSContext* cx, unsigne
         JSString* error = JS_NewStringCopyZ(cx, "Ion is disabled.");
         if (!error)
             return false;
 
         args.rval().setString(error);
         return true;
     }
 
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     if (iter.isIon()) {
         // Reset the counter of the IonScript's script.
         jit::JitFrameIterator jitIter(cx);
         ++jitIter;
         jitIter.script()->resetWarmUpResetCounter();
     } else {
         // Check if we missed multiple attempts at compiling the innermost script.
         JSScript* script = cx->currentScript();
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -631,17 +631,17 @@ TokenStream::reportCompileErrorNumberVA(
         err.report.lineno = srcCoords.lineNum(offset);
         err.report.column = srcCoords.columnIndex(offset);
     }
 
     // If we have no location information, try to get one from the caller.
     bool callerFilename = false;
     if (offset != NoOffset && !err.report.filename && cx->isJSContext()) {
         NonBuiltinFrameIter iter(cx->asJSContext(),
-                                 FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED,
+                                 FrameIter::ALL_CONTEXTS,
                                  FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
                                  cx->compartment()->principals());
         if (!iter.done() && iter.filename()) {
             callerFilename = true;
             err.report.filename = iter.filename();
             err.report.lineno = iter.computeLine(&err.report.column);
         }
     }
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2855,17 +2855,17 @@ jit::SetEnterJitData(JSContext* cx, Ente
         if (state.script()->isForEval() && state.script()->isDirectEvalInFunction()) {
             // Push newTarget onto the stack.
             if (!vals.reserve(1))
                 return false;
 
             data.maxArgc = 1;
             data.maxArgv = vals.begin();
             if (state.asExecute()->newTarget().isNull()) {
-                ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+                ScriptFrameIter iter(cx);
                 vals.infallibleAppend(iter.newTarget());
             } else {
                 vals.infallibleAppend(state.asExecute()->newTarget());
             }
         }
     }
 
     return true;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1265,17 +1265,17 @@ void
 MarkObjectGroupFromIon(JSRuntime* rt, ObjectGroup** groupp)
 {
     TraceManuallyBarrieredEdge(&rt->gc.marker, groupp, "write barrier");
 }
 
 bool
 ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber)
 {
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     RootedScript script(cx, iter.script());
     ReportRuntimeLexicalError(cx, errorNumber, script, iter.pc());
     return false;
 }
 
 bool
 ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6500,17 +6500,17 @@ JS_PUBLIC_API(JSObject*)
 GetScriptedCallerGlobal(JSContext* cx)
 {
     Activation* activation;
 
     if (GetScriptedCallerActivationFast(cx, &activation)) {
         if (!activation)
             return nullptr;
     } else {
-        NonBuiltinFrameIter i(cx, FrameIter::GO_THROUGH_SAVED);
+        NonBuiltinFrameIter i(cx);
         if (i.done())
             return nullptr;
         activation = i.activation();
     }
 
     // If the caller is hidden, the embedding wants us to return null here so
     // that it can check its own stack (see HideScriptedCaller).
     if (activation->scriptedCallerIsHidden())
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -398,17 +398,17 @@ JS_FRIEND_API(bool)
 js::RunningWithTrustedPrincipals(JSContext* cx)
 {
     return cx->runningWithTrustedPrincipals();
 }
 
 JS_FRIEND_API(JSFunction*)
 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx)
 {
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
 
     // Skip eval frames.
     while (!iter.done() && iter.isEvalFrame())
         ++iter;
 
     if (iter.done())
         return nullptr;
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -159,17 +159,17 @@ ArgumentsGetterImpl(JSContext* cx, const
 {
     MOZ_ASSERT(IsFunction(args.thisv()));
 
     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     if (!ArgumentsRestrictions(cx, fun))
         return false;
 
     // Return null if this function wasn't found on the stack.
-    NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    NonBuiltinScriptFrameIter iter(cx);
     if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
         args.rval().setNull();
         return true;
     }
 
     Rooted<ArgumentsObject*> argsobj(cx, ArgumentsObject::createUnexpected(cx, iter));
     if (!argsobj)
         return false;
@@ -250,17 +250,17 @@ CallerGetterImpl(JSContext* cx, const Ca
     // assume it'll never be invoked on natives, strict mode functions, bound
     // functions, or anything else that ordinarily has immutable .caller
     // defined with [[ThrowTypeError]].
     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     if (!CallerRestrictions(cx, fun))
         return false;
 
     // Also return null if this function wasn't found on the stack.
-    NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    NonBuiltinScriptFrameIter iter(cx);
     if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
         args.rval().setNull();
         return true;
     }
 
     ++iter;
     while (!iter.done() && iter.isEvalFrame())
         ++iter;
@@ -321,17 +321,17 @@ CallerSetterImpl(JSContext* cx, const Ca
     // Return |undefined| unless an error must be thrown.
     args.rval().setUndefined();
 
     // We can almost just return |undefined| here -- but if the caller function
     // was strict mode code, we still have to throw a TypeError.  This requires
     // computing the caller, checking that no security boundaries are crossed,
     // and throwing a TypeError if the resulting caller is strict.
 
-    NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    NonBuiltinScriptFrameIter iter(cx);
     if (!AdvanceToActiveCallLinear(cx, iter, fun))
         return true;
 
     ++iter;
     while (!iter.done() && iter.isEvalFrame())
         ++iter;
 
     if (iter.done() || !iter.isFunctionFrame())
@@ -1216,17 +1216,17 @@ js::fun_apply(JSContext* cx, unsigned ar
     InvokeArgs args2(cx);
 
     // A JS_OPTIMIZED_ARGUMENTS magic value means that 'arguments' flows into
     // this apply call from a scripted caller and, as an optimization, we've
     // avoided creating it since apply can simply pull the argument values from
     // the calling frame (which we must do now).
     if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         // Step 3-6.
-        ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+        ScriptFrameIter iter(cx);
         MOZ_ASSERT(iter.numActualArgs() <= ARGS_LENGTH_MAX);
         if (!args2.init(iter.numActualArgs()))
             return false;
 
         // Steps 7-8.
         iter.unaliasedForEachActual(cx, CopyTo(args2.array()));
     } else {
         // Step 3.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3553,17 +3553,17 @@ MaybeDumpValue(const char* name, const V
         fputc('\n', stderr);
     }
 }
 
 JS_FRIEND_API(void)
 js::DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start)
 {
     /* This should only called during live debugging. */
-    ScriptFrameIter i(cx, ScriptFrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter i(cx);
     if (!start) {
         if (i.done()) {
             fprintf(stderr, "no stack for cx = %p\n", (void*) cx);
             return;
         }
     } else {
         while (!i.done() && !i.isJit() && i.interpFrame() != start)
             ++i;
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -714,17 +714,17 @@ js::Disassemble(JSContext* cx, HandleScr
 
 JS_FRIEND_API(bool)
 js::DumpPC(JSContext* cx)
 {
     gc::AutoSuppressGC suppressGC(cx);
     Sprinter sprinter(cx);
     if (!sprinter.init())
         return false;
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     if (iter.done()) {
         fprintf(stdout, "Empty stack.\n");
         return true;
     }
     RootedScript script(cx, iter.script());
     bool ok = DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
     fprintf(stdout, "%s", sprinter.string());
     return ok;
@@ -1410,17 +1410,17 @@ DecompileExpressionFromStack(JSContext* 
     /*
      * Give up if we need deterministic behavior for differential testing.
      * IonMonkey doesn't use InterpreterFrames and this ensures we get the same
      * error messages.
      */
     return true;
 #endif
 
-    FrameIter frameIter(cx, FrameIter::GO_THROUGH_SAVED);
+    FrameIter frameIter(cx);
 
     if (frameIter.done() || !frameIter.hasScript() || frameIter.compartment() != cx->compartment())
         return true;
 
     RootedScript script(cx, frameIter.script());
     jsbytecode* valuepc = frameIter.pc();
 
     MOZ_ASSERT(script->containsPC(valuepc));
@@ -1480,17 +1480,17 @@ DecompileArgumentFromStack(JSContext* cx
     /* See note in DecompileExpressionFromStack. */
     return true;
 #endif
 
     /*
      * Settle on the nearest script frame, which should be the builtin that
      * called the intrinsic.
      */
-    FrameIter frameIter(cx, FrameIter::GO_THROUGH_SAVED);
+    FrameIter frameIter(cx);
     MOZ_ASSERT(!frameIter.done());
     MOZ_ASSERT(frameIter.script()->selfHosted());
 
     /*
      * Get the second-to-top frame, the caller of the builtin that called the
      * intrinsic.
      */
     ++frameIter;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2043,17 +2043,17 @@ ValueToScript(JSContext* cx, Value vArg,
         *funp = fun;
 
     return script;
 }
 
 static JSScript*
 GetTopScript(JSContext* cx)
 {
-    NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    NonBuiltinScriptFrameIter iter(cx);
     return iter.done() ? nullptr : iter.script();
 }
 
 static bool
 GetScriptAndPCArgs(JSContext* cx, unsigned argc, Value* argv, MutableHandleScript scriptp,
                    int32_t* ip)
 {
     RootedScript script(cx, GetTopScript(cx));
@@ -4290,17 +4290,17 @@ DecompileFunction(JSContext* cx, unsigne
     return true;
 }
 
 static bool
 DecompileThisScript(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    NonBuiltinScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    NonBuiltinScriptFrameIter iter(cx);
     if (iter.done()) {
         args.rval().setString(cx->runtime()->emptyString);
         return true;
     }
 
     {
         JSAutoCompartment ac(cx, iter.script());
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1476,17 +1476,17 @@ Debugger::fireDebuggerStatement(JSContex
 {
     RootedObject hook(cx, getHook(OnDebuggerStatement));
     MOZ_ASSERT(hook);
     MOZ_ASSERT(hook->isCallable());
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     RootedValue scriptFrame(cx);
     if (!getScriptFrame(cx, iter, &scriptFrame))
         return handleUncaughtException(ac, false);
 
     RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
     bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
     return parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
@@ -1505,17 +1505,17 @@ Debugger::fireExceptionUnwind(JSContext*
     cx->clearPendingException();
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
     RootedValue scriptFrame(cx);
     RootedValue wrappedExc(cx, exc);
 
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     if (!getScriptFrame(cx, iter, &scriptFrame) || !wrapDebuggeeValue(cx, &wrappedExc))
         return handleUncaughtException(ac, false);
 
     RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
     bool ok = js::Call(cx, fval, object, scriptFrame, wrappedExc, &rv);
     JSTrapStatus st = parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
     if (st == JSTRAP_CONTINUE)
@@ -1677,17 +1677,17 @@ Debugger::slowPathOnNewWasmModule(JSCont
     }
 
     MOZ_ASSERT(status == JSTRAP_CONTINUE);
 }
 
 /* static */ JSTrapStatus
 Debugger::onTrap(JSContext* cx, MutableHandleValue vp)
 {
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     RootedScript script(cx, iter.script());
     MOZ_ASSERT(script->isDebuggee());
     Rooted<GlobalObject*> scriptGlobal(cx, &script->global());
     jsbytecode* pc = iter.pc();
     BreakpointSite* site = script->getBreakpointSite(pc);
     JSOp op = JSOp(*pc);
 
     /* Build list of breakpoint handlers. */
@@ -1741,17 +1741,17 @@ Debugger::onTrap(JSContext* cx, MutableH
     /* By convention, return the true op to the interpreter in vp. */
     vp.setInt32(op);
     return JSTRAP_CONTINUE;
 }
 
 /* static */ JSTrapStatus
 Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
 {
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
 
     /*
      * We may be stepping over a JSOP_EXCEPTION, that pushes the context's
      * pending exception for a 'catch' clause to handle. Don't let the
      * onStep handlers mess with that (other than by returning a resumption
      * value).
      */
     RootedValue exception(cx, UndefinedValue());
@@ -2204,18 +2204,17 @@ Debugger::updateExecutionObservabilityOf
         jit::JitContext jctx(cx, nullptr);
         if (!jit::RecompileOnStackBaselineScriptsForDebugMode(cx, obs, observing)) {
             ReportOutOfMemory(cx);
             return false;
         }
     }
 
     AbstractFramePtr oldestEnabledFrame;
-    for (ScriptFrameIter iter(cx, ScriptFrameIter::ALL_CONTEXTS,
-                              ScriptFrameIter::GO_THROUGH_SAVED);
+    for (ScriptFrameIter iter(cx, ScriptFrameIter::ALL_CONTEXTS);
          !iter.done();
          ++iter)
     {
         if (obs.shouldMarkAsDebuggee(iter)) {
             if (observing) {
                 if (!iter.abstractFramePtr().isDebuggee()) {
                     oldestEnabledFrame = iter.abstractFramePtr();
                     oldestEnabledFrame.setIsDebuggee();
@@ -2511,18 +2510,17 @@ Debugger::updateObservesCoverageOnDebugg
         // dangling pointers to freed PCCounts.
         if (!obs.add(comp))
             return false;
     }
 
     // If any frame on the stack belongs to the debuggee, then we cannot update
     // the ScriptCounts, because this would imply to invalidate a Debugger.Frame
     // to recompile it with/without ScriptCount support.
-    for (ScriptFrameIter iter(cx, ScriptFrameIter::ALL_CONTEXTS,
-                              ScriptFrameIter::GO_THROUGH_SAVED);
+    for (ScriptFrameIter iter(cx, ScriptFrameIter::ALL_CONTEXTS);
          !iter.done();
          ++iter)
     {
         if (obs.shouldMarkAsDebuggee(iter)) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
             return false;
         }
     }
@@ -3486,17 +3484,17 @@ Debugger::getNewestFrame(JSContext* cx, 
     /* Since there may be multiple contexts, use AllFramesIter. */
     for (AllFramesIter i(cx); !i.done(); ++i) {
         if (dbg->observesFrame(i)) {
             // Ensure that Ion frames are rematerialized. Only rematerialized
             // Ion frames may be used as AbstractFramePtrs.
             if (i.isIon() && !i.ensureHasRematerializedFrame(cx))
                 return false;
             AbstractFramePtr frame = i.abstractFramePtr();
-            ScriptFrameIter iter(i.activation()->cx(), ScriptFrameIter::GO_THROUGH_SAVED);
+            ScriptFrameIter iter(i.activation()->cx());
             while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != frame)
                 ++iter;
             return dbg->getScriptFrame(cx, iter, args.rval());
         }
     }
     args.rval().setNull();
     return true;
 }
@@ -6032,33 +6030,33 @@ Debugger::removeFromFrameMapsAndClearBre
         RootedScript script(cx, frame.script());
         script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), nullptr, nullptr);
     }
 }
 
 /* static */ bool
 Debugger::handleBaselineOsr(JSContext* cx, InterpreterFrame* from, jit::BaselineFrame* to)
 {
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     MOZ_ASSERT(iter.abstractFramePtr() == to);
     return replaceFrameGuts(cx, from, to, iter);
 }
 
 /* static */ bool
 Debugger::handleIonBailout(JSContext* cx, jit::RematerializedFrame* from, jit::BaselineFrame* to)
 {
     // When we return to a bailed-out Ion real frame, we must update all
     // Debugger.Frames that refer to its inline frames. However, since we
     // can't pop individual inline frames off the stack (we can only pop the
     // real frame that contains them all, as a unit), we cannot assume that
     // the frame we're dealing with is the top frame. Advance the iterator
     // across any inlined frames younger than |to|, the baseline frame
     // reconstructed during bailout from the Ion frame corresponding to
     // |from|.
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     while (iter.abstractFramePtr() != to)
         ++iter;
     return replaceFrameGuts(cx, from, to, iter);
 }
 
 /* static */ void
 Debugger::handleUnrecoverableIonBailoutError(JSContext* cx, jit::RematerializedFrame* frame)
 {
@@ -7007,17 +7005,16 @@ CheckThisFrame(JSContext* cx, const Call
     THIS_FRAME_THISOBJ(cx, argc, vp, fnname, args, thisobj);                   \
     Maybe<ScriptFrameIter> maybeIter;                                          \
     {                                                                          \
         AbstractFramePtr f = AbstractFramePtr::FromRaw(thisobj->getPrivate()); \
         if (f.isScriptFrameIterData()) {                                       \
             maybeIter.emplace(*(ScriptFrameIter::Data*)(f.raw()));             \
         } else {                                                               \
             maybeIter.emplace(cx, ScriptFrameIter::ALL_CONTEXTS,               \
-                              ScriptFrameIter::GO_THROUGH_SAVED,               \
                               ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK); \
             ScriptFrameIter& iter = *maybeIter;                                \
             while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != f) \
                 ++iter;                                                        \
             AbstractFramePtr data = iter.copyDataAsAbstractFramePtr();         \
             if (!data)                                                         \
                 return false;                                                  \
             thisobj->setPrivate(data.raw());                                   \
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -586,17 +586,17 @@ InvokeInterruptCallback(JSContext* cx)
     JSInterruptCallback cb = cx->runtime()->interruptCallback;
     if (!cb)
         return true;
 
     if (cb(cx)) {
         // Debugger treats invoking the interrupt callback as a "step", so
         // invoke the onStep handler.
         if (cx->compartment()->isDebuggee()) {
-            ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+            ScriptFrameIter iter(cx);
             if (!iter.done() &&
                 cx->compartment() == iter.compartment() &&
                 iter.script()->stepModeEnabled())
             {
                 RootedValue rval(cx);
                 switch (Debugger::onSingleStep(cx, &rval)) {
                   case JSTRAP_ERROR:
                     return false;
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1078,17 +1078,17 @@ SavedStacks::saveCurrentStack(JSContext*
         !cx->global() ||
         !cx->global()->isStandardClassResolved(JSProto_Object))
     {
         frame.set(nullptr);
         return true;
     }
 
     AutoSPSEntry psuedoFrame(cx->runtime(), "js::SavedStacks::saveCurrentStack");
-    FrameIter iter(cx, FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED);
+    FrameIter iter(cx, FrameIter::ALL_CONTEXTS);
     return insertFrames(cx, iter, frame, maxFrameCount);
 }
 
 bool
 SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
                             MutableHandleSavedFrame adoptedStack, unsigned maxFrameCount)
 {
     MOZ_ASSERT(initialized());
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -801,17 +801,17 @@ intrinsic_NewListIterator(JSContext* cx,
 }
 
 static bool
 intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     MOZ_ASSERT(iter.isFunctionFrame());
     args.rval().setObject(*iter.callee(cx));
     return true;
 }
 
 static bool
 intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -1756,17 +1756,17 @@ js::ReportIncompatibleSelfHostedMethod(J
     // which would be reported as the called function instead.
 
     // Lookup the selfhosted method that was invoked.  But skip over
     // IsTypedArrayEnsuringArrayBuffer frames, because those are never the
     // actual self-hosted callee from external code.  We can't just skip
     // self-hosted things until we find a non-self-hosted one because of cases
     // like array.sort(somethingSelfHosted), where we want to report the error
     // in the somethingSelfHosted, not in the sort() call.
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     MOZ_ASSERT(iter.isFunctionFrame());
 
     while (!iter.done()) {
         MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic() &&
                    !iter.callee(cx)->isBoundFunction());
         JSAutoByteString funNameBytes;
         const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
         if (!funName)
@@ -1943,17 +1943,17 @@ intrinsic_ConstructFunction(JSContext* c
 
 
 static bool
 intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
-    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+    ScriptFrameIter iter(cx);
     bool isConstructing = iter.isConstructing();
     args.rval().setBoolean(isConstructing);
     return true;
 }
 
 static bool
 intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -42,17 +42,17 @@ InterpreterFrame::initExecuteFrame(JSCon
     // newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
     // It should never be passed from Ion code.
     RootedValue newTarget(cx, newTargetValue);
     if (script->isDirectEvalInFunction()) {
         if (evalInFramePrev) {
             if (newTarget.isNull() && evalInFramePrev.script()->functionOrCallerFunction())
                 newTarget = evalInFramePrev.newTarget();
         } else {
-            FrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
+            FrameIter iter(cx);
             MOZ_ASSERT(!iter.isWasm());
             if (newTarget.isNull() && iter.script()->functionOrCallerFunction())
                 newTarget = iter.newTarget();
         }
     }
 
     Value* dstvp = (Value*)this - 1;
     dstvp[0] = newTarget;
@@ -512,23 +512,16 @@ FrameIter::settleOnActivation()
     while (true) {
         if (data_.activations_.done()) {
             data_.state_ = DONE;
             return;
         }
 
         Activation* activation = data_.activations_.activation();
 
-        // If JS_SaveFrameChain was called, stop iterating here (unless
-        // GO_THROUGH_SAVED is set).
-        if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) {
-            data_.state_ = DONE;
-            return;
-        }
-
         // Skip activations from another context if needed.
         MOZ_ASSERT(activation->cx());
         MOZ_ASSERT(data_.cx_);
         if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) {
             ++data_.activations_;
             continue;
         }
 
@@ -592,72 +585,69 @@ FrameIter::settleOnActivation()
 
         MOZ_ASSERT(!data_.interpFrames_.frame()->runningInJit());
         data_.pc_ = data_.interpFrames_.pc();
         data_.state_ = INTERP;
         return;
     }
 }
 
-FrameIter::Data::Data(JSContext* cx, SavedOption savedOption,
-                      ContextOption contextOption, DebuggerEvalOption debuggerEvalOption,
-                      JSPrincipals* principals)
+FrameIter::Data::Data(JSContext* cx, ContextOption contextOption,
+                      DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals)
   : cx_(cx),
-    savedOption_(savedOption),
     contextOption_(contextOption),
     debuggerEvalOption_(debuggerEvalOption),
     principals_(principals),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->runtime()),
     jitFrames_(),
     ionInlineFrameNo_(0),
     wasmFrames_()
 {
 }
 
 FrameIter::Data::Data(const FrameIter::Data& other)
   : cx_(other.cx_),
-    savedOption_(other.savedOption_),
     contextOption_(other.contextOption_),
     debuggerEvalOption_(other.debuggerEvalOption_),
     principals_(other.principals_),
     state_(other.state_),
     pc_(other.pc_),
     interpFrames_(other.interpFrames_),
     activations_(other.activations_),
     jitFrames_(other.jitFrames_),
     ionInlineFrameNo_(other.ionInlineFrameNo_),
     wasmFrames_(other.wasmFrames_)
 {
 }
 
-FrameIter::FrameIter(JSContext* cx, SavedOption savedOption)
-  : data_(cx, savedOption, CURRENT_CONTEXT, FOLLOW_DEBUGGER_EVAL_PREV_LINK, nullptr),
+FrameIter::FrameIter(JSContext* cx)
+  : data_(cx, CURRENT_CONTEXT, FOLLOW_DEBUGGER_EVAL_PREV_LINK, nullptr),
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     // settleOnActivation can only GC if principals are given.
     JS::AutoSuppressGCAnalysis nogc;
     settleOnActivation();
 }
 
 FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
-                     SavedOption savedOption, DebuggerEvalOption debuggerEvalOption)
-  : data_(cx, savedOption, contextOption, debuggerEvalOption, nullptr),
+                     DebuggerEvalOption debuggerEvalOption)
+  : data_(cx, contextOption, debuggerEvalOption, nullptr),
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     // settleOnActivation can only GC if principals are given.
     JS::AutoSuppressGCAnalysis nogc;
     settleOnActivation();
 }
 
 FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
-                     SavedOption savedOption, DebuggerEvalOption debuggerEvalOption,
+                     DebuggerEvalOption debuggerEvalOption,
                      JSPrincipals* principals)
-  : data_(cx, savedOption, contextOption, debuggerEvalOption, principals),
+  : data_(cx, contextOption, debuggerEvalOption, principals),
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     settleOnActivation();
 }
 
 FrameIter::FrameIter(const FrameIter& other)
   : data_(other.data_),
     ionInlineFrames_(other.data_.cx_,
@@ -730,34 +720,30 @@ FrameIter::operator++()
         MOZ_CRASH("Unexpected state");
       case INTERP:
         if (interpFrame()->isDebuggerEvalFrame() &&
             interpFrame()->evalInFramePrev() &&
             data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK)
         {
             AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
 
-            // Eval-in-frame can cross contexts and works across saved frame
-            // chains.
+            // Eval-in-frame can cross contexts.
             ContextOption prevContextOption = data_.contextOption_;
-            SavedOption prevSavedOption = data_.savedOption_;
             data_.contextOption_ = ALL_CONTEXTS;
-            data_.savedOption_ = GO_THROUGH_SAVED;
 
             popInterpreterFrame();
 
             while (!hasUsableAbstractFramePtr() || abstractFramePtr() != eifPrev) {
                 if (data_.state_ == JIT)
                     popJitFrame();
                 else
                     popInterpreterFrame();
             }
 
             data_.contextOption_ = prevContextOption;
-            data_.savedOption_ = prevSavedOption;
             data_.cx_ = data_.activations_->cx();
             break;
         }
         popInterpreterFrame();
         break;
       case JIT:
         popJitFrame();
         break;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1207,19 +1207,17 @@ class Activation
 {
   protected:
     JSContext* cx_;
     JSCompartment* compartment_;
     Activation* prev_;
     Activation* prevProfiling_;
 
     // Counter incremented by JS_SaveFrameChain on the top-most activation and
-    // decremented by JS_RestoreFrameChain. If > 0, ScriptFrameIter should stop
-    // iterating when it reaches this activation (if GO_THROUGH_SAVED is not
-    // set).
+    // decremented by JS_RestoreFrameChain.
     size_t savedFrameChain_;
 
     // Counter incremented by JS::HideScriptedCaller and decremented by
     // JS::UnhideScriptedCaller. If > 0 for the top activation,
     // DescribeScriptedCaller will return null instead of querying that
     // activation, which should prompt the caller to consult embedding-specific
     // data structures instead.
     size_t hideScriptedCallerCount_;
@@ -1717,19 +1715,16 @@ class WasmActivation : public Activation
     void* resumePC() const { return resumePC_; }
 };
 
 // A FrameIter walks over the runtime's stack of JS script activations,
 // abstracting over whether the JS scripts were running in the interpreter or
 // different modes of compiled code.
 //
 // FrameIter is parameterized by what it includes in the stack iteration:
-//  - The SavedOption controls whether FrameIter stops when it finds an
-//    activation that was set aside via JS_SaveFrameChain (and not yet restored
-//    by JS_RestoreFrameChain). (Hopefully this will go away.)
 //  - The ContextOption determines whether the iteration will view frames from
 //    all JSContexts or just the given JSContext. (Hopefully this will go away.)
 //  - When provided, the optional JSPrincipal argument will cause FrameIter to
 //    only show frames in globals whose JSPrincipals are subsumed (via
 //    JSSecurityCallbacks::subsume) by the given JSPrincipal.
 //
 // Additionally, there are derived FrameIter types that automatically skip
 // certain frames:
@@ -1737,52 +1732,50 @@ class WasmActivation : public Activation
 //    (currently everything other than asm.js stack frames). When !hasScript(),
 //    clients must stick to the portion of the
 //    interface marked below.
 //  - NonBuiltinScriptFrameIter additionally filters out builtin (self-hosted)
 //    scripts.
 class FrameIter
 {
   public:
-    enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
     enum ContextOption { CURRENT_CONTEXT, ALL_CONTEXTS };
     enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
                               IGNORE_DEBUGGER_EVAL_PREV_LINK };
     enum State { DONE, INTERP, JIT, WASM };
 
     // Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
     // the heap, so this structure should not contain any GC things.
     struct Data
     {
         JSContext * cx_;
-        SavedOption         savedOption_;
         ContextOption       contextOption_;
         DebuggerEvalOption  debuggerEvalOption_;
         JSPrincipals *      principals_;
 
         State               state_;
 
         jsbytecode *        pc_;
 
         InterpreterFrameIterator interpFrames_;
         ActivationIterator activations_;
 
         jit::JitFrameIterator jitFrames_;
         unsigned ionInlineFrameNo_;
         wasm::FrameIterator wasmFrames_;
 
-        Data(JSContext* cx, SavedOption savedOption, ContextOption contextOption,
+        Data(JSContext* cx, ContextOption contextOption,
              DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
         Data(const Data& other);
     };
 
-    FrameIter(JSContext* cx, SavedOption);
-    FrameIter(JSContext* cx, ContextOption, SavedOption,
+    explicit FrameIter(JSContext* cx);
+    FrameIter(JSContext* cx, ContextOption,
               DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
-    FrameIter(JSContext* cx, ContextOption, SavedOption, DebuggerEvalOption, JSPrincipals*);
+    FrameIter(JSContext* cx, ContextOption, DebuggerEvalOption, JSPrincipals*);
     FrameIter(const FrameIter& iter);
     MOZ_IMPLICIT FrameIter(const Data& data);
     MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
 
     bool done() const { return data_.state_ == DONE; }
 
     // -------------------------------------------------------
     // The following functions can only be called when !done()
@@ -1910,37 +1903,35 @@ class FrameIter
 class ScriptFrameIter : public FrameIter
 {
     void settle() {
         while (!done() && !hasScript())
             FrameIter::operator++();
     }
 
   public:
-    ScriptFrameIter(JSContext* cx, SavedOption savedOption)
-      : FrameIter(cx, savedOption)
+    explicit ScriptFrameIter(JSContext* cx)
+      : FrameIter(cx)
     {
         settle();
     }
 
     ScriptFrameIter(JSContext* cx,
                     ContextOption cxOption,
-                    SavedOption savedOption,
                     DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
-      : FrameIter(cx, cxOption, savedOption, debuggerEvalOption)
+      : FrameIter(cx, cxOption, debuggerEvalOption)
     {
         settle();
     }
 
     ScriptFrameIter(JSContext* cx,
                     ContextOption cxOption,
-                    SavedOption savedOption,
                     DebuggerEvalOption debuggerEvalOption,
                     JSPrincipals* prin)
-      : FrameIter(cx, cxOption, savedOption, debuggerEvalOption, prin)
+      : FrameIter(cx, cxOption, debuggerEvalOption, prin)
     {
         settle();
     }
 
     ScriptFrameIter(const ScriptFrameIter& iter) : FrameIter(iter) { settle(); }
     explicit ScriptFrameIter(const FrameIter::Data& data) : FrameIter(data) { settle(); }
     explicit ScriptFrameIter(AbstractFramePtr frame) : FrameIter(frame) { settle(); }
 
@@ -1962,45 +1953,43 @@ SelfHostedFramesVisible()
 #endif
 
 /* A filtering of the FrameIter to only stop at non-self-hosted scripts. */
 class NonBuiltinFrameIter : public FrameIter
 {
     void settle();
 
   public:
-    NonBuiltinFrameIter(JSContext* cx, FrameIter::SavedOption opt)
-      : FrameIter(cx, opt)
+    explicit NonBuiltinFrameIter(JSContext* cx)
+      : FrameIter(cx)
     {
         settle();
     }
 
     NonBuiltinFrameIter(JSContext* cx,
                         FrameIter::ContextOption contextOption,
-                        FrameIter::SavedOption savedOption,
                         FrameIter::DebuggerEvalOption debuggerEvalOption =
                         FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
-      : FrameIter(cx, contextOption, savedOption, debuggerEvalOption)
+      : FrameIter(cx, contextOption, debuggerEvalOption)
     {
         settle();
     }
 
     NonBuiltinFrameIter(JSContext* cx,
                         FrameIter::ContextOption contextOption,
-                        FrameIter::SavedOption savedOption,
                         FrameIter::DebuggerEvalOption debuggerEvalOption,
                         JSPrincipals* principals)
-      : FrameIter(cx, contextOption, savedOption, debuggerEvalOption, principals)
+      : FrameIter(cx, contextOption, debuggerEvalOption, principals)
     {
         settle();
     }
 
     NonBuiltinFrameIter(JSContext* cx, JSPrincipals* principals)
-        : FrameIter(cx, FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED,
-                    FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK, principals)
+        : FrameIter(cx, FrameIter::ALL_CONTEXTS, FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
+                    principals)
     {
         settle();
     }
 
     explicit NonBuiltinFrameIter(const FrameIter::Data& data)
       : FrameIter(data)
     {}
 
@@ -2012,39 +2001,36 @@ class NonBuiltinFrameIter : public Frame
 };
 
 /* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */
 class NonBuiltinScriptFrameIter : public ScriptFrameIter
 {
     void settle();
 
   public:
-    explicit NonBuiltinScriptFrameIter(JSContext* cx,
-                                       ScriptFrameIter::SavedOption opt)
-      : ScriptFrameIter(cx, opt)
+    explicit NonBuiltinScriptFrameIter(JSContext* cx)
+      : ScriptFrameIter(cx)
     {
         settle();
     }
 
     NonBuiltinScriptFrameIter(JSContext* cx,
                               ScriptFrameIter::ContextOption contextOption,
-                              ScriptFrameIter::SavedOption savedOption,
                               ScriptFrameIter::DebuggerEvalOption debuggerEvalOption =
                               ScriptFrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
-      : ScriptFrameIter(cx, contextOption, savedOption, debuggerEvalOption)
+      : ScriptFrameIter(cx, contextOption, debuggerEvalOption)
     {
         settle();
     }
 
     NonBuiltinScriptFrameIter(JSContext* cx,
                               ScriptFrameIter::ContextOption contextOption,
-                              ScriptFrameIter::SavedOption savedOption,
                               ScriptFrameIter::DebuggerEvalOption debuggerEvalOption,
                               JSPrincipals* principals)
-      : ScriptFrameIter(cx, contextOption, savedOption, debuggerEvalOption, principals)
+      : ScriptFrameIter(cx, contextOption, debuggerEvalOption, principals)
     {
         settle();
     }
 
     explicit NonBuiltinScriptFrameIter(const ScriptFrameIter::Data& data)
       : ScriptFrameIter(data)
     {}
 
@@ -2058,17 +2044,17 @@ class NonBuiltinScriptFrameIter : public
 /*
  * Blindly iterate over all frames in the current thread's stack. These frames
  * can be from different contexts and compartments, so beware.
  */
 class AllFramesIter : public ScriptFrameIter
 {
   public:
     explicit AllFramesIter(JSContext* cx)
-      : ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS, ScriptFrameIter::GO_THROUGH_SAVED,
+      : ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS,
                         ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
     {}
 };
 
 /* Popular inline definitions. */
 
 inline JSScript*
 FrameIter::script() const
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3883,17 +3883,17 @@ TypeNewScript::rollbackPartiallyInitiali
 
     if (!initializerList)
         return false;
 
     bool found = false;
 
     RootedFunction function(cx, this->function());
     Vector<uint32_t, 32> pcOffsets(cx);
-    for (ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED); !iter.done(); ++iter) {
+    for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
         {
             AutoEnterOOMUnsafeRegion oomUnsafe;
             if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
                 oomUnsafe.crash("rollbackPartiallyInitializedObjects");
         }
 
         if (!iter.isConstructing() || !iter.matchCallee(cx, function))
             continue;