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 +}