diff options
Diffstat (limited to 'js/src/vm/Stack-inl.h')
-rw-r--r-- | js/src/vm/Stack-inl.h | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h new file mode 100644 index 000000000..a51c0aa14 --- /dev/null +++ b/js/src/vm/Stack-inl.h @@ -0,0 +1,998 @@ +/* -*- 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<CallObject>() || obj->is<LexicalEnvironmentObject>(); + + 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 <class Op> +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<EnvironmentObject>(); + for (unsigned i = ec.hops(); i; i--) + env = &env->as<EnvironmentObject>().enclosingEnvironment(); + return env->as<EnvironmentObject>(); +} + +template <typename SpecificEnvironment> +inline void +InterpreterFrame::pushOnEnvironmentChain(SpecificEnvironment& env) +{ + MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment()); + envChain_ = &env; + if (IsFrameInitialEnvironment(this, env)) + flags_ |= HAS_INITIAL_ENV; +} + +template <typename SpecificEnvironment> +inline void +InterpreterFrame::popOffEnvironmentChain() +{ + MOZ_ASSERT(envChain_->is<SpecificEnvironment>()); + envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment(); +} + +inline void +InterpreterFrame::replaceInnermostEnvironment(EnvironmentObject& env) +{ + MOZ_ASSERT(env.enclosingEnvironment() == + envChain_->as<EnvironmentObject>().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<CallObject>())) + pobj = pobj->enclosingEnvironment(); + return pobj->as<CallObject>(); +} + +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<uint8_t*>(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<JSFunction>(); + + 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<InterpreterFrame*>(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<Value*>(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<InterpreterFrame*>(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<JSFunction>()); + 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<Value*>(buffer) + 2; + argv[-2] = ObjectValue(*callee); + argv[-1] = UndefinedValue(); + SetValueRangeToUndefined(argv, nformal); + if (constructing) + argv[nformal] = newTarget; + + InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(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 <class Op> +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 <typename SpecificEnvironment> +inline void +AbstractFramePtr::pushOnEnvironmentChain(SpecificEnvironment& env) +{ + if (isInterpreterFrame()) { + asInterpreterFrame()->pushOnEnvironmentChain(env); + return; + } + if (isBaselineFrame()) { + asBaselineFrame()->pushOnEnvironmentChain(env); + return; + } + asRematerializedFrame()->pushOnEnvironmentChain(env); +} + +template <typename SpecificEnvironment> +inline void +AbstractFramePtr::popOffEnvironmentChain() +{ + if (isInterpreterFrame()) { + asInterpreterFrame()->popOffEnvironmentChain<SpecificEnvironment>(); + return; + } + if (isBaselineFrame()) { + asBaselineFrame()->popOffEnvironmentChain<SpecificEnvironment>(); + return; + } + asRematerializedFrame()->popOffEnvironmentChain<SpecificEnvironment>(); +} + +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 */ |