LCOV - code coverage report
Current view: top level - js/src/vm - Stack.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 268 998 26.9 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "vm/Stack-inl.h"
       8             : 
       9             : #include <utility>
      10             : 
      11             : #include "gc/Marking.h"
      12             : #include "jit/BaselineFrame.h"
      13             : #include "jit/JitcodeMap.h"
      14             : #include "jit/JitRealm.h"
      15             : #include "vm/Debugger.h"
      16             : #include "vm/JSContext.h"
      17             : #include "vm/Opcodes.h"
      18             : 
      19             : #include "jit/JSJitFrameIter-inl.h"
      20             : #include "vm/Compartment-inl.h"
      21             : #include "vm/EnvironmentObject-inl.h"
      22             : #include "vm/Interpreter-inl.h"
      23             : #include "vm/Probes-inl.h"
      24             : 
      25             : using namespace js;
      26             : 
      27             : using mozilla::ArrayLength;
      28             : using mozilla::DebugOnly;
      29             : using mozilla::Maybe;
      30             : 
      31             : /*****************************************************************************/
      32             : 
      33             : void
      34         425 : InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script,
      35             :                                    AbstractFramePtr evalInFramePrev,
      36             :                                    const Value& newTargetValue, HandleObject envChain)
      37             : {
      38         425 :     flags_ = 0;
      39         425 :     script_ = script;
      40             : 
      41             :     // newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
      42             :     // It should never be passed from Ion code.
      43           0 :     RootedValue newTarget(cx, newTargetValue);
      44           0 :     if (script->isDirectEvalInFunction()) {
      45           0 :         FrameIter iter(cx);
      46          60 :         if (newTarget.isNull() &&
      47           0 :             iter.hasScript() &&
      48          60 :             iter.script()->bodyScope()->hasOnChain(ScopeKind::Function))
      49             :         {
      50           0 :             newTarget = iter.newTarget();
      51             :         }
      52           0 :     } else if (evalInFramePrev) {
      53           0 :         if (newTarget.isNull() &&
      54           0 :             evalInFramePrev.hasScript() &&
      55           0 :             evalInFramePrev.script()->bodyScope()->hasOnChain(ScopeKind::Function))
      56             :         {
      57           0 :             newTarget = evalInFramePrev.newTarget();
      58             :         }
      59             :     }
      60             : 
      61           0 :     Value* dstvp = (Value*)this - 1;
      62           0 :     dstvp[0] = newTarget;
      63             : 
      64           0 :     envChain_ = envChain.get();
      65         425 :     prev_ = nullptr;
      66           0 :     prevpc_ = nullptr;
      67           0 :     prevsp_ = nullptr;
      68             : 
      69           0 :     evalInFramePrev_ = evalInFramePrev;
      70           0 :     MOZ_ASSERT_IF(evalInFramePrev, isDebuggerEvalFrame());
      71             : 
      72         850 :     if (script->isDebuggee())
      73           0 :         setIsDebuggee();
      74             : 
      75             : #ifdef DEBUG
      76         850 :     Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
      77             : #endif
      78           1 : }
      79             : 
      80             : bool
      81           0 : InterpreterFrame::isNonGlobalEvalFrame() const
      82             : {
      83           0 :     return isEvalFrame() && script()->bodyScope()->as<EvalScope>().isNonGlobal();
      84             : }
      85             : 
      86             : ArrayObject*
      87           0 : InterpreterFrame::createRestParameter(JSContext* cx)
      88             : {
      89           0 :     MOZ_ASSERT(script()->hasRest());
      90           0 :     unsigned nformal = callee().nargs() - 1, nactual = numActualArgs();
      91           0 :     unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
      92         387 :     Value* restvp = argv() + nformal;
      93         387 :     return ObjectGroup::newArrayObject(cx, restvp, nrest, GenericObject,
      94         387 :                                        ObjectGroup::NewArrayKind::UnknownIndex);
      95             : }
      96             : 
      97             : static inline void
      98           0 : AssertScopeMatchesEnvironment(Scope* scope, JSObject* originalEnv)
      99             : {
     100             : #ifdef DEBUG
     101           0 :     JSObject* env = originalEnv;
     102           0 :     for (ScopeIter si(scope); si; si++) {
     103           0 :         if (si.kind() == ScopeKind::NonSyntactic) {
     104           0 :             while (env->is<WithEnvironmentObject>() ||
     105       96051 :                    env->is<NonSyntacticVariablesObject>() ||
     106           0 :                    (env->is<LexicalEnvironmentObject>() &&
     107           0 :                     !env->as<LexicalEnvironmentObject>().isSyntactic()))
     108             :             {
     109           0 :                 MOZ_ASSERT(!IsSyntacticEnvironment(env));
     110           0 :                 env = &env->as<EnvironmentObject>().enclosingEnvironment();
     111             :             }
     112           0 :         } else if (si.hasSyntacticEnvironment()) {
     113       15579 :             switch (si.kind()) {
     114             :               case ScopeKind::Function:
     115           0 :                 MOZ_ASSERT(env->as<CallObject>().callee().existingScriptNonDelazifying() ==
     116             :                            si.scope()->as<FunctionScope>().script());
     117       13072 :                 env = &env->as<CallObject>().enclosingEnvironment();
     118        6536 :                 break;
     119             : 
     120             :               case ScopeKind::FunctionBodyVar:
     121             :               case ScopeKind::ParameterExpressionVar:
     122         236 :                 MOZ_ASSERT(&env->as<VarEnvironmentObject>().scope() == si.scope());
     123         472 :                 env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
     124         236 :                 break;
     125             : 
     126             :               case ScopeKind::Lexical:
     127             :               case ScopeKind::SimpleCatch:
     128             :               case ScopeKind::Catch:
     129             :               case ScopeKind::NamedLambda:
     130             :               case ScopeKind::StrictNamedLambda:
     131        3094 :                 MOZ_ASSERT(&env->as<LexicalEnvironmentObject>().scope() == si.scope());
     132        6188 :                 env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment();
     133           0 :                 break;
     134             : 
     135             :               case ScopeKind::With:
     136           0 :                 MOZ_ASSERT(&env->as<WithEnvironmentObject>().scope() == si.scope());
     137           0 :                 env = &env->as<WithEnvironmentObject>().enclosingEnvironment();
     138           0 :                 break;
     139             : 
     140             :               case ScopeKind::Eval:
     141             :               case ScopeKind::StrictEval:
     142        1334 :                 env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
     143           0 :                 break;
     144             : 
     145             :               case ScopeKind::Global:
     146        5046 :                 MOZ_ASSERT(env->as<LexicalEnvironmentObject>().isGlobal());
     147       10092 :                 env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment();
     148        5046 :                 MOZ_ASSERT(env->is<GlobalObject>());
     149             :                 break;
     150             : 
     151             :               case ScopeKind::NonSyntactic:
     152           0 :                 MOZ_CRASH("NonSyntactic should not have a syntactic environment");
     153             :                 break;
     154             : 
     155             :               case ScopeKind::Module:
     156           0 :                 MOZ_ASSERT(env->as<ModuleEnvironmentObject>().module().script() ==
     157             :                            si.scope()->as<ModuleScope>().script());
     158           0 :                 env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
     159           0 :                 break;
     160             : 
     161             :               case ScopeKind::WasmInstance:
     162           0 :                 env = &env->as<WasmInstanceEnvironmentObject>().enclosingEnvironment();
     163           0 :                 break;
     164             : 
     165             :               case ScopeKind::WasmFunction:
     166           0 :                 env = &env->as<WasmFunctionCallObject>().enclosingEnvironment();
     167           0 :                 break;
     168             :             }
     169             :         }
     170             :     }
     171             : 
     172             :     // In the case of a non-syntactic env chain, the immediate parent of the
     173             :     // outermost non-syntactic env may be the global lexical env, or, if
     174             :     // called from Debugger, a DebugEnvironmentProxy.
     175             :     //
     176             :     // In the case of a syntactic env chain, the outermost env is always a
     177             :     // GlobalObject.
     178           0 :     MOZ_ASSERT(env->is<GlobalObject>() || IsGlobalLexicalEnvironment(env) ||
     179             :                env->is<DebugEnvironmentProxy>());
     180             : #endif
     181           0 : }
     182             : 
     183             : static inline void
     184       14927 : AssertScopeMatchesEnvironment(InterpreterFrame* fp, jsbytecode* pc)
     185             : {
     186             : #ifdef DEBUG
     187             :     // If we OOMed before fully initializing the environment chain, the scope
     188             :     // and environment will definitely mismatch.
     189           0 :     if (fp->script()->initialEnvironmentShape() && fp->hasInitialEnvironment())
     190        6736 :         AssertScopeMatchesEnvironment(fp->script()->innermostScope(pc), fp->environmentChain());
     191             : #endif
     192           1 : }
     193             : 
     194             : bool
     195           0 : InterpreterFrame::initFunctionEnvironmentObjects(JSContext* cx)
     196             : {
     197        2349 :     return js::InitFunctionEnvironmentObjects(cx, this);
     198             : }
     199             : 
     200             : bool
     201       14078 : InterpreterFrame::prologue(JSContext* cx)
     202             : {
     203       28156 :     RootedScript script(cx, this->script());
     204             : 
     205           0 :     MOZ_ASSERT(cx->interpreterRegs().pc == script->code());
     206             : 
     207       28156 :     if (isEvalFrame()) {
     208          60 :         if (!script->bodyScope()->hasEnvironment()) {
     209           0 :             MOZ_ASSERT(!script->strict());
     210             :             // Non-strict eval may introduce var bindings that conflict with
     211             :             // lexical bindings in an enclosing lexical scope.
     212           0 :             RootedObject varObjRoot(cx, &varObj());
     213           0 :             if (!CheckEvalDeclarationConflicts(cx, script, environmentChain(), varObjRoot))
     214           0 :                 return false;
     215             :         }
     216           0 :         return probes::EnterScript(cx, script, nullptr, this);
     217             :     }
     218             : 
     219           0 :     if (isGlobalFrame()) {
     220           0 :         Rooted<LexicalEnvironmentObject*> lexicalEnv(cx);
     221           0 :         RootedObject varObjRoot(cx);
     222         810 :         if (script->hasNonSyntacticScope()) {
     223           0 :             lexicalEnv = &extensibleLexicalEnvironment();
     224           0 :             varObjRoot = &varObj();
     225             :         } else {
     226           0 :             lexicalEnv = &cx->global()->lexicalEnvironment();
     227         252 :             varObjRoot = cx->global();
     228             :         }
     229        1215 :         if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, varObjRoot))
     230             :             return false;
     231           0 :         return probes::EnterScript(cx, script, nullptr, this);
     232             :     }
     233             : 
     234       27306 :     if (isModuleFrame())
     235           0 :         return probes::EnterScript(cx, script, nullptr, this);
     236             : 
     237             :     // At this point, we've yet to push any environments. Check that they
     238             :     // match the enclosing scope.
     239           0 :     AssertScopeMatchesEnvironment(script->enclosingScope(), environmentChain());
     240             : 
     241       27306 :     MOZ_ASSERT(isFunctionFrame());
     242           0 :     if (callee().needsFunctionEnvironmentObjects() && !initFunctionEnvironmentObjects(cx))
     243             :         return false;
     244             : 
     245           0 :     MOZ_ASSERT_IF(isConstructing(),
     246             :                   thisArgument().isObject() || thisArgument().isMagic(JS_UNINITIALIZED_LEXICAL));
     247             : 
     248       27306 :     return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
     249             : }
     250             : 
     251             : void
     252           0 : InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc)
     253             : {
     254       15340 :     RootedScript script(cx, this->script());
     255       74635 :     probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedGeckoProfilerFrame());
     256             : 
     257             :     // Check that the scope matches the environment at the point of leaving
     258             :     // the frame.
     259           0 :     AssertScopeMatchesEnvironment(this, pc);
     260             : 
     261           0 :     EnvironmentIter ei(cx, this, pc);
     262           0 :     UnwindAllEnvironmentsInFrame(cx, ei);
     263             : 
     264           0 :     if (isFunctionFrame()) {
     265           0 :         if (!callee().isGenerator() &&
     266           0 :             !callee().isAsync() &&
     267       13861 :             isConstructing() &&
     268           0 :             thisArgument().isObject() &&
     269        1206 :             returnValue().isPrimitive())
     270             :         {
     271           0 :             setReturnValue(thisArgument());
     272             :         }
     273             : 
     274           0 :         return;
     275             :     }
     276             : 
     277        1220 :     MOZ_ASSERT(isEvalFrame() || isGlobalFrame() || isModuleFrame());
     278             : }
     279             : 
     280             : bool
     281           0 : InterpreterFrame::checkReturn(JSContext* cx, HandleValue thisv)
     282             : {
     283         658 :     MOZ_ASSERT(script()->isDerivedClassConstructor());
     284           0 :     MOZ_ASSERT(isFunctionFrame());
     285           0 :     MOZ_ASSERT(callee().isClassConstructor());
     286             : 
     287         658 :     HandleValue retVal = returnValue();
     288           0 :     if (retVal.isObject())
     289             :         return true;
     290             : 
     291         329 :     if (!retVal.isUndefined()) {
     292           0 :         ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, retVal, nullptr);
     293           0 :         return false;
     294             :     }
     295             : 
     296           0 :     if (thisv.isMagic(JS_UNINITIALIZED_LEXICAL))
     297           0 :         return ThrowUninitializedThis(cx, this);
     298             : 
     299         658 :     setReturnValue(thisv);
     300         329 :     return true;
     301             : }
     302             : 
     303             : bool
     304         102 : InterpreterFrame::pushVarEnvironment(JSContext* cx, HandleScope scope)
     305             : {
     306         102 :     return js::PushVarEnvironmentObject(cx, scope, this);
     307             : }
     308             : 
     309             : bool
     310           0 : InterpreterFrame::pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope)
     311             : {
     312        1223 :     LexicalEnvironmentObject* env = LexicalEnvironmentObject::create(cx, scope, this);
     313           0 :     if (!env)
     314             :         return false;
     315             : 
     316        1223 :     pushOnEnvironmentChain(*env);
     317        1223 :     return true;
     318             : }
     319             : 
     320             : bool
     321           0 : InterpreterFrame::freshenLexicalEnvironment(JSContext* cx)
     322             : {
     323           0 :     Rooted<LexicalEnvironmentObject*> env(cx, &envChain_->as<LexicalEnvironmentObject>());
     324           0 :     LexicalEnvironmentObject* fresh = LexicalEnvironmentObject::clone(cx, env);
     325           0 :     if (!fresh)
     326             :         return false;
     327             : 
     328           0 :     replaceInnermostEnvironment(*fresh);
     329           0 :     return true;
     330             : }
     331             : 
     332             : bool
     333           0 : InterpreterFrame::recreateLexicalEnvironment(JSContext* cx)
     334             : {
     335         620 :     Rooted<LexicalEnvironmentObject*> env(cx, &envChain_->as<LexicalEnvironmentObject>());
     336         310 :     LexicalEnvironmentObject* fresh = LexicalEnvironmentObject::recreate(cx, env);
     337           0 :     if (!fresh)
     338             :         return false;
     339             : 
     340         310 :     replaceInnermostEnvironment(*fresh);
     341         310 :     return true;
     342             : }
     343             : 
     344             : void
     345           0 : InterpreterFrame::trace(JSTracer* trc, Value* sp, jsbytecode* pc)
     346             : {
     347           0 :     TraceRoot(trc, &envChain_, "env chain");
     348           0 :     TraceRoot(trc, &script_, "script");
     349             : 
     350           0 :     if (flags_ & HAS_ARGS_OBJ)
     351           0 :         TraceRoot(trc, &argsObj_, "arguments");
     352             : 
     353           0 :     if (hasReturnValue())
     354           2 :         TraceRoot(trc, &rval_, "rval");
     355             : 
     356          53 :     MOZ_ASSERT(sp >= slots());
     357             : 
     358          53 :     if (hasArgs()) {
     359             :         // Trace the callee and |this|. When we're doing a moving GC, we
     360             :         // need to fix up the callee pointer before we use it below, under
     361             :         // numFormalArgs() and script().
     362           0 :         TraceRootRange(trc, 2, argv_ - 2, "fp callee and this");
     363             : 
     364             :         // Trace arguments.
     365         104 :         unsigned argc = Max(numActualArgs(), numFormalArgs());
     366           0 :         TraceRootRange(trc, argc + isConstructing(), argv_, "fp argv");
     367             :     } else {
     368             :         // Trace newTarget.
     369           0 :         TraceRoot(trc, ((Value*)this) - 1, "stack newTarget");
     370             :     }
     371             : 
     372          53 :     JSScript* script = this->script();
     373           0 :     size_t nfixed = script->nfixed();
     374          53 :     size_t nlivefixed = script->calculateLiveFixed(pc);
     375             : 
     376          53 :     if (nfixed == nlivefixed) {
     377             :         // All locals are live.
     378           0 :         traceValues(trc, 0, sp - slots());
     379             :     } else {
     380             :         // Trace operand stack.
     381           0 :         traceValues(trc, nfixed, sp - slots());
     382             : 
     383             :         // Clear dead block-scoped locals.
     384          49 :         while (nfixed > nlivefixed)
     385           0 :             unaliasedLocal(--nfixed).setUndefined();
     386             : 
     387             :         // Trace live locals.
     388           0 :         traceValues(trc, 0, nlivefixed);
     389             :     }
     390             : 
     391         106 :     if (auto* debugEnvs = script->realm()->debugEnvs())
     392           0 :         debugEnvs->traceLiveFrame(trc, this);
     393           0 : }
     394             : 
     395             : void
     396           0 : InterpreterFrame::traceValues(JSTracer* trc, unsigned start, unsigned end)
     397             : {
     398          72 :     if (start < end)
     399          63 :         TraceRootRange(trc, end - start, slots() + start, "vm_stack");
     400           0 : }
     401             : 
     402             : static void
     403           0 : TraceInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
     404             : {
     405         126 :     for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
     406           0 :         InterpreterFrame* fp = frames.frame();
     407          53 :         fp->trace(trc, frames.sp(), frames.pc());
     408             :     }
     409           0 : }
     410             : 
     411             : void
     412           0 : js::TraceInterpreterActivations(JSContext* cx, JSTracer* trc)
     413             : {
     414           0 :     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
     415          29 :         Activation* act = iter.activation();
     416           0 :         if (act->isInterpreter())
     417          20 :             TraceInterpreterActivation(trc, act->asInterpreter());
     418             :     }
     419           4 : }
     420             : 
     421             : /*****************************************************************************/
     422             : 
     423             : // Unlike the other methods of this class, this method is defined here so that
     424             : // we don't have to #include jsautooplen.h in vm/Stack.h.
     425             : void
     426           0 : InterpreterRegs::setToEndOfScript()
     427             : {
     428         102 :     sp = fp()->base();
     429          51 : }
     430             : 
     431             : /*****************************************************************************/
     432             : 
     433             : InterpreterFrame*
     434        6579 : InterpreterStack::pushInvokeFrame(JSContext* cx, const CallArgs& args, MaybeConstruct constructing)
     435             : {
     436           0 :     LifoAlloc::Mark mark = allocator_.mark();
     437             : 
     438       19737 :     RootedFunction fun(cx, &args.callee().as<JSFunction>());
     439           0 :     RootedScript script(cx, fun->nonLazyScript());
     440             : 
     441             :     Value* argv;
     442        6579 :     InterpreterFrame* fp = getCallFrame(cx, args, script, constructing, &argv);
     443           0 :     if (!fp)
     444             :         return nullptr;
     445             : 
     446           0 :     fp->mark_ = mark;
     447       19737 :     fp->initCallFrame(nullptr, nullptr, nullptr, *fun, script, argv, args.length(),
     448       19737 :                       constructing);
     449        6579 :     return fp;
     450             : }
     451             : 
     452             : InterpreterFrame*
     453           0 : InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Value& newTargetValue,
     454             :                                    HandleObject envChain, AbstractFramePtr evalInFrame)
     455             : {
     456           0 :     LifoAlloc::Mark mark = allocator_.mark();
     457             : 
     458         425 :     unsigned nvars = 1 /* newTarget */ + script->nslots();
     459         425 :     uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
     460           0 :     if (!buffer)
     461             :         return nullptr;
     462             : 
     463         425 :     InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer + 1 * sizeof(Value));
     464         425 :     fp->mark_ = mark;
     465         425 :     fp->initExecuteFrame(cx, script, evalInFrame, newTargetValue, envChain);
     466             :     fp->initLocals();
     467             : 
     468             :     return fp;
     469             : }
     470             : 
     471             : /*****************************************************************************/
     472             : 
     473           0 : JitFrameIter::JitFrameIter(const JitFrameIter& another)
     474             : {
     475           0 :     *this = another;
     476           0 : }
     477             : 
     478             : JitFrameIter&
     479        3869 : JitFrameIter::operator=(const JitFrameIter& another)
     480             : {
     481           0 :     MOZ_ASSERT(this != &another);
     482             : 
     483           0 :     act_ = another.act_;
     484           0 :     mustUnwindActivation_ = another.mustUnwindActivation_;
     485             : 
     486        3869 :     if (isSome())
     487           0 :         iter_.destroy();
     488           0 :     if (!another.isSome())
     489             :         return *this;
     490             : 
     491           0 :     if (another.isJSJit()) {
     492           0 :         iter_.construct<jit::JSJitFrameIter>(another.asJSJit());
     493             :     } else {
     494           0 :         MOZ_ASSERT(another.isWasm());
     495           0 :         iter_.construct<wasm::WasmFrameIter>(another.asWasm());
     496             :     }
     497             : 
     498             :     return *this;
     499             : }
     500             : 
     501           0 : JitFrameIter::JitFrameIter(jit::JitActivation* act, bool mustUnwindActivation)
     502             : {
     503           0 :     act_ = act;
     504           0 :     mustUnwindActivation_ = mustUnwindActivation;
     505        8781 :     MOZ_ASSERT(act->hasExitFP(), "packedExitFP is used to determine if JSJit or wasm");
     506           0 :     if (act->hasJSExitFP()) {
     507           0 :         iter_.construct<jit::JSJitFrameIter>(act);
     508             :     } else {
     509           0 :         MOZ_ASSERT(act->hasWasmExitFP());
     510           0 :         iter_.construct<wasm::WasmFrameIter>(act);
     511             :     }
     512        8781 :     settle();
     513           0 : }
     514             : 
     515             : void
     516        8422 : JitFrameIter::skipNonScriptedJSFrames()
     517             : {
     518           0 :     if (isJSJit()) {
     519             :         // Stop at the first scripted frame.
     520           0 :         jit::JSJitFrameIter& frames = asJSJit();
     521       41510 :         while (!frames.isScripted() && !frames.done())
     522           0 :             ++frames;
     523        8422 :         settle();
     524             :     }
     525           0 : }
     526             : 
     527             : bool
     528        1188 : JitFrameIter::isSelfHostedIgnoringInlining() const
     529             : {
     530        1188 :     MOZ_ASSERT(!done());
     531             : 
     532           0 :     if (isWasm())
     533             :         return false;
     534             : 
     535        2376 :     return asJSJit().script()->selfHosted();
     536             : }
     537             : 
     538             : JS::Realm*
     539        1077 : JitFrameIter::realm() const
     540             : {
     541           1 :     MOZ_ASSERT(!done());
     542             : 
     543           0 :     if (isWasm())
     544           0 :         return asWasm().instance()->realm();
     545             : 
     546        1077 :     return asJSJit().script()->realm();
     547             : }
     548             : 
     549             : bool
     550       20292 : JitFrameIter::done() const
     551             : {
     552           0 :     if (!isSome())
     553             :         return true;
     554           0 :     if (isJSJit())
     555           1 :         return asJSJit().done();
     556           0 :     if (isWasm())
     557           0 :         return asWasm().done();
     558           0 :     MOZ_CRASH("unhandled case");
     559             : }
     560             : 
     561             : void
     562           0 : JitFrameIter::settle()
     563             : {
     564       26114 :     if (isJSJit()) {
     565       26114 :         const jit::JSJitFrameIter& jitFrame = asJSJit();
     566       26114 :         if (jitFrame.type() != jit::JitFrame_WasmToJSJit)
     567             :             return;
     568             : 
     569             :         // Transition from js jit frames to wasm frames: we're on the
     570             :         // wasm-to-jit fast path. The current stack layout is as follows:
     571             :         // (stack grows downward)
     572             :         //
     573             :         // [--------------------]
     574             :         // [WASM FUNC           ]
     575             :         // [WASM JIT EXIT FRAME ]
     576             :         // [JIT WASM ENTRY FRAME] <-- we're here.
     577             :         //
     578             :         // So prevFP points to the wasm jit exit FP, maintaing the invariant in
     579             :         // WasmFrameIter that the first frame is an exit frame and can be
     580             :         // popped.
     581             : 
     582           0 :         wasm::Frame* prevFP = (wasm::Frame*) jitFrame.prevFp();
     583             : 
     584           0 :         if (mustUnwindActivation_)
     585           0 :             act_->setWasmExitFP(prevFP);
     586             : 
     587           0 :         iter_.destroy();
     588           0 :         iter_.construct<wasm::WasmFrameIter>(act_, prevFP);
     589           0 :         MOZ_ASSERT(!asWasm().done());
     590             :         return;
     591             :     }
     592             : 
     593           0 :     if (isWasm()) {
     594           0 :         const wasm::WasmFrameIter& wasmFrame = asWasm();
     595           0 :         if (!wasmFrame.unwoundIonCallerFP())
     596             :             return;
     597             : 
     598             :         // Transition from wasm frames to jit frames: we're on the
     599             :         // jit-to-wasm fast path. The current stack layout is as follows:
     600             :         // (stack grows downward)
     601             :         //
     602             :         // [--------------------]
     603             :         // [JIT FRAME           ]
     604             :         // [WASM JIT ENTRY FRAME] <-- we're here
     605             :         //
     606             :         // The wasm iterator has saved the previous jit frame pointer for us.
     607             : 
     608           0 :         MOZ_ASSERT(wasmFrame.done());
     609           0 :         uint8_t* prevFP = wasmFrame.unwoundIonCallerFP();
     610             : 
     611           0 :         if (mustUnwindActivation_)
     612           0 :             act_->setJSExitFP(prevFP);
     613             : 
     614           0 :         iter_.destroy();
     615           0 :         iter_.construct<jit::JSJitFrameIter>(act_, prevFP);
     616           0 :         MOZ_ASSERT(!asJSJit().done());
     617             :         return;
     618             :     }
     619             : }
     620             : 
     621             : void
     622           0 : JitFrameIter::operator++()
     623             : {
     624        8911 :     MOZ_ASSERT(isSome());
     625           0 :     if (isJSJit()) {
     626           0 :         const jit::JSJitFrameIter& jitFrame = asJSJit();
     627             : 
     628        8911 :         jit::JitFrameLayout* prevFrame = nullptr;
     629           0 :         if (mustUnwindActivation_ && jitFrame.isScripted())
     630          35 :             prevFrame = jitFrame.jsFrame();
     631             : 
     632        8911 :         ++asJSJit();
     633             : 
     634        8911 :         if (prevFrame) {
     635             :             // Unwind the frame by updating packedExitFP. This is necessary
     636             :             // so that (1) debugger exception unwind and leave frame hooks
     637             :             // don't see this frame when they use ScriptFrameIter, and (2)
     638             :             // ScriptFrameIter does not crash when accessing an IonScript
     639             :             // that's destroyed by the ionScript->decref call.
     640           0 :             EnsureBareExitFrame(act_, prevFrame);
     641             :         }
     642           0 :     } else if (isWasm()) {
     643           0 :         ++asWasm();
     644             :     } else {
     645           0 :         MOZ_CRASH("unhandled case");
     646             :     }
     647           0 :     settle();
     648           0 : }
     649             : 
     650           0 : OnlyJSJitFrameIter::OnlyJSJitFrameIter(jit::JitActivation* act)
     651           0 :   : JitFrameIter(act)
     652             : {
     653           1 :     settle();
     654           0 : }
     655             : 
     656           0 : OnlyJSJitFrameIter::OnlyJSJitFrameIter(JSContext* cx)
     657           0 :   : OnlyJSJitFrameIter(cx->activation()->asJit())
     658             : {
     659           0 : }
     660             : 
     661           0 : OnlyJSJitFrameIter::OnlyJSJitFrameIter(const ActivationIterator& iter)
     662        7440 :   : OnlyJSJitFrameIter(iter->asJit())
     663             : {
     664        3720 : }
     665             : 
     666             : /*****************************************************************************/
     667             : 
     668             : void
     669           0 : FrameIter::popActivation()
     670             : {
     671        3823 :     ++data_.activations_;
     672        3823 :     settleOnActivation();
     673           0 : }
     674             : 
     675             : bool
     676       14552 : FrameIter::principalsSubsumeFrame() const
     677             : {
     678             :     // If the caller supplied principals, only show frames which are
     679             :     // subsumed (of the same origin or of an origin accessible) by these
     680             :     // principals.
     681             : 
     682       29104 :     MOZ_ASSERT(!done());
     683             : 
     684           0 :     if (!data_.principals_)
     685             :         return true;
     686             : 
     687         390 :     JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes;
     688           0 :     if (!subsumes)
     689             :         return true;
     690             : 
     691          98 :     return subsumes(data_.principals_, realm()->principals());
     692             : }
     693             : 
     694             : void
     695        4234 : FrameIter::popInterpreterFrame()
     696             : {
     697        4234 :     MOZ_ASSERT(data_.state_ == INTERP);
     698             : 
     699        4234 :     ++data_.interpFrames_;
     700             : 
     701           0 :     if (data_.interpFrames_.done())
     702             :         popActivation();
     703             :     else
     704        2401 :         data_.pc_ = data_.interpFrames_.pc();
     705           0 : }
     706             : 
     707             : void
     708       14669 : FrameIter::settleOnActivation()
     709             : {
     710           0 :     MOZ_ASSERT(!data_.cx_->inUnsafeCallWithABI);
     711             : 
     712             :     while (true) {
     713       29350 :         if (data_.activations_.done()) {
     714        3854 :             data_.state_ = DONE;
     715           0 :             return;
     716             :         }
     717             : 
     718           0 :         Activation* activation = data_.activations_.activation();
     719             : 
     720           0 :         if (activation->isJit()) {
     721        7738 :             data_.jitFrames_ = JitFrameIter(activation->asJit());
     722        3869 :             data_.jitFrames_.skipNonScriptedJSFrames();
     723        3869 :             if (data_.jitFrames_.done()) {
     724             :                 // It's possible to have an JitActivation with no scripted
     725             :                 // frames, for instance if we hit an over-recursion during
     726             :                 // bailout.
     727           0 :                 ++data_.activations_;
     728           0 :                 continue;
     729             :             }
     730        3869 :             data_.state_ = JIT;
     731        3869 :             nextJitFrame();
     732           0 :             return;
     733             :         }
     734             : 
     735           0 :         MOZ_ASSERT(activation->isInterpreter());
     736             : 
     737        6952 :         InterpreterActivation* interpAct = activation->asInterpreter();
     738        6952 :         data_.interpFrames_ = InterpreterFrameIterator(interpAct);
     739             : 
     740             :         // If we OSR'ed into JIT code, skip the interpreter frame so that
     741             :         // the same frame is not reported twice.
     742           0 :         if (data_.interpFrames_.frame()->runningInJit()) {
     743           0 :             ++data_.interpFrames_;
     744          53 :             if (data_.interpFrames_.done()) {
     745           6 :                 ++data_.activations_;
     746           6 :                 continue;
     747             :             }
     748             :         }
     749             : 
     750           0 :         MOZ_ASSERT(!data_.interpFrames_.frame()->runningInJit());
     751        6946 :         data_.pc_ = data_.interpFrames_.pc();
     752        6946 :         data_.state_ = INTERP;
     753        6946 :         return;
     754             :     }
     755             : }
     756             : 
     757           0 : FrameIter::Data::Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
     758       10846 :                       JSPrincipals* principals)
     759             :   : cx_(cx),
     760             :     debuggerEvalOption_(debuggerEvalOption),
     761             :     principals_(principals),
     762             :     state_(DONE),
     763             :     pc_(nullptr),
     764             :     interpFrames_(nullptr),
     765             :     activations_(cx),
     766       32538 :     ionInlineFrameNo_(0)
     767             : {
     768           0 : }
     769             : 
     770           0 : FrameIter::Data::Data(const FrameIter::Data& other)
     771           0 :   : cx_(other.cx_),
     772           0 :     debuggerEvalOption_(other.debuggerEvalOption_),
     773           0 :     principals_(other.principals_),
     774           0 :     state_(other.state_),
     775           0 :     pc_(other.pc_),
     776             :     interpFrames_(other.interpFrames_),
     777             :     activations_(other.activations_),
     778             :     jitFrames_(other.jitFrames_),
     779           0 :     ionInlineFrameNo_(other.ionInlineFrameNo_)
     780             : {
     781           0 : }
     782             : 
     783       10716 : FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption)
     784             :   : data_(cx, debuggerEvalOption, nullptr),
     785           0 :     ionInlineFrames_(cx, (js::jit::JSJitFrameIter*) nullptr)
     786             : {
     787             :     // settleOnActivation can only GC if principals are given.
     788       21431 :     JS::AutoSuppressGCAnalysis nogc;
     789           0 :     settleOnActivation();
     790             : 
     791             :     // No principals so we can see all frames.
     792           0 :     MOZ_ASSERT_IF(!done(), principalsSubsumeFrame());
     793           0 : }
     794             : 
     795           0 : FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
     796         130 :                      JSPrincipals* principals)
     797             :   : data_(cx, debuggerEvalOption, principals),
     798         260 :     ionInlineFrames_(cx, (js::jit::JSJitFrameIter*) nullptr)
     799             : {
     800         130 :     settleOnActivation();
     801             : 
     802             :     // If we're not allowed to see this frame, call operator++ to skip this (and
     803             :     // other) cross-origin frames.
     804         130 :     if (!done() && !principalsSubsumeFrame())
     805           0 :         ++*this;
     806         130 : }
     807             : 
     808           0 : FrameIter::FrameIter(const FrameIter& other)
     809             :   : data_(other.data_),
     810           0 :     ionInlineFrames_(other.data_.cx_, isIonScripted() ? &other.ionInlineFrames_ : nullptr)
     811             : {
     812           0 : }
     813             : 
     814           0 : FrameIter::FrameIter(const Data& data)
     815             :   : data_(data),
     816           0 :     ionInlineFrames_(data.cx_, isIonScripted() ? &jsJitFrame() : nullptr)
     817             : {
     818           0 :     MOZ_ASSERT(data.cx_);
     819           0 :     if (isIonScripted()) {
     820           0 :         while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
     821           0 :             ++ionInlineFrames_;
     822             :     }
     823           0 : }
     824             : 
     825             : void
     826        5205 : FrameIter::nextJitFrame()
     827             : {
     828           0 :     MOZ_ASSERT(data_.jitFrames_.isSome());
     829             : 
     830           0 :     if (isJSJit()) {
     831       10410 :         if (jsJitFrame().isIonScripted()) {
     832           0 :             ionInlineFrames_.resetOn(&jsJitFrame());
     833           0 :             data_.pc_ = ionInlineFrames_.pc();
     834             :         } else {
     835        5205 :             MOZ_ASSERT(jsJitFrame().isBaselineJS());
     836       10410 :             jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
     837             :         }
     838             :         return;
     839             :     }
     840             : 
     841           0 :     MOZ_ASSERT(isWasm());
     842           0 :     data_.pc_ = nullptr;
     843             : }
     844             : 
     845             : void
     846           0 : FrameIter::popJitFrame()
     847             : {
     848           0 :     MOZ_ASSERT(data_.state_ == JIT);
     849           0 :     MOZ_ASSERT(data_.jitFrames_.isSome());
     850             : 
     851           0 :     if (isJSJit() && jsJitFrame().isIonScripted() && ionInlineFrames_.more()) {
     852           0 :         ++ionInlineFrames_;
     853           0 :         data_.pc_ = ionInlineFrames_.pc();
     854           0 :         return;
     855             :     }
     856             : 
     857           0 :     ++data_.jitFrames_;
     858           0 :     data_.jitFrames_.skipNonScriptedJSFrames();
     859             : 
     860           0 :     if (!data_.jitFrames_.done()) {
     861        1336 :         nextJitFrame();
     862             :     } else {
     863        1990 :         data_.jitFrames_.reset();
     864             :         popActivation();
     865             :     }
     866             : }
     867             : 
     868             : FrameIter&
     869           0 : FrameIter::operator++()
     870             : {
     871             :     while (true) {
     872        7560 :         switch (data_.state_) {
     873             :           case DONE:
     874           0 :             MOZ_CRASH("Unexpected state");
     875             :           case INTERP:
     876           0 :             if (interpFrame()->isDebuggerEvalFrame() &&
     877           0 :                 data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK)
     878             :             {
     879           0 :                 AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
     880             : 
     881           0 :                 popInterpreterFrame();
     882             : 
     883           0 :                 while (!hasUsableAbstractFramePtr() || abstractFramePtr() != eifPrev) {
     884           0 :                     if (data_.state_ == JIT)
     885           0 :                         popJitFrame();
     886             :                     else
     887           0 :                         popInterpreterFrame();
     888             :                 }
     889             : 
     890             :                 break;
     891             :             }
     892           0 :             popInterpreterFrame();
     893           0 :             break;
     894             :           case JIT:
     895        3326 :             popJitFrame();
     896           0 :             break;
     897             :         }
     898             : 
     899        7560 :         if (done() || principalsSubsumeFrame())
     900             :             break;
     901             :     }
     902             : 
     903        7560 :     return *this;
     904             : }
     905             : 
     906             : FrameIter::Data*
     907           0 : FrameIter::copyData() const
     908             : {
     909           0 :     Data* data = data_.cx_->new_<Data>(data_);
     910           0 :     if (!data)
     911             :         return nullptr;
     912             : 
     913           0 :     if (data && isIonScripted())
     914           0 :         data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
     915             :     return data;
     916             : }
     917             : 
     918             : void*
     919           0 : FrameIter::rawFramePtr() const
     920             : {
     921           0 :     switch (data_.state_) {
     922             :       case DONE:
     923             :         return nullptr;
     924             :       case INTERP:
     925           0 :         return interpFrame();
     926             :       case JIT:
     927           0 :         if (isJSJit())
     928           0 :             return jsJitFrame().fp();
     929           0 :         MOZ_ASSERT(isWasm());
     930             :         return nullptr;
     931             :     }
     932           0 :     MOZ_CRASH("Unexpected state");
     933             : }
     934             : 
     935             : JS::Compartment*
     936        7491 : FrameIter::compartment() const
     937             : {
     938        7491 :     switch (data_.state_) {
     939             :       case DONE:
     940             :         break;
     941             :       case INTERP:
     942             :       case JIT:
     943       14982 :         return data_.activations_->compartment();
     944             :     }
     945           0 :     MOZ_CRASH("Unexpected state");
     946             : }
     947             : 
     948             : Realm*
     949       15117 : FrameIter::realm() const
     950             : {
     951           0 :     MOZ_ASSERT(!done());
     952             : 
     953           0 :     if (hasScript())
     954       15117 :         return script()->realm();
     955             : 
     956           0 :     return wasmInstance()->realm();
     957             : }
     958             : 
     959             : bool
     960           0 : FrameIter::isEvalFrame() const
     961             : {
     962           0 :     switch (data_.state_) {
     963             :       case DONE:
     964             :         break;
     965             :       case INTERP:
     966           0 :         return interpFrame()->isEvalFrame();
     967             :       case JIT:
     968           0 :         if (isJSJit()) {
     969           0 :             if (jsJitFrame().isBaselineJS())
     970           0 :                 return jsJitFrame().baselineFrame()->isEvalFrame();
     971           0 :             MOZ_ASSERT(!script()->isForEval());
     972             :             return false;
     973             :         }
     974           0 :         MOZ_ASSERT(isWasm());
     975             :         return false;
     976             :     }
     977           0 :     MOZ_CRASH("Unexpected state");
     978             : }
     979             : 
     980             : bool
     981           0 : FrameIter::isFunctionFrame() const
     982             : {
     983       23260 :     MOZ_ASSERT(!done());
     984       11630 :     switch (data_.state_) {
     985             :       case DONE:
     986             :         break;
     987             :       case INTERP:
     988           0 :         return interpFrame()->isFunctionFrame();
     989             :       case JIT:
     990           0 :         if (isJSJit()) {
     991        3294 :             if (jsJitFrame().isBaselineJS())
     992           1 :                 return jsJitFrame().baselineFrame()->isFunctionFrame();
     993           0 :             return script()->functionNonDelazifying();
     994             :         }
     995           0 :         MOZ_ASSERT(isWasm());
     996             :         return false;
     997             :     }
     998           0 :     MOZ_CRASH("Unexpected state");
     999             : }
    1000             : 
    1001             : JSAtom*
    1002        7489 : FrameIter::maybeFunctionDisplayAtom() const
    1003             : {
    1004        7489 :     switch (data_.state_) {
    1005             :       case DONE:
    1006             :         break;
    1007             :       case INTERP:
    1008             :       case JIT:
    1009           0 :         if (isWasm())
    1010           0 :             return wasmFrame().functionDisplayAtom();
    1011        7489 :         if (isFunctionFrame())
    1012       14644 :             return calleeTemplate()->displayAtom();
    1013             :         return nullptr;
    1014             :     }
    1015             : 
    1016           0 :     MOZ_CRASH("Unexpected state");
    1017             : }
    1018             : 
    1019             : ScriptSource*
    1020          61 : FrameIter::scriptSource() const
    1021             : {
    1022          61 :     switch (data_.state_) {
    1023             :       case DONE:
    1024             :         break;
    1025             :       case INTERP:
    1026             :       case JIT:
    1027           1 :         return script()->scriptSource();
    1028             :     }
    1029             : 
    1030           0 :     MOZ_CRASH("Unexpected state");
    1031             : }
    1032             : 
    1033             : const char*
    1034          69 : FrameIter::filename() const
    1035             : {
    1036          69 :     switch (data_.state_) {
    1037             :       case DONE:
    1038             :         break;
    1039             :       case INTERP:
    1040             :       case JIT:
    1041          69 :         if (isWasm())
    1042           0 :             return wasmFrame().filename();
    1043           1 :         return script()->filename();
    1044             :     }
    1045             : 
    1046           0 :     MOZ_CRASH("Unexpected state");
    1047             : }
    1048             : 
    1049             : const char16_t*
    1050        1641 : FrameIter::displayURL() const
    1051             : {
    1052        1641 :     switch (data_.state_) {
    1053             :       case DONE:
    1054             :         break;
    1055             :       case INTERP:
    1056             :       case JIT:
    1057           0 :         if (isWasm())
    1058           0 :             return wasmFrame().displayURL();
    1059           1 :         ScriptSource* ss = script()->scriptSource();
    1060        1641 :         return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
    1061             :     }
    1062           0 :     MOZ_CRASH("Unexpected state");
    1063             : }
    1064             : 
    1065             : unsigned
    1066          73 : FrameIter::computeLine(uint32_t* column) const
    1067             : {
    1068          73 :     switch (data_.state_) {
    1069             :       case DONE:
    1070             :         break;
    1071             :       case INTERP:
    1072             :       case JIT:
    1073          73 :         if (isWasm())
    1074           0 :             return wasmFrame().computeLine(column);
    1075           1 :         return PCToLineNumber(script(), pc(), column);
    1076             :     }
    1077             : 
    1078           0 :     MOZ_CRASH("Unexpected state");
    1079             : }
    1080             : 
    1081             : bool
    1082          45 : FrameIter::mutedErrors() const
    1083             : {
    1084          45 :     switch (data_.state_) {
    1085             :       case DONE:
    1086             :         break;
    1087             :       case INTERP:
    1088             :       case JIT:
    1089          45 :         if (isWasm())
    1090           0 :             return wasmFrame().mutedErrors();
    1091          90 :         return script()->mutedErrors();
    1092             :     }
    1093           0 :     MOZ_CRASH("Unexpected state");
    1094             : }
    1095             : 
    1096             : bool
    1097         783 : FrameIter::isConstructing() const
    1098             : {
    1099         783 :     switch (data_.state_) {
    1100             :       case DONE:
    1101             :         break;
    1102             :       case JIT:
    1103           0 :         MOZ_ASSERT(isJSJit());
    1104           0 :         if (jsJitFrame().isIonScripted())
    1105           0 :             return ionInlineFrames_.isConstructing();
    1106           0 :         MOZ_ASSERT(jsJitFrame().isBaselineJS());
    1107         738 :         return jsJitFrame().isConstructing();
    1108             :       case INTERP:
    1109           1 :         return interpFrame()->isConstructing();
    1110             :     }
    1111             : 
    1112           0 :     MOZ_CRASH("Unexpected state");
    1113             : }
    1114             : 
    1115             : bool
    1116           0 : FrameIter::ensureHasRematerializedFrame(JSContext* cx)
    1117             : {
    1118           0 :     MOZ_ASSERT(isIon());
    1119           0 :     return !!activation()->asJit()->getRematerializedFrame(cx, jsJitFrame());
    1120             : }
    1121             : 
    1122             : bool
    1123       24000 : FrameIter::hasUsableAbstractFramePtr() const
    1124             : {
    1125       24000 :     switch (data_.state_) {
    1126             :       case DONE:
    1127             :         return false;
    1128             :       case JIT:
    1129          14 :         if (isJSJit()) {
    1130           0 :             if (jsJitFrame().isBaselineJS())
    1131             :                 return true;
    1132             : 
    1133           0 :             MOZ_ASSERT(jsJitFrame().isIonScripted());
    1134           0 :             return !!activation()->asJit()->lookupRematerializedFrame(jsJitFrame().fp(),
    1135           0 :                                                                       ionInlineFrames_.frameNo());
    1136             :         }
    1137           0 :         MOZ_ASSERT(isWasm());
    1138           0 :         return wasmFrame().debugEnabled();
    1139             :       case INTERP:
    1140       23986 :         return true;
    1141             :     }
    1142           0 :     MOZ_CRASH("Unexpected state");
    1143             : }
    1144             : 
    1145             : AbstractFramePtr
    1146           0 : FrameIter::abstractFramePtr() const
    1147             : {
    1148       12008 :     MOZ_ASSERT(hasUsableAbstractFramePtr());
    1149       12008 :     switch (data_.state_) {
    1150             :       case DONE:
    1151             :         break;
    1152             :       case JIT: {
    1153           0 :         if (isJSJit()) {
    1154           0 :             if (jsJitFrame().isBaselineJS())
    1155           0 :                 return jsJitFrame().baselineFrame();
    1156           0 :             MOZ_ASSERT(isIonScripted());
    1157           0 :             return activation()->asJit()->lookupRematerializedFrame(jsJitFrame().fp(),
    1158           0 :                                                                     ionInlineFrames_.frameNo());
    1159             :         }
    1160           0 :         MOZ_ASSERT(isWasm());
    1161           0 :         MOZ_ASSERT(wasmFrame().debugEnabled());
    1162           0 :         return wasmFrame().debugFrame();
    1163             :       }
    1164             :       case INTERP:
    1165           1 :         MOZ_ASSERT(interpFrame());
    1166       12001 :         return AbstractFramePtr(interpFrame());
    1167             :     }
    1168           0 :     MOZ_CRASH("Unexpected state");
    1169             : }
    1170             : 
    1171             : void
    1172           0 : FrameIter::updatePcQuadratic()
    1173             : {
    1174           0 :     switch (data_.state_) {
    1175             :       case DONE:
    1176             :         break;
    1177             :       case INTERP: {
    1178           0 :         InterpreterFrame* frame = interpFrame();
    1179           0 :         InterpreterActivation* activation = data_.activations_->asInterpreter();
    1180             : 
    1181             :         // Look for the current frame.
    1182           0 :         data_.interpFrames_ = InterpreterFrameIterator(activation);
    1183           0 :         while (data_.interpFrames_.frame() != frame)
    1184           0 :             ++data_.interpFrames_;
    1185             : 
    1186             :         // Update the pc.
    1187           0 :         MOZ_ASSERT(data_.interpFrames_.frame() == frame);
    1188           0 :         data_.pc_ = data_.interpFrames_.pc();
    1189           0 :         return;
    1190             :       }
    1191             :       case JIT:
    1192           0 :         if (jsJitFrame().isBaselineJS()) {
    1193           0 :             jit::BaselineFrame* frame = jsJitFrame().baselineFrame();
    1194           0 :             jit::JitActivation* activation = data_.activations_->asJit();
    1195             : 
    1196             :             // activation's exitFP may be invalid, so create a new
    1197             :             // activation iterator.
    1198           0 :             data_.activations_ = ActivationIterator(data_.cx_);
    1199           0 :             while (data_.activations_.activation() != activation)
    1200           0 :                 ++data_.activations_;
    1201             : 
    1202             :             // Look for the current frame.
    1203           0 :             data_.jitFrames_ = JitFrameIter(data_.activations_->asJit());
    1204           0 :             while (!isJSJit() ||
    1205           0 :                    !jsJitFrame().isBaselineJS() ||
    1206           0 :                    jsJitFrame().baselineFrame() != frame)
    1207             :             {
    1208           0 :                 ++data_.jitFrames_;
    1209             :             }
    1210             : 
    1211             :             // Update the pc.
    1212           0 :             MOZ_ASSERT(jsJitFrame().baselineFrame() == frame);
    1213           0 :             jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
    1214           0 :             return;
    1215             :         }
    1216             :         break;
    1217             :     }
    1218           0 :     MOZ_CRASH("Unexpected state");
    1219             : }
    1220             : 
    1221             : void
    1222           0 : FrameIter::wasmUpdateBytecodeOffset()
    1223             : {
    1224           0 :     MOZ_RELEASE_ASSERT(isWasm(), "Unexpected state");
    1225             : 
    1226           0 :     wasm::DebugFrame* frame = wasmFrame().debugFrame();
    1227             : 
    1228             :     // Relookup the current frame, updating the bytecode offset in the process.
    1229           0 :     data_.jitFrames_ = JitFrameIter(data_.activations_->asJit());
    1230           0 :     while (wasmFrame().debugFrame() != frame)
    1231           0 :         ++data_.jitFrames_;
    1232             : 
    1233           0 :     MOZ_ASSERT(wasmFrame().debugFrame() == frame);
    1234           0 : }
    1235             : 
    1236             : JSFunction*
    1237        7356 : FrameIter::calleeTemplate() const
    1238             : {
    1239        7356 :     switch (data_.state_) {
    1240             :       case DONE:
    1241             :         break;
    1242             :       case INTERP:
    1243           0 :         MOZ_ASSERT(isFunctionFrame());
    1244           0 :         return &interpFrame()->callee();
    1245             :       case JIT:
    1246           0 :         if (jsJitFrame().isBaselineJS())
    1247        3287 :             return jsJitFrame().callee();
    1248           0 :         MOZ_ASSERT(jsJitFrame().isIonScripted());
    1249           0 :         return ionInlineFrames_.calleeTemplate();
    1250             :     }
    1251           0 :     MOZ_CRASH("Unexpected state");
    1252             : }
    1253             : 
    1254             : JSFunction*
    1255          34 : FrameIter::callee(JSContext* cx) const
    1256             : {
    1257          34 :     switch (data_.state_) {
    1258             :       case DONE:
    1259             :         break;
    1260             :       case INTERP:
    1261           0 :         return calleeTemplate();
    1262             :       case JIT:
    1263           7 :         if (isIonScripted()) {
    1264           0 :             jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
    1265           0 :             return ionInlineFrames_.callee(recover);
    1266             :         }
    1267           1 :         MOZ_ASSERT(jsJitFrame().isBaselineJS());
    1268           7 :         return calleeTemplate();
    1269             :     }
    1270           0 :     MOZ_CRASH("Unexpected state");
    1271             : }
    1272             : 
    1273             : bool
    1274           0 : FrameIter::matchCallee(JSContext* cx, HandleFunction fun) const
    1275             : {
    1276           0 :     RootedFunction currentCallee(cx, calleeTemplate());
    1277             : 
    1278             :     // As we do not know if the calleeTemplate is the real function, or the
    1279             :     // template from which it would be cloned, we compare properties which are
    1280             :     // stable across the cloning of JSFunctions.
    1281           0 :     if (((currentCallee->flags() ^ fun->flags()) & JSFunction::STABLE_ACROSS_CLONES) != 0 ||
    1282           0 :         currentCallee->nargs() != fun->nargs())
    1283             :     {
    1284             :         return false;
    1285             :     }
    1286             : 
    1287             :     // Use the same condition as |js::CloneFunctionObject|, to know if we should
    1288             :     // expect both functions to have the same JSScript. If so, and if they are
    1289             :     // different, then they cannot be equal.
    1290           0 :     RootedObject global(cx, &fun->global());
    1291           0 :     bool useSameScript = CanReuseScriptForClone(fun->compartment(), currentCallee, global);
    1292           0 :     if (useSameScript &&
    1293           0 :         (currentCallee->hasScript() != fun->hasScript() ||
    1294           0 :          currentCallee->nonLazyScript() != fun->nonLazyScript()))
    1295             :     {
    1296             :         return false;
    1297             :     }
    1298             : 
    1299             :     // If none of the previous filters worked, then take the risk of
    1300             :     // invalidating the frame to identify the JSFunction.
    1301           0 :     return callee(cx) == fun;
    1302             : }
    1303             : 
    1304             : unsigned
    1305           4 : FrameIter::numActualArgs() const
    1306             : {
    1307           4 :     switch (data_.state_) {
    1308             :       case DONE:
    1309             :         break;
    1310             :       case INTERP:
    1311           0 :         MOZ_ASSERT(isFunctionFrame());
    1312           0 :         return interpFrame()->numActualArgs();
    1313             :       case JIT:
    1314           0 :         if (isIonScripted())
    1315           0 :             return ionInlineFrames_.numActualArgs();
    1316           0 :         MOZ_ASSERT(jsJitFrame().isBaselineJS());
    1317           0 :         return jsJitFrame().numActualArgs();
    1318             :     }
    1319           0 :     MOZ_CRASH("Unexpected state");
    1320             : }
    1321             : 
    1322             : unsigned
    1323           0 : FrameIter::numFormalArgs() const
    1324             : {
    1325           0 :     return script()->functionNonDelazifying()->nargs();
    1326             : }
    1327             : 
    1328             : Value
    1329           0 : FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
    1330             : {
    1331           0 :     return abstractFramePtr().unaliasedActual(i, checkAliasing);
    1332             : }
    1333             : 
    1334             : JSObject*
    1335         567 : FrameIter::environmentChain(JSContext* cx) const
    1336             : {
    1337         567 :     switch (data_.state_) {
    1338             :       case DONE:
    1339             :         break;
    1340             :       case JIT:
    1341           0 :         if (isJSJit()) {
    1342          17 :             if (isIonScripted()) {
    1343           0 :                 jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
    1344           0 :                 return ionInlineFrames_.environmentChain(recover);
    1345             :             }
    1346           0 :             return jsJitFrame().baselineFrame()->environmentChain();
    1347             :         }
    1348           0 :         MOZ_ASSERT(isWasm());
    1349           0 :         return wasmFrame().debugFrame()->environmentChain();
    1350             :       case INTERP:
    1351        1650 :         return interpFrame()->environmentChain();
    1352             :     }
    1353           0 :     MOZ_CRASH("Unexpected state");
    1354             : }
    1355             : 
    1356             : CallObject&
    1357           0 : FrameIter::callObj(JSContext* cx) const
    1358             : {
    1359           0 :     MOZ_ASSERT(calleeTemplate()->needsCallObject());
    1360             : 
    1361           0 :     JSObject* pobj = environmentChain(cx);
    1362           0 :     while (!pobj->is<CallObject>())
    1363           0 :         pobj = pobj->enclosingEnvironment();
    1364           0 :     return pobj->as<CallObject>();
    1365             : }
    1366             : 
    1367             : bool
    1368           0 : FrameIter::hasArgsObj() const
    1369             : {
    1370           0 :     return abstractFramePtr().hasArgsObj();
    1371             : }
    1372             : 
    1373             : ArgumentsObject&
    1374           0 : FrameIter::argsObj() const
    1375             : {
    1376           0 :     MOZ_ASSERT(hasArgsObj());
    1377           0 :     return abstractFramePtr().argsObj();
    1378             : }
    1379             : 
    1380             : Value
    1381           0 : FrameIter::thisArgument(JSContext* cx) const
    1382             : {
    1383           0 :     MOZ_ASSERT(isFunctionFrame());
    1384             : 
    1385           0 :     switch (data_.state_) {
    1386             :       case DONE:
    1387             :         break;
    1388             :       case JIT:
    1389           0 :         if (isIonScripted()) {
    1390           0 :             jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
    1391           0 :             return ionInlineFrames_.thisArgument(recover);
    1392             :         }
    1393           0 :         return jsJitFrame().baselineFrame()->thisArgument();
    1394             :       case INTERP:
    1395           0 :         return interpFrame()->thisArgument();
    1396             :     }
    1397           0 :     MOZ_CRASH("Unexpected state");
    1398             : }
    1399             : 
    1400             : Value
    1401          20 : FrameIter::newTarget() const
    1402             : {
    1403          20 :     switch (data_.state_) {
    1404             :       case DONE:
    1405             :         break;
    1406             :       case INTERP:
    1407           0 :         return interpFrame()->newTarget();
    1408             :       case JIT:
    1409           0 :         MOZ_ASSERT(jsJitFrame().isBaselineJS());
    1410           0 :         return jsJitFrame().baselineFrame()->newTarget();
    1411             :     }
    1412           0 :     MOZ_CRASH("Unexpected state");
    1413             : }
    1414             : 
    1415             : Value
    1416           0 : FrameIter::returnValue() const
    1417             : {
    1418           0 :     switch (data_.state_) {
    1419             :       case DONE:
    1420             :         break;
    1421             :       case JIT:
    1422           0 :         if (jsJitFrame().isBaselineJS())
    1423           0 :             return jsJitFrame().baselineFrame()->returnValue();
    1424             :         break;
    1425             :       case INTERP:
    1426           0 :         return interpFrame()->returnValue();
    1427             :     }
    1428           0 :     MOZ_CRASH("Unexpected state");
    1429             : }
    1430             : 
    1431             : void
    1432           0 : FrameIter::setReturnValue(const Value& v)
    1433             : {
    1434           0 :     switch (data_.state_) {
    1435             :       case DONE:
    1436             :         break;
    1437             :       case JIT:
    1438           0 :         if (jsJitFrame().isBaselineJS()) {
    1439           0 :             jsJitFrame().baselineFrame()->setReturnValue(v);
    1440             :             return;
    1441             :         }
    1442             :         break;
    1443             :       case INTERP:
    1444           0 :         interpFrame()->setReturnValue(v);
    1445             :         return;
    1446             :     }
    1447           0 :     MOZ_CRASH("Unexpected state");
    1448             : }
    1449             : 
    1450             : size_t
    1451           2 : FrameIter::numFrameSlots() const
    1452             : {
    1453           2 :     switch (data_.state_) {
    1454             :       case DONE:
    1455             :         break;
    1456             :       case JIT: {
    1457           0 :         if (isIonScripted()) {
    1458           0 :             return ionInlineFrames_.snapshotIterator().numAllocations() -
    1459           0 :                    ionInlineFrames_.script()->nfixed();
    1460             :         }
    1461           0 :         jit::BaselineFrame* frame = jsJitFrame().baselineFrame();
    1462           0 :         return frame->numValueSlots() - jsJitFrame().script()->nfixed();
    1463             :       }
    1464             :       case INTERP:
    1465           1 :         MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
    1466           4 :         return data_.interpFrames_.sp() - interpFrame()->base();
    1467             :     }
    1468           0 :     MOZ_CRASH("Unexpected state");
    1469             : }
    1470             : 
    1471             : Value
    1472           2 : FrameIter::frameSlotValue(size_t index) const
    1473             : {
    1474           2 :     switch (data_.state_) {
    1475             :       case DONE:
    1476             :         break;
    1477             :       case JIT:
    1478           0 :         if (isIonScripted()) {
    1479           0 :             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
    1480           0 :             index += ionInlineFrames_.script()->nfixed();
    1481           0 :             return si.maybeReadAllocByIndex(index);
    1482             :         }
    1483           0 :         index += jsJitFrame().script()->nfixed();
    1484           0 :         return *jsJitFrame().baselineFrame()->valueSlot(index);
    1485             :       case INTERP:
    1486           4 :           return interpFrame()->base()[index];
    1487             :     }
    1488           0 :     MOZ_CRASH("Unexpected state");
    1489             : }
    1490             : 
    1491             : #ifdef DEBUG
    1492             : bool
    1493         171 : js::SelfHostedFramesVisible()
    1494             : {
    1495             :     static bool checked = false;
    1496             :     static bool visible = false;
    1497           0 :     if (!checked) {
    1498           1 :         checked = true;
    1499           0 :         char* env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
    1500           1 :         visible = !!env;
    1501             :     }
    1502         171 :     return visible;
    1503             : }
    1504             : #endif
    1505             : 
    1506             : void
    1507           0 : NonBuiltinFrameIter::settle()
    1508             : {
    1509         171 :     if (!SelfHostedFramesVisible()) {
    1510           0 :         while (!done() && hasScript() && script()->selfHosted())
    1511          41 :             FrameIter::operator++();
    1512             :     }
    1513           0 : }
    1514             : 
    1515             : void
    1516           0 : NonBuiltinScriptFrameIter::settle()
    1517             : {
    1518           0 :     if (!SelfHostedFramesVisible()) {
    1519           0 :         while (!done() && script()->selfHosted())
    1520           0 :             ScriptFrameIter::operator++();
    1521             :     }
    1522           0 : }
    1523             : 
    1524           0 : ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx)
    1525           0 :   : cx_(cx), entryMonitor_(cx->entryMonitor)
    1526             : {
    1527       45334 :     cx->entryMonitor = nullptr;
    1528           0 : }
    1529             : 
    1530             : Value
    1531           0 : ActivationEntryMonitor::asyncStack(JSContext* cx)
    1532             : {
    1533           0 :     RootedValue stack(cx, ObjectOrNullValue(cx->asyncStackForNewActivations()));
    1534           0 :     if (!cx->compartment()->wrap(cx, &stack)) {
    1535           0 :         cx->clearPendingException();
    1536           0 :         return UndefinedValue();
    1537             :     }
    1538           0 :     return stack;
    1539             : }
    1540             : 
    1541           0 : ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame)
    1542        7004 :   : ActivationEntryMonitor(cx)
    1543             : {
    1544           0 :     if (entryMonitor_) {
    1545             :         // The InterpreterFrame is not yet part of an Activation, so it won't
    1546             :         // be traced if we trigger GC here. Suppress GC to avoid this.
    1547           0 :         gc::AutoSuppressGC suppressGC(cx);
    1548           0 :         RootedValue stack(cx, asyncStack(cx));
    1549           0 :         const char* asyncCause = cx->asyncCauseForNewActivations;
    1550           0 :         if (entryFrame->isFunctionFrame())
    1551           0 :             entryMonitor_->Entry(cx, &entryFrame->callee(), stack, asyncCause);
    1552             :         else
    1553           0 :             entryMonitor_->Entry(cx, entryFrame->script(), stack, asyncCause);
    1554             :     }
    1555           0 : }
    1556             : 
    1557           0 : ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken)
    1558       15663 :   : ActivationEntryMonitor(cx)
    1559             : {
    1560           0 :     if (entryMonitor_) {
    1561             :         // The CalleeToken is not traced at this point and we also don't want
    1562             :         // a GC to discard the code we're about to enter, so we suppress GC.
    1563           0 :         gc::AutoSuppressGC suppressGC(cx);
    1564           0 :         RootedValue stack(cx, asyncStack(cx));
    1565           0 :         const char* asyncCause = cx->asyncCauseForNewActivations;
    1566           0 :         if (jit::CalleeTokenIsFunction(entryToken))
    1567           0 :             entryMonitor_->Entry(cx_, jit::CalleeTokenToFunction(entryToken), stack, asyncCause);
    1568             :         else
    1569           0 :             entryMonitor_->Entry(cx_, jit::CalleeTokenToScript(entryToken), stack, asyncCause);
    1570             :     }
    1571       15663 : }
    1572             : 
    1573             : /*****************************************************************************/
    1574             : 
    1575       15663 : jit::JitActivation::JitActivation(JSContext* cx)
    1576             :   : Activation(cx, Jit),
    1577             :     packedExitFP_(nullptr),
    1578             :     encodedWasmExitReason_(0),
    1579             :     prevJitActivation_(cx->jitActivation),
    1580             :     rematerializedFrames_(nullptr),
    1581             :     ionRecovery_(cx),
    1582             :     bailoutData_(nullptr),
    1583             :     lastProfilingFrame_(nullptr),
    1584           0 :     lastProfilingCallSite_(nullptr)
    1585             : {
    1586       31324 :     cx->jitActivation = this;
    1587           0 :     registerProfiling();
    1588       15662 : }
    1589             : 
    1590           0 : jit::JitActivation::~JitActivation()
    1591             : {
    1592       15662 :     if (isProfiling())
    1593       15662 :         unregisterProfiling();
    1594           0 :     cx_->jitActivation = prevJitActivation_;
    1595             : 
    1596             :     // All reocvered value are taken from activation during the bailout.
    1597       15662 :     MOZ_ASSERT(ionRecovery_.empty());
    1598             : 
    1599             :     // The BailoutFrameInfo should have unregistered itself from the
    1600             :     // JitActivations.
    1601           0 :     MOZ_ASSERT(!bailoutData_);
    1602             : 
    1603             :     // Traps get handled immediately.
    1604           0 :     MOZ_ASSERT(!isWasmTrapping());
    1605             : 
    1606       15662 :     clearRematerializedFrames();
    1607       31324 :     js_delete(rematerializedFrames_);
    1608           0 : }
    1609             : 
    1610             : void
    1611           0 : jit::JitActivation::setBailoutData(jit::BailoutFrameInfo* bailoutData)
    1612             : {
    1613          29 :     MOZ_ASSERT(!bailoutData_);
    1614          29 :     bailoutData_ = bailoutData;
    1615           0 : }
    1616             : 
    1617             : void
    1618           0 : jit::JitActivation::cleanBailoutData()
    1619             : {
    1620          29 :     MOZ_ASSERT(bailoutData_);
    1621          29 :     bailoutData_ = nullptr;
    1622           0 : }
    1623             : 
    1624             : void
    1625           0 : jit::JitActivation::removeRematerializedFrame(uint8_t* top)
    1626             : {
    1627           0 :     if (!rematerializedFrames_)
    1628             :         return;
    1629             : 
    1630           0 :     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
    1631           0 :         RematerializedFrame::FreeInVector(p->value());
    1632           0 :         rematerializedFrames_->remove(p);
    1633             :     }
    1634             : }
    1635             : 
    1636             : void
    1637       15662 : jit::JitActivation::clearRematerializedFrames()
    1638             : {
    1639           0 :     if (!rematerializedFrames_)
    1640             :         return;
    1641             : 
    1642           0 :     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
    1643           0 :         RematerializedFrame::FreeInVector(e.front().value());
    1644           0 :         e.removeFront();
    1645             :     }
    1646             : }
    1647             : 
    1648             : jit::RematerializedFrame*
    1649           0 : jit::JitActivation::getRematerializedFrame(JSContext* cx, const JSJitFrameIter& iter,
    1650             :                                            size_t inlineDepth)
    1651             : {
    1652           0 :     MOZ_ASSERT(iter.activation() == this);
    1653           0 :     MOZ_ASSERT(iter.isIonScripted());
    1654             : 
    1655           0 :     if (!rematerializedFrames_) {
    1656           0 :         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
    1657           0 :         if (!rematerializedFrames_)
    1658             :             return nullptr;
    1659           0 :         if (!rematerializedFrames_->init()) {
    1660           0 :             rematerializedFrames_ = nullptr;
    1661           0 :             ReportOutOfMemory(cx);
    1662           0 :             return nullptr;
    1663             :         }
    1664             :     }
    1665             : 
    1666           0 :     uint8_t* top = iter.fp();
    1667           0 :     RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
    1668           0 :     if (!p) {
    1669           0 :         RematerializedFrameVector frames(cx);
    1670             : 
    1671             :         // The unit of rematerialization is an uninlined frame and its inlined
    1672             :         // frames. Since inlined frames do not exist outside of snapshots, it
    1673             :         // is impossible to synchronize their rematerialized copies to
    1674             :         // preserve identity. Therefore, we always rematerialize an uninlined
    1675             :         // frame and all its inlined frames at once.
    1676           0 :         InlineFrameIterator inlineIter(cx, &iter);
    1677           0 :         MaybeReadFallback recover(cx, this, &iter);
    1678             : 
    1679             :         // Frames are often rematerialized with the cx inside a Debugger's
    1680             :         // realm. To recover slots and to create CallObjects, we need to
    1681             :         // be in the script's realm.
    1682           0 :         AutoRealmUnchecked ar(cx, iter.script()->realm());
    1683             : 
    1684           0 :         if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover, frames))
    1685           0 :             return nullptr;
    1686             : 
    1687           0 :         if (!rematerializedFrames_->add(p, top, std::move(frames))) {
    1688           0 :             ReportOutOfMemory(cx);
    1689           0 :             return nullptr;
    1690             :         }
    1691             : 
    1692             :         // See comment in unsetPrevUpToDateUntil.
    1693           0 :         DebugEnvironments::unsetPrevUpToDateUntil(cx, p->value()[inlineDepth]);
    1694             :     }
    1695             : 
    1696           0 :     return p->value()[inlineDepth];
    1697             : }
    1698             : 
    1699             : jit::RematerializedFrame*
    1700          29 : jit::JitActivation::lookupRematerializedFrame(uint8_t* top, size_t inlineDepth)
    1701             : {
    1702           0 :     if (!rematerializedFrames_)
    1703             :         return nullptr;
    1704           0 :     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
    1705           0 :         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
    1706           0 :     return nullptr;
    1707             : }
    1708             : 
    1709             : void
    1710           0 : jit::JitActivation::removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top)
    1711             : {
    1712             :     // Ion bailout can fail due to overrecursion and OOM. In such cases we
    1713             :     // cannot honor any further Debugger hooks on the frame, and need to
    1714             :     // ensure that its Debugger.Frame entry is cleaned up.
    1715           0 :     if (!cx->realm()->isDebuggee() || !rematerializedFrames_)
    1716             :         return;
    1717           0 :     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
    1718           0 :         for (uint32_t i = 0; i < p->value().length(); i++)
    1719           0 :             Debugger::handleUnrecoverableIonBailoutError(cx, p->value()[i]);
    1720             :     }
    1721             : }
    1722             : 
    1723             : void
    1724           9 : jit::JitActivation::traceRematerializedFrames(JSTracer* trc)
    1725             : {
    1726           0 :     if (!rematerializedFrames_)
    1727             :         return;
    1728           0 :     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront())
    1729           0 :         e.front().value().trace(trc);
    1730             : }
    1731             : 
    1732             : bool
    1733           0 : jit::JitActivation::registerIonFrameRecovery(RInstructionResults&& results)
    1734             : {
    1735             :     // Check that there is no entry in the vector yet.
    1736          14 :     MOZ_ASSERT(!maybeIonFrameRecovery(results.frame()));
    1737           0 :     if (!ionRecovery_.append(std::move(results)))
    1738             :         return false;
    1739             : 
    1740          14 :     return true;
    1741             : }
    1742             : 
    1743             : jit::RInstructionResults*
    1744           0 : jit::JitActivation::maybeIonFrameRecovery(JitFrameLayout* fp)
    1745             : {
    1746         142 :     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); ) {
    1747          28 :         if (it->frame() == fp)
    1748             :             return it;
    1749             :     }
    1750             : 
    1751             :     return nullptr;
    1752             : }
    1753             : 
    1754             : void
    1755           0 : jit::JitActivation::removeIonFrameRecovery(JitFrameLayout* fp)
    1756             : {
    1757          29 :     RInstructionResults* elem = maybeIonFrameRecovery(fp);
    1758           0 :     if (!elem)
    1759             :         return;
    1760             : 
    1761          14 :     ionRecovery_.erase(elem);
    1762             : }
    1763             : 
    1764             : void
    1765           1 : jit::JitActivation::traceIonRecovery(JSTracer* trc)
    1766             : {
    1767          18 :     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++)
    1768           0 :         it->trace(trc);
    1769           0 : }
    1770             : 
    1771             : void
    1772           0 : jit::JitActivation::startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset,
    1773             :                                   const wasm::RegisterState& state)
    1774             : {
    1775           0 :     MOZ_ASSERT(!isWasmTrapping());
    1776             : 
    1777             :     bool unwound;
    1778           0 :     wasm::UnwindState unwindState;
    1779           0 :     MOZ_ALWAYS_TRUE(wasm::StartUnwinding(state, &unwindState, &unwound));
    1780           0 :     MOZ_ASSERT(unwound == (trap == wasm::Trap::IndirectCallBadSig));
    1781             : 
    1782           0 :     void* pc = unwindState.pc;
    1783           0 :     wasm::Frame* fp = unwindState.fp;
    1784             : 
    1785           0 :     const wasm::Code& code = fp->tls->instance->code();
    1786           0 :     MOZ_RELEASE_ASSERT(&code == wasm::LookupCode(pc));
    1787             : 
    1788             :     // If the frame was unwound, the bytecodeOffset must be recovered from the
    1789             :     // callsite so that it is accurate.
    1790           0 :     if (unwound)
    1791           0 :         bytecodeOffset = code.lookupCallSite(pc)->lineOrBytecode();
    1792             : 
    1793           0 :     setWasmExitFP(fp);
    1794           0 :     wasmTrapData_.emplace();
    1795           0 :     wasmTrapData_->resumePC = ((uint8_t*)state.pc) + jit::WasmTrapInstructionLength;
    1796           0 :     wasmTrapData_->unwoundPC = pc;
    1797           0 :     wasmTrapData_->trap = trap;
    1798           0 :     wasmTrapData_->bytecodeOffset = bytecodeOffset;
    1799             : 
    1800           0 :     MOZ_ASSERT(isWasmTrapping());
    1801           0 : }
    1802             : 
    1803             : void
    1804           0 : jit::JitActivation::finishWasmTrap()
    1805             : {
    1806           0 :     MOZ_ASSERT(isWasmTrapping());
    1807           0 :     packedExitFP_ = nullptr;
    1808           0 :     wasmTrapData_.reset();
    1809           0 :     MOZ_ASSERT(!isWasmTrapping());
    1810           0 : }
    1811             : 
    1812             : InterpreterFrameIterator&
    1813           0 : InterpreterFrameIterator::operator++()
    1814             : {
    1815           0 :     MOZ_ASSERT(!done());
    1816           0 :     if (fp_ != activation_->entryFrame_) {
    1817        2495 :         pc_ = fp_->prevpc();
    1818           0 :         sp_ = fp_->prevsp();
    1819           0 :         fp_ = fp_->prev();
    1820             :     } else {
    1821        1861 :         pc_ = nullptr;
    1822           0 :         sp_ = nullptr;
    1823        1861 :         fp_ = nullptr;
    1824             :     }
    1825        4356 :     return *this;
    1826             : }
    1827             : 
    1828             : void
    1829           0 : Activation::registerProfiling()
    1830             : {
    1831       15662 :     MOZ_ASSERT(isProfiling());
    1832       15662 :     cx_->profilingActivation_ = this;
    1833           0 : }
    1834             : 
    1835             : void
    1836           0 : Activation::unregisterProfiling()
    1837             : {
    1838           0 :     MOZ_ASSERT(isProfiling());
    1839       15662 :     MOZ_ASSERT(cx_->profilingActivation_ == this);
    1840           0 :     cx_->profilingActivation_ = prevProfiling_;
    1841           0 : }
    1842             : 
    1843           0 : ActivationIterator::ActivationIterator(JSContext* cx)
    1844           0 :   : activation_(cx->activation_)
    1845             : {
    1846       23358 :     MOZ_ASSERT(cx == TlsContext.get());
    1847           0 : }
    1848             : 
    1849             : ActivationIterator&
    1850           0 : ActivationIterator::operator++()
    1851             : {
    1852       20490 :     MOZ_ASSERT(activation_);
    1853       20490 :     activation_ = activation_->prev();
    1854           0 :     return *this;
    1855             : }
    1856             : 
    1857           0 : JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const RegisterState& state,
    1858           0 :                                                    const Maybe<uint64_t>& samplePositionInProfilerBuffer)
    1859             :   : cx_(cx),
    1860             :     samplePositionInProfilerBuffer_(samplePositionInProfilerBuffer),
    1861           0 :     activation_(nullptr)
    1862             : {
    1863           0 :     if (!cx->runtime()->geckoProfiler().enabled())
    1864           0 :         MOZ_CRASH("ProfilingFrameIterator called when geckoProfiler not enabled for runtime.");
    1865             : 
    1866           0 :     if (!cx->profilingActivation())
    1867             :         return;
    1868             : 
    1869             :     // If profiler sampling is not enabled, skip.
    1870           0 :     if (!cx->isProfilerSamplingEnabled())
    1871             :         return;
    1872             : 
    1873           0 :     activation_ = cx->profilingActivation();
    1874             : 
    1875           0 :     MOZ_ASSERT(activation_->isProfiling());
    1876             : 
    1877             :     static_assert(sizeof(wasm::ProfilingFrameIterator) <= StorageSpace &&
    1878             :                   sizeof(jit::JSJitProfilingFrameIterator) <= StorageSpace,
    1879             :                   "ProfilingFrameIterator::storage_ is too small");
    1880             :     static_assert(alignof(void*) >= alignof(wasm::ProfilingFrameIterator) &&
    1881             :                   alignof(void*) >= alignof(jit::JSJitProfilingFrameIterator),
    1882             :                   "ProfilingFrameIterator::storage_ is too weakly aligned");
    1883             : 
    1884           0 :     iteratorConstruct(state);
    1885           0 :     settle();
    1886             : }
    1887             : 
    1888           0 : JS::ProfilingFrameIterator::~ProfilingFrameIterator()
    1889             : {
    1890           0 :     if (!done()) {
    1891           0 :         MOZ_ASSERT(activation_->isProfiling());
    1892           0 :         iteratorDestroy();
    1893             :     }
    1894           0 : }
    1895             : 
    1896             : void
    1897           0 : JS::ProfilingFrameIterator::operator++()
    1898             : {
    1899           0 :     MOZ_ASSERT(!done());
    1900           0 :     MOZ_ASSERT(activation_->isJit());
    1901           0 :     if (isWasm())
    1902           0 :         ++wasmIter();
    1903             :     else
    1904           0 :         ++jsJitIter();
    1905           0 :     settle();
    1906           0 : }
    1907             : 
    1908             : void
    1909           0 : JS::ProfilingFrameIterator::settleFrames()
    1910             : {
    1911             :     // Handle transition frames (see comment in JitFrameIter::operator++).
    1912           0 :     if (isJSJit() && !jsJitIter().done() && jsJitIter().frameType() == jit::JitFrame_WasmToJSJit) {
    1913           0 :         wasm::Frame* fp = (wasm::Frame*) jsJitIter().fp();
    1914           0 :         iteratorDestroy();
    1915           0 :         new (storage()) wasm::ProfilingFrameIterator(*activation_->asJit(), fp);
    1916           0 :         kind_ = Kind::Wasm;
    1917           0 :         MOZ_ASSERT(!wasmIter().done());
    1918             :         return;
    1919             :     }
    1920             : 
    1921           0 :     if (isWasm() && wasmIter().done() && wasmIter().unwoundIonCallerFP()) {
    1922           0 :         uint8_t* fp = wasmIter().unwoundIonCallerFP();
    1923           0 :         iteratorDestroy();
    1924             :         // Using this ctor will skip the first ion->wasm frame, which is
    1925             :         // needed because the profiling iterator doesn't know how to unwind
    1926             :         // when the callee has no script.
    1927           0 :         new (storage()) jit::JSJitProfilingFrameIterator((jit::CommonFrameLayout*)fp);
    1928           0 :         kind_ = Kind::JSJit;
    1929           0 :         MOZ_ASSERT(!jsJitIter().done());
    1930             :         return;
    1931             :     }
    1932             : }
    1933             : 
    1934             : void
    1935           0 : JS::ProfilingFrameIterator::settle()
    1936             : {
    1937           0 :     settleFrames();
    1938           0 :     while (iteratorDone()) {
    1939           0 :         iteratorDestroy();
    1940           0 :         activation_ = activation_->prevProfiling();
    1941           0 :         if (!activation_)
    1942             :             return;
    1943           0 :         iteratorConstruct();
    1944           0 :         settleFrames();
    1945             :     }
    1946             : }
    1947             : 
    1948             : void
    1949           0 : JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
    1950             : {
    1951           0 :     MOZ_ASSERT(!done());
    1952           0 :     MOZ_ASSERT(activation_->isJit());
    1953             : 
    1954           0 :     jit::JitActivation* activation = activation_->asJit();
    1955             : 
    1956             :     // We want to know if we should start with a wasm profiling frame iterator
    1957             :     // or not. To determine this, there are three possibilities:
    1958             :     // - we've exited to C++ from wasm, in which case the activation
    1959             :     //   exitFP low bit is tagged and we can test hasWasmExitFP().
    1960             :     // - we're in wasm code, so we can do a lookup on PC.
    1961             :     // - in all the other cases, we're not in wasm or we haven't exited from
    1962             :     //   wasm.
    1963           0 :     if (activation->hasWasmExitFP() || wasm::InCompiledCode(state.pc)) {
    1964           0 :         new (storage()) wasm::ProfilingFrameIterator(*activation, state);
    1965           0 :         kind_ = Kind::Wasm;
    1966           0 :         return;
    1967             :     }
    1968             : 
    1969           0 :     new (storage()) jit::JSJitProfilingFrameIterator(cx_, state.pc);
    1970           0 :     kind_ = Kind::JSJit;
    1971             : }
    1972             : 
    1973             : void
    1974           0 : JS::ProfilingFrameIterator::iteratorConstruct()
    1975             : {
    1976           0 :     MOZ_ASSERT(!done());
    1977           0 :     MOZ_ASSERT(activation_->isJit());
    1978             : 
    1979           0 :     jit::JitActivation* activation = activation_->asJit();
    1980             : 
    1981             :     // The same reasoning as in the above iteratorConstruct variant applies
    1982             :     // here, except that it's even simpler: since this activation is higher up
    1983             :     // on the stack, it can only have exited to C++, through wasm or ion.
    1984           0 :     if (activation->hasWasmExitFP()) {
    1985           0 :         new (storage()) wasm::ProfilingFrameIterator(*activation);
    1986           0 :         kind_ = Kind::Wasm;
    1987           0 :         return;
    1988             :     }
    1989             : 
    1990           0 :     auto* fp = (jit::ExitFrameLayout*) activation->jsExitFP();
    1991           0 :     new (storage()) jit::JSJitProfilingFrameIterator(fp);
    1992           0 :     kind_ = Kind::JSJit;
    1993             : }
    1994             : 
    1995             : void
    1996           0 : JS::ProfilingFrameIterator::iteratorDestroy()
    1997             : {
    1998           0 :     MOZ_ASSERT(!done());
    1999           0 :     MOZ_ASSERT(activation_->isJit());
    2000             : 
    2001           0 :     if (isWasm()) {
    2002           0 :         wasmIter().~ProfilingFrameIterator();
    2003           0 :         return;
    2004             :     }
    2005             : 
    2006           0 :     jsJitIter().~JSJitProfilingFrameIterator();
    2007             : }
    2008             : 
    2009             : bool
    2010           0 : JS::ProfilingFrameIterator::iteratorDone()
    2011             : {
    2012           0 :     MOZ_ASSERT(!done());
    2013           0 :     MOZ_ASSERT(activation_->isJit());
    2014             : 
    2015           0 :     if (isWasm())
    2016           0 :         return wasmIter().done();
    2017             : 
    2018           0 :     return jsJitIter().done();
    2019             : }
    2020             : 
    2021             : void*
    2022           0 : JS::ProfilingFrameIterator::stackAddress() const
    2023             : {
    2024           0 :     MOZ_ASSERT(!done());
    2025           0 :     MOZ_ASSERT(activation_->isJit());
    2026             : 
    2027           0 :     if (isWasm())
    2028           0 :         return wasmIter().stackAddress();
    2029             : 
    2030           0 :     return jsJitIter().stackAddress();
    2031             : }
    2032             : 
    2033             : Maybe<JS::ProfilingFrameIterator::Frame>
    2034           0 : JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry* entry) const
    2035             : {
    2036           0 :     void* stackAddr = stackAddress();
    2037             : 
    2038           0 :     if (isWasm()) {
    2039             :         Frame frame;
    2040           0 :         frame.kind = Frame_Wasm;
    2041           0 :         frame.stackAddress = stackAddr;
    2042           0 :         frame.returnAddress = nullptr;
    2043           0 :         frame.activation = activation_;
    2044           0 :         frame.label = nullptr;
    2045           0 :         frame.endStackAddress = activation_->asJit()->jsOrWasmExitFP();
    2046           0 :         return mozilla::Some(frame);
    2047             :     }
    2048             : 
    2049           0 :     MOZ_ASSERT(isJSJit());
    2050             : 
    2051             :     // Look up an entry for the return address.
    2052           0 :     void* returnAddr = jsJitIter().returnAddressToFp();
    2053           0 :     jit::JitcodeGlobalTable* table = cx_->runtime()->jitRuntime()->getJitcodeGlobalTable();
    2054           0 :     if (samplePositionInProfilerBuffer_)
    2055           0 :         *entry = table->lookupForSamplerInfallible(returnAddr, cx_->runtime(),
    2056           0 :                                                    *samplePositionInProfilerBuffer_);
    2057             :     else
    2058           0 :         *entry = table->lookupInfallible(returnAddr);
    2059             : 
    2060           0 :     MOZ_ASSERT(entry->isIon() || entry->isIonCache() || entry->isBaseline() || entry->isDummy());
    2061             : 
    2062             :     // Dummy frames produce no stack frames.
    2063           0 :     if (entry->isDummy())
    2064             :         return mozilla::Nothing();
    2065             : 
    2066             :     Frame frame;
    2067           0 :     frame.kind = entry->isBaseline() ? Frame_Baseline : Frame_Ion;
    2068           0 :     frame.stackAddress = stackAddr;
    2069           0 :     frame.returnAddress = returnAddr;
    2070           0 :     frame.activation = activation_;
    2071           0 :     frame.label = nullptr;
    2072           0 :     frame.endStackAddress = activation_->asJit()->jsOrWasmExitFP();
    2073             :     return mozilla::Some(frame);
    2074             : }
    2075             : 
    2076             : uint32_t
    2077           0 : JS::ProfilingFrameIterator::extractStack(Frame* frames, uint32_t offset, uint32_t end) const
    2078             : {
    2079           0 :     if (offset >= end)
    2080             :         return 0;
    2081             : 
    2082           0 :     jit::JitcodeGlobalEntry entry;
    2083           0 :     Maybe<Frame> physicalFrame = getPhysicalFrameAndEntry(&entry);
    2084             : 
    2085             :     // Dummy frames produce no stack frames.
    2086           0 :     if (physicalFrame.isNothing())
    2087             :         return 0;
    2088             : 
    2089           0 :     if (isWasm()) {
    2090           0 :         frames[offset] = physicalFrame.value();
    2091           0 :         frames[offset].label = wasmIter().label();
    2092           0 :         return 1;
    2093             :     }
    2094             : 
    2095             :     // Extract the stack for the entry.  Assume maximum inlining depth is <64
    2096             :     const char* labels[64];
    2097           0 :     uint32_t depth = entry.callStackAtAddr(cx_->runtime(), jsJitIter().returnAddressToFp(),
    2098           0 :                                            labels, ArrayLength(labels));
    2099           0 :     MOZ_ASSERT(depth < ArrayLength(labels));
    2100           0 :     for (uint32_t i = 0; i < depth; i++) {
    2101           0 :         if (offset + i >= end)
    2102             :             return i;
    2103           0 :         frames[offset + i] = physicalFrame.value();
    2104           0 :         frames[offset + i].label = labels[i];
    2105             :     }
    2106             : 
    2107             :     return depth;
    2108             : }
    2109             : 
    2110             : Maybe<JS::ProfilingFrameIterator::Frame>
    2111           0 : JS::ProfilingFrameIterator::getPhysicalFrameWithoutLabel() const
    2112             : {
    2113           0 :     jit::JitcodeGlobalEntry unused;
    2114           0 :     return getPhysicalFrameAndEntry(&unused);
    2115             : }
    2116             : 
    2117             : bool
    2118           0 : JS::ProfilingFrameIterator::isWasm() const
    2119             : {
    2120           0 :     MOZ_ASSERT(!done());
    2121           0 :     return kind_ == Kind::Wasm;
    2122             : }
    2123             : 
    2124             : bool
    2125             : JS::ProfilingFrameIterator::isJSJit() const
    2126             : {
    2127             :     return kind_ == Kind::JSJit;
    2128             : }

Generated by: LCOV version 1.13-14-ga5dd952