/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef vm_Stack_inl_h #define vm_Stack_inl_h #include "vm/Stack.h" #include "mozilla/PodOperations.h" #include "jscntxt.h" #include "jsscript.h" #include "jit/BaselineFrame.h" #include "jit/RematerializedFrame.h" #include "js/Debug.h" #include "vm/EnvironmentObject.h" #include "vm/GeneratorObject.h" #include "jsobjinlines.h" #include "jsscriptinlines.h" #include "jit/BaselineFrame-inl.h" namespace js { /* * We cache name lookup results only for the global object or for native * non-global objects without prototype or with prototype that never mutates, * see bug 462734 and bug 487039. */ static inline bool IsCacheableEnvironment(JSObject* obj) { bool cacheable = obj->is() || obj->is(); MOZ_ASSERT_IF(cacheable, !obj->getOpsLookupProperty()); return cacheable; } inline HandleObject InterpreterFrame::environmentChain() const { return HandleObject::fromMarkedLocation(&envChain_); } inline GlobalObject& InterpreterFrame::global() const { return environmentChain()->global(); } inline JSObject& InterpreterFrame::varObj() const { JSObject* obj = environmentChain(); while (!obj->isQualifiedVarObj()) obj = obj->enclosingEnvironment(); return *obj; } inline LexicalEnvironmentObject& InterpreterFrame::extensibleLexicalEnvironment() const { return NearestEnclosingExtensibleLexicalEnvironment(environmentChain()); } inline void InterpreterFrame::initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc, Value* prevsp, JSFunction& callee, JSScript* script, Value* argv, uint32_t nactual, MaybeConstruct constructing) { MOZ_ASSERT(callee.nonLazyScript() == script); /* Initialize stack frame members. */ flags_ = 0; if (constructing) flags_ |= CONSTRUCTING; argv_ = argv; script_ = script; nactual_ = nactual; envChain_ = callee.environment(); prev_ = prev; prevpc_ = prevpc; prevsp_ = prevsp; if (script->isDebuggee()) setIsDebuggee(); initLocals(); } inline void InterpreterFrame::initLocals() { SetValueRangeToUndefined(slots(), script()->nfixed()); } inline Value& InterpreterFrame::unaliasedLocal(uint32_t i) { MOZ_ASSERT(i < script()->nfixed()); return slots()[i]; } inline Value& InterpreterFrame::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing) { MOZ_ASSERT(i < numFormalArgs()); MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); MOZ_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i)); return argv()[i]; } inline Value& InterpreterFrame::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) { MOZ_ASSERT(i < numActualArgs()); MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i)); return argv()[i]; } template inline void InterpreterFrame::unaliasedForEachActual(Op op) { // Don't assert !script()->funHasAnyAliasedFormal() since this function is // called from ArgumentsObject::createUnexpected() which can access aliased // slots. const Value* argsEnd = argv() + numActualArgs(); for (const Value* p = argv(); p < argsEnd; ++p) op(*p); } struct CopyTo { Value* dst; explicit CopyTo(Value* dst) : dst(dst) {} void operator()(const Value& src) { *dst++ = src; } }; struct CopyToHeap { GCPtrValue* dst; explicit CopyToHeap(GCPtrValue* dst) : dst(dst) {} void operator()(const Value& src) { dst->init(src); ++dst; } }; inline ArgumentsObject& InterpreterFrame::argsObj() const { MOZ_ASSERT(script()->needsArgsObj()); MOZ_ASSERT(flags_ & HAS_ARGS_OBJ); return *argsObj_; } inline void InterpreterFrame::initArgsObj(ArgumentsObject& argsobj) { MOZ_ASSERT(script()->needsArgsObj()); flags_ |= HAS_ARGS_OBJ; argsObj_ = &argsobj; } inline EnvironmentObject& InterpreterFrame::aliasedEnvironment(EnvironmentCoordinate ec) const { JSObject* env = &environmentChain()->as(); for (unsigned i = ec.hops(); i; i--) env = &env->as().enclosingEnvironment(); return env->as(); } template inline void InterpreterFrame::pushOnEnvironmentChain(SpecificEnvironment& env) { MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment()); envChain_ = &env; if (IsFrameInitialEnvironment(this, env)) flags_ |= HAS_INITIAL_ENV; } template inline void InterpreterFrame::popOffEnvironmentChain() { MOZ_ASSERT(envChain_->is()); envChain_ = &envChain_->as().enclosingEnvironment(); } inline void InterpreterFrame::replaceInnermostEnvironment(EnvironmentObject& env) { MOZ_ASSERT(env.enclosingEnvironment() == envChain_->as().enclosingEnvironment()); envChain_ = &env; } bool InterpreterFrame::hasInitialEnvironment() const { MOZ_ASSERT(script()->initialEnvironmentShape()); return flags_ & HAS_INITIAL_ENV; } inline CallObject& InterpreterFrame::callObj() const { MOZ_ASSERT(callee().needsCallObject()); JSObject* pobj = environmentChain(); while (MOZ_UNLIKELY(!pobj->is())) pobj = pobj->enclosingEnvironment(); return pobj->as(); } inline void InterpreterFrame::unsetIsDebuggee() { MOZ_ASSERT(!script()->isDebuggee()); flags_ &= ~DEBUGGEE; } /*****************************************************************************/ inline void InterpreterStack::purge(JSRuntime* rt) { rt->gc.freeUnusedLifoBlocksAfterSweeping(&allocator_); } uint8_t* InterpreterStack::allocateFrame(JSContext* cx, size_t size) { size_t maxFrames; if (cx->compartment()->principals() == cx->runtime()->trustedPrincipals()) maxFrames = MAX_FRAMES_TRUSTED; else maxFrames = MAX_FRAMES; if (MOZ_UNLIKELY(frameCount_ >= maxFrames)) { ReportOverRecursed(cx); return nullptr; } uint8_t* buffer = reinterpret_cast(allocator_.alloc(size)); if (!buffer) { ReportOutOfMemory(cx); return nullptr; } frameCount_++; return buffer; } MOZ_ALWAYS_INLINE InterpreterFrame* InterpreterStack::getCallFrame(JSContext* cx, const CallArgs& args, HandleScript script, MaybeConstruct constructing, Value** pargv) { JSFunction* fun = &args.callee().as(); MOZ_ASSERT(fun->nonLazyScript() == script); unsigned nformal = fun->nargs(); unsigned nvals = script->nslots(); if (args.length() >= nformal) { *pargv = args.array(); uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value)); return reinterpret_cast(buffer); } // Pad any missing arguments with |undefined|. MOZ_ASSERT(args.length() < nformal); unsigned nfunctionState = 2 + constructing; // callee, |this|, |new.target| nvals += nformal + nfunctionState; uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value)); if (!buffer) return nullptr; Value* argv = reinterpret_cast(buffer); unsigned nmissing = nformal - args.length(); mozilla::PodCopy(argv, args.base(), 2 + args.length()); SetValueRangeToUndefined(argv + 2 + args.length(), nmissing); if (constructing) argv[2 + nformal] = args.newTarget(); *pargv = argv + 2; return reinterpret_cast(argv + nfunctionState + nformal); } MOZ_ALWAYS_INLINE bool InterpreterStack::pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args, HandleScript script, MaybeConstruct constructing) { RootedFunction callee(cx, &args.callee().as()); MOZ_ASSERT(regs.sp == args.end()); MOZ_ASSERT(callee->nonLazyScript() == script); script->ensureNonLazyCanonicalFunction(cx); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; Value* prevsp = regs.sp; MOZ_ASSERT(prev); LifoAlloc::Mark mark = allocator_.mark(); Value* argv; InterpreterFrame* fp = getCallFrame(cx, args, script, constructing, &argv); if (!fp) return false; fp->mark_ = mark; /* Initialize frame, locals, regs. */ fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, args.length(), constructing); regs.prepareToRun(*fp, script); return true; } MOZ_ALWAYS_INLINE bool InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs, HandleFunction callee, HandleValue newTarget, HandleObject envChain) { MOZ_ASSERT(callee->isGenerator()); RootedScript script(cx, callee->getOrCreateScript(cx)); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; Value* prevsp = regs.sp; MOZ_ASSERT(prev); script->ensureNonLazyCanonicalFunction(cx); LifoAlloc::Mark mark = allocator_.mark(); MaybeConstruct constructing = MaybeConstruct(newTarget.isObject()); // Include callee, |this|, and maybe |new.target| unsigned nformal = callee->nargs(); unsigned nvals = 2 + constructing + nformal + script->nslots(); uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value)); if (!buffer) return false; Value* argv = reinterpret_cast(buffer) + 2; argv[-2] = ObjectValue(*callee); argv[-1] = UndefinedValue(); SetValueRangeToUndefined(argv, nformal); if (constructing) argv[nformal] = newTarget; InterpreterFrame* fp = reinterpret_cast(argv + nformal + constructing); fp->mark_ = mark; fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, 0, constructing); fp->resumeGeneratorFrame(envChain); regs.prepareToRun(*fp, script); return true; } MOZ_ALWAYS_INLINE void InterpreterStack::popInlineFrame(InterpreterRegs& regs) { InterpreterFrame* fp = regs.fp(); regs.popInlineFrame(); regs.sp[-1] = fp->returnValue(); releaseFrame(fp); MOZ_ASSERT(regs.fp()); } template inline void FrameIter::unaliasedForEachActual(JSContext* cx, Op op) { switch (data_.state_) { case DONE: case WASM: break; case INTERP: interpFrame()->unaliasedForEachActual(op); return; case JIT: if (data_.jitFrames_.isIonJS()) { jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_); ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover); } else if (data_.jitFrames_.isBailoutJS()) { // :TODO: (Bug 1070962) If we are introspecting the frame which is // being bailed, then we might be in the middle of recovering // instructions. Stacking computeInstructionResults implies that we // might be recovering result twice. In the mean time, to avoid // that, we just return Undefined values for instruction results // which are not yet recovered. jit::MaybeReadFallback fallback; ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback); } else { MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals); } return; } MOZ_CRASH("Unexpected state"); } inline HandleValue AbstractFramePtr::returnValue() const { if (isInterpreterFrame()) return asInterpreterFrame()->returnValue(); return asBaselineFrame()->returnValue(); } inline void AbstractFramePtr::setReturnValue(const Value& rval) const { if (isInterpreterFrame()) { asInterpreterFrame()->setReturnValue(rval); return; } if (isBaselineFrame()) { asBaselineFrame()->setReturnValue(rval); return; } asRematerializedFrame()->setReturnValue(rval); } inline JSObject* AbstractFramePtr::environmentChain() const { if (isInterpreterFrame()) return asInterpreterFrame()->environmentChain(); if (isBaselineFrame()) return asBaselineFrame()->environmentChain(); return asRematerializedFrame()->environmentChain(); } template inline void AbstractFramePtr::pushOnEnvironmentChain(SpecificEnvironment& env) { if (isInterpreterFrame()) { asInterpreterFrame()->pushOnEnvironmentChain(env); return; } if (isBaselineFrame()) { asBaselineFrame()->pushOnEnvironmentChain(env); return; } asRematerializedFrame()->pushOnEnvironmentChain(env); } template inline void AbstractFramePtr::popOffEnvironmentChain() { if (isInterpreterFrame()) { asInterpreterFrame()->popOffEnvironmentChain(); return; } if (isBaselineFrame()) { asBaselineFrame()->popOffEnvironmentChain(); return; } asRematerializedFrame()->popOffEnvironmentChain(); } inline CallObject& AbstractFramePtr::callObj() const { if (isInterpreterFrame()) return asInterpreterFrame()->callObj(); if (isBaselineFrame()) return asBaselineFrame()->callObj(); return asRematerializedFrame()->callObj(); } inline bool AbstractFramePtr::initFunctionEnvironmentObjects(JSContext* cx) { return js::InitFunctionEnvironmentObjects(cx, *this); } inline bool AbstractFramePtr::pushVarEnvironment(JSContext* cx, HandleScope scope) { return js::PushVarEnvironmentObject(cx, scope, *this); } inline JSCompartment* AbstractFramePtr::compartment() const { return environmentChain()->compartment(); } inline unsigned AbstractFramePtr::numActualArgs() const { if (isInterpreterFrame()) return asInterpreterFrame()->numActualArgs(); if (isBaselineFrame()) return asBaselineFrame()->numActualArgs(); return asRematerializedFrame()->numActualArgs(); } inline unsigned AbstractFramePtr::numFormalArgs() const { if (isInterpreterFrame()) return asInterpreterFrame()->numFormalArgs(); if (isBaselineFrame()) return asBaselineFrame()->numFormalArgs(); return asRematerializedFrame()->numFormalArgs(); } inline Value& AbstractFramePtr::unaliasedLocal(uint32_t i) { if (isInterpreterFrame()) return asInterpreterFrame()->unaliasedLocal(i); if (isBaselineFrame()) return asBaselineFrame()->unaliasedLocal(i); return asRematerializedFrame()->unaliasedLocal(i); } inline Value& AbstractFramePtr::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing) { if (isInterpreterFrame()) return asInterpreterFrame()->unaliasedFormal(i, checkAliasing); if (isBaselineFrame()) return asBaselineFrame()->unaliasedFormal(i, checkAliasing); return asRematerializedFrame()->unaliasedFormal(i, checkAliasing); } inline Value& AbstractFramePtr::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) { if (isInterpreterFrame()) return asInterpreterFrame()->unaliasedActual(i, checkAliasing); if (isBaselineFrame()) return asBaselineFrame()->unaliasedActual(i, checkAliasing); return asRematerializedFrame()->unaliasedActual(i, checkAliasing); } inline bool AbstractFramePtr::hasInitialEnvironment() const { if (isInterpreterFrame()) return asInterpreterFrame()->hasInitialEnvironment(); if (isBaselineFrame()) return asBaselineFrame()->hasInitialEnvironment(); return asRematerializedFrame()->hasInitialEnvironment(); } inline bool AbstractFramePtr::createSingleton() const { if (isInterpreterFrame()) return asInterpreterFrame()->createSingleton(); return false; } inline bool AbstractFramePtr::isGlobalFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isGlobalFrame(); if (isBaselineFrame()) return asBaselineFrame()->isGlobalFrame(); return asRematerializedFrame()->isGlobalFrame(); } inline bool AbstractFramePtr::isModuleFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isModuleFrame(); if (isBaselineFrame()) return asBaselineFrame()->isModuleFrame(); return asRematerializedFrame()->isModuleFrame(); } inline bool AbstractFramePtr::isEvalFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isEvalFrame(); if (isBaselineFrame()) return asBaselineFrame()->isEvalFrame(); MOZ_ASSERT(isRematerializedFrame()); return false; } inline bool AbstractFramePtr::isDebuggerEvalFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isDebuggerEvalFrame(); if (isBaselineFrame()) return asBaselineFrame()->isDebuggerEvalFrame(); MOZ_ASSERT(isRematerializedFrame()); return false; } inline bool AbstractFramePtr::hasCachedSavedFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->hasCachedSavedFrame(); if (isBaselineFrame()) return asBaselineFrame()->hasCachedSavedFrame(); return asRematerializedFrame()->hasCachedSavedFrame(); } inline void AbstractFramePtr::setHasCachedSavedFrame() { if (isInterpreterFrame()) asInterpreterFrame()->setHasCachedSavedFrame(); else if (isBaselineFrame()) asBaselineFrame()->setHasCachedSavedFrame(); else asRematerializedFrame()->setHasCachedSavedFrame(); } inline bool AbstractFramePtr::isDebuggee() const { if (isInterpreterFrame()) return asInterpreterFrame()->isDebuggee(); if (isBaselineFrame()) return asBaselineFrame()->isDebuggee(); return asRematerializedFrame()->isDebuggee(); } inline void AbstractFramePtr::setIsDebuggee() { if (isInterpreterFrame()) asInterpreterFrame()->setIsDebuggee(); else if (isBaselineFrame()) asBaselineFrame()->setIsDebuggee(); else asRematerializedFrame()->setIsDebuggee(); } inline void AbstractFramePtr::unsetIsDebuggee() { if (isInterpreterFrame()) asInterpreterFrame()->unsetIsDebuggee(); else if (isBaselineFrame()) asBaselineFrame()->unsetIsDebuggee(); else asRematerializedFrame()->unsetIsDebuggee(); } inline bool AbstractFramePtr::hasArgs() const { return isFunctionFrame(); } inline JSScript* AbstractFramePtr::script() const { if (isInterpreterFrame()) return asInterpreterFrame()->script(); if (isBaselineFrame()) return asBaselineFrame()->script(); return asRematerializedFrame()->script(); } inline JSFunction* AbstractFramePtr::callee() const { if (isInterpreterFrame()) return &asInterpreterFrame()->callee(); if (isBaselineFrame()) return asBaselineFrame()->callee(); return asRematerializedFrame()->callee(); } inline Value AbstractFramePtr::calleev() const { if (isInterpreterFrame()) return asInterpreterFrame()->calleev(); if (isBaselineFrame()) return asBaselineFrame()->calleev(); return asRematerializedFrame()->calleev(); } inline bool AbstractFramePtr::isFunctionFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isFunctionFrame(); if (isBaselineFrame()) return asBaselineFrame()->isFunctionFrame(); return asRematerializedFrame()->isFunctionFrame(); } inline bool AbstractFramePtr::isNonStrictDirectEvalFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isNonStrictDirectEvalFrame(); if (isBaselineFrame()) return asBaselineFrame()->isNonStrictDirectEvalFrame(); MOZ_ASSERT(isRematerializedFrame()); return false; } inline bool AbstractFramePtr::isStrictEvalFrame() const { if (isInterpreterFrame()) return asInterpreterFrame()->isStrictEvalFrame(); if (isBaselineFrame()) return asBaselineFrame()->isStrictEvalFrame(); MOZ_ASSERT(isRematerializedFrame()); return false; } inline Value* AbstractFramePtr::argv() const { if (isInterpreterFrame()) return asInterpreterFrame()->argv(); if (isBaselineFrame()) return asBaselineFrame()->argv(); return asRematerializedFrame()->argv(); } inline bool AbstractFramePtr::hasArgsObj() const { if (isInterpreterFrame()) return asInterpreterFrame()->hasArgsObj(); if (isBaselineFrame()) return asBaselineFrame()->hasArgsObj(); return asRematerializedFrame()->hasArgsObj(); } inline ArgumentsObject& AbstractFramePtr::argsObj() const { if (isInterpreterFrame()) return asInterpreterFrame()->argsObj(); if (isBaselineFrame()) return asBaselineFrame()->argsObj(); return asRematerializedFrame()->argsObj(); } inline void AbstractFramePtr::initArgsObj(ArgumentsObject& argsobj) const { if (isInterpreterFrame()) { asInterpreterFrame()->initArgsObj(argsobj); return; } asBaselineFrame()->initArgsObj(argsobj); } inline bool AbstractFramePtr::prevUpToDate() const { if (isInterpreterFrame()) return asInterpreterFrame()->prevUpToDate(); if (isBaselineFrame()) return asBaselineFrame()->prevUpToDate(); return asRematerializedFrame()->prevUpToDate(); } inline void AbstractFramePtr::setPrevUpToDate() const { if (isInterpreterFrame()) { asInterpreterFrame()->setPrevUpToDate(); return; } if (isBaselineFrame()) { asBaselineFrame()->setPrevUpToDate(); return; } asRematerializedFrame()->setPrevUpToDate(); } inline void AbstractFramePtr::unsetPrevUpToDate() const { if (isInterpreterFrame()) { asInterpreterFrame()->unsetPrevUpToDate(); return; } if (isBaselineFrame()) { asBaselineFrame()->unsetPrevUpToDate(); return; } asRematerializedFrame()->unsetPrevUpToDate(); } inline Value& AbstractFramePtr::thisArgument() const { if (isInterpreterFrame()) return asInterpreterFrame()->thisArgument(); if (isBaselineFrame()) return asBaselineFrame()->thisArgument(); return asRematerializedFrame()->thisArgument(); } inline Value AbstractFramePtr::newTarget() const { if (isInterpreterFrame()) return asInterpreterFrame()->newTarget(); if (isBaselineFrame()) return asBaselineFrame()->newTarget(); return asRematerializedFrame()->newTarget(); } inline bool AbstractFramePtr::debuggerNeedsCheckPrimitiveReturn() const { return script()->isDerivedClassConstructor(); } ActivationEntryMonitor::~ActivationEntryMonitor() { if (entryMonitor_) entryMonitor_->Exit(cx_); cx_->runtime()->entryMonitor = entryMonitor_; } Activation::Activation(JSContext* cx, Kind kind) : cx_(cx), compartment_(cx->compartment()), prev_(cx->activation_), prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr), hideScriptedCallerCount_(0), frameCache_(cx), asyncStack_(cx, cx->asyncStackForNewActivations), asyncCause_(cx->asyncCauseForNewActivations), asyncCallIsExplicit_(cx->asyncCallIsExplicit), kind_(kind) { cx->asyncStackForNewActivations = nullptr; cx->asyncCauseForNewActivations = nullptr; cx->asyncCallIsExplicit = false; cx->activation_ = this; } Activation::~Activation() { MOZ_ASSERT_IF(isProfiling(), this != cx_->profilingActivation_); MOZ_ASSERT(cx_->activation_ == this); MOZ_ASSERT(hideScriptedCallerCount_ == 0); cx_->activation_ = prev_; cx_->asyncCauseForNewActivations = asyncCause_; cx_->asyncStackForNewActivations = asyncStack_; cx_->asyncCallIsExplicit = asyncCallIsExplicit_; } bool Activation::isProfiling() const { if (isInterpreter()) return asInterpreter()->isProfiling(); if (isJit()) return asJit()->isProfiling(); MOZ_ASSERT(isWasm()); return asWasm()->isProfiling(); } Activation* Activation::mostRecentProfiling() { if (isProfiling()) return this; return prevProfiling_; } inline LiveSavedFrameCache* Activation::getLiveSavedFrameCache(JSContext* cx) { if (!frameCache_.get().initialized() && !frameCache_.get().init(cx)) return nullptr; return frameCache_.address(); } InterpreterActivation::InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame) : Activation(cx, Interpreter), entryFrame_(entryFrame), opMask_(0) #ifdef DEBUG , oldFrameCount_(cx->runtime()->interpreterStack().frameCount_) #endif { regs_.prepareToRun(*entryFrame, state.script()); MOZ_ASSERT(regs_.pc == state.script()->code()); MOZ_ASSERT_IF(entryFrame_->isEvalFrame(), state.script()->isActiveEval()); } InterpreterActivation::~InterpreterActivation() { // Pop all inline frames. while (regs_.fp() != entryFrame_) popInlineFrame(regs_.fp()); MOZ_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_); MOZ_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0); if (entryFrame_) cx_->runtime()->interpreterStack().releaseFrame(entryFrame_); } inline bool InterpreterActivation::pushInlineFrame(const CallArgs& args, HandleScript script, MaybeConstruct constructing) { if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, constructing)) return false; MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment()); return true; } inline void InterpreterActivation::popInlineFrame(InterpreterFrame* frame) { (void)frame; // Quell compiler warning. MOZ_ASSERT(regs_.fp() == frame); MOZ_ASSERT(regs_.fp() != entryFrame_); cx_->runtime()->interpreterStack().popInlineFrame(regs_); } inline bool InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget, HandleObject envChain) { InterpreterStack& stack = cx_->runtime()->interpreterStack(); if (!stack.resumeGeneratorCallFrame(cx_, regs_, callee, newTarget, envChain)) return false; MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_); return true; } inline bool FrameIter::hasCachedSavedFrame() const { if (isWasm()) return false; if (hasUsableAbstractFramePtr()) return abstractFramePtr().hasCachedSavedFrame(); MOZ_ASSERT(data_.jitFrames_.isIonScripted()); // SavedFrame caching is done at the physical frame granularity (rather than // for each inlined frame) for ion. Therefore, it is impossible to have a // cached SavedFrame if this frame is not a physical frame. return isPhysicalIonFrame() && data_.jitFrames_.current()->hasCachedSavedFrame(); } inline void FrameIter::setHasCachedSavedFrame() { MOZ_ASSERT(!isWasm()); if (hasUsableAbstractFramePtr()) { abstractFramePtr().setHasCachedSavedFrame(); return; } MOZ_ASSERT(isPhysicalIonFrame()); data_.jitFrames_.current()->setHasCachedSavedFrame(); } } /* namespace js */ #endif /* vm_Stack_inl_h */