#ifndef vm_Stack_inl_h
#define vm_Stack_inl_h
#include "vm/Stack.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "jit/BaselineFrame.h"
#include "jit/RematerializedFrame.h"
#include "js/Debug.h"
#include "vm/EnvironmentObject.h"
#include "vm/JSContext.h"
#include "vm/JSScript.h"
#include "jit/BaselineFrame-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/NativeObject-inl.h"
namespace js {
inline HandleObject InterpreterFrame::environmentChain() const {
return HandleObject::fromMarkedLocation(&envChain_);
}
inline GlobalObject& InterpreterFrame::global() const {
return script()->global();
}
inline JSObject& InterpreterFrame::varObj() const {
return GetVariablesObject(environmentChain());
}
inline LexicalEnvironmentObject&
InterpreterFrame::extensibleLexicalEnvironment() const {
return NearestEnclosingExtensibleLexicalEnvironment(environmentChain());
}
inline void InterpreterFrame::initCallFrame(InterpreterFrame* prev,
jsbytecode* prevpc, Value* prevsp,
JSFunction& callee,
JSScript* script, Value* argv,
uint32_t nactual,
MaybeConstruct constructing) {
MOZ_ASSERT(callee.nonLazyScript() == script);
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) {
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.queueUnusedLifoBlocksForFree(&allocator_);
}
uint8_t* InterpreterStack::allocateFrame(JSContext* cx, size_t size) {
size_t maxFrames;
if (cx->realm()->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);
}
MOZ_ASSERT(args.length() < nformal);
unsigned nfunctionState = 2 + constructing;
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();
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;
fp->initCallFrame(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,
HandleObject envChain) {
MOZ_ASSERT(callee->isGenerator() || callee->isAsync());
RootedScript script(cx, callee->nonLazyScript());
InterpreterFrame* prev = regs.fp();
jsbytecode* prevpc = regs.pc;
Value* prevsp = regs.sp;
MOZ_ASSERT(prev);
script->ensureNonLazyCanonicalFunction();
LifoAlloc::Mark mark = allocator_.mark();
MOZ_ASSERT(!callee->isConstructor());
unsigned nformal = callee->nargs();
unsigned nvals = 2 + 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);
InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(argv + nformal);
fp->mark_ = mark;
fp->initCallFrame(prev, prevpc, prevsp, *callee, script, argv, 0,
NO_CONSTRUCT);
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:
break;
case INTERP:
interpFrame()->unaliasedForEachActual(op);
return;
case JIT:
MOZ_ASSERT(isJSJit());
if (jsJitFrame().isIonJS()) {
jit::MaybeReadFallback recover(cx, activation()->asJit(),
&jsJitFrame());
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals,
recover);
} else if (jsJitFrame().isBailoutJS()) {
jit::MaybeReadFallback fallback;
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals,
fallback);
} else {
MOZ_ASSERT(jsJitFrame().isBaselineJS());
jsJitFrame().unaliasedForEachActual(op, jit::ReadFrame_Actuals);
}
return;
}
MOZ_CRASH("Unexpected state");
}
inline HandleValue AbstractFramePtr::returnValue() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->returnValue();
}
if (isWasmDebugFrame()) {
return asWasmDebugFrame()->returnValue();
}
return asBaselineFrame()->returnValue();
}
inline void AbstractFramePtr::setReturnValue(const Value& rval) const {
if (isInterpreterFrame()) {
asInterpreterFrame()->setReturnValue(rval);
return;
}
if (isBaselineFrame()) {
asBaselineFrame()->setReturnValue(rval);
return;
}
if (isWasmDebugFrame()) {
return;
}
asRematerializedFrame()->setReturnValue(rval);
}
inline JSObject* AbstractFramePtr::environmentChain() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->environmentChain();
}
if (isBaselineFrame()) {
return asBaselineFrame()->environmentChain();
}
if (isWasmDebugFrame()) {
return &global()->lexicalEnvironment();
}
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 JS::Realm* AbstractFramePtr::realm() const {
return environmentChain()->nonCCWRealm();
}
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::isGlobalFrame() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->isGlobalFrame();
}
if (isBaselineFrame()) {
return asBaselineFrame()->isGlobalFrame();
}
if (isWasmDebugFrame()) {
return false;
}
return asRematerializedFrame()->isGlobalFrame();
}
inline bool AbstractFramePtr::isModuleFrame() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->isModuleFrame();
}
if (isBaselineFrame()) {
return asBaselineFrame()->isModuleFrame();
}
if (isWasmDebugFrame()) {
return false;
}
return asRematerializedFrame()->isModuleFrame();
}
inline bool AbstractFramePtr::isEvalFrame() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->isEvalFrame();
}
if (isBaselineFrame()) {
return asBaselineFrame()->isEvalFrame();
}
if (isWasmDebugFrame()) {
return false;
}
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::isDebuggee() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->isDebuggee();
}
if (isBaselineFrame()) {
return asBaselineFrame()->isDebuggee();
}
if (isWasmDebugFrame()) {
return asWasmDebugFrame()->isDebuggee();
}
return asRematerializedFrame()->isDebuggee();
}
inline void AbstractFramePtr::setIsDebuggee() {
if (isInterpreterFrame()) {
asInterpreterFrame()->setIsDebuggee();
} else if (isBaselineFrame()) {
asBaselineFrame()->setIsDebuggee();
} else if (isWasmDebugFrame()) {
asWasmDebugFrame()->setIsDebuggee();
} else {
asRematerializedFrame()->setIsDebuggee();
}
}
inline void AbstractFramePtr::unsetIsDebuggee() {
if (isInterpreterFrame()) {
asInterpreterFrame()->unsetIsDebuggee();
} else if (isBaselineFrame()) {
asBaselineFrame()->unsetIsDebuggee();
} else if (isWasmDebugFrame()) {
asWasmDebugFrame()->unsetIsDebuggee();
} else {
asRematerializedFrame()->unsetIsDebuggee();
}
}
inline bool AbstractFramePtr::isConstructing() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->isConstructing();
}
if (isBaselineFrame()) {
return asBaselineFrame()->isConstructing();
}
if (isRematerializedFrame()) {
return asRematerializedFrame()->isConstructing();
}
MOZ_CRASH("Unexpected frame");
}
inline bool AbstractFramePtr::hasArgs() const { return isFunctionFrame(); }
inline bool AbstractFramePtr::hasScript() const { return !isWasmDebugFrame(); }
inline JSScript* AbstractFramePtr::script() const {
if (isInterpreterFrame()) {
return asInterpreterFrame()->script();
}
if (isBaselineFrame()) {
return asBaselineFrame()->script();
}
return asRematerializedFrame()->script();
}
inline wasm::Instance* AbstractFramePtr::wasmInstance() const {
return asWasmDebugFrame()->instance();
}
inline GlobalObject* AbstractFramePtr::global() const {
if (isWasmDebugFrame()) {
return asWasmDebugFrame()->global();
}
return &script()->global();
}
inline bool AbstractFramePtr::hasGlobal(const GlobalObject* global) const {
if (isWasmDebugFrame()) {
return asWasmDebugFrame()->hasGlobal(global);
}
return script()->hasGlobal(global);
}
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();
}
if (isWasmDebugFrame()) {
return false;
}
return asRematerializedFrame()->isFunctionFrame();
}
inline bool AbstractFramePtr::isGeneratorFrame() const {
if (!isFunctionFrame()) {
return false;
}
JSScript* s = script();
return s->isGenerator() || s->isAsync();
}
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();
}
if (isWasmDebugFrame()) {
return asWasmDebugFrame()->prevUpToDate();
}
return asRematerializedFrame()->prevUpToDate();
}
inline void AbstractFramePtr::setPrevUpToDate() const {
if (isInterpreterFrame()) {
asInterpreterFrame()->setPrevUpToDate();
return;
}
if (isBaselineFrame()) {
asBaselineFrame()->setPrevUpToDate();
return;
}
if (isWasmDebugFrame()) {
asWasmDebugFrame()->setPrevUpToDate();
return;
}
asRematerializedFrame()->setPrevUpToDate();
}
inline void AbstractFramePtr::unsetPrevUpToDate() const {
if (isInterpreterFrame()) {
asInterpreterFrame()->unsetPrevUpToDate();
return;
}
if (isBaselineFrame()) {
asBaselineFrame()->unsetPrevUpToDate();
return;
}
if (isWasmDebugFrame()) {
asWasmDebugFrame()->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 {
if (isWasmDebugFrame()) {
return false;
}
return script()->isDerivedClassConstructor();
}
ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx)
: cx_(cx), entryMonitor_(cx->entryMonitor) {
cx->entryMonitor = nullptr;
}
ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx,
InterpreterFrame* entryFrame)
: ActivationEntryMonitor(cx) {
if (MOZ_UNLIKELY(entryMonitor_)) {
init(cx, entryFrame);
}
}
ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx,
jit::CalleeToken entryToken)
: ActivationEntryMonitor(cx) {
if (MOZ_UNLIKELY(entryMonitor_)) {
init(cx, entryToken);
}
}
ActivationEntryMonitor::~ActivationEntryMonitor() {
if (entryMonitor_) {
entryMonitor_->Exit(cx_);
}
cx_->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();
}
MOZ_ASSERT(isJit());
return asJit()->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->interpreterStack().frameCount_)
#endif
{
regs_.prepareToRun(*entryFrame, state.script());
MOZ_ASSERT(regs_.pc == state.script()->code());
}
InterpreterActivation::~InterpreterActivation() {
while (regs_.fp() != entryFrame_) {
popInlineFrame(regs_.fp());
}
MOZ_ASSERT(oldFrameCount_ == cx_->interpreterStack().frameCount_);
MOZ_ASSERT_IF(oldFrameCount_ == 0,
cx_->interpreterStack().allocator_.used() == 0);
if (entryFrame_) {
cx_->interpreterStack().releaseFrame(entryFrame_);
}
}
inline bool InterpreterActivation::pushInlineFrame(
const CallArgs& args, HandleScript script, MaybeConstruct constructing) {
if (!cx_->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; MOZ_ASSERT(regs_.fp() == frame);
MOZ_ASSERT(regs_.fp() != entryFrame_);
cx_->interpreterStack().popInlineFrame(regs_);
}
inline bool InterpreterActivation::resumeGeneratorFrame(HandleFunction callee,
HandleObject envChain) {
InterpreterStack& stack = cx_->interpreterStack();
if (!stack.resumeGeneratorCallFrame(cx_, regs_, callee, envChain)) {
return false;
}
MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_);
return true;
}
inline mozilla::Maybe<LiveSavedFrameCache::FramePtr>
LiveSavedFrameCache::FramePtr::create(const FrameIter& iter) {
if (iter.done()) {
return mozilla::Nothing();
}
if (iter.isPhysicalJitFrame()) {
return mozilla::Some(FramePtr(iter.physicalJitFrame()));
}
if (!iter.hasUsableAbstractFramePtr()) {
return mozilla::Nothing();
}
auto afp = iter.abstractFramePtr();
if (afp.isInterpreterFrame()) {
return mozilla::Some(FramePtr(afp.asInterpreterFrame()));
}
if (afp.isWasmDebugFrame()) {
return mozilla::Some(FramePtr(afp.asWasmDebugFrame()));
}
if (afp.isRematerializedFrame()) {
return mozilla::Some(FramePtr(afp.asRematerializedFrame()));
}
MOZ_CRASH("unexpected frame type");
}
inline LiveSavedFrameCache::FramePtr
LiveSavedFrameCache::FramePtr::create(AbstractFramePtr afp) {
MOZ_ASSERT(afp);
if (afp.isBaselineFrame()) {
js::jit::CommonFrameLayout* common = afp.asBaselineFrame()->framePrefix();
return FramePtr(common);
}
if (afp.isInterpreterFrame()) {
return FramePtr(afp.asInterpreterFrame());
}
if (afp.isWasmDebugFrame()) {
return FramePtr(afp.asWasmDebugFrame());
}
if (afp.isRematerializedFrame()) {
return FramePtr(afp.asRematerializedFrame());
}
MOZ_CRASH("unexpected frame type");
}
struct LiveSavedFrameCache::FramePtr::HasCachedMatcher {
template <typename Frame>
bool match(Frame* f) const {
return f->hasCachedSavedFrame();
}
};
inline bool LiveSavedFrameCache::FramePtr::hasCachedSavedFrame() const {
return ptr.match(HasCachedMatcher());
}
struct LiveSavedFrameCache::FramePtr::SetHasCachedMatcher {
template <typename Frame>
void match(Frame* f) {
f->setHasCachedSavedFrame();
}
};
inline void LiveSavedFrameCache::FramePtr::setHasCachedSavedFrame() {
ptr.match(SetHasCachedMatcher());
}
struct LiveSavedFrameCache::FramePtr::ClearHasCachedMatcher {
template <typename Frame>
void match(Frame* f) {
f->clearHasCachedSavedFrame();
}
};
inline void LiveSavedFrameCache::FramePtr::clearHasCachedSavedFrame() {
ptr.match(ClearHasCachedMatcher());
}
}
#endif