Bug 739380 - Define an ElementsHeader base class for all element subtypes, and define meaningful subclasses through which to use an ElementsHeader. r=bhackett
authorJeff Walden <jwalden@mit.edu>
Wed, 21 Mar 2012 13:32:55 -0700
changeset 90862 c7ce0c86d5e86497deae66b8824dd51d2d6bbecd
parent 90861 029a32f787e928b8b415992231c5a5291d24b54b
child 90863 e86e048872d6f2bf2f8cd34124c90d9f9336e572
push idunknown
push userunknown
push dateunknown
reviewersbhackett
bugs739380
milestone14.0a1
Bug 739380 - Define an ElementsHeader base class for all element subtypes, and define meaningful subclasses through which to use an ElementsHeader. r=bhackett
js/src/jsversion.h
js/src/vm/ObjectImpl.h
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -189,8 +189,18 @@
 /* Feature-test macro for evolving destructuring support. */
 #define JS_HAS_DESTRUCTURING_SHORTHAND  (JS_HAS_DESTRUCTURING == 2)
 
 /*
  * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support;
  * support likely to be made opt-in at some future time.
  */
 #define OLD_GETTER_SETTER_METHODS       1
+
+/* A kill-switch for bug 586842.  Embedders shouldn't touch this! */
+#define USE_NEW_OBJECT_REPRESENTATION 0
+
+#if USE_NEW_OBJECT_REPRESENTATION
+#  define NEW_OBJECT_REPRESENTATION_ONLY() ((void)0)
+#else
+#  define NEW_OBJECT_REPRESENTATION_ONLY() \
+     MOZ_NOT_REACHED("don't call this!  to be used in the new object representation")
+#endif
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -16,16 +16,279 @@
 #include "jsval.h"
 
 #include "gc/Barrier.h"
 
 namespace js {
 
 class ObjectImpl;
 
+class DenseElementsHeader;
+class SparseElementsHeader;
+class Uint8ElementsHeader;
+class Int8ElementsHeader;
+class Uint16ElementsHeader;
+class Int16ElementsHeader;
+class Uint32ElementsHeader;
+class Int32ElementsHeader;
+class Uint8ClampedElementsHeader;
+class Float32ElementsHeader;
+class Float64ElementsHeader;
+class ArrayBufferElementsHeader;
+
+enum ElementsKind {
+    DenseElements,
+    SparseElements,
+    Uint8Elements,
+    Int8Elements,
+    Uint16Elements,
+    Int16Elements,
+    Uint32Elements,
+    Int32Elements,
+    Uint8ClampedElements,
+    Float32Elements,
+    Float64Elements,
+    ArrayBufferElements
+};
+
+class ElementsHeader
+{
+  protected:
+    uint32_t type;
+    uint32_t length; /* Array length, byte length of ArrayBuffer */
+
+    union {
+        class {
+            friend class DenseElementsHeader;
+            uint32_t initializedLength;
+            uint32_t capacity;
+        } dense;
+        class {
+            friend class SparseElementsHeader;
+            Shape * shape;
+        } sparse;
+    };
+
+    void staticAsserts() {
+        MOZ_STATIC_ASSERT(sizeof(ElementsHeader) == ValuesPerHeader * sizeof(Value),
+                          "Elements size and values-per-Elements mismatch");
+    }
+
+  public:
+    ElementsKind kind() const {
+        MOZ_ASSERT(type <= ArrayBufferElements);
+        return ElementsKind(type);
+    }
+
+    inline bool isDenseElements() const { return kind() == DenseElements; }
+    inline bool isSparseElements() const { return kind() == SparseElements; }
+    inline bool isUint8Elements() const { return kind() == Uint8Elements; }
+    inline bool isInt8Elements() const { return kind() == Int8Elements; }
+    inline bool isUint16Elements() const { return kind() == Uint16Elements; }
+    inline bool isInt16Elements() const { return kind() == Int16Elements; }
+    inline bool isUint32Elements() const { return kind() == Uint32Elements; }
+    inline bool isInt32Elements() const { return kind() == Int32Elements; }
+    inline bool isUint8ClampedElements() const { return kind() == Uint8ClampedElements; }
+    inline bool isFloat32Elements() const { return kind() == Float32Elements; }
+    inline bool isFloat64Elements() const { return kind() == Float64Elements; }
+    inline bool isArrayBufferElements() const { return kind() == ArrayBufferElements; }
+
+    inline DenseElementsHeader & asDenseElements();
+    inline SparseElementsHeader & asSparseElements();
+    inline Uint8ElementsHeader & asUint8Elements();
+    inline Int8ElementsHeader & asInt8Elements();
+    inline Uint16ElementsHeader & asUint16Elements();
+    inline Int16ElementsHeader & asInt16Elements();
+    inline Uint32ElementsHeader & asUint32Elements();
+    inline Int32ElementsHeader & asInt32Elements();
+    inline Uint8ClampedElementsHeader & asUint8ClampedElements();
+    inline Float32ElementsHeader & asFloat32Elements();
+    inline Float64ElementsHeader & asFloat64Elements();
+    inline ArrayBufferElementsHeader & asArrayBufferElements();
+
+    static ElementsHeader * fromElements(HeapSlot *elems) {
+        return reinterpret_cast<ElementsHeader *>(uintptr_t(elems) - sizeof(ElementsHeader));
+    }
+
+    static const size_t ValuesPerHeader = 2;
+};
+
+class DenseElementsHeader : public ElementsHeader
+{
+  public:
+    uint32_t capacity() const {
+        MOZ_ASSERT(ElementsHeader::isDenseElements());
+        return dense.capacity;
+    }
+
+    uint32_t initializedLength() const {
+        MOZ_ASSERT(ElementsHeader::isDenseElements());
+        return dense.initializedLength;
+    }
+
+    uint32_t length() const {
+        MOZ_ASSERT(ElementsHeader::isDenseElements());
+        return ElementsHeader::length;
+    }
+
+  private:
+    inline bool isDenseElements() const MOZ_DELETE;
+    inline DenseElementsHeader & asDenseElements() MOZ_DELETE;
+
+    DenseElementsHeader(const DenseElementsHeader &other) MOZ_DELETE;
+    void operator=(const DenseElementsHeader &other) MOZ_DELETE;
+};
+
+class SparseElementsHeader : public ElementsHeader
+{
+  public:
+    Shape * shape() {
+        MOZ_ASSERT(ElementsHeader::isSparseElements());
+        return sparse.shape;
+    }
+
+    uint32_t length() const {
+        MOZ_ASSERT(ElementsHeader::isSparseElements());
+        return ElementsHeader::length;
+    }
+
+  private:
+    inline bool isSparseElements() const MOZ_DELETE;
+    inline SparseElementsHeader & asSparseElements() MOZ_DELETE;
+
+    SparseElementsHeader(const SparseElementsHeader &other) MOZ_DELETE;
+    void operator=(const SparseElementsHeader &other) MOZ_DELETE;
+};
+
+template <typename T>
+class TypedElementsHeader : public ElementsHeader
+{
+  public:
+    uint32_t byteLength() const {
+        return ElementsHeader::length;
+    }
+
+  private:
+    TypedElementsHeader(const TypedElementsHeader &other) MOZ_DELETE;
+    void operator=(const TypedElementsHeader &other) MOZ_DELETE;
+};
+
+class Uint8ElementsHeader : public TypedElementsHeader<uint8_t> { };
+class Int8ElementsHeader : public TypedElementsHeader<int8_t> { };
+class Uint16ElementsHeader : public TypedElementsHeader<uint16_t> { };
+class Int16ElementsHeader : public TypedElementsHeader<int16_t> { };
+class Uint32ElementsHeader : public TypedElementsHeader<uint32_t> { };
+class Int32ElementsHeader : public TypedElementsHeader<int32_t> { };
+class Float32ElementsHeader : public TypedElementsHeader<float> { };
+class Float64ElementsHeader : public TypedElementsHeader<double> { };
+
+class Uint8ClampedElementsHeader : public TypedElementsHeader<uint8_t>
+{
+  private:
+    inline bool isUint8Clamped() const MOZ_DELETE;
+    inline Uint8ClampedElementsHeader & asUint8ClampedElements() MOZ_DELETE;
+
+    Uint8ClampedElementsHeader(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
+    void operator=(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
+};
+
+class ArrayBufferElementsHeader : public ElementsHeader
+{
+  private:
+    inline bool isArrayBufferElements() const MOZ_DELETE;
+    inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE;
+
+    ArrayBufferElementsHeader(const ArrayBufferElementsHeader &other) MOZ_DELETE;
+    void operator=(const ArrayBufferElementsHeader &other) MOZ_DELETE;
+};
+
+inline DenseElementsHeader &
+ElementsHeader::asDenseElements()
+{
+    MOZ_ASSERT(isDenseElements());
+    return *static_cast<DenseElementsHeader *>(this);
+}
+
+inline SparseElementsHeader &
+ElementsHeader::asSparseElements()
+{
+    MOZ_ASSERT(isSparseElements());
+    return *static_cast<SparseElementsHeader *>(this);
+}
+
+inline Uint8ElementsHeader &
+ElementsHeader::asUint8Elements()
+{
+    MOZ_ASSERT(isUint8Elements());
+    return *static_cast<Uint8ElementsHeader *>(this);
+}
+
+inline Int8ElementsHeader &
+ElementsHeader::asInt8Elements()
+{
+    MOZ_ASSERT(isInt8Elements());
+    return *static_cast<Int8ElementsHeader *>(this);
+}
+
+inline Uint16ElementsHeader &
+ElementsHeader::asUint16Elements()
+{
+    MOZ_ASSERT(isUint16Elements());
+    return *static_cast<Uint16ElementsHeader *>(this);
+}
+
+inline Int16ElementsHeader &
+ElementsHeader::asInt16Elements()
+{
+    MOZ_ASSERT(isInt16Elements());
+    return *static_cast<Int16ElementsHeader *>(this);
+}
+
+inline Uint32ElementsHeader &
+ElementsHeader::asUint32Elements()
+{
+    MOZ_ASSERT(isUint32Elements());
+    return *static_cast<Uint32ElementsHeader *>(this);
+}
+
+inline Int32ElementsHeader &
+ElementsHeader::asInt32Elements()
+{
+    MOZ_ASSERT(isInt32Elements());
+    return *static_cast<Int32ElementsHeader *>(this);
+}
+
+inline Uint8ClampedElementsHeader &
+ElementsHeader::asUint8ClampedElements()
+{
+    MOZ_ASSERT(isUint8ClampedElements());
+    return *static_cast<Uint8ClampedElementsHeader *>(this);
+}
+
+inline Float32ElementsHeader &
+ElementsHeader::asFloat32Elements()
+{
+    MOZ_ASSERT(isFloat32Elements());
+    return *static_cast<Float32ElementsHeader *>(this);
+}
+
+inline Float64ElementsHeader &
+ElementsHeader::asFloat64Elements()
+{
+    MOZ_ASSERT(isFloat64Elements());
+    return *static_cast<Float64ElementsHeader *>(this);
+}
+
+inline ArrayBufferElementsHeader &
+ElementsHeader::asArrayBufferElements()
+{
+    MOZ_ASSERT(isArrayBufferElements());
+    return *static_cast<ArrayBufferElementsHeader *>(this);
+}
+
 /*
  * Header structure for object element arrays. This structure is immediately
  * followed by an array of elements, with the elements member in an object
  * pointing to the beginning of that array (the end of this structure).
  * See below for usage of this structure.
  */
 class ObjectElements
 {
@@ -384,16 +647,21 @@ class ObjectImpl : public gc::Cell
     inline size_t sizeOfThis() const;
 
     /* Elements accessors. */
 
     ObjectElements * getElementsHeader() const {
         return ObjectElements::fromElements(elements);
     }
 
+    ElementsHeader & elementsHeader() const {
+        NEW_OBJECT_REPRESENTATION_ONLY();
+        return *ElementsHeader::fromElements(elements);
+    }
+
     inline HeapSlot *fixedElements() const {
         MOZ_STATIC_ASSERT(2 * sizeof(Value) == sizeof(ObjectElements),
                           "when elements are stored inline, the first two "
                           "slots will hold the ObjectElements header");
         return &fixedSlots()[2];
     }
 
     void setFixedElements() { this->elements = fixedElements(); }