tor-browser

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

PropertyInfo.h (7272B)


      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 vm_PropertyInfo_h
      8 #define vm_PropertyInfo_h
      9 
     10 #include "mozilla/Assertions.h"
     11 
     12 #include <limits>
     13 #include <stdint.h>
     14 
     15 #include "jstypes.h"
     16 #include "NamespaceImports.h"
     17 
     18 #include "js/GCVector.h"
     19 #include "js/PropertyDescriptor.h"
     20 #include "util/EnumFlags.h"
     21 
     22 namespace js {
     23 
     24 /* Limit on the number of slotful properties in an object. */
     25 static constexpr uint32_t SHAPE_INVALID_SLOT = Bit(24) - 1;
     26 static constexpr uint32_t SHAPE_MAXIMUM_SLOT = Bit(24) - 2;
     27 
     28 // Flags associated with each property stored in the shape tree.
     29 enum class PropertyFlag : uint8_t {
     30  // Property attributes. See also JS::PropertyAttribute.
     31  Configurable = 1 << 0,
     32  Enumerable = 1 << 1,
     33  Writable = 1 << 2,
     34 
     35  // Whether this is an accessor property. Accessor properties have a slot that
     36  // stores a GetterSetter instance.
     37  AccessorProperty = 1 << 3,
     38 
     39  // If set, this is a custom data property. The property is exposed as a data
     40  // property to JS code and PropertyDescriptor, but instead of an object slot
     41  // it uses custom get/set logic.
     42  //
     43  // This is used to implement the special array.length and ArgumentsObject
     44  // properties.
     45  //
     46  // This flag is deprecated (we don't want to add more uses).
     47  CustomDataProperty = 1 << 4,
     48 };
     49 
     50 class PropertyFlags : public EnumFlags<PropertyFlag> {
     51  using Base = EnumFlags<PropertyFlag>;
     52  using Base::Base;
     53 
     54 public:
     55  static const PropertyFlags defaultDataPropFlags;
     56 
     57  static PropertyFlags fromRaw(uint8_t flags) { return PropertyFlags(flags); }
     58 
     59  bool configurable() const { return hasFlag(PropertyFlag::Configurable); }
     60  bool enumerable() const { return hasFlag(PropertyFlag::Enumerable); }
     61  bool writable() const {
     62    MOZ_ASSERT(isDataDescriptor());
     63    return hasFlag(PropertyFlag::Writable);
     64  }
     65 
     66  // Note: this returns true only for plain data properties with a slot. Returns
     67  // false for custom data properties. See CustomDataProperty flag.
     68  bool isDataProperty() const {
     69    return !isAccessorProperty() && !isCustomDataProperty();
     70  }
     71  bool isAccessorProperty() const {
     72    return hasFlag(PropertyFlag::AccessorProperty);
     73  }
     74  bool isCustomDataProperty() const {
     75    return hasFlag(PropertyFlag::CustomDataProperty);
     76  }
     77 
     78  // Note: unlike isDataProperty, this returns true also for custom data
     79  // properties.
     80  bool isDataDescriptor() const { return !isAccessorProperty(); }
     81 };
     82 
     83 constexpr PropertyFlags PropertyFlags::defaultDataPropFlags = {
     84    PropertyFlag::Configurable, PropertyFlag::Enumerable,
     85    PropertyFlag::Writable};
     86 
     87 // PropertyInfo contains information (PropertyFlags, slot number) for a
     88 // property stored in the Shape tree. Property lookups on NativeObjects return a
     89 // PropertyInfo.
     90 //
     91 // There's also a CompactPropertyInfo type that's used by CompactPropMap to
     92 // store small slot numbers (CompactPropertyInfo is two bytes instead of four).
     93 template <typename T>
     94 class PropertyInfoBase {
     95  static_assert(std::is_same_v<T, uint32_t> || std::is_same_v<T, uint16_t>);
     96 
     97  static constexpr uint32_t FlagsMask = 0xff;
     98  static constexpr uint32_t SlotShift = 8;
     99 
    100  T slotAndFlags_ = 0;
    101 
    102  static_assert(SHAPE_INVALID_SLOT <= (UINT32_MAX >> SlotShift),
    103                "SHAPE_INVALID_SLOT must fit in slotAndFlags_");
    104  static_assert(SHAPE_MAXIMUM_SLOT <= (UINT32_MAX >> SlotShift),
    105                "SHAPE_MAXIMUM_SLOT must fit in slotAndFlags_");
    106 
    107  // Constructor is private, code should prefer Maybe<PropertyInfo>. This
    108  // constructor is only used for the propInfos array in property maps
    109  // (CompactPropMap and LinkedPropMap are friend classes for this reason).
    110  PropertyInfoBase() = default;
    111 
    112  template <typename U>
    113  friend class PropertyInfoBase;
    114  friend class CompactPropMap;
    115  friend class LinkedPropMap;
    116 
    117 public:
    118  static constexpr size_t MaxSlotNumber =
    119      std::numeric_limits<T>::max() >> SlotShift;
    120 
    121  PropertyInfoBase(PropertyFlags flags, uint32_t slot)
    122      : slotAndFlags_((slot << SlotShift) | flags.toRaw()) {
    123    MOZ_ASSERT(maybeSlot() == slot);
    124    MOZ_ASSERT(this->flags() == flags);
    125  }
    126 
    127  template <typename U>
    128  explicit PropertyInfoBase(PropertyInfoBase<U> other)
    129      : slotAndFlags_(other.slotAndFlags_) {
    130    // Assert assigning PropertyInfo to CompactPropertyInfo doesn't lose
    131    // information.
    132    MOZ_ASSERT(slotAndFlags_ == other.slotAndFlags_);
    133  }
    134 
    135  bool isDataProperty() const { return flags().isDataProperty(); }
    136  bool isCustomDataProperty() const { return flags().isCustomDataProperty(); }
    137  bool isAccessorProperty() const { return flags().isAccessorProperty(); }
    138  bool isDataDescriptor() const { return flags().isDataDescriptor(); }
    139 
    140  bool hasSlot() const { return !isCustomDataProperty(); }
    141 
    142  uint32_t slot() const {
    143    MOZ_ASSERT(hasSlot());
    144    MOZ_ASSERT(maybeSlot() < SHAPE_INVALID_SLOT);
    145    return maybeSlot();
    146  }
    147 
    148  uint32_t maybeSlot() const { return slotAndFlags_ >> SlotShift; }
    149 
    150  PropertyFlags flags() const {
    151    return PropertyFlags::fromRaw(slotAndFlags_ & FlagsMask);
    152  }
    153  bool writable() const { return flags().writable(); }
    154  bool configurable() const { return flags().configurable(); }
    155  bool enumerable() const { return flags().enumerable(); }
    156 
    157  JS::PropertyAttributes propAttributes() const {
    158    JS::PropertyAttributes attrs{};
    159    if (configurable()) {
    160      attrs += JS::PropertyAttribute::Configurable;
    161    }
    162    if (enumerable()) {
    163      attrs += JS::PropertyAttribute::Enumerable;
    164    }
    165    if (isDataDescriptor() && writable()) {
    166      attrs += JS::PropertyAttribute::Writable;
    167    }
    168    return attrs;
    169  }
    170 
    171  T toRaw() const { return slotAndFlags_; }
    172 
    173  bool operator==(const PropertyInfoBase<T>& other) const {
    174    return slotAndFlags_ == other.slotAndFlags_;
    175  }
    176  bool operator!=(const PropertyInfoBase<T>& other) const {
    177    return !operator==(other);
    178  }
    179 };
    180 
    181 using PropertyInfo = PropertyInfoBase<uint32_t>;
    182 using CompactPropertyInfo = PropertyInfoBase<uint16_t>;
    183 
    184 static_assert(sizeof(PropertyInfo) == sizeof(uint32_t));
    185 static_assert(sizeof(CompactPropertyInfo) == sizeof(uint16_t));
    186 
    187 class PropertyInfoWithKey : public PropertyInfo {
    188  PropertyKey key_;
    189 
    190 public:
    191  PropertyInfoWithKey(PropertyFlags flags, uint32_t slot, PropertyKey key)
    192      : PropertyInfo(flags, slot), key_(key) {}
    193 
    194  PropertyInfoWithKey(PropertyInfo prop, PropertyKey key)
    195      : PropertyInfo(prop), key_(key) {}
    196 
    197  PropertyKey key() const { return key_; }
    198 
    199  void trace(JSTracer* trc) {
    200    TraceRoot(trc, &key_, "PropertyInfoWithKey-key");
    201  }
    202 };
    203 
    204 template <class Wrapper>
    205 class WrappedPtrOperations<PropertyInfoWithKey, Wrapper> {
    206  const PropertyInfoWithKey& value() const {
    207    return static_cast<const Wrapper*>(this)->get();
    208  }
    209 
    210 public:
    211  bool isDataProperty() const { return value().isDataProperty(); }
    212  uint32_t slot() const { return value().slot(); }
    213  PropertyKey key() const { return value().key(); }
    214  PropertyFlags flags() const { return value().flags(); }
    215 };
    216 
    217 using PropertyInfoWithKeyVector = GCVector<PropertyInfoWithKey, 16>;
    218 
    219 }  // namespace js
    220 
    221 #endif /* vm_PropertyInfo_h */