tor-browser

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

BaselineFrameInfo.h (13118B)


      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 #ifndef jit_BaselineFrameInfo_h
      8 #define jit_BaselineFrameInfo_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Maybe.h"
     12 
     13 #include <new>
     14 
     15 #include "jit/BaselineFrame.h"
     16 #include "jit/BaselineJIT.h"
     17 #include "jit/FixedList.h"
     18 #include "jit/MacroAssembler.h"
     19 #include "jit/SharedICRegisters.h"
     20 
     21 namespace js {
     22 namespace jit {
     23 
     24 struct BytecodeInfo;
     25 class MacroAssembler;
     26 
     27 // [SMDOC] Baseline FrameInfo overview.
     28 //
     29 // FrameInfo is used by BaselineCodeGen to track values stored in the frame.
     30 // There are two implementations:
     31 //
     32 // InterpreterFrameInfo
     33 // --------------------
     34 // The InterpreterFrameInfo class is used by the interpreter generator and is
     35 // a very simple interface on top of the MacroAssembler, because the stack is
     36 // always synced.
     37 //
     38 // CompilerFrameInfo
     39 // -----------------
     40 // The CompilerFrameInfo class is more complicated because it maintains a
     41 // virtual stack to optimize some common stack operations. Locals and arguments
     42 // are always fully synced. Stack values can either be synced, stored as
     43 // constant, stored in a Value register or refer to a local slot. Syncing a
     44 // StackValue ensures it's stored on the stack, e.g. kind == Stack.
     45 //
     46 // To see how this works, consider the following statement:
     47 //
     48 //    var y = x + 9;
     49 //
     50 // Here two values are pushed: StackValue(LocalSlot(0)) and
     51 // StackValue(Int32Value(9)). Only when we reach the ADD op, code is generated
     52 // to load the operands directly into the right operand registers and sync all
     53 // other stack values.
     54 //
     55 // For stack values, the following invariants hold (and are checked between
     56 // ops):
     57 //
     58 // (1) If a value is synced (kind == Stack), all values below it must also be
     59 //     synced. In other words, values with kind other than Stack can only appear
     60 //     on top of the abstract stack.
     61 //
     62 // (2) When we call a stub or IC, all values still on the stack must be synced.
     63 
     64 // Represents a value pushed on the stack. Note that StackValue is not used for
     65 // locals or arguments since these are always fully synced.
     66 class StackValue {
     67 public:
     68  enum Kind {
     69    Constant,
     70    Register,
     71    Stack,
     72    LocalSlot,
     73    ArgSlot,
     74    ThisSlot,
     75 #ifdef DEBUG
     76    // In debug builds, assert Kind is initialized.
     77    Uninitialized,
     78 #endif
     79  };
     80 
     81 private:
     82  MOZ_INIT_OUTSIDE_CTOR Kind kind_;
     83 
     84  MOZ_INIT_OUTSIDE_CTOR union Data {
     85    JS::Value constant;
     86    ValueOperand reg;
     87    uint32_t localSlot;
     88    uint32_t argSlot;
     89 
     90    // |constant| has a non-trivial constructor and therefore MUST be
     91    // placement-new'd into existence.
     92    MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
     93    Data() {}
     94    MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
     95  } data;
     96 
     97  MOZ_INIT_OUTSIDE_CTOR JSValueType knownType_;
     98 
     99 public:
    100  StackValue() { reset(); }
    101 
    102  Kind kind() const { return kind_; }
    103  bool hasKnownType() const { return knownType_ != JSVAL_TYPE_UNKNOWN; }
    104  bool hasKnownType(JSValueType type) const {
    105    MOZ_ASSERT(type != JSVAL_TYPE_UNKNOWN);
    106    return knownType_ == type;
    107  }
    108  JSValueType knownType() const {
    109    MOZ_ASSERT(hasKnownType());
    110    return knownType_;
    111  }
    112  void reset() {
    113 #ifdef DEBUG
    114    kind_ = Uninitialized;
    115    knownType_ = JSVAL_TYPE_UNKNOWN;
    116 #endif
    117  }
    118  Value constant() const {
    119    MOZ_ASSERT(kind_ == Constant);
    120    return data.constant;
    121  }
    122  ValueOperand reg() const {
    123    MOZ_ASSERT(kind_ == Register);
    124    return data.reg;
    125  }
    126  uint32_t localSlot() const {
    127    MOZ_ASSERT(kind_ == LocalSlot);
    128    return data.localSlot;
    129  }
    130  uint32_t argSlot() const {
    131    MOZ_ASSERT(kind_ == ArgSlot);
    132    return data.argSlot;
    133  }
    134 
    135  void setConstant(const Value& v) {
    136    kind_ = Constant;
    137    new (&data.constant) Value(v);
    138    knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
    139  }
    140  void setRegister(const ValueOperand& val,
    141                   JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
    142    kind_ = Register;
    143    new (&data.reg) ValueOperand(val);
    144    knownType_ = knownType;
    145  }
    146  void setLocalSlot(uint32_t slot) {
    147    kind_ = LocalSlot;
    148    new (&data.localSlot) uint32_t(slot);
    149    knownType_ = JSVAL_TYPE_UNKNOWN;
    150  }
    151  void setArgSlot(uint32_t slot) {
    152    kind_ = ArgSlot;
    153    new (&data.argSlot) uint32_t(slot);
    154    knownType_ = JSVAL_TYPE_UNKNOWN;
    155  }
    156  void setThis() {
    157    kind_ = ThisSlot;
    158    knownType_ = JSVAL_TYPE_UNKNOWN;
    159  }
    160  void setStack() {
    161    kind_ = Stack;
    162    knownType_ = JSVAL_TYPE_UNKNOWN;
    163  }
    164 };
    165 
    166 enum StackAdjustment { AdjustStack, DontAdjustStack };
    167 
    168 class FrameInfo {
    169 protected:
    170  MacroAssembler& masm;
    171 
    172 public:
    173  explicit FrameInfo(MacroAssembler& masm) : masm(masm) {}
    174 
    175  Address addressOfLocal(size_t local) const {
    176    return Address(FramePointer, BaselineFrame::reverseOffsetOfLocal(local));
    177  }
    178  Address addressOfArg(size_t arg) const {
    179    return Address(FramePointer, JitFrameLayout::offsetOfActualArg(arg));
    180  }
    181  Address addressOfThis() const {
    182    return Address(FramePointer, JitFrameLayout::offsetOfThis());
    183  }
    184  Address addressOfDescriptor() const {
    185    return Address(FramePointer, CommonFrameLayout::offsetOfDescriptor());
    186  }
    187  Address addressOfCalleeToken() const {
    188    return Address(FramePointer, JitFrameLayout::offsetOfCalleeToken());
    189  }
    190  Address addressOfEnvironmentChain() const {
    191    return Address(FramePointer,
    192                   BaselineFrame::reverseOffsetOfEnvironmentChain());
    193  }
    194  Address addressOfICScript() const {
    195    return Address(FramePointer, BaselineFrame::reverseOffsetOfICScript());
    196  }
    197  Address addressOfFlags() const {
    198    return Address(FramePointer, BaselineFrame::reverseOffsetOfFlags());
    199  }
    200  Address addressOfReturnValue() const {
    201    return Address(FramePointer, BaselineFrame::reverseOffsetOfReturnValue());
    202  }
    203  Address addressOfArgsObj() const {
    204    return Address(FramePointer, BaselineFrame::reverseOffsetOfArgsObj());
    205  }
    206  Address addressOfScratchValue() const {
    207    return Address(FramePointer, BaselineFrame::reverseOffsetOfScratchValue());
    208  }
    209  Address addressOfScratchValueLow32() const {
    210    return Address(FramePointer,
    211                   BaselineFrame::reverseOffsetOfScratchValueLow32());
    212  }
    213  Address addressOfScratchValueHigh32() const {
    214    return Address(FramePointer,
    215                   BaselineFrame::reverseOffsetOfScratchValueHigh32());
    216  }
    217 #ifdef DEBUG
    218  Address addressOfDebugFrameSize() const {
    219    return Address(FramePointer,
    220                   BaselineFrame::reverseOffsetOfDebugFrameSize());
    221  }
    222 #endif
    223  Address addressOfInterpreterScript() const {
    224    return Address(FramePointer,
    225                   BaselineFrame::reverseOffsetOfInterpreterScript());
    226  }
    227 };
    228 
    229 class CompilerFrameInfo : public FrameInfo {
    230  friend class BaselinePerfSpewer;
    231  JSScript* script;
    232  FixedList<StackValue> stack;
    233  size_t spIndex;
    234 
    235 public:
    236  CompilerFrameInfo(JSScript* script, MacroAssembler& masm)
    237      : FrameInfo(masm), script(script), spIndex(0) {}
    238  [[nodiscard]] bool init(TempAllocator& alloc);
    239 
    240  size_t nlocals() const { return script->nfixed(); }
    241  size_t nargs() const { return script->function()->nargs(); }
    242 
    243 private:
    244  inline StackValue* rawPush() {
    245    StackValue* val = &stack[spIndex++];
    246    val->reset();
    247    return val;
    248  }
    249 
    250  inline StackValue* peek(int32_t index) const {
    251    MOZ_ASSERT(index < 0);
    252    return const_cast<StackValue*>(&stack[spIndex + index]);
    253  }
    254 
    255 public:
    256  inline size_t stackDepth() const { return spIndex; }
    257  inline void setStackDepth(uint32_t newDepth) {
    258    if (newDepth <= stackDepth()) {
    259      spIndex = newDepth;
    260    } else {
    261      uint32_t diff = newDepth - stackDepth();
    262      for (uint32_t i = 0; i < diff; i++) {
    263        StackValue* val = rawPush();
    264        val->setStack();
    265      }
    266 
    267      MOZ_ASSERT(spIndex == newDepth);
    268    }
    269  }
    270 
    271  void assertStackDepth(uint32_t depth) { MOZ_ASSERT(stackDepth() == depth); }
    272  void incStackDepth(int32_t diff) { setStackDepth(stackDepth() + diff); }
    273  bool hasKnownStackDepth(uint32_t depth) { return stackDepth() == depth; }
    274 
    275  inline void pop(StackAdjustment adjust = AdjustStack);
    276  inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack);
    277  inline void push(const Value& val) {
    278    StackValue* sv = rawPush();
    279    sv->setConstant(val);
    280  }
    281  inline void push(const ValueOperand& val,
    282                   JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
    283    StackValue* sv = rawPush();
    284    sv->setRegister(val, knownType);
    285  }
    286  inline void pushLocal(uint32_t local) {
    287    MOZ_ASSERT(local < nlocals());
    288    StackValue* sv = rawPush();
    289    sv->setLocalSlot(local);
    290  }
    291  inline void pushArg(uint32_t arg) {
    292    StackValue* sv = rawPush();
    293    sv->setArgSlot(arg);
    294  }
    295  inline void pushThis() {
    296    StackValue* sv = rawPush();
    297    sv->setThis();
    298  }
    299 
    300  inline void pushScratchValue() {
    301    masm.pushValue(addressOfScratchValue());
    302    StackValue* sv = rawPush();
    303    sv->setStack();
    304  }
    305 
    306  Address addressOfLocal(size_t local) const {
    307    MOZ_ASSERT(local < nlocals());
    308    return FrameInfo::addressOfLocal(local);
    309  }
    310  Address addressOfArg(size_t arg) const {
    311    MOZ_ASSERT(arg < nargs());
    312    return FrameInfo::addressOfArg(arg);
    313  }
    314 
    315  Address addressOfStackValue(int32_t depth) const {
    316    const StackValue* value = peek(depth);
    317    MOZ_ASSERT(value->kind() == StackValue::Stack);
    318    size_t slot = value - &stack[0];
    319    MOZ_ASSERT(slot < stackDepth());
    320    return Address(FramePointer,
    321                   BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
    322  }
    323 
    324  void popValue(ValueOperand dest);
    325 
    326  void sync(StackValue* val);
    327  void syncStack(uint32_t uses);
    328  uint32_t numUnsyncedSlots();
    329  void popRegsAndSync(uint32_t uses);
    330 
    331  void assertSyncedStack() const {
    332    MOZ_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
    333  }
    334 
    335  bool stackValueHasKnownType(int32_t depth, JSValueType type) const {
    336    return peek(depth)->hasKnownType(type);
    337  }
    338 
    339  mozilla::Maybe<Value> knownStackValue(int32_t depth) const {
    340    StackValue* val = peek(depth);
    341    if (val->kind() == StackValue::Constant) {
    342      return mozilla::Some(val->constant());
    343    }
    344    return mozilla::Nothing();
    345  }
    346 
    347  void storeStackValue(int32_t depth, const Address& dest,
    348                       const ValueOperand& scratch);
    349 
    350  uint32_t frameSize() const {
    351    return BaselineFrame::frameSizeForNumValueSlots(nlocals() + stackDepth());
    352  }
    353 
    354 #ifdef DEBUG
    355  // Assert the state is valid before excuting "pc".
    356  void assertValidState(const BytecodeInfo& info);
    357 #else
    358  inline void assertValidState(const BytecodeInfo& info) {}
    359 #endif
    360 };
    361 
    362 class InterpreterFrameInfo : public FrameInfo {
    363 public:
    364  explicit InterpreterFrameInfo(MacroAssembler& masm) : FrameInfo(masm) {}
    365 
    366  // These methods are no-ops in the interpreter, because we don't have a
    367  // virtual stack there.
    368  void syncStack(uint32_t uses) {}
    369  void assertSyncedStack() const {}
    370  void assertStackDepth(uint32_t depth) {}
    371  void incStackDepth(int32_t diff) {}
    372  bool hasKnownStackDepth(uint32_t depth) { return false; }
    373  uint32_t numUnsyncedSlots() { return 0; }
    374 
    375  bool stackValueHasKnownType(int32_t depth, JSValueType type) const {
    376    return false;
    377  }
    378 
    379  mozilla::Maybe<Value> knownStackValue(int32_t depth) const {
    380    return mozilla::Nothing();
    381  }
    382 
    383  Address addressOfStackValue(int depth) const {
    384    MOZ_ASSERT(depth < 0);
    385    return Address(masm.getStackPointer(),
    386                   masm.framePushed() + size_t(-(depth + 1)) * sizeof(Value));
    387  }
    388 
    389  BaseIndex addressOfStackValue(Register index, int32_t offset = 0) const {
    390    return BaseIndex(masm.getStackPointer(), index, ValueScale, offset);
    391  }
    392 
    393  void popRegsAndSync(uint32_t uses);
    394 
    395  inline void pop();
    396 
    397  inline void popn(uint32_t n);
    398 
    399  void popn(Register reg) {
    400    // sp := sp + reg * sizeof(Value)
    401    Register spReg = AsRegister(masm.getStackPointer());
    402    masm.computeEffectiveAddress(BaseValueIndex(spReg, reg), spReg);
    403    // On arm64, SP may be < PSP now (that's OK).
    404    // eg testcase: tests/arguments/strict-args-generator-flushstack.js
    405  }
    406 
    407  void popValue(ValueOperand dest) { masm.popValue(dest); }
    408 
    409  void push(const ValueOperand& val,
    410            JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
    411    masm.pushValue(val);
    412  }
    413  void push(const Value& val) { masm.pushValue(val); }
    414 
    415  void pushThis() { masm.pushValue(addressOfThis()); }
    416  void pushScratchValue() { masm.pushValue(addressOfScratchValue()); }
    417 
    418  void storeStackValue(int32_t depth, const Address& dest,
    419                       const ValueOperand& scratch) {
    420    masm.loadValue(addressOfStackValue(depth), scratch);
    421    masm.storeValue(scratch, dest);
    422  }
    423 
    424  void bumpInterpreterICEntry();
    425 
    426  Address addressOfInterpreterPC() const {
    427    return Address(FramePointer, BaselineFrame::reverseOffsetOfInterpreterPC());
    428  }
    429  Address addressOfInterpreterICEntry() const {
    430    return Address(FramePointer,
    431                   BaselineFrame::reverseOffsetOfInterpreterICEntry());
    432  }
    433 };
    434 
    435 }  // namespace jit
    436 }  // namespace js
    437 
    438 #endif /* jit_BaselineFrameInfo_h */