DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
/* -*- 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/. */

#ifndef jit_RematerializedFrame_h
#define jit_RematerializedFrame_h

#include <algorithm>

#include "jit/JitFrames.h"
#include "jit/JSJitFrameIter.h"
#include "js/UniquePtr.h"
#include "vm/EnvironmentObject.h"
#include "vm/JSFunction.h"
#include "vm/Stack.h"

namespace js {
namespace jit {

// RematerializedFrame: An optimized frame that has been rematerialized with
// values read out of Snapshots.
//
// If the Debugger API tries to inspect or modify an IonMonkey frame, much of
// the information it expects to find in a frame is missing: function calls may
// have been inlined, variables may have been optimized out, and so on. So when
// this happens, SpiderMonkey builds one or more Rematerialized frames from the
// IonMonkey frame, using the snapshot metadata built by Ion to reconstruct the
// missing parts. The Rematerialized frames are now the authority on the state
// of those frames, and the Ion frame is ignored: stack iterators ignore the Ion
// frame, producing the Rematerialized frames in their stead; and when control
// returns to the Ion frame, we pop it, rebuild Baseline frames from the
// Rematerialized frames, and resume execution in Baseline.
class RematerializedFrame {
  // See DebugScopes::updateLiveScopes.
  bool prevUpToDate_;

  // Propagated to the Baseline frame once this is popped.
  bool isDebuggee_;

  // Has an initial environment has been pushed on the environment chain for
  // function frames that need a CallObject or eval frames that need a
  // VarEnvironmentObject?
  bool hasInitialEnv_;

  // Is this frame constructing?
  bool isConstructing_;

  // If true, this frame has been on the stack when
  // |js::SavedStacks::saveCurrentStack| was called, and so there is a
  // |js::SavedFrame| object cached for this frame.
  bool hasCachedSavedFrame_;

  // The fp of the top frame associated with this possibly inlined frame.
  uint8_t* top_;

  // The bytecode at the time of rematerialization.
  jsbytecode* pc_;

  size_t frameNo_;
  unsigned numActualArgs_;

  JSScript* script_;
  JSObject* envChain_;
  JSFunction* callee_;
  ArgumentsObject* argsObj_;

  Value returnValue_;
  Value thisArgument_;
  Value newTarget_;
  Value slots_[1];

  RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs,
                      InlineFrameIterator& iter, MaybeReadFallback& fallback);

 public:
  static RematerializedFrame* New(JSContext* cx, uint8_t* top,
                                  InlineFrameIterator& iter,
                                  MaybeReadFallback& fallback);

  // RematerializedFrame are allocated on non-GC heap, so use GCVector and
  // UniquePtr to ensure they are traced and cleaned up correctly.
  using RematerializedFrameVector = GCVector<UniquePtr<RematerializedFrame>>;

  // Rematerialize all remaining frames pointed to by |iter| into |frames|
  // in older-to-younger order, e.g., frames[0] is the oldest frame.
  static MOZ_MUST_USE bool RematerializeInlineFrames(
      JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
      MaybeReadFallback& fallback, RematerializedFrameVector& frames);

  bool prevUpToDate() const { return prevUpToDate_; }
  void setPrevUpToDate() { prevUpToDate_ = true; }
  void unsetPrevUpToDate() { prevUpToDate_ = false; }

  bool isDebuggee() const { return isDebuggee_; }
  void setIsDebuggee() { isDebuggee_ = true; }
  void unsetIsDebuggee() {
    MOZ_ASSERT(!script()->isDebuggee());
    isDebuggee_ = false;
  }

  uint8_t* top() const { return top_; }
  JSScript* outerScript() const {
    JitFrameLayout* jsFrame = (JitFrameLayout*)top_;
    return ScriptFromCalleeToken(jsFrame->calleeToken());
  }
  jsbytecode* pc() const { return pc_; }
  size_t frameNo() const { return frameNo_; }
  bool inlined() const { return frameNo_ > 0; }

  JSObject* environmentChain() const { return envChain_; }

  template <typename SpecificEnvironment>
  void pushOnEnvironmentChain(SpecificEnvironment& env) {
    MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment());
    envChain_ = &env;
    if (IsFrameInitialEnvironment(this, env)) {
      hasInitialEnv_ = true;
    }
  }

  template <typename SpecificEnvironment>
  void popOffEnvironmentChain() {
    MOZ_ASSERT(envChain_->is<SpecificEnvironment>());
    envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment();
  }

  MOZ_MUST_USE bool initFunctionEnvironmentObjects(JSContext* cx);
  MOZ_MUST_USE bool pushVarEnvironment(JSContext* cx, HandleScope scope);

  bool hasInitialEnvironment() const { return hasInitialEnv_; }
  CallObject& callObj() const;

  bool hasArgsObj() const { return !!argsObj_; }
  ArgumentsObject& argsObj() const {
    MOZ_ASSERT(hasArgsObj());
    MOZ_ASSERT(script()->needsArgsObj());
    return *argsObj_;
  }

  bool isFunctionFrame() const { return !!script_->functionNonDelazifying(); }
  bool isGlobalFrame() const { return script_->isGlobalCode(); }
  bool isModuleFrame() const { return script_->module(); }

  JSScript* script() const { return script_; }
  JSFunction* callee() const {
    MOZ_ASSERT(isFunctionFrame());
    MOZ_ASSERT(callee_);
    return callee_;
  }
  Value calleev() const { return ObjectValue(*callee()); }
  Value& thisArgument() { return thisArgument_; }

  bool isConstructing() const { return isConstructing_; }

  bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }

  void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }

  void clearHasCachedSavedFrame() { hasCachedSavedFrame_ = false; }

  unsigned numFormalArgs() const {
    return isFunctionFrame() ? callee()->nargs() : 0;
  }
  unsigned numActualArgs() const { return numActualArgs_; }
  unsigned numArgSlots() const {
    return (std::max)(numFormalArgs(), numActualArgs());
  }

  Value* argv() { return slots_; }
  Value* locals() { return slots_ + numArgSlots(); }

  Value& unaliasedLocal(unsigned i) {
    MOZ_ASSERT(i < script()->nfixed());
    return locals()[i];
  }
  Value& unaliasedFormal(unsigned i,
                         MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
    MOZ_ASSERT(i < numFormalArgs());
    MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
                                     !script()->formalIsAliased(i));
    return argv()[i];
  }
  Value& unaliasedActual(unsigned i,
                         MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
    MOZ_ASSERT(i < numActualArgs());
    MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
    MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(),
                  !script()->formalIsAliased(i));
    return argv()[i];
  }

  Value newTarget() {
    MOZ_ASSERT(isFunctionFrame());
    if (callee()->isArrow()) {
      return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
    }
    MOZ_ASSERT_IF(!isConstructing(), newTarget_.isUndefined());
    return newTarget_;
  }

  void setReturnValue(const Value& value) { returnValue_ = value; }

  Value& returnValue() { return returnValue_; }

  void trace(JSTracer* trc);
  void dump();
};

}  // namespace jit
}  // namespace js

#endif  // jit_RematerializedFrame_h