tor-browser

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

ColumnNumber.h (13161B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 // [SMDOC] Column numbers
      7 //
      8 // Inside SpiderMonkey, column numbers are represented as 1-origin 32-bit
      9 // unsigned integers. Some parts of the engine use the highest bit of a column
     10 // number as a tag to indicate Wasm frame.
     11 //
     12 // These classes help clarifying the origin of the column number, and also
     13 // figuring out whether the column number uses the wasm's tag or not, and also
     14 // help converting between them.
     15 //
     16 // Also these classes support converting from 0-origin column number.
     17 //
     18 // In a 0-origin context, column 0 is the first character of the line.
     19 // In a 1-origin context, column 1 is the first character of the line,
     20 // for example:
     21 //
     22 //           function foo() { ... }
     23 //           ^              ^
     24 // 0-origin: 0              15
     25 // 1-origin: 1              16
     26 
     27 #ifndef js_ColumnNumber_h
     28 #define js_ColumnNumber_h
     29 
     30 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     31 #include "mozilla/Attributes.h"  // MOZ_IMPLICIT
     32 
     33 #include <limits>    // std::numeric_limits
     34 #include <stdint.h>  // uint32_t
     35 
     36 namespace JS {
     37 
     38 // Wasm function index.
     39 //
     40 // This class is used as parameter or return type of
     41 // TaggedColumnNumberOneOrigin class below.
     42 struct WasmFunctionIndex {
     43  // TaggedColumnNumberOneOrigin uses the highest bit as a tag.
     44  static constexpr uint32_t Limit = std::numeric_limits<int32_t>::max() / 2;
     45 
     46  // For wasm frames, the function index is returned as the column with the
     47  // high bit set. In paths that format error stacks into strings, this
     48  // information can be used to synthesize a proper wasm frame. But when raw
     49  // column numbers are handed out, we just fix them to the first column to
     50  // avoid confusion.
     51  static constexpr uint32_t DefaultBinarySourceColumnNumberOneOrigin = 1;
     52 
     53 private:
     54  uint32_t value_ = 0;
     55 
     56 public:
     57  constexpr WasmFunctionIndex() = default;
     58  constexpr WasmFunctionIndex(const WasmFunctionIndex& other) = default;
     59 
     60  inline explicit WasmFunctionIndex(uint32_t value) : value_(value) {
     61    MOZ_ASSERT(valid());
     62  }
     63 
     64  uint32_t value() const { return value_; }
     65 
     66  bool valid() const { return value_ <= Limit; }
     67 };
     68 
     69 // The offset between 2 column numbers.
     70 struct ColumnNumberOffset {
     71 private:
     72  int32_t value_ = 0;
     73 
     74 public:
     75  constexpr ColumnNumberOffset() = default;
     76  constexpr ColumnNumberOffset(const ColumnNumberOffset& other) = default;
     77 
     78  inline explicit ColumnNumberOffset(int32_t value) : value_(value) {}
     79 
     80  static constexpr ColumnNumberOffset zero() { return ColumnNumberOffset(); }
     81 
     82  bool operator==(const ColumnNumberOffset& rhs) const {
     83    return value_ == rhs.value_;
     84  }
     85 
     86  bool operator!=(const ColumnNumberOffset& rhs) const {
     87    return !(*this == rhs);
     88  }
     89 
     90  int32_t value() const { return value_; }
     91 };
     92 
     93 // The positive offset from certain column number.
     94 struct ColumnNumberUnsignedOffset {
     95 private:
     96  uint32_t value_ = 0;
     97 
     98 public:
     99  constexpr ColumnNumberUnsignedOffset() = default;
    100  constexpr ColumnNumberUnsignedOffset(
    101      const ColumnNumberUnsignedOffset& other) = default;
    102 
    103  inline explicit ColumnNumberUnsignedOffset(uint32_t value) : value_(value) {}
    104 
    105  static constexpr ColumnNumberUnsignedOffset zero() {
    106    return ColumnNumberUnsignedOffset();
    107  }
    108 
    109  ColumnNumberUnsignedOffset operator+(
    110      const ColumnNumberUnsignedOffset& offset) const {
    111    return ColumnNumberUnsignedOffset(value_ + offset.value());
    112  }
    113 
    114  ColumnNumberUnsignedOffset& operator+=(
    115      const ColumnNumberUnsignedOffset& offset) {
    116    value_ += offset.value();
    117    return *this;
    118  }
    119 
    120  bool operator==(const ColumnNumberUnsignedOffset& rhs) const {
    121    return value_ == rhs.value_;
    122  }
    123 
    124  bool operator!=(const ColumnNumberUnsignedOffset& rhs) const {
    125    return !(*this == rhs);
    126  }
    127 
    128  uint32_t value() const { return value_; }
    129 
    130  uint32_t* addressOfValueForTranscode() { return &value_; }
    131 };
    132 
    133 struct TaggedColumnNumberOneOrigin;
    134 
    135 namespace detail {
    136 
    137 // Shared implementation of {,Limited}ColumnNumberOneOrigin classes.
    138 //
    139 // LimitValue being 0 means there's no limit.
    140 template <uint32_t LimitValue = 0>
    141 struct MaybeLimitedColumnNumber {
    142 public:
    143  static constexpr uint32_t OriginValue = 1;
    144 
    145 protected:
    146  uint32_t value_ = OriginValue;
    147 
    148  friend struct ::JS::TaggedColumnNumberOneOrigin;
    149 
    150 public:
    151  constexpr MaybeLimitedColumnNumber() = default;
    152  MaybeLimitedColumnNumber(const MaybeLimitedColumnNumber& other) = default;
    153  MaybeLimitedColumnNumber& operator=(const MaybeLimitedColumnNumber& other) =
    154      default;
    155 
    156  explicit MaybeLimitedColumnNumber(uint32_t value) : value_(value) {
    157    MOZ_ASSERT(valid());
    158  }
    159 
    160  bool operator==(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    161    return value_ == rhs.value_;
    162  }
    163 
    164  bool operator!=(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    165    return !(*this == rhs);
    166  }
    167 
    168  MaybeLimitedColumnNumber<LimitValue> operator+(
    169      const ColumnNumberOffset& offset) const {
    170    MOZ_ASSERT(valid());
    171    MOZ_ASSERT(ptrdiff_t(value_) + offset.value() >= 0);
    172    return MaybeLimitedColumnNumber<LimitValue>(value_ + offset.value());
    173  }
    174 
    175  MaybeLimitedColumnNumber<LimitValue> operator+(
    176      const ColumnNumberUnsignedOffset& offset) const {
    177    MOZ_ASSERT(valid());
    178    MOZ_ASSERT(ptrdiff_t(value_) + offset.value() >= 0);
    179    return MaybeLimitedColumnNumber<LimitValue>(value_ + offset.value());
    180  }
    181 
    182  MaybeLimitedColumnNumber<LimitValue> operator-(
    183      const ColumnNumberOffset& offset) const {
    184    MOZ_ASSERT(valid());
    185    MOZ_ASSERT(ptrdiff_t(value_) - offset.value() >= 0);
    186    return MaybeLimitedColumnNumber<LimitValue>(value_ - offset.value());
    187  }
    188  ColumnNumberOffset operator-(
    189      const MaybeLimitedColumnNumber<LimitValue>& other) const {
    190    MOZ_ASSERT(valid());
    191    return ColumnNumberOffset(int32_t(value_) - int32_t(other.value_));
    192  }
    193 
    194  MaybeLimitedColumnNumber<LimitValue>& operator+=(
    195      const ColumnNumberOffset& offset) {
    196    MOZ_ASSERT(valid());
    197    MOZ_ASSERT(ptrdiff_t(value_) + offset.value() >= 0);
    198    value_ += offset.value();
    199    MOZ_ASSERT(valid());
    200    return *this;
    201  }
    202  MaybeLimitedColumnNumber<LimitValue>& operator-=(
    203      const ColumnNumberOffset& offset) {
    204    MOZ_ASSERT(valid());
    205    MOZ_ASSERT(ptrdiff_t(value_) - offset.value() >= 0);
    206    value_ -= offset.value();
    207    MOZ_ASSERT(valid());
    208    return *this;
    209  }
    210 
    211  bool operator<(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    212    MOZ_ASSERT(valid());
    213    MOZ_ASSERT(rhs.valid());
    214    return value_ < rhs.value_;
    215  }
    216  bool operator<=(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    217    MOZ_ASSERT(valid());
    218    MOZ_ASSERT(rhs.valid());
    219    return value_ <= rhs.value_;
    220  }
    221  bool operator>(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    222    MOZ_ASSERT(valid());
    223    MOZ_ASSERT(rhs.valid());
    224    return value_ > rhs.value_;
    225  }
    226  bool operator>=(const MaybeLimitedColumnNumber<LimitValue>& rhs) const {
    227    MOZ_ASSERT(valid());
    228    MOZ_ASSERT(rhs.valid());
    229    return value_ >= rhs.value_;
    230  }
    231 
    232  uint32_t oneOriginValue() const {
    233    MOZ_ASSERT(valid());
    234 
    235    return value_;
    236  }
    237 
    238  uint32_t* addressOfValueForTranscode() { return &value_; }
    239 
    240  bool valid() const {
    241    if constexpr (LimitValue == 0) {
    242      return true;
    243    }
    244 
    245    MOZ_ASSERT(value_ != 0);
    246 
    247    return value_ <= LimitValue;
    248  }
    249 };
    250 
    251 // See the comment for LimitedColumnNumberOneOrigin below
    252 static constexpr uint32_t ColumnNumberOneOriginLimit =
    253    std::numeric_limits<int32_t>::max() / 2;
    254 
    255 }  // namespace detail
    256 
    257 // Column number in 1-origin with 31-bit limit.
    258 //
    259 // Various parts of the engine requires the column number be represented in
    260 // 31 bits.
    261 //
    262 // See:
    263 //  * TaggedColumnNumberOneOrigin
    264 //  * TokenStreamAnyChars::checkOptions
    265 //  * SourceNotes::isRepresentable
    266 //  * WasmFrameIter::computeLine
    267 struct LimitedColumnNumberOneOrigin : public detail::MaybeLimitedColumnNumber<
    268                                          detail::ColumnNumberOneOriginLimit> {
    269 private:
    270  using Base =
    271      detail::MaybeLimitedColumnNumber<detail::ColumnNumberOneOriginLimit>;
    272 
    273 public:
    274  static constexpr uint32_t Limit = detail::ColumnNumberOneOriginLimit;
    275 
    276  static_assert(uint32_t(Limit + Limit) > Limit,
    277                "Adding Limit should not overflow");
    278 
    279  using Base::Base;
    280 
    281  LimitedColumnNumberOneOrigin() = default;
    282  LimitedColumnNumberOneOrigin(const LimitedColumnNumberOneOrigin& other) =
    283      default;
    284  MOZ_IMPLICIT LimitedColumnNumberOneOrigin(const Base& other) : Base(other) {}
    285 
    286  static LimitedColumnNumberOneOrigin limit() {
    287    return LimitedColumnNumberOneOrigin(Limit);
    288  }
    289 
    290  static LimitedColumnNumberOneOrigin fromUnlimited(uint32_t value) {
    291    if (value > Limit) {
    292      return LimitedColumnNumberOneOrigin(Limit);
    293    }
    294    return LimitedColumnNumberOneOrigin(value);
    295  }
    296  static LimitedColumnNumberOneOrigin fromUnlimited(
    297      const MaybeLimitedColumnNumber<0>& value) {
    298    return fromUnlimited(value.oneOriginValue());
    299  }
    300 
    301  static LimitedColumnNumberOneOrigin fromZeroOrigin(uint32_t value) {
    302    return LimitedColumnNumberOneOrigin(value + 1);
    303  }
    304 };
    305 
    306 // Column number in 1-origin.
    307 struct ColumnNumberOneOrigin : public detail::MaybeLimitedColumnNumber<0> {
    308 private:
    309  using Base = detail::MaybeLimitedColumnNumber<0>;
    310 
    311 public:
    312  using Base::Base;
    313  using Base::operator=;
    314 
    315  ColumnNumberOneOrigin() = default;
    316  ColumnNumberOneOrigin(const ColumnNumberOneOrigin& other) = default;
    317  ColumnNumberOneOrigin& operator=(ColumnNumberOneOrigin&) = default;
    318 
    319  MOZ_IMPLICIT ColumnNumberOneOrigin(const Base& other) : Base(other) {}
    320 
    321  explicit ColumnNumberOneOrigin(const LimitedColumnNumberOneOrigin& other)
    322      : Base(other.oneOriginValue()) {}
    323 
    324  static ColumnNumberOneOrigin fromZeroOrigin(uint32_t value) {
    325    return ColumnNumberOneOrigin(value + 1);
    326  }
    327 };
    328 
    329 // Either LimitedColumnNumberOneOrigin, or WasmFunctionIndex.
    330 //
    331 // In order to pass the Wasm frame's (url, bytecode-offset, func-index) tuple
    332 // through the existing (url, line, column) tuple, it tags the highest bit of
    333 // the column to indicate "this is a wasm frame".
    334 //
    335 // When knowing clients see this bit, they shall render the tuple
    336 // (url, line, column|bit) as "url:wasm-function[column]:0xline" according
    337 // to the WebAssembly Web API's Developer-Facing Display Conventions.
    338 //   https://webassembly.github.io/spec/web-api/index.html#conventions
    339 // The wasm bytecode offset continues to be passed as the JS line to avoid
    340 // breaking existing devtools code written when this used to be the case.
    341 //
    342 // 0b0YYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY LimitedColumnNumberOneOrigin
    343 // 0b1YYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY WasmFunctionIndex
    344 //
    345 // The tagged colum number shouldn't escape the JS engine except for the
    346 // following places:
    347 //   * SavedFrame API which can directly access WASM frame's info
    348 //   * ubi::Node API which can also directly access WASM frame's info
    349 struct TaggedColumnNumberOneOrigin {
    350  static constexpr uint32_t WasmFunctionTag = 1u << 31;
    351 
    352  static_assert((WasmFunctionIndex::Limit & WasmFunctionTag) == 0);
    353  static_assert((LimitedColumnNumberOneOrigin::Limit & WasmFunctionTag) == 0);
    354 
    355 protected:
    356  uint32_t value_ = LimitedColumnNumberOneOrigin::OriginValue;
    357 
    358  explicit TaggedColumnNumberOneOrigin(uint32_t value) : value_(value) {}
    359 
    360 public:
    361  constexpr TaggedColumnNumberOneOrigin() = default;
    362  TaggedColumnNumberOneOrigin(const TaggedColumnNumberOneOrigin& other) =
    363      default;
    364 
    365  explicit TaggedColumnNumberOneOrigin(
    366      const LimitedColumnNumberOneOrigin& other)
    367      : value_(other.value_) {
    368    MOZ_ASSERT(isLimitedColumnNumber());
    369  }
    370  explicit TaggedColumnNumberOneOrigin(const WasmFunctionIndex& other)
    371      : value_(other.value() | WasmFunctionTag) {
    372    MOZ_ASSERT(isWasmFunctionIndex());
    373  }
    374 
    375  static TaggedColumnNumberOneOrigin fromRaw(uint32_t value) {
    376    return TaggedColumnNumberOneOrigin(value);
    377  }
    378 
    379  static TaggedColumnNumberOneOrigin forDifferentialTesting() {
    380    return TaggedColumnNumberOneOrigin(LimitedColumnNumberOneOrigin());
    381  }
    382 
    383  bool operator==(const TaggedColumnNumberOneOrigin& rhs) const {
    384    return value_ == rhs.value_;
    385  }
    386 
    387  bool operator!=(const TaggedColumnNumberOneOrigin& rhs) const {
    388    return !(*this == rhs);
    389  }
    390 
    391  bool isLimitedColumnNumber() const { return !isWasmFunctionIndex(); }
    392 
    393  bool isWasmFunctionIndex() const { return !!(value_ & WasmFunctionTag); }
    394 
    395  LimitedColumnNumberOneOrigin toLimitedColumnNumber() const {
    396    MOZ_ASSERT(isLimitedColumnNumber());
    397    return LimitedColumnNumberOneOrigin(value_);
    398  }
    399 
    400  WasmFunctionIndex toWasmFunctionIndex() const {
    401    MOZ_ASSERT(isWasmFunctionIndex());
    402    return WasmFunctionIndex(value_ & ~WasmFunctionTag);
    403  }
    404 
    405  uint32_t oneOriginValue() const {
    406    return isWasmFunctionIndex()
    407               ? WasmFunctionIndex::DefaultBinarySourceColumnNumberOneOrigin
    408               : toLimitedColumnNumber().oneOriginValue();
    409  }
    410 
    411  uint32_t rawValue() const { return value_; }
    412 
    413  uint32_t* addressOfValueForTranscode() { return &value_; }
    414 };
    415 
    416 }  // namespace JS
    417 
    418 #endif /* js_ColumnNumber_h */