summaryrefslogtreecommitdiffstats
path: root/js/src/jit/BaselineFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/BaselineFrame.cpp')
-rw-r--r--js/src/jit/BaselineFrame.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp
new file mode 100644
index 0000000000..49c70c3735
--- /dev/null
+++ b/js/src/jit/BaselineFrame.cpp
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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 "jit/BaselineFrame-inl.h"
+
+#include <algorithm>
+
+#include "debugger/DebugAPI.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/JSContext.h"
+
+#include "jit/JSJitFrameIter-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+static void TraceLocals(BaselineFrame* frame, JSTracer* trc, unsigned start,
+ unsigned end) {
+ if (start < end) {
+ // Stack grows down.
+ Value* last = frame->valueSlot(end - 1);
+ TraceRootRange(trc, end - start, last, "baseline-stack");
+ }
+}
+
+void BaselineFrame::trace(JSTracer* trc, const JSJitFrameIter& frameIterator) {
+ replaceCalleeToken(TraceCalleeToken(trc, calleeToken()));
+
+ // Trace |this|, actual and formal args.
+ if (isFunctionFrame()) {
+ TraceRoot(trc, &thisArgument(), "baseline-this");
+
+ unsigned numArgs = std::max(numActualArgs(), numFormalArgs());
+ TraceRootRange(trc, numArgs + isConstructing(), argv(), "baseline-args");
+ }
+
+ // Trace environment chain, if it exists.
+ if (envChain_) {
+ TraceRoot(trc, &envChain_, "baseline-envchain");
+ }
+
+ // Trace return value.
+ if (hasReturnValue()) {
+ TraceRoot(trc, returnValue().address(), "baseline-rval");
+ }
+
+ if (hasArgsObj()) {
+ TraceRoot(trc, &argsObj_, "baseline-args-obj");
+ }
+
+ if (runningInInterpreter()) {
+ TraceRoot(trc, &interpreterScript_, "baseline-interpreterScript");
+ }
+
+ // Trace locals and stack values.
+ JSScript* script = this->script();
+ size_t nfixed = script->nfixed();
+ jsbytecode* pc;
+ frameIterator.baselineScriptAndPc(nullptr, &pc);
+ size_t nlivefixed = script->calculateLiveFixed(pc);
+
+ uint32_t numValueSlots = frameIterator.baselineFrameNumValueSlots();
+
+ // NB: It is possible that numValueSlots could be zero, even if nfixed is
+ // nonzero. This is the case when we're initializing the environment chain or
+ // failed the prologue stack check.
+ if (numValueSlots > 0) {
+ MOZ_ASSERT(nfixed <= numValueSlots);
+
+ if (nfixed == nlivefixed) {
+ // All locals are live.
+ TraceLocals(this, trc, 0, numValueSlots);
+ } else {
+ // Trace operand stack.
+ TraceLocals(this, trc, nfixed, numValueSlots);
+
+ // Clear dead block-scoped locals.
+ while (nfixed > nlivefixed) {
+ unaliasedLocal(--nfixed).setUndefined();
+ }
+
+ // Trace live locals.
+ TraceLocals(this, trc, 0, nlivefixed);
+ }
+ }
+
+ if (auto* debugEnvs = script->realm()->debugEnvs()) {
+ debugEnvs->traceLiveFrame(trc, this);
+ }
+}
+
+bool BaselineFrame::uninlineIsProfilerSamplingEnabled(JSContext* cx) {
+ return cx->isProfilerSamplingEnabled();
+}
+
+bool BaselineFrame::initFunctionEnvironmentObjects(JSContext* cx) {
+ return js::InitFunctionEnvironmentObjects(cx, this);
+}
+
+bool BaselineFrame::pushVarEnvironment(JSContext* cx, Handle<Scope*> scope) {
+ return js::PushVarEnvironmentObject(cx, scope, this);
+}
+
+void BaselineFrame::setInterpreterFields(JSScript* script, jsbytecode* pc) {
+ uint32_t pcOffset = script->pcToOffset(pc);
+ interpreterScript_ = script;
+ interpreterPC_ = pc;
+ MOZ_ASSERT(icScript_);
+ interpreterICEntry_ = icScript_->interpreterICEntryFromPCOffset(pcOffset);
+}
+
+void BaselineFrame::setInterpreterFieldsForPrologue(JSScript* script) {
+ interpreterScript_ = script;
+ interpreterPC_ = script->code();
+ if (icScript_->numICEntries() > 0) {
+ interpreterICEntry_ = &icScript_->icEntry(0);
+ } else {
+ // If the script does not have any ICEntries (possible for non-function
+ // scripts) the interpreterICEntry_ field won't be used. Just set it to
+ // nullptr.
+ interpreterICEntry_ = nullptr;
+ }
+}
+
+bool BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues) {
+ mozilla::PodZero(this);
+
+ envChain_ = fp->environmentChain();
+
+ if (fp->hasInitialEnvironmentUnchecked()) {
+ flags_ |= BaselineFrame::HAS_INITIAL_ENV;
+ }
+
+ if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
+ flags_ |= BaselineFrame::HAS_ARGS_OBJ;
+ argsObj_ = &fp->argsObj();
+ }
+
+ if (fp->hasReturnValue()) {
+ setReturnValue(fp->returnValue());
+ }
+
+ icScript_ = fp->script()->jitScript()->icScript();
+
+ JSContext* cx =
+ fp->script()->runtimeFromMainThread()->mainContextFromOwnThread();
+
+ Activation* interpActivation = cx->activation()->prev();
+ jsbytecode* pc = interpActivation->asInterpreter()->regs().pc;
+ MOZ_ASSERT(fp->script()->containsPC(pc));
+
+ // We are doing OSR into the Baseline Interpreter. We can get the pc from the
+ // C++ interpreter's activation, we just have to skip the JitActivation.
+ flags_ |= BaselineFrame::RUNNING_IN_INTERPRETER;
+ setInterpreterFields(pc);
+
+#ifdef DEBUG
+ debugFrameSize_ = frameSizeForNumValueSlots(numStackValues);
+ MOZ_ASSERT(debugNumValueSlots() == numStackValues);
+#endif
+
+ for (uint32_t i = 0; i < numStackValues; i++) {
+ *valueSlot(i) = fp->slots()[i];
+ }
+
+ if (fp->isDebuggee()) {
+ // For debuggee frames, update any Debugger.Frame objects for the
+ // InterpreterFrame to point to the BaselineFrame.
+ if (!DebugAPI::handleBaselineOsr(cx, fp, this)) {
+ return false;
+ }
+ setIsDebuggee();
+ }
+
+ return true;
+}