js/src/jit/BaselineFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/BaselineFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,221 @@
     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 "jit/BaselineFrame-inl.h"
    1.11 +
    1.12 +#include "jit/BaselineJIT.h"
    1.13 +#include "jit/Ion.h"
    1.14 +#include "vm/Debugger.h"
    1.15 +#include "vm/ScopeObject.h"
    1.16 +
    1.17 +#include "jit/IonFrames-inl.h"
    1.18 +#include "vm/Stack-inl.h"
    1.19 +
    1.20 +using namespace js;
    1.21 +using namespace js::jit;
    1.22 +
    1.23 +static void
    1.24 +MarkLocals(BaselineFrame *frame, JSTracer *trc, unsigned start, unsigned end)
    1.25 +{
    1.26 +    if (start < end) {
    1.27 +        // Stack grows down.
    1.28 +        Value *last = frame->valueSlot(end - 1);
    1.29 +        gc::MarkValueRootRange(trc, end - start, last, "baseline-stack");
    1.30 +    }
    1.31 +}
    1.32 +
    1.33 +void
    1.34 +BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator)
    1.35 +{
    1.36 +    replaceCalleeToken(MarkCalleeToken(trc, calleeToken()));
    1.37 +
    1.38 +    gc::MarkValueRoot(trc, &thisValue(), "baseline-this");
    1.39 +
    1.40 +    // Mark actual and formal args.
    1.41 +    if (isNonEvalFunctionFrame()) {
    1.42 +        unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
    1.43 +        gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args");
    1.44 +    }
    1.45 +
    1.46 +    // Mark scope chain, if it exists.
    1.47 +    if (scopeChain_)
    1.48 +        gc::MarkObjectRoot(trc, &scopeChain_, "baseline-scopechain");
    1.49 +
    1.50 +    // Mark return value.
    1.51 +    if (hasReturnValue())
    1.52 +        gc::MarkValueRoot(trc, returnValue().address(), "baseline-rval");
    1.53 +
    1.54 +    if (isEvalFrame())
    1.55 +        gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript");
    1.56 +
    1.57 +    if (hasArgsObj())
    1.58 +        gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj");
    1.59 +
    1.60 +    // Mark locals and stack values.
    1.61 +    JSScript *script = this->script();
    1.62 +    size_t nfixed = script->nfixed();
    1.63 +    size_t nlivefixed = script->nfixedvars();
    1.64 +
    1.65 +    if (nfixed != nlivefixed) {
    1.66 +        jsbytecode *pc;
    1.67 +        NestedScopeObject *staticScope;
    1.68 +
    1.69 +        frameIterator.baselineScriptAndPc(nullptr, &pc);
    1.70 +        staticScope = script->getStaticScope(pc);
    1.71 +        while (staticScope && !staticScope->is<StaticBlockObject>())
    1.72 +            staticScope = staticScope->enclosingNestedScope();
    1.73 +
    1.74 +        if (staticScope) {
    1.75 +            StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
    1.76 +            nlivefixed = blockObj.localOffset() + blockObj.numVariables();
    1.77 +        }
    1.78 +    }
    1.79 +
    1.80 +    JS_ASSERT(nlivefixed <= nfixed);
    1.81 +    JS_ASSERT(nlivefixed >= script->nfixedvars());
    1.82 +
    1.83 +    // NB: It is possible that numValueSlots() could be zero, even if nfixed is
    1.84 +    // nonzero.  This is the case if the function has an early stack check.
    1.85 +    if (numValueSlots() == 0)
    1.86 +        return;
    1.87 +
    1.88 +    JS_ASSERT(nfixed <= numValueSlots());
    1.89 +
    1.90 +    if (nfixed == nlivefixed) {
    1.91 +        // All locals are live.
    1.92 +        MarkLocals(this, trc, 0, numValueSlots());
    1.93 +    } else {
    1.94 +        // Mark operand stack.
    1.95 +        MarkLocals(this, trc, nfixed, numValueSlots());
    1.96 +
    1.97 +        // Clear dead locals.
    1.98 +        while (nfixed > nlivefixed)
    1.99 +            unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined();
   1.100 +
   1.101 +        // Mark live locals.
   1.102 +        MarkLocals(this, trc, 0, nlivefixed);
   1.103 +    }
   1.104 +}
   1.105 +
   1.106 +bool
   1.107 +BaselineFrame::copyRawFrameSlots(AutoValueVector *vec) const
   1.108 +{
   1.109 +    unsigned nfixed = script()->nfixed();
   1.110 +    unsigned nformals = numFormalArgs();
   1.111 +
   1.112 +    if (!vec->resize(nformals + nfixed))
   1.113 +        return false;
   1.114 +
   1.115 +    mozilla::PodCopy(vec->begin(), argv(), nformals);
   1.116 +    for (unsigned i = 0; i < nfixed; i++)
   1.117 +        (*vec)[nformals + i] = *valueSlot(i);
   1.118 +    return true;
   1.119 +}
   1.120 +
   1.121 +bool
   1.122 +BaselineFrame::strictEvalPrologue(JSContext *cx)
   1.123 +{
   1.124 +    JS_ASSERT(isStrictEvalFrame());
   1.125 +
   1.126 +    CallObject *callobj = CallObject::createForStrictEval(cx, this);
   1.127 +    if (!callobj)
   1.128 +        return false;
   1.129 +
   1.130 +    pushOnScopeChain(*callobj);
   1.131 +    flags_ |= HAS_CALL_OBJ;
   1.132 +    return true;
   1.133 +}
   1.134 +
   1.135 +bool
   1.136 +BaselineFrame::heavyweightFunPrologue(JSContext *cx)
   1.137 +{
   1.138 +    return initFunctionScopeObjects(cx);
   1.139 +}
   1.140 +
   1.141 +bool
   1.142 +BaselineFrame::initFunctionScopeObjects(JSContext *cx)
   1.143 +{
   1.144 +    JS_ASSERT(isNonEvalFunctionFrame());
   1.145 +    JS_ASSERT(fun()->isHeavyweight());
   1.146 +
   1.147 +    CallObject *callobj = CallObject::createForFunction(cx, this);
   1.148 +    if (!callobj)
   1.149 +        return false;
   1.150 +
   1.151 +    pushOnScopeChain(*callobj);
   1.152 +    flags_ |= HAS_CALL_OBJ;
   1.153 +    return true;
   1.154 +}
   1.155 +
   1.156 +bool
   1.157 +BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues)
   1.158 +{
   1.159 +    mozilla::PodZero(this);
   1.160 +
   1.161 +    scopeChain_ = fp->scopeChain();
   1.162 +
   1.163 +    if (fp->hasCallObjUnchecked())
   1.164 +        flags_ |= BaselineFrame::HAS_CALL_OBJ;
   1.165 +
   1.166 +    if (fp->isEvalFrame()) {
   1.167 +        flags_ |= BaselineFrame::EVAL;
   1.168 +        evalScript_ = fp->script();
   1.169 +    }
   1.170 +
   1.171 +    if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
   1.172 +        flags_ |= BaselineFrame::HAS_ARGS_OBJ;
   1.173 +        argsObj_ = &fp->argsObj();
   1.174 +    }
   1.175 +
   1.176 +    if (fp->hasHookData()) {
   1.177 +        flags_ |= BaselineFrame::HAS_HOOK_DATA;
   1.178 +        hookData_ = fp->hookData();
   1.179 +    }
   1.180 +
   1.181 +    if (fp->hasReturnValue())
   1.182 +        setReturnValue(fp->returnValue());
   1.183 +
   1.184 +    // If the interpreter pushed an SPS frame when it entered the function, the
   1.185 +    // interpreter will pop it after the OSR trampoline returns.  In order for
   1.186 +    // the Baseline frame to have its SPS flag set, it must have its own SPS
   1.187 +    // frame, which the Baseline code will pop on return.  Note that the
   1.188 +    // profiler may have been enabled or disabled after the function was entered
   1.189 +    // but before OSR.
   1.190 +    JSContext *cx = GetJSContextFromJitCode();
   1.191 +    SPSProfiler *p = &(cx->runtime()->spsProfiler);
   1.192 +    if (p->enabled()) {
   1.193 +        p->enter(fp->script(), fp->maybeFun());
   1.194 +        flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
   1.195 +    }
   1.196 +
   1.197 +    frameSize_ = BaselineFrame::FramePointerOffset +
   1.198 +        BaselineFrame::Size() +
   1.199 +        numStackValues * sizeof(Value);
   1.200 +
   1.201 +    JS_ASSERT(numValueSlots() == numStackValues);
   1.202 +
   1.203 +    for (uint32_t i = 0; i < numStackValues; i++)
   1.204 +        *valueSlot(i) = fp->slots()[i];
   1.205 +
   1.206 +    if (cx->compartment()->debugMode()) {
   1.207 +        // In debug mode, update any Debugger.Frame objects for the
   1.208 +        // InterpreterFrame to point to the BaselineFrame.
   1.209 +
   1.210 +        // The caller pushed a fake return address. ScriptFrameIter, used by the
   1.211 +        // debugger, wants a valid return address, but it's okay to just pick one.
   1.212 +        // In debug mode there's always at least 1 ICEntry (since there are always
   1.213 +        // debug prologue/epilogue calls).
   1.214 +        JitFrameIterator iter(cx);
   1.215 +        JS_ASSERT(iter.returnAddress() == nullptr);
   1.216 +        BaselineScript *baseline = fp->script()->baselineScript();
   1.217 +        iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
   1.218 +
   1.219 +        if (!Debugger::handleBaselineOsr(cx, fp, this))
   1.220 +            return false;
   1.221 +    }
   1.222 +
   1.223 +    return true;
   1.224 +}

mercurial