void BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator) { replaceCalleeToken(MarkCalleeToken(trc, calleeToken())); TraceRoot(trc, &thisValue(), "baseline-this"); // Mark actual and formal args. if (isNonEvalFunctionFrame()) { unsigned numArgs = js::Max(numActualArgs(), numFormalArgs()); TraceRootRange(trc, numArgs + isConstructing(), argv(), "baseline-args"); } // Mark scope chain, if it exists. if (scopeChain_) TraceRoot(trc, &scopeChain_, "baseline-scopechain"); // Mark return value. if (hasReturnValue()) TraceRoot(trc, returnValue().address(), "baseline-rval"); if (isEvalFrame()) { TraceRoot(trc, &evalScript_, "baseline-evalscript"); if (isFunctionFrame()) TraceRoot(trc, evalNewTargetAddress(), "baseline-evalNewTarget"); } if (hasArgsObj()) TraceRoot(trc, &argsObj_, "baseline-args-obj"); // Mark locals and stack values. JSScript* script = this->script(); size_t nfixed = script->nfixed(); jsbytecode* pc; frameIterator.baselineScriptAndPc(nullptr, &pc); size_t nlivefixed = script->calculateLiveFixed(pc); // 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; MOZ_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 block-scoped locals. while (nfixed > nlivefixed) unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL); // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); } }
void InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc) { MOZ_ASSERT(sp >= slots()); JSScript *script = this->script(); size_t nfixed = script->nfixed(); size_t nlivefixed = script->nbodyfixed(); if (nfixed != nlivefixed) { NestedScopeObject *staticScope = script->getStaticScope(pc); while (staticScope && !staticScope->is<StaticBlockObject>()) staticScope = staticScope->enclosingNestedScope(); if (staticScope) { StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } } MOZ_ASSERT(nlivefixed <= nfixed); MOZ_ASSERT(nlivefixed >= script->nbodyfixed()); if (nfixed == nlivefixed) { // All locals are live. markValues(trc, 0, sp - slots()); } else { // Mark operand stack. markValues(trc, nfixed, sp - slots()); // Clear dead block-scoped locals. while (nfixed > nlivefixed) unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL); // Mark live locals. markValues(trc, 0, nlivefixed); } if (hasArgs()) { // Mark callee, |this| and arguments. unsigned argc = Max(numActualArgs(), numFormalArgs()); gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv"); } else { // Mark callee and |this| gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this"); } }
bool MResumePoint::writeRecoverData(CompactBufferWriter &writer) const { writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint)); MBasicBlock *bb = block(); JSFunction *fun = bb->info().funMaybeLazy(); JSScript *script = bb->info().script(); uint32_t exprStack = stackDepth() - bb->info().ninvoke(); #ifdef DEBUG // Ensure that all snapshot which are encoded can safely be used for // bailouts. if (GetIonContext()->cx) { uint32_t stackDepth; bool reachablePC; jsbytecode *bailPC = pc(); if (mode() == MResumePoint::ResumeAfter) bailPC = GetNextPc(pc()); if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC)) { return false; } if (reachablePC) { if (JSOp(*bailPC) == JSOP_FUNCALL) { // For fun.call(this, ...); the reconstructStackDepth will // include the this. When inlining that is not included. So the // exprStackSlots will be one less. MOZ_ASSERT(stackDepth - exprStack <= 1); } else if (JSOp(*bailPC) != JSOP_FUNAPPLY && !IsGetPropPC(bailPC) && !IsSetPropPC(bailPC)) { // For fun.apply({}, arguments) the reconstructStackDepth will // have stackdepth 4, but it could be that we inlined the // funapply. In that case exprStackSlots, will have the real // arguments in the slots and not be 4. // With accessors, we have different stack depths depending on // whether or not we inlined the accessor, as the inlined stack // contains a callee function that should never have been there // and we might just be capturing an uneventful property site, // in which case there won't have been any violence. MOZ_ASSERT(exprStack == stackDepth); } } } #endif // Test if we honor the maximum of arguments at all times. This is a sanity // check and not an algorithm limit. So check might be a bit too loose. +4 // to account for scope chain, return value, this value and maybe // arguments_object. MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); uint32_t implicit = StartArgSlot(script); uint32_t formalArgs = CountArgSlots(script, fun); uint32_t nallocs = formalArgs + script->nfixed() + exprStack; JitSpew(JitSpew_IonSnapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", implicit, formalArgs - implicit, script->nfixed(), exprStack); uint32_t pcoff = script->pcToOffset(pc()); JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs); writer.writeUnsigned(pcoff); writer.writeUnsigned(nallocs); return true; }
void BaselineFrame::trace(JSTracer *trc, JitFrameIterator &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->nbodyfixed(); if (nfixed != nlivefixed) { jsbytecode *pc; frameIterator.baselineScriptAndPc(nullptr, &pc); NestedScopeObject *staticScope = script->getStaticScope(pc); while (staticScope && !staticScope->is<StaticBlockObject>()) staticScope = staticScope->enclosingNestedScope(); if (staticScope) { StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } } MOZ_ASSERT(nlivefixed <= nfixed); MOZ_ASSERT(nlivefixed >= script->nbodyfixed()); // 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; MOZ_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 block-scoped locals. while (nfixed > nlivefixed) unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL); // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); } }