void BaselineFrame::trace(JSTracer *trc, IonFrameIterator &frameIterator) { replaceCalleeToken(MarkCalleeToken(trc, calleeToken())); gc::MarkValueRoot(trc, &thisValue(), "baseline-this"); // Mark actual and formal args. if (isNonEvalFunctionFrame()) { unsigned numArgs = js::Max(numActualArgs(), numFormalArgs()); gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args"); } // Mark scope chain, if it exists. if (scopeChain_) gc::MarkObjectRoot(trc, &scopeChain_, "baseline-scopechain"); // Mark return value. if (hasReturnValue()) gc::MarkValueRoot(trc, returnValue().address(), "baseline-rval"); if (isEvalFrame()) gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript"); if (hasArgsObj()) gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj"); // Mark locals and stack values. JSScript *script = this->script(); size_t nfixed = script->nfixed(); size_t nlivefixed = script->nfixedvars(); if (nfixed != nlivefixed) { jsbytecode *pc; NestedScopeObject *staticScope; frameIterator.baselineScriptAndPc(nullptr, &pc); staticScope = script->getStaticScope(pc); while (staticScope && !staticScope->is<StaticBlockObject>()) staticScope = staticScope->enclosingNestedScope(); if (staticScope) { StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } } JS_ASSERT(nlivefixed <= nfixed); JS_ASSERT(nlivefixed >= script->nfixedvars()); // NB: It is possible that numValueSlots() could be zero, even if nfixed is // nonzero. This is the case if the function has an early stack check. if (numValueSlots() == 0) return; JS_ASSERT(nfixed <= numValueSlots()); if (nfixed == nlivefixed) { // All locals are live. MarkLocals(this, trc, 0, numValueSlots()); } else { // Mark operand stack. MarkLocals(this, trc, nfixed, numValueSlots()); // Clear dead locals. while (nfixed > nlivefixed) unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined(); // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); } }