js/src/vm/Stack.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/Stack.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1747 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "vm/Stack-inl.h"
    1.11 +
    1.12 +#include "mozilla/PodOperations.h"
    1.13 +
    1.14 +#include "jscntxt.h"
    1.15 +
    1.16 +#include "gc/Marking.h"
    1.17 +#ifdef JS_ION
    1.18 +#include "jit/AsmJSModule.h"
    1.19 +#include "jit/BaselineFrame.h"
    1.20 +#include "jit/JitCompartment.h"
    1.21 +#endif
    1.22 +#include "js/GCAPI.h"
    1.23 +#include "vm/Opcodes.h"
    1.24 +
    1.25 +#include "jit/JitFrameIterator-inl.h"
    1.26 +#include "vm/Interpreter-inl.h"
    1.27 +#include "vm/Probes-inl.h"
    1.28 +#include "vm/ScopeObject-inl.h"
    1.29 +
    1.30 +using namespace js;
    1.31 +
    1.32 +using mozilla::PodCopy;
    1.33 +
    1.34 +/*****************************************************************************/
    1.35 +
    1.36 +void
    1.37 +InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev,
    1.38 +                                   const Value &thisv, JSObject &scopeChain, ExecuteType type)
    1.39 +{
    1.40 +    /*
    1.41 +     * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
    1.42 +     * script in the context of another frame and the frame type is determined
    1.43 +     * by the context.
    1.44 +     */
    1.45 +    flags_ = type | HAS_SCOPECHAIN;
    1.46 +
    1.47 +    JSObject *callee = nullptr;
    1.48 +    if (!(flags_ & (GLOBAL))) {
    1.49 +        if (evalInFramePrev) {
    1.50 +            JS_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
    1.51 +            if (evalInFramePrev.isFunctionFrame()) {
    1.52 +                callee = evalInFramePrev.callee();
    1.53 +                flags_ |= FUNCTION;
    1.54 +            } else {
    1.55 +                flags_ |= GLOBAL;
    1.56 +            }
    1.57 +        } else {
    1.58 +            FrameIter iter(cx);
    1.59 +            JS_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame());
    1.60 +            JS_ASSERT(!iter.isAsmJS());
    1.61 +            if (iter.isFunctionFrame()) {
    1.62 +                callee = iter.callee();
    1.63 +                flags_ |= FUNCTION;
    1.64 +            } else {
    1.65 +                flags_ |= GLOBAL;
    1.66 +            }
    1.67 +        }
    1.68 +    }
    1.69 +
    1.70 +    Value *dstvp = (Value *)this - 2;
    1.71 +    dstvp[1] = thisv;
    1.72 +
    1.73 +    if (isFunctionFrame()) {
    1.74 +        dstvp[0] = ObjectValue(*callee);
    1.75 +        exec.fun = &callee->as<JSFunction>();
    1.76 +        u.evalScript = script;
    1.77 +    } else {
    1.78 +        JS_ASSERT(isGlobalFrame());
    1.79 +        dstvp[0] = NullValue();
    1.80 +        exec.script = script;
    1.81 +#ifdef DEBUG
    1.82 +        u.evalScript = (JSScript *)0xbad;
    1.83 +#endif
    1.84 +    }
    1.85 +
    1.86 +    scopeChain_ = &scopeChain;
    1.87 +    prev_ = nullptr;
    1.88 +    prevpc_ = nullptr;
    1.89 +    prevsp_ = nullptr;
    1.90 +
    1.91 +    JS_ASSERT_IF(evalInFramePrev, isDebuggerFrame());
    1.92 +    evalInFramePrev_ = evalInFramePrev;
    1.93 +
    1.94 +#ifdef DEBUG
    1.95 +    Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
    1.96 +    hookData_ = (void *)0xbad;
    1.97 +#endif
    1.98 +}
    1.99 +
   1.100 +template <InterpreterFrame::TriggerPostBarriers doPostBarrier>
   1.101 +void
   1.102 +InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
   1.103 +                                     const Value *othervp, Value *othersp)
   1.104 +{
   1.105 +    JS_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin());
   1.106 +    JS_ASSERT(othersp >= otherfp->slots());
   1.107 +    JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots());
   1.108 +
   1.109 +    /* Copy args, InterpreterFrame, and slots. */
   1.110 +    const Value *srcend = otherfp->generatorArgsSnapshotEnd();
   1.111 +    Value *dst = vp;
   1.112 +    for (const Value *src = othervp; src < srcend; src++, dst++) {
   1.113 +        *dst = *src;
   1.114 +        if (doPostBarrier)
   1.115 +            HeapValue::writeBarrierPost(*dst, dst);
   1.116 +    }
   1.117 +
   1.118 +    *this = *otherfp;
   1.119 +    argv_ = vp + 2;
   1.120 +    unsetPushedSPSFrame();
   1.121 +    if (doPostBarrier)
   1.122 +        writeBarrierPost();
   1.123 +
   1.124 +    srcend = othersp;
   1.125 +    dst = slots();
   1.126 +    for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) {
   1.127 +        *dst = *src;
   1.128 +        if (doPostBarrier)
   1.129 +            HeapValue::writeBarrierPost(*dst, dst);
   1.130 +    }
   1.131 +}
   1.132 +
   1.133 +/* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */
   1.134 +template
   1.135 +void InterpreterFrame::copyFrameAndValues<InterpreterFrame::NoPostBarrier>(
   1.136 +                                    JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
   1.137 +template
   1.138 +void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>(
   1.139 +                                    JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
   1.140 +
   1.141 +void
   1.142 +InterpreterFrame::writeBarrierPost()
   1.143 +{
   1.144 +    /* This needs to follow the same rules as in InterpreterFrame::mark. */
   1.145 +    if (scopeChain_)
   1.146 +        JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
   1.147 +    if (flags_ & HAS_ARGS_OBJ)
   1.148 +        JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
   1.149 +    if (isFunctionFrame()) {
   1.150 +        JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
   1.151 +        if (isEvalFrame())
   1.152 +            JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
   1.153 +    } else {
   1.154 +        JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
   1.155 +    }
   1.156 +    if (hasReturnValue())
   1.157 +        HeapValue::writeBarrierPost(rval_, &rval_);
   1.158 +}
   1.159 +
   1.160 +bool
   1.161 +InterpreterFrame::copyRawFrameSlots(AutoValueVector *vec)
   1.162 +{
   1.163 +    if (!vec->resize(numFormalArgs() + script()->nfixed()))
   1.164 +        return false;
   1.165 +    PodCopy(vec->begin(), argv(), numFormalArgs());
   1.166 +    PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed());
   1.167 +    return true;
   1.168 +}
   1.169 +
   1.170 +JSObject *
   1.171 +InterpreterFrame::createRestParameter(JSContext *cx)
   1.172 +{
   1.173 +    JS_ASSERT(fun()->hasRest());
   1.174 +    unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs();
   1.175 +    unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
   1.176 +    Value *restvp = argv() + nformal;
   1.177 +    JSObject *obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr);
   1.178 +    if (!obj)
   1.179 +        return nullptr;
   1.180 +    types::FixRestArgumentsType(cx, obj);
   1.181 +    return obj;
   1.182 +}
   1.183 +
   1.184 +static inline void
   1.185 +AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject *scope)
   1.186 +{
   1.187 +#ifdef DEBUG
   1.188 +    RootedObject enclosingScope(cx, script->enclosingStaticScope());
   1.189 +    for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
   1.190 +        if (i.hasDynamicScopeObject()) {
   1.191 +            switch (i.type()) {
   1.192 +              case StaticScopeIter<NoGC>::BLOCK:
   1.193 +                JS_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope());
   1.194 +                scope = &scope->as<ClonedBlockObject>().enclosingScope();
   1.195 +                break;
   1.196 +              case StaticScopeIter<NoGC>::WITH:
   1.197 +                JS_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope());
   1.198 +                scope = &scope->as<DynamicWithObject>().enclosingScope();
   1.199 +                break;
   1.200 +              case StaticScopeIter<NoGC>::FUNCTION:
   1.201 +                JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
   1.202 +                scope = &scope->as<CallObject>().enclosingScope();
   1.203 +                break;
   1.204 +              case StaticScopeIter<NoGC>::NAMED_LAMBDA:
   1.205 +                scope = &scope->as<DeclEnvObject>().enclosingScope();
   1.206 +                break;
   1.207 +            }
   1.208 +        }
   1.209 +    }
   1.210 +
   1.211 +    /*
   1.212 +     * Ideally, we'd JS_ASSERT(!scope->is<ScopeObject>()) but the enclosing
   1.213 +     * lexical scope chain stops at eval() boundaries. See StaticScopeIter
   1.214 +     * comment.
   1.215 +     */
   1.216 +#endif
   1.217 +}
   1.218 +
   1.219 +bool
   1.220 +InterpreterFrame::initFunctionScopeObjects(JSContext *cx)
   1.221 +{
   1.222 +    CallObject *callobj = CallObject::createForFunction(cx, this);
   1.223 +    if (!callobj)
   1.224 +        return false;
   1.225 +    pushOnScopeChain(*callobj);
   1.226 +    flags_ |= HAS_CALL_OBJ;
   1.227 +    return true;
   1.228 +}
   1.229 +
   1.230 +bool
   1.231 +InterpreterFrame::prologue(JSContext *cx)
   1.232 +{
   1.233 +    RootedScript script(cx, this->script());
   1.234 +
   1.235 +    JS_ASSERT(!isGeneratorFrame());
   1.236 +    JS_ASSERT(cx->interpreterRegs().pc == script->code());
   1.237 +
   1.238 +    if (isEvalFrame()) {
   1.239 +        if (script->strict()) {
   1.240 +            CallObject *callobj = CallObject::createForStrictEval(cx, this);
   1.241 +            if (!callobj)
   1.242 +                return false;
   1.243 +            pushOnScopeChain(*callobj);
   1.244 +            flags_ |= HAS_CALL_OBJ;
   1.245 +        }
   1.246 +        return probes::EnterScript(cx, script, nullptr, this);
   1.247 +    }
   1.248 +
   1.249 +    if (isGlobalFrame())
   1.250 +        return probes::EnterScript(cx, script, nullptr, this);
   1.251 +
   1.252 +    JS_ASSERT(isNonEvalFunctionFrame());
   1.253 +    AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
   1.254 +
   1.255 +    if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx))
   1.256 +        return false;
   1.257 +
   1.258 +    if (isConstructing()) {
   1.259 +        RootedObject callee(cx, &this->callee());
   1.260 +        JSObject *obj = CreateThisForFunction(cx, callee,
   1.261 +                                              useNewType() ? SingletonObject : GenericObject);
   1.262 +        if (!obj)
   1.263 +            return false;
   1.264 +        functionThis() = ObjectValue(*obj);
   1.265 +    }
   1.266 +
   1.267 +    return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
   1.268 +}
   1.269 +
   1.270 +void
   1.271 +InterpreterFrame::epilogue(JSContext *cx)
   1.272 +{
   1.273 +    JS_ASSERT(!isYielding());
   1.274 +
   1.275 +    RootedScript script(cx, this->script());
   1.276 +    probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
   1.277 +
   1.278 +    if (isEvalFrame()) {
   1.279 +        if (isStrictEvalFrame()) {
   1.280 +            JS_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
   1.281 +            if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   1.282 +                DebugScopes::onPopStrictEvalScope(this);
   1.283 +        } else if (isDirectEvalFrame()) {
   1.284 +            if (isDebuggerFrame())
   1.285 +                JS_ASSERT(!scopeChain()->is<ScopeObject>());
   1.286 +        } else {
   1.287 +            /*
   1.288 +             * Debugger.Object.prototype.evalInGlobal creates indirect eval
   1.289 +             * frames scoped to the given global;
   1.290 +             * Debugger.Object.prototype.evalInGlobalWithBindings creates
   1.291 +             * indirect eval frames scoped to an object carrying the introduced
   1.292 +             * bindings.
   1.293 +             */
   1.294 +            if (isDebuggerFrame()) {
   1.295 +                JS_ASSERT(scopeChain()->is<GlobalObject>() ||
   1.296 +                          scopeChain()->enclosingScope()->is<GlobalObject>());
   1.297 +            } else {
   1.298 +                JS_ASSERT(scopeChain()->is<GlobalObject>());
   1.299 +            }
   1.300 +        }
   1.301 +        return;
   1.302 +    }
   1.303 +
   1.304 +    if (isGlobalFrame()) {
   1.305 +        JS_ASSERT(!scopeChain()->is<ScopeObject>());
   1.306 +        return;
   1.307 +    }
   1.308 +
   1.309 +    JS_ASSERT(isNonEvalFunctionFrame());
   1.310 +
   1.311 +    if (fun()->isHeavyweight())
   1.312 +        JS_ASSERT_IF(hasCallObj(),
   1.313 +                     scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
   1.314 +    else
   1.315 +        AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
   1.316 +
   1.317 +    if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   1.318 +        DebugScopes::onPopCall(this, cx);
   1.319 +
   1.320 +    if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive())
   1.321 +        setReturnValue(ObjectValue(constructorThis()));
   1.322 +}
   1.323 +
   1.324 +bool
   1.325 +InterpreterFrame::pushBlock(JSContext *cx, StaticBlockObject &block)
   1.326 +{
   1.327 +    JS_ASSERT (block.needsClone());
   1.328 +
   1.329 +    Rooted<StaticBlockObject *> blockHandle(cx, &block);
   1.330 +    ClonedBlockObject *clone = ClonedBlockObject::create(cx, blockHandle, this);
   1.331 +    if (!clone)
   1.332 +        return false;
   1.333 +
   1.334 +    pushOnScopeChain(*clone);
   1.335 +
   1.336 +    return true;
   1.337 +}
   1.338 +
   1.339 +void
   1.340 +InterpreterFrame::popBlock(JSContext *cx)
   1.341 +{
   1.342 +    JS_ASSERT(scopeChain_->is<ClonedBlockObject>());
   1.343 +    popOffScopeChain();
   1.344 +}
   1.345 +
   1.346 +void
   1.347 +InterpreterFrame::popWith(JSContext *cx)
   1.348 +{
   1.349 +    if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
   1.350 +        DebugScopes::onPopWith(this);
   1.351 +
   1.352 +    JS_ASSERT(scopeChain()->is<DynamicWithObject>());
   1.353 +    popOffScopeChain();
   1.354 +}
   1.355 +
   1.356 +void
   1.357 +InterpreterFrame::mark(JSTracer *trc)
   1.358 +{
   1.359 +    /*
   1.360 +     * Normally we would use MarkRoot here, except that generators also take
   1.361 +     * this path. However, generators use a special write barrier when the stack
   1.362 +     * frame is copied to the floating frame. Therefore, no barrier is needed.
   1.363 +     */
   1.364 +    if (flags_ & HAS_SCOPECHAIN)
   1.365 +        gc::MarkObjectUnbarriered(trc, &scopeChain_, "scope chain");
   1.366 +    if (flags_ & HAS_ARGS_OBJ)
   1.367 +        gc::MarkObjectUnbarriered(trc, &argsObj_, "arguments");
   1.368 +    if (isFunctionFrame()) {
   1.369 +        gc::MarkObjectUnbarriered(trc, &exec.fun, "fun");
   1.370 +        if (isEvalFrame())
   1.371 +            gc::MarkScriptUnbarriered(trc, &u.evalScript, "eval script");
   1.372 +    } else {
   1.373 +        gc::MarkScriptUnbarriered(trc, &exec.script, "script");
   1.374 +    }
   1.375 +    if (IS_GC_MARKING_TRACER(trc))
   1.376 +        script()->compartment()->zone()->active = true;
   1.377 +    gc::MarkValueUnbarriered(trc, returnValue().address(), "rval");
   1.378 +}
   1.379 +
   1.380 +void
   1.381 +InterpreterFrame::markValues(JSTracer *trc, unsigned start, unsigned end)
   1.382 +{
   1.383 +    if (start < end)
   1.384 +        gc::MarkValueRootRange(trc, end - start, slots() + start, "vm_stack");
   1.385 +}
   1.386 +
   1.387 +void
   1.388 +InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
   1.389 +{
   1.390 +    JS_ASSERT(sp >= slots());
   1.391 +
   1.392 +    NestedScopeObject *staticScope;
   1.393 +
   1.394 +    staticScope = script()->getStaticScope(pc);
   1.395 +    while (staticScope && !staticScope->is<StaticBlockObject>())
   1.396 +        staticScope = staticScope->enclosingNestedScope();
   1.397 +
   1.398 +    size_t nfixed = script()->nfixed();
   1.399 +    size_t nlivefixed;
   1.400 +
   1.401 +    if (staticScope) {
   1.402 +        StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
   1.403 +        nlivefixed = blockObj.localOffset() + blockObj.numVariables();
   1.404 +    } else {
   1.405 +        nlivefixed = script()->nfixedvars();
   1.406 +    }
   1.407 +
   1.408 +    if (nfixed == nlivefixed) {
   1.409 +        // All locals are live.
   1.410 +        markValues(trc, 0, sp - slots());
   1.411 +    } else {
   1.412 +        // Mark operand stack.
   1.413 +        markValues(trc, nfixed, sp - slots());
   1.414 +
   1.415 +        // Clear dead locals.
   1.416 +        while (nfixed > nlivefixed)
   1.417 +            unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined();
   1.418 +
   1.419 +        // Mark live locals.
   1.420 +        markValues(trc, 0, nlivefixed);
   1.421 +    }
   1.422 +
   1.423 +    if (hasArgs()) {
   1.424 +        // Mark callee, |this| and arguments.
   1.425 +        unsigned argc = Max(numActualArgs(), numFormalArgs());
   1.426 +        gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv");
   1.427 +    } else {
   1.428 +        // Mark callee and |this|
   1.429 +        gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
   1.430 +    }
   1.431 +}
   1.432 +
   1.433 +static void
   1.434 +MarkInterpreterActivation(JSTracer *trc, InterpreterActivation *act)
   1.435 +{
   1.436 +    for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
   1.437 +        InterpreterFrame *fp = frames.frame();
   1.438 +        fp->markValues(trc, frames.sp(), frames.pc());
   1.439 +        fp->mark(trc);
   1.440 +    }
   1.441 +}
   1.442 +
   1.443 +void
   1.444 +js::MarkInterpreterActivations(JSRuntime *rt, JSTracer *trc)
   1.445 +{
   1.446 +    for (ActivationIterator iter(rt); !iter.done(); ++iter) {
   1.447 +        Activation *act = iter.activation();
   1.448 +        if (act->isInterpreter())
   1.449 +            MarkInterpreterActivation(trc, act->asInterpreter());
   1.450 +    }
   1.451 +
   1.452 +}
   1.453 +
   1.454 +/*****************************************************************************/
   1.455 +
   1.456 +// Unlike the other methods of this calss, this method is defined here so that
   1.457 +// we don't have to #include jsautooplen.h in vm/Stack.h.
   1.458 +void
   1.459 +InterpreterRegs::setToEndOfScript()
   1.460 +{
   1.461 +    JSScript *script = fp()->script();
   1.462 +    sp = fp()->base();
   1.463 +    pc = script->codeEnd() - JSOP_RETRVAL_LENGTH;
   1.464 +    JS_ASSERT(*pc == JSOP_RETRVAL);
   1.465 +}
   1.466 +
   1.467 +/*****************************************************************************/
   1.468 +
   1.469 +InterpreterFrame *
   1.470 +InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial)
   1.471 +{
   1.472 +    LifoAlloc::Mark mark = allocator_.mark();
   1.473 +
   1.474 +    RootedFunction fun(cx, &args.callee().as<JSFunction>());
   1.475 +    RootedScript script(cx, fun->nonLazyScript());
   1.476 +
   1.477 +    InterpreterFrame::Flags flags = ToFrameFlags(initial);
   1.478 +    Value *argv;
   1.479 +    InterpreterFrame *fp = getCallFrame(cx, args, script, &flags, &argv);
   1.480 +    if (!fp)
   1.481 +        return nullptr;
   1.482 +
   1.483 +    fp->mark_ = mark;
   1.484 +    fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
   1.485 +    return fp;
   1.486 +}
   1.487 +
   1.488 +InterpreterFrame *
   1.489 +InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
   1.490 +                                   HandleObject scopeChain, ExecuteType type,
   1.491 +                                   AbstractFramePtr evalInFrame)
   1.492 +{
   1.493 +    LifoAlloc::Mark mark = allocator_.mark();
   1.494 +
   1.495 +    unsigned nvars = 2 /* callee, this */ + script->nslots();
   1.496 +    uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
   1.497 +    if (!buffer)
   1.498 +        return nullptr;
   1.499 +
   1.500 +    InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value));
   1.501 +    fp->mark_ = mark;
   1.502 +    fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
   1.503 +    fp->initVarsToUndefined();
   1.504 +
   1.505 +    return fp;
   1.506 +}
   1.507 +
   1.508 +/*****************************************************************************/
   1.509 +
   1.510 +/* MSVC PGO causes xpcshell startup crashes. */
   1.511 +#if defined(_MSC_VER)
   1.512 +# pragma optimize("g", off)
   1.513 +#endif
   1.514 +
   1.515 +void
   1.516 +FrameIter::popActivation()
   1.517 +{
   1.518 +    ++data_.activations_;
   1.519 +    settleOnActivation();
   1.520 +}
   1.521 +
   1.522 +void
   1.523 +FrameIter::popInterpreterFrame()
   1.524 +{
   1.525 +    JS_ASSERT(data_.state_ == INTERP);
   1.526 +
   1.527 +    ++data_.interpFrames_;
   1.528 +
   1.529 +    if (data_.interpFrames_.done())
   1.530 +        popActivation();
   1.531 +    else
   1.532 +        data_.pc_ = data_.interpFrames_.pc();
   1.533 +}
   1.534 +
   1.535 +void
   1.536 +FrameIter::settleOnActivation()
   1.537 +{
   1.538 +    while (true) {
   1.539 +        if (data_.activations_.done()) {
   1.540 +            data_.state_ = DONE;
   1.541 +            return;
   1.542 +        }
   1.543 +
   1.544 +        Activation *activation = data_.activations_.activation();
   1.545 +
   1.546 +        // If JS_SaveFrameChain was called, stop iterating here (unless
   1.547 +        // GO_THROUGH_SAVED is set).
   1.548 +        if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) {
   1.549 +            data_.state_ = DONE;
   1.550 +            return;
   1.551 +        }
   1.552 +
   1.553 +        // Skip activations from another context if needed.
   1.554 +        JS_ASSERT(activation->cx());
   1.555 +        JS_ASSERT(data_.cx_);
   1.556 +        if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) {
   1.557 +            ++data_.activations_;
   1.558 +            continue;
   1.559 +        }
   1.560 +
   1.561 +        // If the caller supplied principals, only show activations which are subsumed (of the same
   1.562 +        // origin or of an origin accessible) by these principals.
   1.563 +        if (data_.principals_) {
   1.564 +            if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) {
   1.565 +                JS::AutoAssertNoGC nogc;
   1.566 +                if (!subsumes(data_.principals_, activation->compartment()->principals)) {
   1.567 +                    ++data_.activations_;
   1.568 +                    continue;
   1.569 +                }
   1.570 +            }
   1.571 +        }
   1.572 +
   1.573 +#ifdef JS_ION
   1.574 +        if (activation->isJit()) {
   1.575 +            data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
   1.576 +
   1.577 +            // Stop at the first scripted frame.
   1.578 +            while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
   1.579 +                ++data_.jitFrames_;
   1.580 +
   1.581 +            // It's possible to have an JitActivation with no scripted frames,
   1.582 +            // for instance if we hit an over-recursion during bailout.
   1.583 +            if (data_.jitFrames_.done()) {
   1.584 +                ++data_.activations_;
   1.585 +                continue;
   1.586 +            }
   1.587 +
   1.588 +            nextJitFrame();
   1.589 +            data_.state_ = JIT;
   1.590 +            return;
   1.591 +        }
   1.592 +
   1.593 +        if (activation->isAsmJS()) {
   1.594 +            data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
   1.595 +
   1.596 +            if (data_.asmJSFrames_.done()) {
   1.597 +                ++data_.activations_;
   1.598 +                continue;
   1.599 +            }
   1.600 +
   1.601 +            data_.state_ = ASMJS;
   1.602 +            return;
   1.603 +        }
   1.604 +
   1.605 +        // ForkJoin activations don't contain iterable frames, so skip them.
   1.606 +        if (activation->isForkJoin()) {
   1.607 +            ++data_.activations_;
   1.608 +            continue;
   1.609 +        }
   1.610 +#endif
   1.611 +
   1.612 +        JS_ASSERT(activation->isInterpreter());
   1.613 +
   1.614 +        InterpreterActivation *interpAct = activation->asInterpreter();
   1.615 +        data_.interpFrames_ = InterpreterFrameIterator(interpAct);
   1.616 +
   1.617 +        // If we OSR'ed into JIT code, skip the interpreter frame so that
   1.618 +        // the same frame is not reported twice.
   1.619 +        if (data_.interpFrames_.frame()->runningInJit()) {
   1.620 +            ++data_.interpFrames_;
   1.621 +            if (data_.interpFrames_.done()) {
   1.622 +                ++data_.activations_;
   1.623 +                continue;
   1.624 +            }
   1.625 +        }
   1.626 +
   1.627 +        JS_ASSERT(!data_.interpFrames_.frame()->runningInJit());
   1.628 +        data_.pc_ = data_.interpFrames_.pc();
   1.629 +        data_.state_ = INTERP;
   1.630 +        return;
   1.631 +    }
   1.632 +}
   1.633 +
   1.634 +FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption,
   1.635 +                      JSPrincipals *principals)
   1.636 +  : cx_(cx),
   1.637 +    savedOption_(savedOption),
   1.638 +    contextOption_(contextOption),
   1.639 +    principals_(principals),
   1.640 +    pc_(nullptr),
   1.641 +    interpFrames_(nullptr),
   1.642 +    activations_(cx->runtime())
   1.643 +#ifdef JS_ION
   1.644 +  , jitFrames_((uint8_t *)nullptr, SequentialExecution)
   1.645 +  , ionInlineFrameNo_(0)
   1.646 +  , asmJSFrames_(nullptr)
   1.647 +#endif
   1.648 +{
   1.649 +}
   1.650 +
   1.651 +FrameIter::Data::Data(const FrameIter::Data &other)
   1.652 +  : cx_(other.cx_),
   1.653 +    savedOption_(other.savedOption_),
   1.654 +    contextOption_(other.contextOption_),
   1.655 +    principals_(other.principals_),
   1.656 +    state_(other.state_),
   1.657 +    pc_(other.pc_),
   1.658 +    interpFrames_(other.interpFrames_),
   1.659 +    activations_(other.activations_)
   1.660 +#ifdef JS_ION
   1.661 +  , jitFrames_(other.jitFrames_)
   1.662 +  , ionInlineFrameNo_(other.ionInlineFrameNo_)
   1.663 +  , asmJSFrames_(other.asmJSFrames_)
   1.664 +#endif
   1.665 +{
   1.666 +}
   1.667 +
   1.668 +FrameIter::FrameIter(JSContext *cx, SavedOption savedOption)
   1.669 +  : data_(cx, savedOption, CURRENT_CONTEXT, nullptr)
   1.670 +#ifdef JS_ION
   1.671 +  , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
   1.672 +#endif
   1.673 +{
   1.674 +    // settleOnActivation can only GC if principals are given.
   1.675 +    JS::AutoAssertNoGC nogc;
   1.676 +    settleOnActivation();
   1.677 +}
   1.678 +
   1.679 +FrameIter::FrameIter(JSContext *cx, ContextOption contextOption,
   1.680 +                     SavedOption savedOption, JSPrincipals *principals)
   1.681 +  : data_(cx, savedOption, contextOption, principals)
   1.682 +#ifdef JS_ION
   1.683 +  , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
   1.684 +#endif
   1.685 +{
   1.686 +    settleOnActivation();
   1.687 +}
   1.688 +
   1.689 +FrameIter::FrameIter(const FrameIter &other)
   1.690 +  : data_(other.data_)
   1.691 +#ifdef JS_ION
   1.692 +  , ionInlineFrames_(other.data_.cx_,
   1.693 +                     data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
   1.694 +#endif
   1.695 +{
   1.696 +}
   1.697 +
   1.698 +FrameIter::FrameIter(const Data &data)
   1.699 +  : data_(data)
   1.700 +#ifdef JS_ION
   1.701 +  , ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
   1.702 +#endif
   1.703 +{
   1.704 +    JS_ASSERT(data.cx_);
   1.705 +
   1.706 +#ifdef JS_ION
   1.707 +    if (data_.jitFrames_.isIonJS()) {
   1.708 +        while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
   1.709 +            ++ionInlineFrames_;
   1.710 +    }
   1.711 +#endif
   1.712 +}
   1.713 +
   1.714 +#ifdef JS_ION
   1.715 +void
   1.716 +FrameIter::nextJitFrame()
   1.717 +{
   1.718 +    if (data_.jitFrames_.isIonJS()) {
   1.719 +        ionInlineFrames_.resetOn(&data_.jitFrames_);
   1.720 +        data_.pc_ = ionInlineFrames_.pc();
   1.721 +    } else {
   1.722 +        JS_ASSERT(data_.jitFrames_.isBaselineJS());
   1.723 +        data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
   1.724 +    }
   1.725 +}
   1.726 +
   1.727 +void
   1.728 +FrameIter::popJitFrame()
   1.729 +{
   1.730 +    JS_ASSERT(data_.state_ == JIT);
   1.731 +
   1.732 +    if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
   1.733 +        ++ionInlineFrames_;
   1.734 +        data_.pc_ = ionInlineFrames_.pc();
   1.735 +        return;
   1.736 +    }
   1.737 +
   1.738 +    ++data_.jitFrames_;
   1.739 +    while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
   1.740 +        ++data_.jitFrames_;
   1.741 +
   1.742 +    if (!data_.jitFrames_.done()) {
   1.743 +        nextJitFrame();
   1.744 +        return;
   1.745 +    }
   1.746 +
   1.747 +    popActivation();
   1.748 +}
   1.749 +
   1.750 +void
   1.751 +FrameIter::popAsmJSFrame()
   1.752 +{
   1.753 +    JS_ASSERT(data_.state_ == ASMJS);
   1.754 +
   1.755 +    ++data_.asmJSFrames_;
   1.756 +    if (data_.asmJSFrames_.done())
   1.757 +        popActivation();
   1.758 +}
   1.759 +#endif
   1.760 +
   1.761 +FrameIter &
   1.762 +FrameIter::operator++()
   1.763 +{
   1.764 +    switch (data_.state_) {
   1.765 +      case DONE:
   1.766 +        MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.767 +      case INTERP:
   1.768 +        if (interpFrame()->isDebuggerFrame() && interpFrame()->evalInFramePrev()) {
   1.769 +            AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
   1.770 +            MOZ_ASSERT(!eifPrev.isRematerializedFrame());
   1.771 +
   1.772 +            // Eval-in-frame can cross contexts and works across saved frame
   1.773 +            // chains.
   1.774 +            ContextOption prevContextOption = data_.contextOption_;
   1.775 +            SavedOption prevSavedOption = data_.savedOption_;
   1.776 +            data_.contextOption_ = ALL_CONTEXTS;
   1.777 +            data_.savedOption_ = GO_THROUGH_SAVED;
   1.778 +
   1.779 +            popInterpreterFrame();
   1.780 +
   1.781 +            while (isIon() || abstractFramePtr() != eifPrev) {
   1.782 +                if (data_.state_ == JIT) {
   1.783 +#ifdef JS_ION
   1.784 +                    popJitFrame();
   1.785 +#else
   1.786 +                    MOZ_ASSUME_UNREACHABLE("Invalid state");
   1.787 +#endif
   1.788 +                } else {
   1.789 +                    popInterpreterFrame();
   1.790 +                }
   1.791 +            }
   1.792 +
   1.793 +            data_.contextOption_ = prevContextOption;
   1.794 +            data_.savedOption_ = prevSavedOption;
   1.795 +            data_.cx_ = data_.activations_->cx();
   1.796 +            break;
   1.797 +        }
   1.798 +        popInterpreterFrame();
   1.799 +        break;
   1.800 +#ifdef JS_ION
   1.801 +      case JIT:
   1.802 +        popJitFrame();
   1.803 +        break;
   1.804 +      case ASMJS:
   1.805 +        popAsmJSFrame();
   1.806 +        break;
   1.807 +#else
   1.808 +    default:
   1.809 +        MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.810 +#endif
   1.811 +    }
   1.812 +    return *this;
   1.813 +}
   1.814 +
   1.815 +FrameIter::Data *
   1.816 +FrameIter::copyData() const
   1.817 +{
   1.818 +    Data *data = data_.cx_->new_<Data>(data_);
   1.819 +#ifdef JS_ION
   1.820 +    JS_ASSERT(data_.state_ != ASMJS);
   1.821 +    if (data && data_.jitFrames_.isIonJS())
   1.822 +        data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
   1.823 +#endif
   1.824 +    return data;
   1.825 +}
   1.826 +
   1.827 +AbstractFramePtr
   1.828 +FrameIter::copyDataAsAbstractFramePtr() const
   1.829 +{
   1.830 +    AbstractFramePtr frame;
   1.831 +    if (Data *data = copyData())
   1.832 +        frame.ptr_ = uintptr_t(data);
   1.833 +    return frame;
   1.834 +}
   1.835 +
   1.836 +JSCompartment *
   1.837 +FrameIter::compartment() const
   1.838 +{
   1.839 +    switch (data_.state_) {
   1.840 +      case DONE:
   1.841 +        break;
   1.842 +      case INTERP:
   1.843 +      case JIT:
   1.844 +      case ASMJS:
   1.845 +        return data_.activations_->compartment();
   1.846 +    }
   1.847 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.848 +}
   1.849 +
   1.850 +bool
   1.851 +FrameIter::isFunctionFrame() const
   1.852 +{
   1.853 +    switch (data_.state_) {
   1.854 +      case DONE:
   1.855 +        break;
   1.856 +      case INTERP:
   1.857 +        return interpFrame()->isFunctionFrame();
   1.858 +      case JIT:
   1.859 +#ifdef JS_ION
   1.860 +        JS_ASSERT(data_.jitFrames_.isScripted());
   1.861 +        if (data_.jitFrames_.isBaselineJS())
   1.862 +            return data_.jitFrames_.isFunctionFrame();
   1.863 +        return ionInlineFrames_.isFunctionFrame();
   1.864 +#else
   1.865 +        break;
   1.866 +#endif
   1.867 +      case ASMJS:
   1.868 +        return true;
   1.869 +    }
   1.870 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.871 +}
   1.872 +
   1.873 +bool
   1.874 +FrameIter::isGlobalFrame() const
   1.875 +{
   1.876 +    switch (data_.state_) {
   1.877 +      case DONE:
   1.878 +        break;
   1.879 +      case INTERP:
   1.880 +        return interpFrame()->isGlobalFrame();
   1.881 +      case JIT:
   1.882 +#ifdef JS_ION
   1.883 +        if (data_.jitFrames_.isBaselineJS())
   1.884 +            return data_.jitFrames_.baselineFrame()->isGlobalFrame();
   1.885 +        JS_ASSERT(!script()->isForEval());
   1.886 +        return !script()->functionNonDelazifying();
   1.887 +#else
   1.888 +        break;
   1.889 +#endif
   1.890 +      case ASMJS:
   1.891 +        return false;
   1.892 +    }
   1.893 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.894 +}
   1.895 +
   1.896 +bool
   1.897 +FrameIter::isEvalFrame() const
   1.898 +{
   1.899 +    switch (data_.state_) {
   1.900 +      case DONE:
   1.901 +        break;
   1.902 +      case INTERP:
   1.903 +        return interpFrame()->isEvalFrame();
   1.904 +      case JIT:
   1.905 +#ifdef JS_ION
   1.906 +        if (data_.jitFrames_.isBaselineJS())
   1.907 +            return data_.jitFrames_.baselineFrame()->isEvalFrame();
   1.908 +        JS_ASSERT(!script()->isForEval());
   1.909 +        return false;
   1.910 +#else
   1.911 +        break;
   1.912 +#endif
   1.913 +      case ASMJS:
   1.914 +        return false;
   1.915 +    }
   1.916 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.917 +}
   1.918 +
   1.919 +bool
   1.920 +FrameIter::isNonEvalFunctionFrame() const
   1.921 +{
   1.922 +    JS_ASSERT(!done());
   1.923 +    switch (data_.state_) {
   1.924 +      case DONE:
   1.925 +        break;
   1.926 +      case INTERP:
   1.927 +        return interpFrame()->isNonEvalFunctionFrame();
   1.928 +      case JIT:
   1.929 +        return !isEvalFrame() && isFunctionFrame();
   1.930 +      case ASMJS:
   1.931 +        return true;
   1.932 +    }
   1.933 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.934 +}
   1.935 +
   1.936 +bool
   1.937 +FrameIter::isGeneratorFrame() const
   1.938 +{
   1.939 +    switch (data_.state_) {
   1.940 +      case DONE:
   1.941 +        break;
   1.942 +      case INTERP:
   1.943 +        return interpFrame()->isGeneratorFrame();
   1.944 +      case JIT:
   1.945 +        return false;
   1.946 +      case ASMJS:
   1.947 +        return false;
   1.948 +    }
   1.949 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.950 +}
   1.951 +
   1.952 +JSAtom *
   1.953 +FrameIter::functionDisplayAtom() const
   1.954 +{
   1.955 +    JS_ASSERT(isNonEvalFunctionFrame());
   1.956 +
   1.957 +    switch (data_.state_) {
   1.958 +      case DONE:
   1.959 +        break;
   1.960 +      case INTERP:
   1.961 +      case JIT:
   1.962 +        return callee()->displayAtom();
   1.963 +      case ASMJS: {
   1.964 +#ifdef JS_ION
   1.965 +        return data_.asmJSFrames_.functionDisplayAtom();
   1.966 +#else
   1.967 +        break;
   1.968 +#endif
   1.969 +      }
   1.970 +    }
   1.971 +
   1.972 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.973 +}
   1.974 +
   1.975 +ScriptSource *
   1.976 +FrameIter::scriptSource() const
   1.977 +{
   1.978 +    switch (data_.state_) {
   1.979 +      case DONE:
   1.980 +        break;
   1.981 +      case INTERP:
   1.982 +      case JIT:
   1.983 +        return script()->scriptSource();
   1.984 +      case ASMJS:
   1.985 +#ifdef JS_ION
   1.986 +        return data_.activations_->asAsmJS()->module().scriptSource();
   1.987 +#else
   1.988 +        break;
   1.989 +#endif
   1.990 +    }
   1.991 +
   1.992 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
   1.993 +}
   1.994 +
   1.995 +const char *
   1.996 +FrameIter::scriptFilename() const
   1.997 +{
   1.998 +    switch (data_.state_) {
   1.999 +      case DONE:
  1.1000 +        break;
  1.1001 +      case INTERP:
  1.1002 +      case JIT:
  1.1003 +        return script()->filename();
  1.1004 +      case ASMJS:
  1.1005 +#ifdef JS_ION
  1.1006 +        return data_.activations_->asAsmJS()->module().scriptSource()->filename();
  1.1007 +#else
  1.1008 +        break;
  1.1009 +#endif
  1.1010 +    }
  1.1011 +
  1.1012 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1013 +}
  1.1014 +
  1.1015 +unsigned
  1.1016 +FrameIter::computeLine(uint32_t *column) const
  1.1017 +{
  1.1018 +    switch (data_.state_) {
  1.1019 +      case DONE:
  1.1020 +        break;
  1.1021 +      case INTERP:
  1.1022 +      case JIT:
  1.1023 +        return PCToLineNumber(script(), pc(), column);
  1.1024 +      case ASMJS:
  1.1025 +#ifdef JS_ION
  1.1026 +        return data_.asmJSFrames_.computeLine(column);
  1.1027 +#else
  1.1028 +        break;
  1.1029 +#endif
  1.1030 +    }
  1.1031 +
  1.1032 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1033 +}
  1.1034 +
  1.1035 +JSPrincipals *
  1.1036 +FrameIter::originPrincipals() const
  1.1037 +{
  1.1038 +    switch (data_.state_) {
  1.1039 +      case DONE:
  1.1040 +        break;
  1.1041 +      case INTERP:
  1.1042 +      case JIT:
  1.1043 +        return script()->originPrincipals();
  1.1044 +      case ASMJS: {
  1.1045 +#ifdef JS_ION
  1.1046 +        return data_.activations_->asAsmJS()->module().scriptSource()->originPrincipals();
  1.1047 +#else
  1.1048 +        break;
  1.1049 +#endif
  1.1050 +      }
  1.1051 +    }
  1.1052 +
  1.1053 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1054 +}
  1.1055 +
  1.1056 +bool
  1.1057 +FrameIter::isConstructing() const
  1.1058 +{
  1.1059 +    switch (data_.state_) {
  1.1060 +      case DONE:
  1.1061 +      case ASMJS:
  1.1062 +        break;
  1.1063 +      case JIT:
  1.1064 +#ifdef JS_ION
  1.1065 +        if (data_.jitFrames_.isIonJS())
  1.1066 +            return ionInlineFrames_.isConstructing();
  1.1067 +        JS_ASSERT(data_.jitFrames_.isBaselineJS());
  1.1068 +        return data_.jitFrames_.isConstructing();
  1.1069 +#else
  1.1070 +        break;
  1.1071 +#endif
  1.1072 +      case INTERP:
  1.1073 +        return interpFrame()->isConstructing();
  1.1074 +    }
  1.1075 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1076 +}
  1.1077 +
  1.1078 +bool
  1.1079 +FrameIter::ensureHasRematerializedFrame()
  1.1080 +{
  1.1081 +#ifdef JS_ION
  1.1082 +    MOZ_ASSERT(isIon());
  1.1083 +    return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_);
  1.1084 +#else
  1.1085 +    return true;
  1.1086 +#endif
  1.1087 +}
  1.1088 +
  1.1089 +bool
  1.1090 +FrameIter::hasUsableAbstractFramePtr() const
  1.1091 +{
  1.1092 +    switch (data_.state_) {
  1.1093 +      case DONE:
  1.1094 +      case ASMJS:
  1.1095 +        return false;
  1.1096 +      case JIT:
  1.1097 +#ifdef JS_ION
  1.1098 +        if (data_.jitFrames_.isBaselineJS())
  1.1099 +            return true;
  1.1100 +
  1.1101 +        MOZ_ASSERT(data_.jitFrames_.isIonJS());
  1.1102 +        return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
  1.1103 +                                                                  ionInlineFrames_.frameNo());
  1.1104 +#endif
  1.1105 +        break;
  1.1106 +      case INTERP:
  1.1107 +        return true;
  1.1108 +    }
  1.1109 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1110 +}
  1.1111 +
  1.1112 +AbstractFramePtr
  1.1113 +FrameIter::abstractFramePtr() const
  1.1114 +{
  1.1115 +    MOZ_ASSERT(hasUsableAbstractFramePtr());
  1.1116 +    switch (data_.state_) {
  1.1117 +      case DONE:
  1.1118 +      case ASMJS:
  1.1119 +        break;
  1.1120 +      case JIT: {
  1.1121 +#ifdef JS_ION
  1.1122 +        if (data_.jitFrames_.isBaselineJS())
  1.1123 +            return data_.jitFrames_.baselineFrame();
  1.1124 +
  1.1125 +        MOZ_ASSERT(data_.jitFrames_.isIonJS());
  1.1126 +        return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
  1.1127 +                                                                ionInlineFrames_.frameNo());
  1.1128 +#endif
  1.1129 +        break;
  1.1130 +      }
  1.1131 +      case INTERP:
  1.1132 +        JS_ASSERT(interpFrame());
  1.1133 +        return AbstractFramePtr(interpFrame());
  1.1134 +    }
  1.1135 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1136 +}
  1.1137 +
  1.1138 +void
  1.1139 +FrameIter::updatePcQuadratic()
  1.1140 +{
  1.1141 +    switch (data_.state_) {
  1.1142 +      case DONE:
  1.1143 +      case ASMJS:
  1.1144 +        break;
  1.1145 +      case INTERP: {
  1.1146 +        InterpreterFrame *frame = interpFrame();
  1.1147 +        InterpreterActivation *activation = data_.activations_->asInterpreter();
  1.1148 +
  1.1149 +        // Look for the current frame.
  1.1150 +        data_.interpFrames_ = InterpreterFrameIterator(activation);
  1.1151 +        while (data_.interpFrames_.frame() != frame)
  1.1152 +            ++data_.interpFrames_;
  1.1153 +
  1.1154 +        // Update the pc.
  1.1155 +        JS_ASSERT(data_.interpFrames_.frame() == frame);
  1.1156 +        data_.pc_ = data_.interpFrames_.pc();
  1.1157 +        return;
  1.1158 +      }
  1.1159 +      case JIT:
  1.1160 +#ifdef JS_ION
  1.1161 +        if (data_.jitFrames_.isBaselineJS()) {
  1.1162 +            jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
  1.1163 +            jit::JitActivation *activation = data_.activations_->asJit();
  1.1164 +
  1.1165 +            // ActivationIterator::ionTop_ may be invalid, so create a new
  1.1166 +            // activation iterator.
  1.1167 +            data_.activations_ = ActivationIterator(data_.cx_->runtime());
  1.1168 +            while (data_.activations_.activation() != activation)
  1.1169 +                ++data_.activations_;
  1.1170 +
  1.1171 +            // Look for the current frame.
  1.1172 +            data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
  1.1173 +            while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
  1.1174 +                ++data_.jitFrames_;
  1.1175 +
  1.1176 +            // Update the pc.
  1.1177 +            JS_ASSERT(data_.jitFrames_.baselineFrame() == frame);
  1.1178 +            data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
  1.1179 +            return;
  1.1180 +        }
  1.1181 +#endif
  1.1182 +        break;
  1.1183 +    }
  1.1184 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1185 +}
  1.1186 +
  1.1187 +JSFunction *
  1.1188 +FrameIter::callee() const
  1.1189 +{
  1.1190 +    switch (data_.state_) {
  1.1191 +      case DONE:
  1.1192 +      case ASMJS:
  1.1193 +        break;
  1.1194 +      case INTERP:
  1.1195 +        JS_ASSERT(isFunctionFrame());
  1.1196 +        return &interpFrame()->callee();
  1.1197 +      case JIT:
  1.1198 +#ifdef JS_ION
  1.1199 +        if (data_.jitFrames_.isBaselineJS())
  1.1200 +            return data_.jitFrames_.callee();
  1.1201 +        JS_ASSERT(data_.jitFrames_.isIonJS());
  1.1202 +        return ionInlineFrames_.callee();
  1.1203 +#else
  1.1204 +        break;
  1.1205 +#endif
  1.1206 +    }
  1.1207 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1208 +}
  1.1209 +
  1.1210 +Value
  1.1211 +FrameIter::calleev() const
  1.1212 +{
  1.1213 +    switch (data_.state_) {
  1.1214 +      case DONE:
  1.1215 +      case ASMJS:
  1.1216 +        break;
  1.1217 +      case INTERP:
  1.1218 +        JS_ASSERT(isFunctionFrame());
  1.1219 +        return interpFrame()->calleev();
  1.1220 +      case JIT:
  1.1221 +#ifdef JS_ION
  1.1222 +        return ObjectValue(*callee());
  1.1223 +#else
  1.1224 +        break;
  1.1225 +#endif
  1.1226 +    }
  1.1227 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1228 +}
  1.1229 +
  1.1230 +unsigned
  1.1231 +FrameIter::numActualArgs() const
  1.1232 +{
  1.1233 +    switch (data_.state_) {
  1.1234 +      case DONE:
  1.1235 +      case ASMJS:
  1.1236 +        break;
  1.1237 +      case INTERP:
  1.1238 +        JS_ASSERT(isFunctionFrame());
  1.1239 +        return interpFrame()->numActualArgs();
  1.1240 +      case JIT:
  1.1241 +#ifdef JS_ION
  1.1242 +        if (data_.jitFrames_.isIonJS())
  1.1243 +            return ionInlineFrames_.numActualArgs();
  1.1244 +
  1.1245 +        JS_ASSERT(data_.jitFrames_.isBaselineJS());
  1.1246 +        return data_.jitFrames_.numActualArgs();
  1.1247 +#else
  1.1248 +        break;
  1.1249 +#endif
  1.1250 +    }
  1.1251 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1252 +}
  1.1253 +
  1.1254 +unsigned
  1.1255 +FrameIter::numFormalArgs() const
  1.1256 +{
  1.1257 +    return script()->functionNonDelazifying()->nargs();
  1.1258 +}
  1.1259 +
  1.1260 +Value
  1.1261 +FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
  1.1262 +{
  1.1263 +    return abstractFramePtr().unaliasedActual(i, checkAliasing);
  1.1264 +}
  1.1265 +
  1.1266 +JSObject *
  1.1267 +FrameIter::scopeChain() const
  1.1268 +{
  1.1269 +    switch (data_.state_) {
  1.1270 +      case DONE:
  1.1271 +      case ASMJS:
  1.1272 +        break;
  1.1273 +      case JIT:
  1.1274 +#ifdef JS_ION
  1.1275 +        if (data_.jitFrames_.isIonJS())
  1.1276 +            return ionInlineFrames_.scopeChain();
  1.1277 +        return data_.jitFrames_.baselineFrame()->scopeChain();
  1.1278 +#else
  1.1279 +        break;
  1.1280 +#endif
  1.1281 +      case INTERP:
  1.1282 +        return interpFrame()->scopeChain();
  1.1283 +    }
  1.1284 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1285 +}
  1.1286 +
  1.1287 +CallObject &
  1.1288 +FrameIter::callObj() const
  1.1289 +{
  1.1290 +    JS_ASSERT(callee()->isHeavyweight());
  1.1291 +
  1.1292 +    JSObject *pobj = scopeChain();
  1.1293 +    while (!pobj->is<CallObject>())
  1.1294 +        pobj = pobj->enclosingScope();
  1.1295 +    return pobj->as<CallObject>();
  1.1296 +}
  1.1297 +
  1.1298 +bool
  1.1299 +FrameIter::hasArgsObj() const
  1.1300 +{
  1.1301 +    return abstractFramePtr().hasArgsObj();
  1.1302 +}
  1.1303 +
  1.1304 +ArgumentsObject &
  1.1305 +FrameIter::argsObj() const
  1.1306 +{
  1.1307 +    MOZ_ASSERT(hasArgsObj());
  1.1308 +    return abstractFramePtr().argsObj();
  1.1309 +}
  1.1310 +
  1.1311 +bool
  1.1312 +FrameIter::computeThis(JSContext *cx) const
  1.1313 +{
  1.1314 +    JS_ASSERT(!done() && !isAsmJS());
  1.1315 +    assertSameCompartment(cx, scopeChain());
  1.1316 +    return ComputeThis(cx, abstractFramePtr());
  1.1317 +}
  1.1318 +
  1.1319 +Value
  1.1320 +FrameIter::computedThisValue() const
  1.1321 +{
  1.1322 +    return abstractFramePtr().thisValue();
  1.1323 +}
  1.1324 +
  1.1325 +Value
  1.1326 +FrameIter::thisv() const
  1.1327 +{
  1.1328 +    switch (data_.state_) {
  1.1329 +      case DONE:
  1.1330 +      case ASMJS:
  1.1331 +        break;
  1.1332 +      case JIT:
  1.1333 +#ifdef JS_ION
  1.1334 +        if (data_.jitFrames_.isIonJS())
  1.1335 +            return ionInlineFrames_.thisValue();
  1.1336 +        return data_.jitFrames_.baselineFrame()->thisValue();
  1.1337 +#else
  1.1338 +        break;
  1.1339 +#endif
  1.1340 +      case INTERP:
  1.1341 +        return interpFrame()->thisValue();
  1.1342 +    }
  1.1343 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1344 +}
  1.1345 +
  1.1346 +Value
  1.1347 +FrameIter::returnValue() const
  1.1348 +{
  1.1349 +    switch (data_.state_) {
  1.1350 +      case DONE:
  1.1351 +      case ASMJS:
  1.1352 +        break;
  1.1353 +      case JIT:
  1.1354 +#ifdef JS_ION
  1.1355 +        if (data_.jitFrames_.isBaselineJS())
  1.1356 +            return data_.jitFrames_.baselineFrame()->returnValue();
  1.1357 +#endif
  1.1358 +        break;
  1.1359 +      case INTERP:
  1.1360 +        return interpFrame()->returnValue();
  1.1361 +    }
  1.1362 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1363 +}
  1.1364 +
  1.1365 +void
  1.1366 +FrameIter::setReturnValue(const Value &v)
  1.1367 +{
  1.1368 +    switch (data_.state_) {
  1.1369 +      case DONE:
  1.1370 +      case ASMJS:
  1.1371 +        break;
  1.1372 +      case JIT:
  1.1373 +#ifdef JS_ION
  1.1374 +        if (data_.jitFrames_.isBaselineJS()) {
  1.1375 +            data_.jitFrames_.baselineFrame()->setReturnValue(v);
  1.1376 +            return;
  1.1377 +        }
  1.1378 +#endif
  1.1379 +        break;
  1.1380 +      case INTERP:
  1.1381 +        interpFrame()->setReturnValue(v);
  1.1382 +        return;
  1.1383 +    }
  1.1384 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1385 +}
  1.1386 +
  1.1387 +size_t
  1.1388 +FrameIter::numFrameSlots() const
  1.1389 +{
  1.1390 +    switch (data_.state_) {
  1.1391 +      case DONE:
  1.1392 +      case ASMJS:
  1.1393 +        break;
  1.1394 +      case JIT: {
  1.1395 +#ifdef JS_ION
  1.1396 +        if (data_.jitFrames_.isIonJS()) {
  1.1397 +            return ionInlineFrames_.snapshotIterator().numAllocations() -
  1.1398 +                ionInlineFrames_.script()->nfixed();
  1.1399 +        }
  1.1400 +        jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
  1.1401 +        return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
  1.1402 +#else
  1.1403 +        break;
  1.1404 +#endif
  1.1405 +      }
  1.1406 +      case INTERP:
  1.1407 +        JS_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
  1.1408 +        return data_.interpFrames_.sp() - interpFrame()->base();
  1.1409 +    }
  1.1410 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1411 +}
  1.1412 +
  1.1413 +Value
  1.1414 +FrameIter::frameSlotValue(size_t index) const
  1.1415 +{
  1.1416 +    switch (data_.state_) {
  1.1417 +      case DONE:
  1.1418 +      case ASMJS:
  1.1419 +        break;
  1.1420 +      case JIT:
  1.1421 +#ifdef JS_ION
  1.1422 +        if (data_.jitFrames_.isIonJS()) {
  1.1423 +            jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
  1.1424 +            index += ionInlineFrames_.script()->nfixed();
  1.1425 +            return si.maybeReadAllocByIndex(index);
  1.1426 +        }
  1.1427 +
  1.1428 +        index += data_.jitFrames_.script()->nfixed();
  1.1429 +        return *data_.jitFrames_.baselineFrame()->valueSlot(index);
  1.1430 +#else
  1.1431 +        break;
  1.1432 +#endif
  1.1433 +      case INTERP:
  1.1434 +          return interpFrame()->base()[index];
  1.1435 +    }
  1.1436 +    MOZ_ASSUME_UNREACHABLE("Unexpected state");
  1.1437 +}
  1.1438 +
  1.1439 +#if defined(_MSC_VER)
  1.1440 +# pragma optimize("", on)
  1.1441 +#endif
  1.1442 +
  1.1443 +#ifdef DEBUG
  1.1444 +bool
  1.1445 +js::SelfHostedFramesVisible()
  1.1446 +{
  1.1447 +    static bool checked = false;
  1.1448 +    static bool visible = false;
  1.1449 +    if (!checked) {
  1.1450 +        checked = true;
  1.1451 +        char *env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
  1.1452 +        visible = !!env;
  1.1453 +    }
  1.1454 +    return visible;
  1.1455 +}
  1.1456 +#endif
  1.1457 +
  1.1458 +void
  1.1459 +NonBuiltinFrameIter::settle()
  1.1460 +{
  1.1461 +    if (!SelfHostedFramesVisible()) {
  1.1462 +        while (!done() && hasScript() && script()->selfHosted())
  1.1463 +            FrameIter::operator++();
  1.1464 +    }
  1.1465 +}
  1.1466 +
  1.1467 +void
  1.1468 +NonBuiltinScriptFrameIter::settle()
  1.1469 +{
  1.1470 +    if (!SelfHostedFramesVisible()) {
  1.1471 +        while (!done() && script()->selfHosted())
  1.1472 +            ScriptFrameIter::operator++();
  1.1473 +    }
  1.1474 +}
  1.1475 +
  1.1476 +/*****************************************************************************/
  1.1477 +
  1.1478 +JSObject *
  1.1479 +AbstractFramePtr::evalPrevScopeChain(JSContext *cx) const
  1.1480 +{
  1.1481 +    // Eval frames are not compiled by Ion, though their caller might be.
  1.1482 +    AllFramesIter iter(cx);
  1.1483 +    while (iter.isIon() || iter.abstractFramePtr() != *this)
  1.1484 +        ++iter;
  1.1485 +    ++iter;
  1.1486 +    return iter.scopeChain();
  1.1487 +}
  1.1488 +
  1.1489 +bool
  1.1490 +AbstractFramePtr::hasPushedSPSFrame() const
  1.1491 +{
  1.1492 +    if (isInterpreterFrame())
  1.1493 +        return asInterpreterFrame()->hasPushedSPSFrame();
  1.1494 +#ifdef JS_ION
  1.1495 +    return asBaselineFrame()->hasPushedSPSFrame();
  1.1496 +#else
  1.1497 +    MOZ_ASSUME_UNREACHABLE("Invalid frame");
  1.1498 +#endif
  1.1499 +}
  1.1500 +
  1.1501 +#ifdef DEBUG
  1.1502 +void
  1.1503 +js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i)
  1.1504 +{
  1.1505 +    if (!checkAliasing)
  1.1506 +        return;
  1.1507 +
  1.1508 +    JS_ASSERT(i < script->nfixed());
  1.1509 +    if (i < script->bindings.numVars()) {
  1.1510 +        JS_ASSERT(!script->varIsAliased(i));
  1.1511 +    } else {
  1.1512 +        // FIXME: The callers of this function do not easily have the PC of the
  1.1513 +        // current frame, and so they do not know the block scope.
  1.1514 +    }
  1.1515 +}
  1.1516 +#endif
  1.1517 +
  1.1518 +jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
  1.1519 +  : Activation(cx, Jit),
  1.1520 +    firstFrameIsConstructing_(firstFrameIsConstructing),
  1.1521 +    active_(active)
  1.1522 +#ifdef JS_ION
  1.1523 +  , rematerializedFrames_(cx)
  1.1524 +#endif
  1.1525 +{
  1.1526 +    if (active) {
  1.1527 +        prevIonTop_ = cx->mainThread().ionTop;
  1.1528 +        prevJitJSContext_ = cx->mainThread().jitJSContext;
  1.1529 +        cx->mainThread().jitJSContext = cx;
  1.1530 +    } else {
  1.1531 +        prevIonTop_ = nullptr;
  1.1532 +        prevJitJSContext_ = nullptr;
  1.1533 +    }
  1.1534 +}
  1.1535 +
  1.1536 +jit::JitActivation::~JitActivation()
  1.1537 +{
  1.1538 +    if (active_) {
  1.1539 +        cx_->mainThread().ionTop = prevIonTop_;
  1.1540 +        cx_->mainThread().jitJSContext = prevJitJSContext_;
  1.1541 +    }
  1.1542 +
  1.1543 +#ifdef JS_ION
  1.1544 +    clearRematerializedFrames();
  1.1545 +#endif
  1.1546 +}
  1.1547 +
  1.1548 +// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
  1.1549 +// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
  1.1550 +// and disable activation instruction sequences.
  1.1551 +void
  1.1552 +jit::JitActivation::setActive(JSContext *cx, bool active)
  1.1553 +{
  1.1554 +    // Only allowed to deactivate/activate if activation is top.
  1.1555 +    // (Not tested and will probably fail in other situations.)
  1.1556 +    JS_ASSERT(cx->mainThread().activation_ == this);
  1.1557 +    JS_ASSERT(active != active_);
  1.1558 +    active_ = active;
  1.1559 +
  1.1560 +    if (active) {
  1.1561 +        prevIonTop_ = cx->mainThread().ionTop;
  1.1562 +        prevJitJSContext_ = cx->mainThread().jitJSContext;
  1.1563 +        cx->mainThread().jitJSContext = cx;
  1.1564 +    } else {
  1.1565 +        cx->mainThread().ionTop = prevIonTop_;
  1.1566 +        cx->mainThread().jitJSContext = prevJitJSContext_;
  1.1567 +    }
  1.1568 +}
  1.1569 +
  1.1570 +#ifdef JS_ION
  1.1571 +
  1.1572 +void
  1.1573 +jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector &frames)
  1.1574 +{
  1.1575 +    for (size_t i = 0; i < frames.length(); i++) {
  1.1576 +        RematerializedFrame *f = frames[i];
  1.1577 +        f->RematerializedFrame::~RematerializedFrame();
  1.1578 +        js_free(f);
  1.1579 +    }
  1.1580 +    frames.clear();
  1.1581 +}
  1.1582 +
  1.1583 +void
  1.1584 +jit::JitActivation::removeRematerializedFrame(uint8_t *top)
  1.1585 +{
  1.1586 +    if (!rematerializedFrames_.initialized())
  1.1587 +        return;
  1.1588 +
  1.1589 +    if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) {
  1.1590 +        freeRematerializedFramesInVector(p->value());
  1.1591 +        rematerializedFrames_.remove(p);
  1.1592 +    }
  1.1593 +}
  1.1594 +
  1.1595 +void
  1.1596 +jit::JitActivation::clearRematerializedFrames()
  1.1597 +{
  1.1598 +    if (!rematerializedFrames_.initialized())
  1.1599 +        return;
  1.1600 +
  1.1601 +    for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
  1.1602 +        freeRematerializedFramesInVector(e.front().value());
  1.1603 +        e.removeFront();
  1.1604 +    }
  1.1605 +}
  1.1606 +
  1.1607 +jit::RematerializedFrame *
  1.1608 +jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
  1.1609 +                                           size_t inlineDepth)
  1.1610 +{
  1.1611 +    MOZ_ASSERT(iter.activation() == this);
  1.1612 +    MOZ_ASSERT(iter.isIonJS());
  1.1613 +
  1.1614 +    if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init())
  1.1615 +        return nullptr;
  1.1616 +
  1.1617 +    // The unit of rematerialization is an uninlined frame and its inlined
  1.1618 +    // frames. Since inlined frames do not exist outside of snapshots, it is
  1.1619 +    // impossible to synchronize their rematerialized copies to preserve
  1.1620 +    // identity. Therefore, we always rematerialize an uninlined frame and all
  1.1621 +    // its inlined frames at once.
  1.1622 +
  1.1623 +    uint8_t *top = iter.fp();
  1.1624 +    RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top);
  1.1625 +    if (!p) {
  1.1626 +        RematerializedFrameVector empty(cx);
  1.1627 +        if (!rematerializedFrames_.add(p, top, Move(empty)))
  1.1628 +            return nullptr;
  1.1629 +
  1.1630 +        InlineFrameIterator inlineIter(cx, &iter);
  1.1631 +        if (!p->value().resize(inlineIter.frameCount()))
  1.1632 +            return nullptr;
  1.1633 +
  1.1634 +        while (true) {
  1.1635 +            size_t frameNo = inlineIter.frameNo();
  1.1636 +            p->value()[frameNo] = RematerializedFrame::New(cx, top, inlineIter);
  1.1637 +            if (!p->value()[frameNo])
  1.1638 +                return nullptr;
  1.1639 +
  1.1640 +            if (!inlineIter.more())
  1.1641 +                break;
  1.1642 +            ++inlineIter;
  1.1643 +        }
  1.1644 +    }
  1.1645 +
  1.1646 +    return p->value()[inlineDepth];
  1.1647 +}
  1.1648 +
  1.1649 +jit::RematerializedFrame *
  1.1650 +jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
  1.1651 +{
  1.1652 +    if (!rematerializedFrames_.initialized())
  1.1653 +        return nullptr;
  1.1654 +    if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top))
  1.1655 +        return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
  1.1656 +    return nullptr;
  1.1657 +}
  1.1658 +
  1.1659 +void
  1.1660 +jit::JitActivation::markRematerializedFrames(JSTracer *trc)
  1.1661 +{
  1.1662 +    if (!rematerializedFrames_.initialized())
  1.1663 +        return;
  1.1664 +    for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
  1.1665 +        RematerializedFrameVector &frames = e.front().value();
  1.1666 +        for (size_t i = 0; i < frames.length(); i++)
  1.1667 +            frames[i]->mark(trc);
  1.1668 +    }
  1.1669 +}
  1.1670 +
  1.1671 +#endif // JS_ION
  1.1672 +
  1.1673 +AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
  1.1674 +  : Activation(cx, AsmJS),
  1.1675 +    module_(module),
  1.1676 +    errorRejoinSP_(nullptr),
  1.1677 +    profiler_(nullptr),
  1.1678 +    resumePC_(nullptr),
  1.1679 +    exitSP_(nullptr)
  1.1680 +{
  1.1681 +    if (cx->runtime()->spsProfiler.enabled()) {
  1.1682 +        // Use a profiler string that matches jsMatch regex in
  1.1683 +        // browser/devtools/profiler/cleopatra/js/parserWorker.js.
  1.1684 +        // (For now use a single static string to avoid further slowing down
  1.1685 +        // calls into asm.js.)
  1.1686 +        profiler_ = &cx->runtime()->spsProfiler;
  1.1687 +        profiler_->enterNative("asm.js code :0", this);
  1.1688 +    }
  1.1689 +
  1.1690 +    prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_;
  1.1691 +
  1.1692 +    JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
  1.1693 +    cx_->runtime()->mainThread.asmJSActivationStack_ = this;
  1.1694 +
  1.1695 +    (void) errorRejoinSP_;  // squelch GCC warning
  1.1696 +}
  1.1697 +
  1.1698 +AsmJSActivation::~AsmJSActivation()
  1.1699 +{
  1.1700 +    if (profiler_)
  1.1701 +        profiler_->exitNative();
  1.1702 +
  1.1703 +    JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this);
  1.1704 +
  1.1705 +    JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
  1.1706 +    cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_;
  1.1707 +}
  1.1708 +
  1.1709 +InterpreterFrameIterator &
  1.1710 +InterpreterFrameIterator::operator++()
  1.1711 +{
  1.1712 +    JS_ASSERT(!done());
  1.1713 +    if (fp_ != activation_->entryFrame_) {
  1.1714 +        pc_ = fp_->prevpc();
  1.1715 +        sp_ = fp_->prevsp();
  1.1716 +        fp_ = fp_->prev();
  1.1717 +    } else {
  1.1718 +        pc_ = nullptr;
  1.1719 +        sp_ = nullptr;
  1.1720 +        fp_ = nullptr;
  1.1721 +    }
  1.1722 +    return *this;
  1.1723 +}
  1.1724 +
  1.1725 +ActivationIterator::ActivationIterator(JSRuntime *rt)
  1.1726 +  : jitTop_(rt->mainThread.ionTop),
  1.1727 +    activation_(rt->mainThread.activation_)
  1.1728 +{
  1.1729 +    settle();
  1.1730 +}
  1.1731 +
  1.1732 +ActivationIterator &
  1.1733 +ActivationIterator::operator++()
  1.1734 +{
  1.1735 +    JS_ASSERT(activation_);
  1.1736 +    if (activation_->isJit() && activation_->asJit()->isActive())
  1.1737 +        jitTop_ = activation_->asJit()->prevIonTop();
  1.1738 +    activation_ = activation_->prev();
  1.1739 +    settle();
  1.1740 +    return *this;
  1.1741 +}
  1.1742 +
  1.1743 +void
  1.1744 +ActivationIterator::settle()
  1.1745 +{
  1.1746 +    // Stop at the next active activation. No need to update jitTop_, since
  1.1747 +    // we don't iterate over an active jit activation.
  1.1748 +    while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
  1.1749 +        activation_ = activation_->prev();
  1.1750 +}

mercurial