summaryrefslogtreecommitdiffstats
path: root/js/src/vm/PropertyInfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/PropertyInfo.h')
-rw-r--r--js/src/vm/PropertyInfo.h221
1 files changed, 221 insertions, 0 deletions
diff --git a/js/src/vm/PropertyInfo.h b/js/src/vm/PropertyInfo.h
new file mode 100644
index 0000000000..2b41c3693c
--- /dev/null
+++ b/js/src/vm/PropertyInfo.h
@@ -0,0 +1,221 @@
+/* -*- 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 vm_PropertyInfo_h
+#define vm_PropertyInfo_h
+
+#include "mozilla/Assertions.h"
+
+#include <limits>
+#include <stdint.h>
+
+#include "jstypes.h"
+#include "NamespaceImports.h"
+
+#include "js/GCVector.h"
+#include "js/PropertyDescriptor.h"
+#include "util/EnumFlags.h"
+
+namespace js {
+
+/* Limit on the number of slotful properties in an object. */
+static constexpr uint32_t SHAPE_INVALID_SLOT = Bit(24) - 1;
+static constexpr uint32_t SHAPE_MAXIMUM_SLOT = Bit(24) - 2;
+
+// Flags associated with each property stored in the shape tree.
+enum class PropertyFlag : uint8_t {
+ // Property attributes. See also JS::PropertyAttribute.
+ Configurable = 1 << 0,
+ Enumerable = 1 << 1,
+ Writable = 1 << 2,
+
+ // Whether this is an accessor property. Accessor properties have a slot that
+ // stores a GetterSetter instance.
+ AccessorProperty = 1 << 3,
+
+ // If set, this is a custom data property. The property is exposed as a data
+ // property to JS code and PropertyDescriptor, but instead of an object slot
+ // it uses custom get/set logic.
+ //
+ // This is used to implement the special array.length and ArgumentsObject
+ // properties.
+ //
+ // This flag is deprecated (we don't want to add more uses).
+ CustomDataProperty = 1 << 4,
+};
+
+class PropertyFlags : public EnumFlags<PropertyFlag> {
+ using Base = EnumFlags<PropertyFlag>;
+ using Base::Base;
+
+ public:
+ static const PropertyFlags defaultDataPropFlags;
+
+ static PropertyFlags fromRaw(uint8_t flags) { return PropertyFlags(flags); }
+
+ bool configurable() const { return hasFlag(PropertyFlag::Configurable); }
+ bool enumerable() const { return hasFlag(PropertyFlag::Enumerable); }
+ bool writable() const {
+ MOZ_ASSERT(isDataDescriptor());
+ return hasFlag(PropertyFlag::Writable);
+ }
+
+ // Note: this returns true only for plain data properties with a slot. Returns
+ // false for custom data properties. See CustomDataProperty flag.
+ bool isDataProperty() const {
+ return !isAccessorProperty() && !isCustomDataProperty();
+ }
+ bool isAccessorProperty() const {
+ return hasFlag(PropertyFlag::AccessorProperty);
+ }
+ bool isCustomDataProperty() const {
+ return hasFlag(PropertyFlag::CustomDataProperty);
+ }
+
+ // Note: unlike isDataProperty, this returns true also for custom data
+ // properties.
+ bool isDataDescriptor() const { return !isAccessorProperty(); }
+};
+
+constexpr PropertyFlags PropertyFlags::defaultDataPropFlags = {
+ PropertyFlag::Configurable, PropertyFlag::Enumerable,
+ PropertyFlag::Writable};
+
+// PropertyInfo contains information (PropertyFlags, slot number) for a
+// property stored in the Shape tree. Property lookups on NativeObjects return a
+// PropertyInfo.
+//
+// There's also a CompactPropertyInfo type that's used by CompactPropMap to
+// store small slot numbers (CompactPropertyInfo is two bytes instead of four).
+template <typename T>
+class PropertyInfoBase {
+ static_assert(std::is_same_v<T, uint32_t> || std::is_same_v<T, uint16_t>);
+
+ static constexpr uint32_t FlagsMask = 0xff;
+ static constexpr uint32_t SlotShift = 8;
+
+ T slotAndFlags_ = 0;
+
+ static_assert(SHAPE_INVALID_SLOT <= (UINT32_MAX >> SlotShift),
+ "SHAPE_INVALID_SLOT must fit in slotAndFlags_");
+ static_assert(SHAPE_MAXIMUM_SLOT <= (UINT32_MAX >> SlotShift),
+ "SHAPE_MAXIMUM_SLOT must fit in slotAndFlags_");
+
+ // Constructor is private, code should prefer Maybe<PropertyInfo>. This
+ // constructor is only used for the propInfos array in property maps
+ // (CompactPropMap and LinkedPropMap are friend classes for this reason).
+ PropertyInfoBase() = default;
+
+ template <typename U>
+ friend class PropertyInfoBase;
+ friend class CompactPropMap;
+ friend class LinkedPropMap;
+
+ public:
+ static constexpr size_t MaxSlotNumber =
+ std::numeric_limits<T>::max() >> SlotShift;
+
+ PropertyInfoBase(PropertyFlags flags, uint32_t slot)
+ : slotAndFlags_((slot << SlotShift) | flags.toRaw()) {
+ MOZ_ASSERT(maybeSlot() == slot);
+ MOZ_ASSERT(this->flags() == flags);
+ }
+
+ template <typename U>
+ explicit PropertyInfoBase(PropertyInfoBase<U> other)
+ : slotAndFlags_(other.slotAndFlags_) {
+ // Assert assigning PropertyInfo to CompactPropertyInfo doesn't lose
+ // information.
+ MOZ_ASSERT(slotAndFlags_ == other.slotAndFlags_);
+ }
+
+ bool isDataProperty() const { return flags().isDataProperty(); }
+ bool isCustomDataProperty() const { return flags().isCustomDataProperty(); }
+ bool isAccessorProperty() const { return flags().isAccessorProperty(); }
+ bool isDataDescriptor() const { return flags().isDataDescriptor(); }
+
+ bool hasSlot() const { return !isCustomDataProperty(); }
+
+ uint32_t slot() const {
+ MOZ_ASSERT(hasSlot());
+ MOZ_ASSERT(maybeSlot() < SHAPE_INVALID_SLOT);
+ return maybeSlot();
+ }
+
+ uint32_t maybeSlot() const { return slotAndFlags_ >> SlotShift; }
+
+ PropertyFlags flags() const {
+ return PropertyFlags::fromRaw(slotAndFlags_ & FlagsMask);
+ }
+ bool writable() const { return flags().writable(); }
+ bool configurable() const { return flags().configurable(); }
+ bool enumerable() const { return flags().enumerable(); }
+
+ JS::PropertyAttributes propAttributes() const {
+ JS::PropertyAttributes attrs{};
+ if (configurable()) {
+ attrs += JS::PropertyAttribute::Configurable;
+ }
+ if (enumerable()) {
+ attrs += JS::PropertyAttribute::Enumerable;
+ }
+ if (isDataDescriptor() && writable()) {
+ attrs += JS::PropertyAttribute::Writable;
+ }
+ return attrs;
+ }
+
+ T toRaw() const { return slotAndFlags_; }
+
+ bool operator==(const PropertyInfoBase<T>& other) const {
+ return slotAndFlags_ == other.slotAndFlags_;
+ }
+ bool operator!=(const PropertyInfoBase<T>& other) const {
+ return !operator==(other);
+ }
+};
+
+using PropertyInfo = PropertyInfoBase<uint32_t>;
+using CompactPropertyInfo = PropertyInfoBase<uint16_t>;
+
+static_assert(sizeof(PropertyInfo) == sizeof(uint32_t));
+static_assert(sizeof(CompactPropertyInfo) == sizeof(uint16_t));
+
+class PropertyInfoWithKey : public PropertyInfo {
+ PropertyKey key_;
+
+ public:
+ PropertyInfoWithKey(PropertyFlags flags, uint32_t slot, PropertyKey key)
+ : PropertyInfo(flags, slot), key_(key) {}
+
+ PropertyInfoWithKey(PropertyInfo prop, PropertyKey key)
+ : PropertyInfo(prop), key_(key) {}
+
+ PropertyKey key() const { return key_; }
+
+ void trace(JSTracer* trc) {
+ TraceRoot(trc, &key_, "PropertyInfoWithKey-key");
+ }
+};
+
+template <class Wrapper>
+class WrappedPtrOperations<PropertyInfoWithKey, Wrapper> {
+ const PropertyInfoWithKey& value() const {
+ return static_cast<const Wrapper*>(this)->get();
+ }
+
+ public:
+ bool isDataProperty() const { return value().isDataProperty(); }
+ uint32_t slot() const { return value().slot(); }
+ PropertyKey key() const { return value().key(); }
+ PropertyFlags flags() const { return value().flags(); }
+};
+
+using PropertyInfoWithKeyVector = GCVector<PropertyInfoWithKey, 8>;
+
+} // namespace js
+
+#endif /* vm_PropertyInfo_h */