blob: 55d94bc4cef9dcccfef8e18bf8e3fb89c91b933f [file] [log] [blame]
/* -*- 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/GeneratorObject.h"
#include "vm/ScopeObject.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
IsCacheableNonGlobalScope(JSObject* obj)
{
bool cacheable = obj->is<CallObject>() || obj->is<BlockObject>() || obj->is<DeclEnvObject>();
MOZ_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
return cacheable;
}
inline HandleObject
InterpreterFrame::scopeChain() const
{
MOZ_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
if (!(flags_ & HAS_SCOPECHAIN)) {
scopeChain_ = callee().environment();
flags_ |= HAS_SCOPECHAIN;
}
return HandleObject::fromMarkedLocation(&scopeChain_);
}
inline GlobalObject&
InterpreterFrame::global() const
{
return scopeChain()->global();
}
inline JSObject&
InterpreterFrame::varObj() const
{
JSObject* obj = scopeChain();
while (!obj->isQualifiedVarObj())
obj = obj->enclosingScope();
return *obj;
}
inline ClonedBlockObject&
InterpreterFrame::extensibleLexicalScope() const
{
return NearestEnclosingExtensibleLexicalScope(scopeChain());
}
inline JSCompartment*
InterpreterFrame::compartment() const
{
MOZ_ASSERT(scopeChain()->compartment() == script()->compartment());
return scopeChain()->compartment();
}
inline void
InterpreterFrame::initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc,
Value* prevsp, JSFunction& callee, JSScript* script, Value* argv,
uint32_t nactual, InterpreterFrame::Flags flagsArg)
{
MOZ_ASSERT((flagsArg & ~CONSTRUCTING) == 0);
MOZ_ASSERT(callee.nonLazyScript() == script);
/* Initialize stack frame members. */
flags_ = FUNCTION | HAS_SCOPECHAIN | flagsArg;
argv_ = argv;
exec.fun = &callee;
u.nactual = nactual;
scopeChain_ = callee.environment();
prev_ = prev;
prevpc_ = prevpc;
prevsp_ = prevsp;
if (script->isDebuggee())
setIsDebuggee();
initLocals();
}
inline void
InterpreterFrame::initLocals()
{
SetValueRangeToUndefined(slots(), script()->nfixedvars());
// Lexical bindings throw ReferenceErrors if they are used before
// initialization. See ES6 8.1.1.1.6.
//
// For completeness, lexical bindings are initialized in ES6 by calling
// InitializeBinding, after which touching the binding will no longer
// throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
// 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
Value* lexicalEnd = slots() + script()->fixedLexicalEnd();
for (Value* lexical = slots() + script()->fixedLexicalBegin(); lexical != lexicalEnd; ++lexical)
lexical->setMagic(JS_UNINITIALIZED_LEXICAL);
}
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
{
HeapValue* dst;
explicit CopyToHeap(HeapValue* 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 ScopeObject&
InterpreterFrame::aliasedVarScope(ScopeCoordinate sc) const
{
JSObject* scope = &scopeChain()->as<ScopeObject>();
for (unsigned i = sc.hops(); i; i--)
scope = &scope->as<ScopeObject>().enclosingScope();
return scope->as<ScopeObject>();
}
inline void
InterpreterFrame::pushOnScopeChain(ScopeObject& scope)
{
MOZ_ASSERT(*scopeChain() == scope.enclosingScope() ||
*scopeChain() == scope.as<CallObject>().enclosingScope().as<DeclEnvObject>().enclosingScope());
scopeChain_ = &scope;
flags_ |= HAS_SCOPECHAIN;
}
inline void
InterpreterFrame::popOffScopeChain()
{
MOZ_ASSERT(flags_ & HAS_SCOPECHAIN);
scopeChain_ = &scopeChain_->as<ScopeObject>().enclosingScope();
}
inline void
InterpreterFrame::replaceInnermostScope(ScopeObject& scope)
{
MOZ_ASSERT(flags_ & HAS_SCOPECHAIN);
MOZ_ASSERT(scope.enclosingScope() == scopeChain_->as<ScopeObject>().enclosingScope());
scopeChain_ = &scope;
}
bool
InterpreterFrame::hasCallObj() const
{
MOZ_ASSERT(isStrictEvalFrame() || fun()->needsCallObject());
return flags_ & HAS_CALL_OBJ;
}
inline CallObject&
InterpreterFrame::callObj() const
{
MOZ_ASSERT(fun()->needsCallObject());
JSObject* pobj = scopeChain();
while (MOZ_UNLIKELY(!pobj->is<CallObject>()))
pobj = pobj->enclosingScope();
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,
InterpreterFrame::Flags* flags, 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);
bool isConstructing = *flags & InterpreterFrame::CONSTRUCTING;
unsigned nfunctionState = 2 + isConstructing; // 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 (isConstructing)
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, InitialFrameFlags initial)
{
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();
InterpreterFrame::Flags flags = ToFrameFlags(initial);
Value* argv;
InterpreterFrame* fp = getCallFrame(cx, args, script, &flags, &argv);
if (!fp)
return false;
fp->mark_ = mark;
/* Initialize frame, locals, regs. */
fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, args.length(), flags);
regs.prepareToRun(*fp, script);
return true;
}
MOZ_ALWAYS_INLINE bool
InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
HandleFunction callee, HandleValue newTarget,
HandleObject scopeChain)
{
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();
bool constructing = 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);
InterpreterFrame::Flags flags = constructing ? ToFrameFlags(INITIAL_CONSTRUCT)
: ToFrameFlags(INITIAL_NONE);
fp->mark_ = mark;
fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, 0, flags);
fp->resumeGeneratorFrame(scopeChain);
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 ASMJS:
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;
}
asBaselineFrame()->setReturnValue(rval);
}
inline JSObject*
AbstractFramePtr::scopeChain() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->scopeChain();
if (isBaselineFrame())
return asBaselineFrame()->scopeChain();
return asRematerializedFrame()->scopeChain();
}
inline void
AbstractFramePtr::pushOnScopeChain(ScopeObject& scope)
{
if (isInterpreterFrame()) {
asInterpreterFrame()->pushOnScopeChain(scope);
return;
}
asBaselineFrame()->pushOnScopeChain(scope);
}
inline CallObject&
AbstractFramePtr::callObj() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->callObj();
if (isBaselineFrame())
return asBaselineFrame()->callObj();
return asRematerializedFrame()->callObj();
}
inline bool
AbstractFramePtr::initFunctionScopeObjects(JSContext* cx)
{
if (isInterpreterFrame())
return asInterpreterFrame()->initFunctionScopeObjects(cx);
if (isBaselineFrame())
return asBaselineFrame()->initFunctionScopeObjects(cx);
return asRematerializedFrame()->initFunctionScopeObjects(cx);
}
inline JSCompartment*
AbstractFramePtr::compartment() const
{
return scopeChain()->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::hasCallObj() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->hasCallObj();
if (isBaselineFrame())
return asBaselineFrame()->hasCallObj();
return asRematerializedFrame()->hasCallObj();
}
inline bool
AbstractFramePtr::createSingleton() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->createSingleton();
return false;
}
inline bool
AbstractFramePtr::isFunctionFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isFunctionFrame();
if (isBaselineFrame())
return asBaselineFrame()->isFunctionFrame();
return asRematerializedFrame()->isFunctionFrame();
}
inline bool
AbstractFramePtr::isModuleFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isModuleFrame();
if (isBaselineFrame())
return asBaselineFrame()->isModuleFrame();
return asRematerializedFrame()->isModuleFrame();
}
inline bool
AbstractFramePtr::isGlobalFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isGlobalFrame();
if (isBaselineFrame())
return asBaselineFrame()->isGlobalFrame();
return asRematerializedFrame()->isGlobalFrame();
}
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 isNonEvalFunctionFrame();
}
inline JSScript*
AbstractFramePtr::script() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->script();
if (isBaselineFrame())
return asBaselineFrame()->script();
return asRematerializedFrame()->script();
}
inline JSFunction*
AbstractFramePtr::fun() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->fun();
if (isBaselineFrame())
return asBaselineFrame()->fun();
return asRematerializedFrame()->fun();
}
inline JSFunction*
AbstractFramePtr::maybeFun() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->maybeFun();
if (isBaselineFrame())
return asBaselineFrame()->maybeFun();
return asRematerializedFrame()->maybeFun();
}
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::isNonEvalFunctionFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isNonEvalFunctionFrame();
if (isBaselineFrame())
return asBaselineFrame()->isNonEvalFunctionFrame();
return asRematerializedFrame()->isNonEvalFunctionFrame();
}
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::copyRawFrameSlots(AutoValueVector* vec) const
{
if (isInterpreterFrame())
return asInterpreterFrame()->copyRawFrameSlots(vec);
return asBaselineFrame()->copyRawFrameSlots(vec);
}
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::freshenBlock(JSContext* cx) const
{
if (isInterpreterFrame())
return asInterpreterFrame()->freshenBlock(cx);
return asBaselineFrame()->freshenBlock(cx);
}
inline void
AbstractFramePtr::popBlock(JSContext* cx) const
{
if (isInterpreterFrame()) {
asInterpreterFrame()->popBlock(cx);
return;
}
asBaselineFrame()->popBlock(cx);
}
inline void
AbstractFramePtr::popWith(JSContext* cx) const
{
if (isInterpreterFrame()) {
asInterpreterFrame()->popWith(cx);
return;
}
asBaselineFrame()->popWith(cx);
}
ActivationEntryMonitor::~ActivationEntryMonitor()
{
if (entryMonitor_)
entryMonitor_->Exit(cx_);
cx_->runtime()->entryMonitor = entryMonitor_;
}
Activation::Activation(JSContext* cx, Kind kind)
: cx_(cx),
compartment_(cx->compartment()),
prev_(cx->runtime_->activation_),
prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr),
savedFrameChain_(0),
hideScriptedCallerCount_(0),
frameCache_(cx),
asyncStack_(cx, cx->runtime_->asyncStackForNewActivations),
asyncCause_(cx, cx->runtime_->asyncCauseForNewActivations),
asyncCallIsExplicit_(cx->runtime_->asyncCallIsExplicit),
kind_(kind)
{
cx->runtime_->asyncStackForNewActivations = nullptr;
cx->runtime_->asyncCauseForNewActivations = nullptr;
cx->runtime_->asyncCallIsExplicit = false;
cx->runtime_->activation_ = this;
}
Activation::~Activation()
{
MOZ_ASSERT_IF(isProfiling(), this != cx_->runtime()->profilingActivation_);
MOZ_ASSERT(cx_->runtime_->activation_ == this);
MOZ_ASSERT(hideScriptedCallerCount_ == 0);
cx_->runtime_->activation_ = prev_;
cx_->runtime_->asyncCauseForNewActivations = asyncCause_;
cx_->runtime_->asyncStackForNewActivations = asyncStack_;
cx_->runtime_->asyncCallIsExplicit = asyncCallIsExplicit_;
}
bool
Activation::isProfiling() const
{
if (isInterpreter())
return asInterpreter()->isProfiling();
if (isJit())
return asJit()->isProfiling();
MOZ_ASSERT(isAsmJS());
return asAsmJS()->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());
JSContext* cx = cx_->asJSContext();
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,
InitialFrameFlags initial)
{
JSContext* cx = cx_->asJSContext();
if (!cx->runtime()->interpreterStack().pushInlineFrame(cx, regs_, args, script, initial))
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_->asJSContext()->runtime()->interpreterStack().popInlineFrame(regs_);
}
inline bool
InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
HandleObject scopeChain)
{
InterpreterStack& stack = cx_->asJSContext()->runtime()->interpreterStack();
if (!stack.resumeGeneratorCallFrame(cx_->asJSContext(), regs_, callee, newTarget, scopeChain))
return false;
MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_);
return true;
}
inline JSContext*
AsmJSActivation::cx()
{
return cx_->asJSContext();
}
inline bool
FrameIter::hasCachedSavedFrame() const
{
if (isAsmJS())
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(!isAsmJS());
if (hasUsableAbstractFramePtr()) {
abstractFramePtr().setHasCachedSavedFrame();
return;
}
MOZ_ASSERT(isPhysicalIonFrame());
data_.jitFrames_.current()->setHasCachedSavedFrame();
}
} /* namespace js */
#endif /* vm_Stack_inl_h */