Bug 1842773 - Part 32: Allow constructing growable SharedArrayBuffers. r=sfink
[gecko.git] / js / src / vm / PropertyInfo.h
blob497c2a242aae45131dea29f8a237c8cdb8dbc462
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/. */
7 #ifndef vm_PropertyInfo_h
8 #define vm_PropertyInfo_h
10 #include "mozilla/Assertions.h"
12 #include <limits>
13 #include <stdint.h>
15 #include "jstypes.h"
16 #include "NamespaceImports.h"
18 #include "js/GCVector.h"
19 #include "js/PropertyDescriptor.h"
20 #include "util/EnumFlags.h"
22 namespace js {
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;
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,
35 // Whether this is an accessor property. Accessor properties have a slot that
36 // stores a GetterSetter instance.
37 AccessorProperty = 1 << 3,
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.
43 // This is used to implement the special array.length and ArgumentsObject
44 // properties.
46 // This flag is deprecated (we don't want to add more uses).
47 CustomDataProperty = 1 << 4,
50 class PropertyFlags : public EnumFlags<PropertyFlag> {
51 using Base = EnumFlags<PropertyFlag>;
52 using Base::Base;
54 public:
55 static const PropertyFlags defaultDataPropFlags;
57 static PropertyFlags fromRaw(uint8_t flags) { return PropertyFlags(flags); }
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);
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();
71 bool isAccessorProperty() const {
72 return hasFlag(PropertyFlag::AccessorProperty);
74 bool isCustomDataProperty() const {
75 return hasFlag(PropertyFlag::CustomDataProperty);
78 // Note: unlike isDataProperty, this returns true also for custom data
79 // properties.
80 bool isDataDescriptor() const { return !isAccessorProperty(); }
83 constexpr PropertyFlags PropertyFlags::defaultDataPropFlags = {
84 PropertyFlag::Configurable, PropertyFlag::Enumerable,
85 PropertyFlag::Writable};
87 // PropertyInfo contains information (PropertyFlags, slot number) for a
88 // property stored in the Shape tree. Property lookups on NativeObjects return a
89 // PropertyInfo.
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>);
97 static constexpr uint32_t FlagsMask = 0xff;
98 static constexpr uint32_t SlotShift = 8;
100 T slotAndFlags_ = 0;
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_");
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;
112 template <typename U>
113 friend class PropertyInfoBase;
114 friend class CompactPropMap;
115 friend class LinkedPropMap;
117 public:
118 static constexpr size_t MaxSlotNumber =
119 std::numeric_limits<T>::max() >> SlotShift;
121 PropertyInfoBase(PropertyFlags flags, uint32_t slot)
122 : slotAndFlags_((slot << SlotShift) | flags.toRaw()) {
123 MOZ_ASSERT(maybeSlot() == slot);
124 MOZ_ASSERT(this->flags() == flags);
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_);
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(); }
140 bool hasSlot() const { return !isCustomDataProperty(); }
142 uint32_t slot() const {
143 MOZ_ASSERT(hasSlot());
144 MOZ_ASSERT(maybeSlot() < SHAPE_INVALID_SLOT);
145 return maybeSlot();
148 uint32_t maybeSlot() const { return slotAndFlags_ >> SlotShift; }
150 PropertyFlags flags() const {
151 return PropertyFlags::fromRaw(slotAndFlags_ & FlagsMask);
153 bool writable() const { return flags().writable(); }
154 bool configurable() const { return flags().configurable(); }
155 bool enumerable() const { return flags().enumerable(); }
157 JS::PropertyAttributes propAttributes() const {
158 JS::PropertyAttributes attrs{};
159 if (configurable()) {
160 attrs += JS::PropertyAttribute::Configurable;
162 if (enumerable()) {
163 attrs += JS::PropertyAttribute::Enumerable;
165 if (isDataDescriptor() && writable()) {
166 attrs += JS::PropertyAttribute::Writable;
168 return attrs;
171 T toRaw() const { return slotAndFlags_; }
173 bool operator==(const PropertyInfoBase<T>& other) const {
174 return slotAndFlags_ == other.slotAndFlags_;
176 bool operator!=(const PropertyInfoBase<T>& other) const {
177 return !operator==(other);
181 using PropertyInfo = PropertyInfoBase<uint32_t>;
182 using CompactPropertyInfo = PropertyInfoBase<uint16_t>;
184 static_assert(sizeof(PropertyInfo) == sizeof(uint32_t));
185 static_assert(sizeof(CompactPropertyInfo) == sizeof(uint16_t));
187 class PropertyInfoWithKey : public PropertyInfo {
188 PropertyKey key_;
190 public:
191 PropertyInfoWithKey(PropertyFlags flags, uint32_t slot, PropertyKey key)
192 : PropertyInfo(flags, slot), key_(key) {}
194 PropertyInfoWithKey(PropertyInfo prop, PropertyKey key)
195 : PropertyInfo(prop), key_(key) {}
197 PropertyKey key() const { return key_; }
199 void trace(JSTracer* trc) {
200 TraceRoot(trc, &key_, "PropertyInfoWithKey-key");
204 template <class Wrapper>
205 class WrappedPtrOperations<PropertyInfoWithKey, Wrapper> {
206 const PropertyInfoWithKey& value() const {
207 return static_cast<const Wrapper*>(this)->get();
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(); }
217 using PropertyInfoWithKeyVector = GCVector<PropertyInfoWithKey, 16>;
219 } // namespace js
221 #endif /* vm_PropertyInfo_h */