blob: 0ba4111a26bf0006a6950000467cbf23dd901d78 [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/. */
#include "BaselineFrame.h"
#include "BaselineFrame-inl.h"
#include "BaselineIC.h"
#include "BaselineJIT.h"
#include "Ion.h"
#include "IonFrames-inl.h"
#include "vm/Debugger.h"
#include "vm/ScopeObject.h"
using namespace js;
using namespace js::jit;
void
BaselineFrame::trace(JSTracer *trc)
{
replaceCalleeToken(MarkCalleeToken(trc, calleeToken()));
gc::MarkValueRoot(trc, &thisValue(), "baseline-this");
// Mark actual and formal args.
if (isNonEvalFunctionFrame()) {
unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args");
}
// Mark scope chain.
gc::MarkObjectRoot(trc, &scopeChain_, "baseline-scopechain");
// Mark return value.
if (hasReturnValue())
gc::MarkValueRoot(trc, returnValue(), "baseline-rval");
if (isEvalFrame())
gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript");
if (hasArgsObj())
gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj");
// Mark locals and stack values.
size_t nvalues = numValueSlots();
if (nvalues > 0) {
// The stack grows down, so start at the last Value.
Value *last = valueSlot(nvalues - 1);
gc::MarkValueRootRange(trc, nvalues, last, "baseline-stack");
}
}
bool
BaselineFrame::copyRawFrameSlots(AutoValueVector *vec) const
{
unsigned nfixed = script()->nfixed;
unsigned nformals = numFormalArgs();
if (!vec->resize(nformals + nfixed))
return false;
mozilla::PodCopy(vec->begin(), argv(), nformals);
for (unsigned i = 0; i < nfixed; i++)
(*vec)[nformals + i] = *valueSlot(i);
return true;
}
bool
BaselineFrame::strictEvalPrologue(JSContext *cx)
{
JS_ASSERT(isStrictEvalFrame());
CallObject *callobj = CallObject::createForStrictEval(cx, this);
if (!callobj)
return false;
pushOnScopeChain(*callobj);
flags_ |= HAS_CALL_OBJ;
return true;
}
bool
BaselineFrame::heavyweightFunPrologue(JSContext *cx)
{
return initFunctionScopeObjects(cx);
}
bool
BaselineFrame::initFunctionScopeObjects(JSContext *cx)
{
JS_ASSERT(isNonEvalFunctionFrame());
JS_ASSERT(fun()->isHeavyweight());
CallObject *callobj = CallObject::createForFunction(cx, this);
if (!callobj)
return false;
pushOnScopeChain(*callobj);
flags_ |= HAS_CALL_OBJ;
return true;
}
bool
BaselineFrame::initForOsr(StackFrame *fp, uint32_t numStackValues)
{
mozilla::PodZero(this);
scopeChain_ = fp->scopeChain();
if (fp->hasCallObjUnchecked())
flags_ |= BaselineFrame::HAS_CALL_OBJ;
if (fp->hasBlockChain()) {
flags_ |= BaselineFrame::HAS_BLOCKCHAIN;
blockChain_ = &fp->blockChain();
}
if (fp->isEvalFrame()) {
flags_ |= BaselineFrame::EVAL;
evalScript_ = fp->script();
}
if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
flags_ |= BaselineFrame::HAS_ARGS_OBJ;
argsObj_ = &fp->argsObj();
}
if (fp->hasHookData()) {
flags_ |= BaselineFrame::HAS_HOOK_DATA;
hookData_ = fp->hookData();
}
if (fp->hasReturnValue())
setReturnValue(fp->returnValue());
if (fp->hasPushedSPSFrame())
flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
frameSize_ = BaselineFrame::FramePointerOffset +
BaselineFrame::Size() +
numStackValues * sizeof(Value);
JS_ASSERT(numValueSlots() == numStackValues);
for (uint32_t i = 0; i < numStackValues; i++)
*valueSlot(i) = fp->slots()[i];
JSContext *cx = GetIonContext()->cx;
if (cx->compartment()->debugMode()) {
// In debug mode, update any Debugger.Frame objects for the StackFrame to
// point to the BaselineFrame.
// The caller pushed a fake return address. ScriptFrameIter, used by the
// debugger, wants a valid return address, but it's okay to just pick one.
// In debug mode there's always at least 1 ICEntry (since there are always
// debug prologue/epilogue calls).
IonFrameIterator iter(cx->mainThread().ionTop);
JS_ASSERT(iter.returnAddress() == NULL);
BaselineScript *baseline = fp->script()->baselineScript();
iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
if (!Debugger::handleBaselineOsr(cx, fp, this))
return false;
}
return true;
}