js/src/vm/Stack.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "vm/Stack-inl.h"
     9 #include "mozilla/PodOperations.h"
    11 #include "jscntxt.h"
    13 #include "gc/Marking.h"
    14 #ifdef JS_ION
    15 #include "jit/AsmJSModule.h"
    16 #include "jit/BaselineFrame.h"
    17 #include "jit/JitCompartment.h"
    18 #endif
    19 #include "js/GCAPI.h"
    20 #include "vm/Opcodes.h"
    22 #include "jit/JitFrameIterator-inl.h"
    23 #include "vm/Interpreter-inl.h"
    24 #include "vm/Probes-inl.h"
    25 #include "vm/ScopeObject-inl.h"
    27 using namespace js;
    29 using mozilla::PodCopy;
    31 /*****************************************************************************/
    33 void
    34 InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev,
    35                                    const Value &thisv, JSObject &scopeChain, ExecuteType type)
    36 {
    37     /*
    38      * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
    39      * script in the context of another frame and the frame type is determined
    40      * by the context.
    41      */
    42     flags_ = type | HAS_SCOPECHAIN;
    44     JSObject *callee = nullptr;
    45     if (!(flags_ & (GLOBAL))) {
    46         if (evalInFramePrev) {
    47             JS_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
    48             if (evalInFramePrev.isFunctionFrame()) {
    49                 callee = evalInFramePrev.callee();
    50                 flags_ |= FUNCTION;
    51             } else {
    52                 flags_ |= GLOBAL;
    53             }
    54         } else {
    55             FrameIter iter(cx);
    56             JS_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame());
    57             JS_ASSERT(!iter.isAsmJS());
    58             if (iter.isFunctionFrame()) {
    59                 callee = iter.callee();
    60                 flags_ |= FUNCTION;
    61             } else {
    62                 flags_ |= GLOBAL;
    63             }
    64         }
    65     }
    67     Value *dstvp = (Value *)this - 2;
    68     dstvp[1] = thisv;
    70     if (isFunctionFrame()) {
    71         dstvp[0] = ObjectValue(*callee);
    72         exec.fun = &callee->as<JSFunction>();
    73         u.evalScript = script;
    74     } else {
    75         JS_ASSERT(isGlobalFrame());
    76         dstvp[0] = NullValue();
    77         exec.script = script;
    78 #ifdef DEBUG
    79         u.evalScript = (JSScript *)0xbad;
    80 #endif
    81     }
    83     scopeChain_ = &scopeChain;
    84     prev_ = nullptr;
    85     prevpc_ = nullptr;
    86     prevsp_ = nullptr;
    88     JS_ASSERT_IF(evalInFramePrev, isDebuggerFrame());
    89     evalInFramePrev_ = evalInFramePrev;
    91 #ifdef DEBUG
    92     Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
    93     hookData_ = (void *)0xbad;
    94 #endif
    95 }
    97 template <InterpreterFrame::TriggerPostBarriers doPostBarrier>
    98 void
    99 InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
   100                                      const Value *othervp, Value *othersp)
   101 {
   102     JS_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin());
   103     JS_ASSERT(othersp >= otherfp->slots());
   104     JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots());
   106     /* Copy args, InterpreterFrame, and slots. */
   107     const Value *srcend = otherfp->generatorArgsSnapshotEnd();
   108     Value *dst = vp;
   109     for (const Value *src = othervp; src < srcend; src++, dst++) {
   110         *dst = *src;
   111         if (doPostBarrier)
   112             HeapValue::writeBarrierPost(*dst, dst);
   113     }
   115     *this = *otherfp;
   116     argv_ = vp + 2;
   117     unsetPushedSPSFrame();
   118     if (doPostBarrier)
   119         writeBarrierPost();
   121     srcend = othersp;
   122     dst = slots();
   123     for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) {
   124         *dst = *src;
   125         if (doPostBarrier)
   126             HeapValue::writeBarrierPost(*dst, dst);
   127     }
   128 }
   130 /* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */
   131 template
   132 void InterpreterFrame::copyFrameAndValues<InterpreterFrame::NoPostBarrier>(
   133                                     JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
   134 template
   135 void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>(
   136                                     JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
   138 void
   139 InterpreterFrame::writeBarrierPost()
   140 {
   141     /* This needs to follow the same rules as in InterpreterFrame::mark. */
   142     if (scopeChain_)
   143         JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
   144     if (flags_ & HAS_ARGS_OBJ)
   145         JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
   146     if (isFunctionFrame()) {
   147         JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
   148         if (isEvalFrame())
   149             JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
   150     } else {
   151         JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
   152     }
   153     if (hasReturnValue())
   154         HeapValue::writeBarrierPost(rval_, &rval_);
   155 }
   157 bool
   158 InterpreterFrame::copyRawFrameSlots(AutoValueVector *vec)
   159 {
   160     if (!vec->resize(numFormalArgs() + script()->nfixed()))
   161         return false;
   162     PodCopy(vec->begin(), argv(), numFormalArgs());
   163     PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed());
   164     return true;
   165 }
   167 JSObject *
   168 InterpreterFrame::createRestParameter(JSContext *cx)
   169 {
   170     JS_ASSERT(fun()->hasRest());
   171     unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs();
   172     unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
   173     Value *restvp = argv() + nformal;
   174     JSObject *obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr);
   175     if (!obj)
   176         return nullptr;
   177     types::FixRestArgumentsType(cx, obj);
   178     return obj;
   179 }
   181 static inline void
   182 AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject *scope)
   183 {
   184 #ifdef DEBUG
   185     RootedObject enclosingScope(cx, script->enclosingStaticScope());
   186     for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
   187         if (i.hasDynamicScopeObject()) {
   188             switch (i.type()) {
   189               case StaticScopeIter<NoGC>::BLOCK:
   190                 JS_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope());
   191                 scope = &scope->as<ClonedBlockObject>().enclosingScope();
   192                 break;
   193               case StaticScopeIter<NoGC>::WITH:
   194                 JS_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope());
   195                 scope = &scope->as<DynamicWithObject>().enclosingScope();
   196                 break;
   197               case StaticScopeIter<NoGC>::FUNCTION:
   198                 JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
   199                 scope = &scope->as<CallObject>().enclosingScope();
   200                 break;
   201               case StaticScopeIter<NoGC>::NAMED_LAMBDA:
   202                 scope = &scope->as<DeclEnvObject>().enclosingScope();
   203                 break;
   204             }
   205         }
   206     }
   208     /*
   209      * Ideally, we'd JS_ASSERT(!scope->is<ScopeObject>()) but the enclosing
   210      * lexical scope chain stops at eval() boundaries. See StaticScopeIter
   211      * comment.
   212      */
   213 #endif
   214 }
   216 bool
   217 InterpreterFrame::initFunctionScopeObjects(JSContext *cx)
   218 {
   219     CallObject *callobj = CallObject::createForFunction(cx, this);
   220     if (!callobj)
   221         return false;
   222     pushOnScopeChain(*callobj);
   223     flags_ |= HAS_CALL_OBJ;
   224     return true;
   225 }
   227 bool
   228 InterpreterFrame::prologue(JSContext *cx)
   229 {
   230     RootedScript script(cx, this->script());
   232     JS_ASSERT(!isGeneratorFrame());
   233     JS_ASSERT(cx->interpreterRegs().pc == script->code());
   235     if (isEvalFrame()) {
   236         if (script->strict()) {
   237             CallObject *callobj = CallObject::createForStrictEval(cx, this);
   238             if (!callobj)
   239                 return false;
   240             pushOnScopeChain(*callobj);
   241             flags_ |= HAS_CALL_OBJ;
   242         }
   243         return probes::EnterScript(cx, script, nullptr, this);
   244     }
   246     if (isGlobalFrame())
   247         return probes::EnterScript(cx, script, nullptr, this);
   249     JS_ASSERT(isNonEvalFunctionFrame());
   250     AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
   252     if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx))
   253         return false;
   255     if (isConstructing()) {
   256         RootedObject callee(cx, &this->callee());
   257         JSObject *obj = CreateThisForFunction(cx, callee,
   258                                               useNewType() ? SingletonObject : GenericObject);
   259         if (!obj)
   260             return false;
   261         functionThis() = ObjectValue(*obj);
   262     }
   264     return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
   265 }
   267 void
   268 InterpreterFrame::epilogue(JSContext *cx)
   269 {
   270     JS_ASSERT(!isYielding());
   272     RootedScript script(cx, this->script());
   273     probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
   275     if (isEvalFrame()) {
   276         if (isStrictEvalFrame()) {
   277             JS_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
   278             if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   279                 DebugScopes::onPopStrictEvalScope(this);
   280         } else if (isDirectEvalFrame()) {
   281             if (isDebuggerFrame())
   282                 JS_ASSERT(!scopeChain()->is<ScopeObject>());
   283         } else {
   284             /*
   285              * Debugger.Object.prototype.evalInGlobal creates indirect eval
   286              * frames scoped to the given global;
   287              * Debugger.Object.prototype.evalInGlobalWithBindings creates
   288              * indirect eval frames scoped to an object carrying the introduced
   289              * bindings.
   290              */
   291             if (isDebuggerFrame()) {
   292                 JS_ASSERT(scopeChain()->is<GlobalObject>() ||
   293                           scopeChain()->enclosingScope()->is<GlobalObject>());
   294             } else {
   295                 JS_ASSERT(scopeChain()->is<GlobalObject>());
   296             }
   297         }
   298         return;
   299     }
   301     if (isGlobalFrame()) {
   302         JS_ASSERT(!scopeChain()->is<ScopeObject>());
   303         return;
   304     }
   306     JS_ASSERT(isNonEvalFunctionFrame());
   308     if (fun()->isHeavyweight())
   309         JS_ASSERT_IF(hasCallObj(),
   310                      scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
   311     else
   312         AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
   314     if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   315         DebugScopes::onPopCall(this, cx);
   317     if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive())
   318         setReturnValue(ObjectValue(constructorThis()));
   319 }
   321 bool
   322 InterpreterFrame::pushBlock(JSContext *cx, StaticBlockObject &block)
   323 {
   324     JS_ASSERT (block.needsClone());
   326     Rooted<StaticBlockObject *> blockHandle(cx, &block);
   327     ClonedBlockObject *clone = ClonedBlockObject::create(cx, blockHandle, this);
   328     if (!clone)
   329         return false;
   331     pushOnScopeChain(*clone);
   333     return true;
   334 }
   336 void
   337 InterpreterFrame::popBlock(JSContext *cx)
   338 {
   339     JS_ASSERT(scopeChain_->is<ClonedBlockObject>());
   340     popOffScopeChain();
   341 }
   343 void
   344 InterpreterFrame::popWith(JSContext *cx)
   345 {
   346     if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   347         DebugScopes::onPopWith(this);
   349     JS_ASSERT(scopeChain()->is<DynamicWithObject>());
   350     popOffScopeChain();
   351 }
   353 void
   354 InterpreterFrame::mark(JSTracer *trc)
   355 {
   356     /*
   357      * Normally we would use MarkRoot here, except that generators also take
   358      * this path. However, generators use a special write barrier when the stack
   359      * frame is copied to the floating frame. Therefore, no barrier is needed.
   360      */
   361     if (flags_ & HAS_SCOPECHAIN)
   362         gc::MarkObjectUnbarriered(trc, &scopeChain_, "scope chain");
   363     if (flags_ & HAS_ARGS_OBJ)
   364         gc::MarkObjectUnbarriered(trc, &argsObj_, "arguments");
   365     if (isFunctionFrame()) {
   366         gc::MarkObjectUnbarriered(trc, &exec.fun, "fun");
   367         if (isEvalFrame())
   368             gc::MarkScriptUnbarriered(trc, &u.evalScript, "eval script");
   369     } else {
   370         gc::MarkScriptUnbarriered(trc, &exec.script, "script");
   371     }
   372     if (IS_GC_MARKING_TRACER(trc))
   373         script()->compartment()->zone()->active = true;
   374     gc::MarkValueUnbarriered(trc, returnValue().address(), "rval");
   375 }
   377 void
   378 InterpreterFrame::markValues(JSTracer *trc, unsigned start, unsigned end)
   379 {
   380     if (start < end)
   381         gc::MarkValueRootRange(trc, end - start, slots() + start, "vm_stack");
   382 }
   384 void
   385 InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
   386 {
   387     JS_ASSERT(sp >= slots());
   389     NestedScopeObject *staticScope;
   391     staticScope = script()->getStaticScope(pc);
   392     while (staticScope && !staticScope->is<StaticBlockObject>())
   393         staticScope = staticScope->enclosingNestedScope();
   395     size_t nfixed = script()->nfixed();
   396     size_t nlivefixed;
   398     if (staticScope) {
   399         StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
   400         nlivefixed = blockObj.localOffset() + blockObj.numVariables();
   401     } else {
   402         nlivefixed = script()->nfixedvars();
   403     }
   405     if (nfixed == nlivefixed) {
   406         // All locals are live.
   407         markValues(trc, 0, sp - slots());
   408     } else {
   409         // Mark operand stack.
   410         markValues(trc, nfixed, sp - slots());
   412         // Clear dead locals.
   413         while (nfixed > nlivefixed)
   414             unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined();
   416         // Mark live locals.
   417         markValues(trc, 0, nlivefixed);
   418     }
   420     if (hasArgs()) {
   421         // Mark callee, |this| and arguments.
   422         unsigned argc = Max(numActualArgs(), numFormalArgs());
   423         gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv");
   424     } else {
   425         // Mark callee and |this|
   426         gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
   427     }
   428 }
   430 static void
   431 MarkInterpreterActivation(JSTracer *trc, InterpreterActivation *act)
   432 {
   433     for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
   434         InterpreterFrame *fp = frames.frame();
   435         fp->markValues(trc, frames.sp(), frames.pc());
   436         fp->mark(trc);
   437     }
   438 }
   440 void
   441 js::MarkInterpreterActivations(JSRuntime *rt, JSTracer *trc)
   442 {
   443     for (ActivationIterator iter(rt); !iter.done(); ++iter) {
   444         Activation *act = iter.activation();
   445         if (act->isInterpreter())
   446             MarkInterpreterActivation(trc, act->asInterpreter());
   447     }
   449 }
   451 /*****************************************************************************/
   453 // Unlike the other methods of this calss, this method is defined here so that
   454 // we don't have to #include jsautooplen.h in vm/Stack.h.
   455 void
   456 InterpreterRegs::setToEndOfScript()
   457 {
   458     JSScript *script = fp()->script();
   459     sp = fp()->base();
   460     pc = script->codeEnd() - JSOP_RETRVAL_LENGTH;
   461     JS_ASSERT(*pc == JSOP_RETRVAL);
   462 }
   464 /*****************************************************************************/
   466 InterpreterFrame *
   467 InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial)
   468 {
   469     LifoAlloc::Mark mark = allocator_.mark();
   471     RootedFunction fun(cx, &args.callee().as<JSFunction>());
   472     RootedScript script(cx, fun->nonLazyScript());
   474     InterpreterFrame::Flags flags = ToFrameFlags(initial);
   475     Value *argv;
   476     InterpreterFrame *fp = getCallFrame(cx, args, script, &flags, &argv);
   477     if (!fp)
   478         return nullptr;
   480     fp->mark_ = mark;
   481     fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
   482     return fp;
   483 }
   485 InterpreterFrame *
   486 InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
   487                                    HandleObject scopeChain, ExecuteType type,
   488                                    AbstractFramePtr evalInFrame)
   489 {
   490     LifoAlloc::Mark mark = allocator_.mark();
   492     unsigned nvars = 2 /* callee, this */ + script->nslots();
   493     uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
   494     if (!buffer)
   495         return nullptr;
   497     InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value));
   498     fp->mark_ = mark;
   499     fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
   500     fp->initVarsToUndefined();
   502     return fp;
   503 }
   505 /*****************************************************************************/
   507 /* MSVC PGO causes xpcshell startup crashes. */
   508 #if defined(_MSC_VER)
   509 # pragma optimize("g", off)
   510 #endif
   512 void
   513 FrameIter::popActivation()
   514 {
   515     ++data_.activations_;
   516     settleOnActivation();
   517 }
   519 void
   520 FrameIter::popInterpreterFrame()
   521 {
   522     JS_ASSERT(data_.state_ == INTERP);
   524     ++data_.interpFrames_;
   526     if (data_.interpFrames_.done())
   527         popActivation();
   528     else
   529         data_.pc_ = data_.interpFrames_.pc();
   530 }
   532 void
   533 FrameIter::settleOnActivation()
   534 {
   535     while (true) {
   536         if (data_.activations_.done()) {
   537             data_.state_ = DONE;
   538             return;
   539         }
   541         Activation *activation = data_.activations_.activation();
   543         // If JS_SaveFrameChain was called, stop iterating here (unless
   544         // GO_THROUGH_SAVED is set).
   545         if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) {
   546             data_.state_ = DONE;
   547             return;
   548         }
   550         // Skip activations from another context if needed.
   551         JS_ASSERT(activation->cx());
   552         JS_ASSERT(data_.cx_);
   553         if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) {
   554             ++data_.activations_;
   555             continue;
   556         }
   558         // If the caller supplied principals, only show activations which are subsumed (of the same
   559         // origin or of an origin accessible) by these principals.
   560         if (data_.principals_) {
   561             if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) {
   562                 JS::AutoAssertNoGC nogc;
   563                 if (!subsumes(data_.principals_, activation->compartment()->principals)) {
   564                     ++data_.activations_;
   565                     continue;
   566                 }
   567             }
   568         }
   570 #ifdef JS_ION
   571         if (activation->isJit()) {
   572             data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
   574             // Stop at the first scripted frame.
   575             while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
   576                 ++data_.jitFrames_;
   578             // It's possible to have an JitActivation with no scripted frames,
   579             // for instance if we hit an over-recursion during bailout.
   580             if (data_.jitFrames_.done()) {
   581                 ++data_.activations_;
   582                 continue;
   583             }
   585             nextJitFrame();
   586             data_.state_ = JIT;
   587             return;
   588         }
   590         if (activation->isAsmJS()) {
   591             data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
   593             if (data_.asmJSFrames_.done()) {
   594                 ++data_.activations_;
   595                 continue;
   596             }
   598             data_.state_ = ASMJS;
   599             return;
   600         }
   602         // ForkJoin activations don't contain iterable frames, so skip them.
   603         if (activation->isForkJoin()) {
   604             ++data_.activations_;
   605             continue;
   606         }
   607 #endif
   609         JS_ASSERT(activation->isInterpreter());
   611         InterpreterActivation *interpAct = activation->asInterpreter();
   612         data_.interpFrames_ = InterpreterFrameIterator(interpAct);
   614         // If we OSR'ed into JIT code, skip the interpreter frame so that
   615         // the same frame is not reported twice.
   616         if (data_.interpFrames_.frame()->runningInJit()) {
   617             ++data_.interpFrames_;
   618             if (data_.interpFrames_.done()) {
   619                 ++data_.activations_;
   620                 continue;
   621             }
   622         }
   624         JS_ASSERT(!data_.interpFrames_.frame()->runningInJit());
   625         data_.pc_ = data_.interpFrames_.pc();
   626         data_.state_ = INTERP;
   627         return;
   628     }
   629 }
   631 FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption,
   632                       JSPrincipals *principals)
   633   : cx_(cx),
   634     savedOption_(savedOption),
   635     contextOption_(contextOption),
   636     principals_(principals),
   637     pc_(nullptr),
   638     interpFrames_(nullptr),
   639     activations_(cx->runtime())
   640 #ifdef JS_ION
   641   , jitFrames_((uint8_t *)nullptr, SequentialExecution)
   642   , ionInlineFrameNo_(0)
   643   , asmJSFrames_(nullptr)
   644 #endif
   645 {
   646 }
   648 FrameIter::Data::Data(const FrameIter::Data &other)
   649   : cx_(other.cx_),
   650     savedOption_(other.savedOption_),
   651     contextOption_(other.contextOption_),
   652     principals_(other.principals_),
   653     state_(other.state_),
   654     pc_(other.pc_),
   655     interpFrames_(other.interpFrames_),
   656     activations_(other.activations_)
   657 #ifdef JS_ION
   658   , jitFrames_(other.jitFrames_)
   659   , ionInlineFrameNo_(other.ionInlineFrameNo_)
   660   , asmJSFrames_(other.asmJSFrames_)
   661 #endif
   662 {
   663 }
   665 FrameIter::FrameIter(JSContext *cx, SavedOption savedOption)
   666   : data_(cx, savedOption, CURRENT_CONTEXT, nullptr)
   667 #ifdef JS_ION
   668   , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
   669 #endif
   670 {
   671     // settleOnActivation can only GC if principals are given.
   672     JS::AutoAssertNoGC nogc;
   673     settleOnActivation();
   674 }
   676 FrameIter::FrameIter(JSContext *cx, ContextOption contextOption,
   677                      SavedOption savedOption, JSPrincipals *principals)
   678   : data_(cx, savedOption, contextOption, principals)
   679 #ifdef JS_ION
   680   , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
   681 #endif
   682 {
   683     settleOnActivation();
   684 }
   686 FrameIter::FrameIter(const FrameIter &other)
   687   : data_(other.data_)
   688 #ifdef JS_ION
   689   , ionInlineFrames_(other.data_.cx_,
   690                      data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
   691 #endif
   692 {
   693 }
   695 FrameIter::FrameIter(const Data &data)
   696   : data_(data)
   697 #ifdef JS_ION
   698   , ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
   699 #endif
   700 {
   701     JS_ASSERT(data.cx_);
   703 #ifdef JS_ION
   704     if (data_.jitFrames_.isIonJS()) {
   705         while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
   706             ++ionInlineFrames_;
   707     }
   708 #endif
   709 }
   711 #ifdef JS_ION
   712 void
   713 FrameIter::nextJitFrame()
   714 {
   715     if (data_.jitFrames_.isIonJS()) {
   716         ionInlineFrames_.resetOn(&data_.jitFrames_);
   717         data_.pc_ = ionInlineFrames_.pc();
   718     } else {
   719         JS_ASSERT(data_.jitFrames_.isBaselineJS());
   720         data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
   721     }
   722 }
   724 void
   725 FrameIter::popJitFrame()
   726 {
   727     JS_ASSERT(data_.state_ == JIT);
   729     if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
   730         ++ionInlineFrames_;
   731         data_.pc_ = ionInlineFrames_.pc();
   732         return;
   733     }
   735     ++data_.jitFrames_;
   736     while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
   737         ++data_.jitFrames_;
   739     if (!data_.jitFrames_.done()) {
   740         nextJitFrame();
   741         return;
   742     }
   744     popActivation();
   745 }
   747 void
   748 FrameIter::popAsmJSFrame()
   749 {
   750     JS_ASSERT(data_.state_ == ASMJS);
   752     ++data_.asmJSFrames_;
   753     if (data_.asmJSFrames_.done())
   754         popActivation();
   755 }
   756 #endif
   758 FrameIter &
   759 FrameIter::operator++()
   760 {
   761     switch (data_.state_) {
   762       case DONE:
   763         MOZ_ASSUME_UNREACHABLE("Unexpected state");
   764       case INTERP:
   765         if (interpFrame()->isDebuggerFrame() && interpFrame()->evalInFramePrev()) {
   766             AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
   767             MOZ_ASSERT(!eifPrev.isRematerializedFrame());
   769             // Eval-in-frame can cross contexts and works across saved frame
   770             // chains.
   771             ContextOption prevContextOption = data_.contextOption_;
   772             SavedOption prevSavedOption = data_.savedOption_;
   773             data_.contextOption_ = ALL_CONTEXTS;
   774             data_.savedOption_ = GO_THROUGH_SAVED;
   776             popInterpreterFrame();
   778             while (isIon() || abstractFramePtr() != eifPrev) {
   779                 if (data_.state_ == JIT) {
   780 #ifdef JS_ION
   781                     popJitFrame();
   782 #else
   783                     MOZ_ASSUME_UNREACHABLE("Invalid state");
   784 #endif
   785                 } else {
   786                     popInterpreterFrame();
   787                 }
   788             }
   790             data_.contextOption_ = prevContextOption;
   791             data_.savedOption_ = prevSavedOption;
   792             data_.cx_ = data_.activations_->cx();
   793             break;
   794         }
   795         popInterpreterFrame();
   796         break;
   797 #ifdef JS_ION
   798       case JIT:
   799         popJitFrame();
   800         break;
   801       case ASMJS:
   802         popAsmJSFrame();
   803         break;
   804 #else
   805     default:
   806         MOZ_ASSUME_UNREACHABLE("Unexpected state");
   807 #endif
   808     }
   809     return *this;
   810 }
   812 FrameIter::Data *
   813 FrameIter::copyData() const
   814 {
   815     Data *data = data_.cx_->new_<Data>(data_);
   816 #ifdef JS_ION
   817     JS_ASSERT(data_.state_ != ASMJS);
   818     if (data && data_.jitFrames_.isIonJS())
   819         data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
   820 #endif
   821     return data;
   822 }
   824 AbstractFramePtr
   825 FrameIter::copyDataAsAbstractFramePtr() const
   826 {
   827     AbstractFramePtr frame;
   828     if (Data *data = copyData())
   829         frame.ptr_ = uintptr_t(data);
   830     return frame;
   831 }
   833 JSCompartment *
   834 FrameIter::compartment() const
   835 {
   836     switch (data_.state_) {
   837       case DONE:
   838         break;
   839       case INTERP:
   840       case JIT:
   841       case ASMJS:
   842         return data_.activations_->compartment();
   843     }
   844     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   845 }
   847 bool
   848 FrameIter::isFunctionFrame() const
   849 {
   850     switch (data_.state_) {
   851       case DONE:
   852         break;
   853       case INTERP:
   854         return interpFrame()->isFunctionFrame();
   855       case JIT:
   856 #ifdef JS_ION
   857         JS_ASSERT(data_.jitFrames_.isScripted());
   858         if (data_.jitFrames_.isBaselineJS())
   859             return data_.jitFrames_.isFunctionFrame();
   860         return ionInlineFrames_.isFunctionFrame();
   861 #else
   862         break;
   863 #endif
   864       case ASMJS:
   865         return true;
   866     }
   867     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   868 }
   870 bool
   871 FrameIter::isGlobalFrame() const
   872 {
   873     switch (data_.state_) {
   874       case DONE:
   875         break;
   876       case INTERP:
   877         return interpFrame()->isGlobalFrame();
   878       case JIT:
   879 #ifdef JS_ION
   880         if (data_.jitFrames_.isBaselineJS())
   881             return data_.jitFrames_.baselineFrame()->isGlobalFrame();
   882         JS_ASSERT(!script()->isForEval());
   883         return !script()->functionNonDelazifying();
   884 #else
   885         break;
   886 #endif
   887       case ASMJS:
   888         return false;
   889     }
   890     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   891 }
   893 bool
   894 FrameIter::isEvalFrame() const
   895 {
   896     switch (data_.state_) {
   897       case DONE:
   898         break;
   899       case INTERP:
   900         return interpFrame()->isEvalFrame();
   901       case JIT:
   902 #ifdef JS_ION
   903         if (data_.jitFrames_.isBaselineJS())
   904             return data_.jitFrames_.baselineFrame()->isEvalFrame();
   905         JS_ASSERT(!script()->isForEval());
   906         return false;
   907 #else
   908         break;
   909 #endif
   910       case ASMJS:
   911         return false;
   912     }
   913     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   914 }
   916 bool
   917 FrameIter::isNonEvalFunctionFrame() const
   918 {
   919     JS_ASSERT(!done());
   920     switch (data_.state_) {
   921       case DONE:
   922         break;
   923       case INTERP:
   924         return interpFrame()->isNonEvalFunctionFrame();
   925       case JIT:
   926         return !isEvalFrame() && isFunctionFrame();
   927       case ASMJS:
   928         return true;
   929     }
   930     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   931 }
   933 bool
   934 FrameIter::isGeneratorFrame() const
   935 {
   936     switch (data_.state_) {
   937       case DONE:
   938         break;
   939       case INTERP:
   940         return interpFrame()->isGeneratorFrame();
   941       case JIT:
   942         return false;
   943       case ASMJS:
   944         return false;
   945     }
   946     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   947 }
   949 JSAtom *
   950 FrameIter::functionDisplayAtom() const
   951 {
   952     JS_ASSERT(isNonEvalFunctionFrame());
   954     switch (data_.state_) {
   955       case DONE:
   956         break;
   957       case INTERP:
   958       case JIT:
   959         return callee()->displayAtom();
   960       case ASMJS: {
   961 #ifdef JS_ION
   962         return data_.asmJSFrames_.functionDisplayAtom();
   963 #else
   964         break;
   965 #endif
   966       }
   967     }
   969     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   970 }
   972 ScriptSource *
   973 FrameIter::scriptSource() const
   974 {
   975     switch (data_.state_) {
   976       case DONE:
   977         break;
   978       case INTERP:
   979       case JIT:
   980         return script()->scriptSource();
   981       case ASMJS:
   982 #ifdef JS_ION
   983         return data_.activations_->asAsmJS()->module().scriptSource();
   984 #else
   985         break;
   986 #endif
   987     }
   989     MOZ_ASSUME_UNREACHABLE("Unexpected state");
   990 }
   992 const char *
   993 FrameIter::scriptFilename() const
   994 {
   995     switch (data_.state_) {
   996       case DONE:
   997         break;
   998       case INTERP:
   999       case JIT:
  1000         return script()->filename();
  1001       case ASMJS:
  1002 #ifdef JS_ION
  1003         return data_.activations_->asAsmJS()->module().scriptSource()->filename();
  1004 #else
  1005         break;
  1006 #endif
  1009     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1012 unsigned
  1013 FrameIter::computeLine(uint32_t *column) const
  1015     switch (data_.state_) {
  1016       case DONE:
  1017         break;
  1018       case INTERP:
  1019       case JIT:
  1020         return PCToLineNumber(script(), pc(), column);
  1021       case ASMJS:
  1022 #ifdef JS_ION
  1023         return data_.asmJSFrames_.computeLine(column);
  1024 #else
  1025         break;
  1026 #endif
  1029     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1032 JSPrincipals *
  1033 FrameIter::originPrincipals() const
  1035     switch (data_.state_) {
  1036       case DONE:
  1037         break;
  1038       case INTERP:
  1039       case JIT:
  1040         return script()->originPrincipals();
  1041       case ASMJS: {
  1042 #ifdef JS_ION
  1043         return data_.activations_->asAsmJS()->module().scriptSource()->originPrincipals();
  1044 #else
  1045         break;
  1046 #endif
  1050     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1053 bool
  1054 FrameIter::isConstructing() const
  1056     switch (data_.state_) {
  1057       case DONE:
  1058       case ASMJS:
  1059         break;
  1060       case JIT:
  1061 #ifdef JS_ION
  1062         if (data_.jitFrames_.isIonJS())
  1063             return ionInlineFrames_.isConstructing();
  1064         JS_ASSERT(data_.jitFrames_.isBaselineJS());
  1065         return data_.jitFrames_.isConstructing();
  1066 #else
  1067         break;
  1068 #endif
  1069       case INTERP:
  1070         return interpFrame()->isConstructing();
  1072     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1075 bool
  1076 FrameIter::ensureHasRematerializedFrame()
  1078 #ifdef JS_ION
  1079     MOZ_ASSERT(isIon());
  1080     return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_);
  1081 #else
  1082     return true;
  1083 #endif
  1086 bool
  1087 FrameIter::hasUsableAbstractFramePtr() const
  1089     switch (data_.state_) {
  1090       case DONE:
  1091       case ASMJS:
  1092         return false;
  1093       case JIT:
  1094 #ifdef JS_ION
  1095         if (data_.jitFrames_.isBaselineJS())
  1096             return true;
  1098         MOZ_ASSERT(data_.jitFrames_.isIonJS());
  1099         return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
  1100                                                                   ionInlineFrames_.frameNo());
  1101 #endif
  1102         break;
  1103       case INTERP:
  1104         return true;
  1106     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1109 AbstractFramePtr
  1110 FrameIter::abstractFramePtr() const
  1112     MOZ_ASSERT(hasUsableAbstractFramePtr());
  1113     switch (data_.state_) {
  1114       case DONE:
  1115       case ASMJS:
  1116         break;
  1117       case JIT: {
  1118 #ifdef JS_ION
  1119         if (data_.jitFrames_.isBaselineJS())
  1120             return data_.jitFrames_.baselineFrame();
  1122         MOZ_ASSERT(data_.jitFrames_.isIonJS());
  1123         return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
  1124                                                                 ionInlineFrames_.frameNo());
  1125 #endif
  1126         break;
  1128       case INTERP:
  1129         JS_ASSERT(interpFrame());
  1130         return AbstractFramePtr(interpFrame());
  1132     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1135 void
  1136 FrameIter::updatePcQuadratic()
  1138     switch (data_.state_) {
  1139       case DONE:
  1140       case ASMJS:
  1141         break;
  1142       case INTERP: {
  1143         InterpreterFrame *frame = interpFrame();
  1144         InterpreterActivation *activation = data_.activations_->asInterpreter();
  1146         // Look for the current frame.
  1147         data_.interpFrames_ = InterpreterFrameIterator(activation);
  1148         while (data_.interpFrames_.frame() != frame)
  1149             ++data_.interpFrames_;
  1151         // Update the pc.
  1152         JS_ASSERT(data_.interpFrames_.frame() == frame);
  1153         data_.pc_ = data_.interpFrames_.pc();
  1154         return;
  1156       case JIT:
  1157 #ifdef JS_ION
  1158         if (data_.jitFrames_.isBaselineJS()) {
  1159             jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
  1160             jit::JitActivation *activation = data_.activations_->asJit();
  1162             // ActivationIterator::ionTop_ may be invalid, so create a new
  1163             // activation iterator.
  1164             data_.activations_ = ActivationIterator(data_.cx_->runtime());
  1165             while (data_.activations_.activation() != activation)
  1166                 ++data_.activations_;
  1168             // Look for the current frame.
  1169             data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
  1170             while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
  1171                 ++data_.jitFrames_;
  1173             // Update the pc.
  1174             JS_ASSERT(data_.jitFrames_.baselineFrame() == frame);
  1175             data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
  1176             return;
  1178 #endif
  1179         break;
  1181     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1184 JSFunction *
  1185 FrameIter::callee() const
  1187     switch (data_.state_) {
  1188       case DONE:
  1189       case ASMJS:
  1190         break;
  1191       case INTERP:
  1192         JS_ASSERT(isFunctionFrame());
  1193         return &interpFrame()->callee();
  1194       case JIT:
  1195 #ifdef JS_ION
  1196         if (data_.jitFrames_.isBaselineJS())
  1197             return data_.jitFrames_.callee();
  1198         JS_ASSERT(data_.jitFrames_.isIonJS());
  1199         return ionInlineFrames_.callee();
  1200 #else
  1201         break;
  1202 #endif
  1204     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1207 Value
  1208 FrameIter::calleev() const
  1210     switch (data_.state_) {
  1211       case DONE:
  1212       case ASMJS:
  1213         break;
  1214       case INTERP:
  1215         JS_ASSERT(isFunctionFrame());
  1216         return interpFrame()->calleev();
  1217       case JIT:
  1218 #ifdef JS_ION
  1219         return ObjectValue(*callee());
  1220 #else
  1221         break;
  1222 #endif
  1224     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1227 unsigned
  1228 FrameIter::numActualArgs() const
  1230     switch (data_.state_) {
  1231       case DONE:
  1232       case ASMJS:
  1233         break;
  1234       case INTERP:
  1235         JS_ASSERT(isFunctionFrame());
  1236         return interpFrame()->numActualArgs();
  1237       case JIT:
  1238 #ifdef JS_ION
  1239         if (data_.jitFrames_.isIonJS())
  1240             return ionInlineFrames_.numActualArgs();
  1242         JS_ASSERT(data_.jitFrames_.isBaselineJS());
  1243         return data_.jitFrames_.numActualArgs();
  1244 #else
  1245         break;
  1246 #endif
  1248     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1251 unsigned
  1252 FrameIter::numFormalArgs() const
  1254     return script()->functionNonDelazifying()->nargs();
  1257 Value
  1258 FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
  1260     return abstractFramePtr().unaliasedActual(i, checkAliasing);
  1263 JSObject *
  1264 FrameIter::scopeChain() const
  1266     switch (data_.state_) {
  1267       case DONE:
  1268       case ASMJS:
  1269         break;
  1270       case JIT:
  1271 #ifdef JS_ION
  1272         if (data_.jitFrames_.isIonJS())
  1273             return ionInlineFrames_.scopeChain();
  1274         return data_.jitFrames_.baselineFrame()->scopeChain();
  1275 #else
  1276         break;
  1277 #endif
  1278       case INTERP:
  1279         return interpFrame()->scopeChain();
  1281     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1284 CallObject &
  1285 FrameIter::callObj() const
  1287     JS_ASSERT(callee()->isHeavyweight());
  1289     JSObject *pobj = scopeChain();
  1290     while (!pobj->is<CallObject>())
  1291         pobj = pobj->enclosingScope();
  1292     return pobj->as<CallObject>();
  1295 bool
  1296 FrameIter::hasArgsObj() const
  1298     return abstractFramePtr().hasArgsObj();
  1301 ArgumentsObject &
  1302 FrameIter::argsObj() const
  1304     MOZ_ASSERT(hasArgsObj());
  1305     return abstractFramePtr().argsObj();
  1308 bool
  1309 FrameIter::computeThis(JSContext *cx) const
  1311     JS_ASSERT(!done() && !isAsmJS());
  1312     assertSameCompartment(cx, scopeChain());
  1313     return ComputeThis(cx, abstractFramePtr());
  1316 Value
  1317 FrameIter::computedThisValue() const
  1319     return abstractFramePtr().thisValue();
  1322 Value
  1323 FrameIter::thisv() const
  1325     switch (data_.state_) {
  1326       case DONE:
  1327       case ASMJS:
  1328         break;
  1329       case JIT:
  1330 #ifdef JS_ION
  1331         if (data_.jitFrames_.isIonJS())
  1332             return ionInlineFrames_.thisValue();
  1333         return data_.jitFrames_.baselineFrame()->thisValue();
  1334 #else
  1335         break;
  1336 #endif
  1337       case INTERP:
  1338         return interpFrame()->thisValue();
  1340     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1343 Value
  1344 FrameIter::returnValue() const
  1346     switch (data_.state_) {
  1347       case DONE:
  1348       case ASMJS:
  1349         break;
  1350       case JIT:
  1351 #ifdef JS_ION
  1352         if (data_.jitFrames_.isBaselineJS())
  1353             return data_.jitFrames_.baselineFrame()->returnValue();
  1354 #endif
  1355         break;
  1356       case INTERP:
  1357         return interpFrame()->returnValue();
  1359     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1362 void
  1363 FrameIter::setReturnValue(const Value &v)
  1365     switch (data_.state_) {
  1366       case DONE:
  1367       case ASMJS:
  1368         break;
  1369       case JIT:
  1370 #ifdef JS_ION
  1371         if (data_.jitFrames_.isBaselineJS()) {
  1372             data_.jitFrames_.baselineFrame()->setReturnValue(v);
  1373             return;
  1375 #endif
  1376         break;
  1377       case INTERP:
  1378         interpFrame()->setReturnValue(v);
  1379         return;
  1381     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1384 size_t
  1385 FrameIter::numFrameSlots() const
  1387     switch (data_.state_) {
  1388       case DONE:
  1389       case ASMJS:
  1390         break;
  1391       case JIT: {
  1392 #ifdef JS_ION
  1393         if (data_.jitFrames_.isIonJS()) {
  1394             return ionInlineFrames_.snapshotIterator().numAllocations() -
  1395                 ionInlineFrames_.script()->nfixed();
  1397         jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
  1398         return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
  1399 #else
  1400         break;
  1401 #endif
  1403       case INTERP:
  1404         JS_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
  1405         return data_.interpFrames_.sp() - interpFrame()->base();
  1407     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1410 Value
  1411 FrameIter::frameSlotValue(size_t index) const
  1413     switch (data_.state_) {
  1414       case DONE:
  1415       case ASMJS:
  1416         break;
  1417       case JIT:
  1418 #ifdef JS_ION
  1419         if (data_.jitFrames_.isIonJS()) {
  1420             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
  1421             index += ionInlineFrames_.script()->nfixed();
  1422             return si.maybeReadAllocByIndex(index);
  1425         index += data_.jitFrames_.script()->nfixed();
  1426         return *data_.jitFrames_.baselineFrame()->valueSlot(index);
  1427 #else
  1428         break;
  1429 #endif
  1430       case INTERP:
  1431           return interpFrame()->base()[index];
  1433     MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1436 #if defined(_MSC_VER)
  1437 # pragma optimize("", on)
  1438 #endif
  1440 #ifdef DEBUG
  1441 bool
  1442 js::SelfHostedFramesVisible()
  1444     static bool checked = false;
  1445     static bool visible = false;
  1446     if (!checked) {
  1447         checked = true;
  1448         char *env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
  1449         visible = !!env;
  1451     return visible;
  1453 #endif
  1455 void
  1456 NonBuiltinFrameIter::settle()
  1458     if (!SelfHostedFramesVisible()) {
  1459         while (!done() && hasScript() && script()->selfHosted())
  1460             FrameIter::operator++();
  1464 void
  1465 NonBuiltinScriptFrameIter::settle()
  1467     if (!SelfHostedFramesVisible()) {
  1468         while (!done() && script()->selfHosted())
  1469             ScriptFrameIter::operator++();
  1473 /*****************************************************************************/
  1475 JSObject *
  1476 AbstractFramePtr::evalPrevScopeChain(JSContext *cx) const
  1478     // Eval frames are not compiled by Ion, though their caller might be.
  1479     AllFramesIter iter(cx);
  1480     while (iter.isIon() || iter.abstractFramePtr() != *this)
  1481         ++iter;
  1482     ++iter;
  1483     return iter.scopeChain();
  1486 bool
  1487 AbstractFramePtr::hasPushedSPSFrame() const
  1489     if (isInterpreterFrame())
  1490         return asInterpreterFrame()->hasPushedSPSFrame();
  1491 #ifdef JS_ION
  1492     return asBaselineFrame()->hasPushedSPSFrame();
  1493 #else
  1494     MOZ_ASSUME_UNREACHABLE("Invalid frame");
  1495 #endif
  1498 #ifdef DEBUG
  1499 void
  1500 js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i)
  1502     if (!checkAliasing)
  1503         return;
  1505     JS_ASSERT(i < script->nfixed());
  1506     if (i < script->bindings.numVars()) {
  1507         JS_ASSERT(!script->varIsAliased(i));
  1508     } else {
  1509         // FIXME: The callers of this function do not easily have the PC of the
  1510         // current frame, and so they do not know the block scope.
  1513 #endif
  1515 jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
  1516   : Activation(cx, Jit),
  1517     firstFrameIsConstructing_(firstFrameIsConstructing),
  1518     active_(active)
  1519 #ifdef JS_ION
  1520   , rematerializedFrames_(cx)
  1521 #endif
  1523     if (active) {
  1524         prevIonTop_ = cx->mainThread().ionTop;
  1525         prevJitJSContext_ = cx->mainThread().jitJSContext;
  1526         cx->mainThread().jitJSContext = cx;
  1527     } else {
  1528         prevIonTop_ = nullptr;
  1529         prevJitJSContext_ = nullptr;
  1533 jit::JitActivation::~JitActivation()
  1535     if (active_) {
  1536         cx_->mainThread().ionTop = prevIonTop_;
  1537         cx_->mainThread().jitJSContext = prevJitJSContext_;
  1540 #ifdef JS_ION
  1541     clearRematerializedFrames();
  1542 #endif
  1545 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
  1546 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
  1547 // and disable activation instruction sequences.
  1548 void
  1549 jit::JitActivation::setActive(JSContext *cx, bool active)
  1551     // Only allowed to deactivate/activate if activation is top.
  1552     // (Not tested and will probably fail in other situations.)
  1553     JS_ASSERT(cx->mainThread().activation_ == this);
  1554     JS_ASSERT(active != active_);
  1555     active_ = active;
  1557     if (active) {
  1558         prevIonTop_ = cx->mainThread().ionTop;
  1559         prevJitJSContext_ = cx->mainThread().jitJSContext;
  1560         cx->mainThread().jitJSContext = cx;
  1561     } else {
  1562         cx->mainThread().ionTop = prevIonTop_;
  1563         cx->mainThread().jitJSContext = prevJitJSContext_;
  1567 #ifdef JS_ION
  1569 void
  1570 jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector &frames)
  1572     for (size_t i = 0; i < frames.length(); i++) {
  1573         RematerializedFrame *f = frames[i];
  1574         f->RematerializedFrame::~RematerializedFrame();
  1575         js_free(f);
  1577     frames.clear();
  1580 void
  1581 jit::JitActivation::removeRematerializedFrame(uint8_t *top)
  1583     if (!rematerializedFrames_.initialized())
  1584         return;
  1586     if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) {
  1587         freeRematerializedFramesInVector(p->value());
  1588         rematerializedFrames_.remove(p);
  1592 void
  1593 jit::JitActivation::clearRematerializedFrames()
  1595     if (!rematerializedFrames_.initialized())
  1596         return;
  1598     for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
  1599         freeRematerializedFramesInVector(e.front().value());
  1600         e.removeFront();
  1604 jit::RematerializedFrame *
  1605 jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
  1606                                            size_t inlineDepth)
  1608     MOZ_ASSERT(iter.activation() == this);
  1609     MOZ_ASSERT(iter.isIonJS());
  1611     if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init())
  1612         return nullptr;
  1614     // The unit of rematerialization is an uninlined frame and its inlined
  1615     // frames. Since inlined frames do not exist outside of snapshots, it is
  1616     // impossible to synchronize their rematerialized copies to preserve
  1617     // identity. Therefore, we always rematerialize an uninlined frame and all
  1618     // its inlined frames at once.
  1620     uint8_t *top = iter.fp();
  1621     RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top);
  1622     if (!p) {
  1623         RematerializedFrameVector empty(cx);
  1624         if (!rematerializedFrames_.add(p, top, Move(empty)))
  1625             return nullptr;
  1627         InlineFrameIterator inlineIter(cx, &iter);
  1628         if (!p->value().resize(inlineIter.frameCount()))
  1629             return nullptr;
  1631         while (true) {
  1632             size_t frameNo = inlineIter.frameNo();
  1633             p->value()[frameNo] = RematerializedFrame::New(cx, top, inlineIter);
  1634             if (!p->value()[frameNo])
  1635                 return nullptr;
  1637             if (!inlineIter.more())
  1638                 break;
  1639             ++inlineIter;
  1643     return p->value()[inlineDepth];
  1646 jit::RematerializedFrame *
  1647 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
  1649     if (!rematerializedFrames_.initialized())
  1650         return nullptr;
  1651     if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top))
  1652         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
  1653     return nullptr;
  1656 void
  1657 jit::JitActivation::markRematerializedFrames(JSTracer *trc)
  1659     if (!rematerializedFrames_.initialized())
  1660         return;
  1661     for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
  1662         RematerializedFrameVector &frames = e.front().value();
  1663         for (size_t i = 0; i < frames.length(); i++)
  1664             frames[i]->mark(trc);
  1668 #endif // JS_ION
  1670 AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
  1671   : Activation(cx, AsmJS),
  1672     module_(module),
  1673     errorRejoinSP_(nullptr),
  1674     profiler_(nullptr),
  1675     resumePC_(nullptr),
  1676     exitSP_(nullptr)
  1678     if (cx->runtime()->spsProfiler.enabled()) {
  1679         // Use a profiler string that matches jsMatch regex in
  1680         // browser/devtools/profiler/cleopatra/js/parserWorker.js.
  1681         // (For now use a single static string to avoid further slowing down
  1682         // calls into asm.js.)
  1683         profiler_ = &cx->runtime()->spsProfiler;
  1684         profiler_->enterNative("asm.js code :0", this);
  1687     prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_;
  1689     JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
  1690     cx_->runtime()->mainThread.asmJSActivationStack_ = this;
  1692     (void) errorRejoinSP_;  // squelch GCC warning
  1695 AsmJSActivation::~AsmJSActivation()
  1697     if (profiler_)
  1698         profiler_->exitNative();
  1700     JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this);
  1702     JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
  1703     cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_;
  1706 InterpreterFrameIterator &
  1707 InterpreterFrameIterator::operator++()
  1709     JS_ASSERT(!done());
  1710     if (fp_ != activation_->entryFrame_) {
  1711         pc_ = fp_->prevpc();
  1712         sp_ = fp_->prevsp();
  1713         fp_ = fp_->prev();
  1714     } else {
  1715         pc_ = nullptr;
  1716         sp_ = nullptr;
  1717         fp_ = nullptr;
  1719     return *this;
  1722 ActivationIterator::ActivationIterator(JSRuntime *rt)
  1723   : jitTop_(rt->mainThread.ionTop),
  1724     activation_(rt->mainThread.activation_)
  1726     settle();
  1729 ActivationIterator &
  1730 ActivationIterator::operator++()
  1732     JS_ASSERT(activation_);
  1733     if (activation_->isJit() && activation_->asJit()->isActive())
  1734         jitTop_ = activation_->asJit()->prevIonTop();
  1735     activation_ = activation_->prev();
  1736     settle();
  1737     return *this;
  1740 void
  1741 ActivationIterator::settle()
  1743     // Stop at the next active activation. No need to update jitTop_, since
  1744     // we don't iterate over an active jit activation.
  1745     while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
  1746         activation_ = activation_->prev();

mercurial