tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BaselineFrame.cpp (5877B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "jit/BaselineFrame-inl.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "debugger/DebugAPI.h"
     12 #include "vm/EnvironmentObject.h"
     13 #include "vm/JSContext.h"
     14 
     15 #include "jit/JSJitFrameIter-inl.h"
     16 #include "vm/Stack-inl.h"
     17 
     18 using namespace js;
     19 using namespace js::jit;
     20 
     21 static void TraceLocals(BaselineFrame* frame, JSTracer* trc, unsigned start,
     22                        unsigned end) {
     23  if (start < end) {
     24    // Stack grows down.
     25    Value* last = frame->valueSlot(end - 1);
     26    TraceRootRange(trc, end - start, last, "baseline-stack");
     27  }
     28 }
     29 
     30 void BaselineFrame::trace(JSTracer* trc, const JSJitFrameIter& frameIterator) {
     31  replaceCalleeToken(TraceCalleeToken(trc, calleeToken()));
     32 
     33  // Trace |this|, actual and formal args.
     34  if (isFunctionFrame()) {
     35    TraceRoot(trc, &thisArgument(), "baseline-this");
     36 
     37    unsigned numArgs = std::max(numActualArgs(), numFormalArgs());
     38    TraceRootRange(trc, numArgs + isConstructing(), argv(), "baseline-args");
     39  }
     40 
     41  // Trace environment chain, if it exists.
     42  if (envChain_) {
     43    TraceRoot(trc, &envChain_, "baseline-envchain");
     44  }
     45 
     46  // Trace return value.
     47  if (hasReturnValue()) {
     48    TraceRoot(trc, returnValue().address(), "baseline-rval");
     49  }
     50 
     51  if (hasArgsObj()) {
     52    TraceRoot(trc, &argsObj_, "baseline-args-obj");
     53  }
     54 
     55  mozilla::DebugOnly<bool> isBaselineSelfHosted =
     56      this->script()->selfHosted() && !runningInInterpreter();
     57  MOZ_ASSERT_IF(
     58      JS::Prefs::experimental_self_hosted_cache() && isBaselineSelfHosted,
     59      isRealmIndependent());
     60  if (runningInInterpreter() || isRealmIndependent()) {
     61    TraceRoot(trc, &interpreterScript_, "baseline-interpreterScript");
     62  }
     63 
     64  // Trace locals and stack values.
     65  JSScript* script = this->script();
     66  size_t nfixed = script->nfixed();
     67  jsbytecode* pc;
     68  frameIterator.baselineScriptAndPc(nullptr, &pc);
     69  size_t nlivefixed = script->calculateLiveFixed(pc);
     70 
     71  uint32_t numValueSlots = frameIterator.baselineFrameNumValueSlots();
     72 
     73  // NB: It is possible that numValueSlots could be zero, even if nfixed is
     74  // nonzero.  This is the case when we're initializing the environment chain or
     75  // failed the prologue stack check.
     76  if (numValueSlots > 0) {
     77    MOZ_ASSERT(nfixed <= numValueSlots);
     78 
     79    if (nfixed == nlivefixed) {
     80      // All locals are live.
     81      TraceLocals(this, trc, 0, numValueSlots);
     82    } else {
     83      // Trace operand stack.
     84      TraceLocals(this, trc, nfixed, numValueSlots);
     85 
     86      // Clear dead block-scoped locals.
     87      while (nfixed > nlivefixed) {
     88        unaliasedLocal(--nfixed).setUndefined();
     89      }
     90 
     91      // Trace live locals.
     92      TraceLocals(this, trc, 0, nlivefixed);
     93    }
     94  }
     95 
     96  if (auto* debugEnvs = script->realm()->debugEnvs()) {
     97    debugEnvs->traceLiveFrame(trc, this);
     98  }
     99 }
    100 
    101 bool BaselineFrame::uninlineIsProfilerSamplingEnabled(JSContext* cx) {
    102  return cx->isProfilerSamplingEnabled();
    103 }
    104 
    105 bool BaselineFrame::initFunctionEnvironmentObjects(JSContext* cx) {
    106  return js::InitFunctionEnvironmentObjects(cx, this);
    107 }
    108 
    109 bool BaselineFrame::pushVarEnvironment(JSContext* cx, Handle<Scope*> scope) {
    110  return js::PushVarEnvironmentObject(cx, scope, this);
    111 }
    112 
    113 void BaselineFrame::setInterpreterFields(JSScript* script, jsbytecode* pc) {
    114  uint32_t pcOffset = script->pcToOffset(pc);
    115  interpreterScript_ = script;
    116  interpreterPC_ = pc;
    117  MOZ_ASSERT(icScript_);
    118  interpreterICEntry_ = icScript_->interpreterICEntryFromPCOffset(pcOffset);
    119 }
    120 
    121 void BaselineFrame::setInterpreterFieldsForPrologue(JSScript* script) {
    122  interpreterScript_ = script;
    123  interpreterPC_ = script->code();
    124  if (icScript_->numICEntries() > 0) {
    125    interpreterICEntry_ = &icScript_->icEntry(0);
    126  } else {
    127    // If the script does not have any ICEntries (possible for non-function
    128    // scripts) the interpreterICEntry_ field won't be used. Just set it to
    129    // nullptr.
    130    interpreterICEntry_ = nullptr;
    131  }
    132 }
    133 
    134 bool BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues) {
    135  mozilla::PodZero(this);
    136 
    137  envChain_ = fp->environmentChain();
    138 
    139  if (fp->hasInitialEnvironmentUnchecked()) {
    140    flags_ |= BaselineFrame::HAS_INITIAL_ENV;
    141  }
    142 
    143  if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
    144    flags_ |= BaselineFrame::HAS_ARGS_OBJ;
    145    argsObj_ = &fp->argsObj();
    146  }
    147 
    148  if (fp->hasReturnValue()) {
    149    setReturnValue(fp->returnValue());
    150  }
    151 
    152  icScript_ = fp->script()->jitScript()->icScript();
    153 
    154  JSContext* cx =
    155      fp->script()->runtimeFromMainThread()->mainContextFromOwnThread();
    156 
    157  Activation* interpActivation = cx->activation()->prev();
    158  jsbytecode* pc = interpActivation->asInterpreter()->regs().pc;
    159  MOZ_ASSERT(fp->script()->containsPC(pc));
    160 
    161  // We are doing OSR into the Baseline Interpreter. We can get the pc from the
    162  // C++ interpreter's activation, we just have to skip the JitActivation.
    163  flags_ |= BaselineFrame::RUNNING_IN_INTERPRETER;
    164  setInterpreterFields(pc);
    165 
    166 #ifdef DEBUG
    167  debugFrameSize_ = frameSizeForNumValueSlots(numStackValues);
    168  MOZ_ASSERT(debugNumValueSlots() == numStackValues);
    169 #endif
    170 
    171  for (uint32_t i = 0; i < numStackValues; i++) {
    172    *valueSlot(i) = fp->slots()[i];
    173  }
    174 
    175  // The InterpreterFrame won't be used anymore, but a GC might still trace it.
    176  // Clear its stack slots to avoid keeping GC things alive.
    177  std::fill_n(fp->slots(), numStackValues, UndefinedValue());
    178 
    179  if (fp->isDebuggee()) {
    180    // For debuggee frames, update any Debugger.Frame objects for the
    181    // InterpreterFrame to point to the BaselineFrame.
    182    if (!DebugAPI::handleBaselineOsr(cx, fp, this)) {
    183      return false;
    184    }
    185    setIsDebuggee();
    186  }
    187 
    188  return true;
    189 }