Files
tubestation/js/src/vm/ObjectImpl.h

320 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* 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 ObjectImpl_h___
#define ObjectImpl_h___
#include "mozilla/Assertions.h"
#include "mozilla/StandardInteger.h"
#include "jsfriendapi.h"
#include "jsinfer.h"
#include "jsval.h"
#include "gc/Barrier.h"
namespace js {
/*
* 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
{
friend struct ::JSObject;
/* Number of allocated slots. */
uint32_t capacity;
/*
* Number of initialized elements. This is <= the capacity, and for arrays
* is <= the length. Memory for elements above the initialized length is
* uninitialized, but values between the initialized length and the proper
* length are conceptually holes.
*/
uint32_t initializedLength;
/* 'length' property of array objects, unused for other objects. */
uint32_t length;
/* :XXX: bug 586842 store state about sparse slots. */
uint32_t unused;
void staticAsserts() {
MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
"Elements size and values-per-Elements mismatch");
}
public:
ObjectElements(uint32_t capacity, uint32_t length)
: capacity(capacity), initializedLength(0), length(length)
{}
HeapSlot *elements() { return (HeapSlot *)(uintptr_t(this) + sizeof(ObjectElements)); }
static ObjectElements * fromElements(HeapSlot *elems) {
return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements));
}
static int offsetOfCapacity() {
return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements);
}
static int offsetOfInitializedLength() {
return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements);
}
static int offsetOfLength() {
return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements);
}
static const size_t VALUES_PER_HEADER = 2;
};
/* Shared singleton for objects with no elements. */
extern HeapSlot *emptyObjectElements;
struct Class;
struct GCMarker;
struct ObjectOps;
struct Shape;
class NewObjectCache;
/*
* ObjectImpl specifies the internal implementation of an object. (In contrast
* JSObject specifies an "external" interface, at the conceptual level of that
* exposed in ECMAScript.)
*
* The |shape_| member stores the shape of the object, which includes the
* object's class and the layout of all its properties.
*
* The type member stores the type of the object, which contains its prototype
* object and the possible types of its properties.
*
* The rest of the object stores its named properties and indexed elements.
* These are stored separately from one another. Objects are followed by an
* variable-sized array of values for inline storage, which may be used by
* either properties of native objects (fixed slots) or by elements.
*
* Two native objects with the same shape are guaranteed to have the same
* number of fixed slots.
*
* Named property storage can be split between fixed slots and a dynamically
* allocated array (the slots member). For an object with N fixed slots, shapes
* with slots [0..N-1] are stored in the fixed slots, and the remainder are
* stored in the dynamic array. If all properties fit in the fixed slots, the
* 'slots' member is NULL.
*
* Elements are indexed via the 'elements' member. This member can point to
* either the shared emptyObjectElements singleton, into the inline value array
* (the address of the third value, to leave room for a ObjectElements header;
* in this case numFixedSlots() is zero) or to a dynamically allocated array.
*
* Only certain combinations of properties and elements storage are currently
* possible. This will be changing soon :XXX: bug 586842.
*
* - For objects other than arrays and typed arrays, the elements are empty.
*
* - For 'slow' arrays, both elements and properties are used, but the
* elements have zero capacity --- only the length member is used.
*
* - For dense arrays, elements are used and properties are not used.
*
* - For typed array buffers, elements are used and properties are not used.
* The data indexed by the elements do not represent Values, but primitive
* unboxed integers or floating point values.
*
* The members of this class are currently protected; in the long run this will
* will change so that some members are private, and only certain methods that
* act upon them will be protected.
*/
class ObjectImpl : public gc::Cell
{
protected:
/*
* Shape of the object, encodes the layout of the object's properties and
* all other information about its structure. See jsscope.h.
*/
HeapPtrShape shape_;
/*
* The object's type and prototype. For objects with the LAZY_TYPE flag
* set, this is the prototype's default 'new' type and can only be used
* to get that prototype.
*/
HeapPtrTypeObject type_;
HeapSlot *slots; /* Slots for object properties. */
HeapSlot *elements; /* Slots for object elements. */
private:
static void staticAsserts() {
MOZ_STATIC_ASSERT(sizeof(ObjectImpl) == sizeof(shadow::Object),
"shadow interface must match actual implementation");
MOZ_STATIC_ASSERT(sizeof(ObjectImpl) % sizeof(Value) == 0,
"fixed slots after an object must be aligned");
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
"shadow shape must match actual shape");
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
"shadow type must match actual type");
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
"shadow slots must match actual slots");
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
"shadow placeholder must match actual elements");
}
JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
protected:
friend struct GCMarker;
friend struct Shape;
friend class NewObjectCache;
/* Minimum size for dynamically allocated slots. */
static const uint32_t SLOT_CAPACITY_MIN = 8;
HeapSlot *fixedSlots() const {
return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
}
/*
* These functions are currently public for simplicity; in the long run
* it may make sense to make at least some of them private.
*/
public:
Shape * lastProperty() const {
MOZ_ASSERT(shape_);
return shape_;
}
types::TypeObject *type() const {
MOZ_ASSERT(!hasLazyType());
return type_;
}
size_t numFixedSlots() const {
return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
}
/*
* Whether this is the only object which has its specified type. This
* object will have its type constructed lazily as needed by analysis.
*/
bool hasSingletonType() const { return !!type_->singleton; }
/*
* Whether the object's type has not been constructed yet. If an object
* might have a lazy type, use getType() below, otherwise type().
*/
bool hasLazyType() const { return type_->lazy(); }
inline bool isNative() const;
const Shape * nativeLookup(JSContext *cx, jsid id);
inline Class *getClass() const;
inline JSClass *getJSClass() const;
inline bool hasClass(const Class *c) const;
inline const ObjectOps *getOps() const;
/*
* An object is a delegate if it is on another object's prototype or scope
* chain, and therefore the delegate might be asked implicitly to get or
* set a property on behalf of another object. Delegates may be accessed
* directly too, as may any object, but only those objects linked after the
* head of any prototype or scope chain are flagged as delegates. This
* definition helps to optimize shape-based property cache invalidation
* (see Purge{Scope,Proto}Chain in jsobj.cpp).
*/
inline bool isDelegate() const;
/*
* Return true if this object is a native one that has been converted from
* shared-immutable prototype-rooted shape storage to dictionary-shapes in
* a doubly-linked list.
*/
inline bool inDictionaryMode() const;
/*
* Get the number of dynamic slots to allocate to cover the properties in
* an object with the given number of fixed slots and slot span. The slot
* capacity is not stored explicitly, and the allocated size of the slot
* array is kept in sync with this count.
*/
static inline size_t dynamicSlotsCount(size_t nfixed, size_t span);
/* Memory usage functions. */
inline size_t sizeOfThis() const;
/* Elements accessors. */
ObjectElements * getElementsHeader() const {
return ObjectElements::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(); }
inline bool hasDynamicElements() const {
/*
* Note: for objects with zero fixed slots this could potentially give
* a spurious 'true' result, if the end of this object is exactly
* aligned with the end of its arena and dynamic slots are allocated
* immediately afterwards. Such cases cannot occur for dense arrays
* (which have at least two fixed slots) and can only result in a leak.
*/
return elements != emptyObjectElements && elements != fixedElements();
}
/* Write barrier support. */
static inline void readBarrier(ObjectImpl *obj);
static inline void writeBarrierPre(ObjectImpl *obj);
static inline void writeBarrierPost(ObjectImpl *obj, void *addr);
inline void privateWriteBarrierPre(void **oldval);
inline void privateWriteBarrierPost(void **oldval);
/* JIT Accessors */
static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
HeapPtrShape *addressOfShape() { return &shape_; }
static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
HeapPtrTypeObject *addressOfType() { return &type_; }
static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
static size_t offsetOfFixedElements() {
return sizeof(ObjectImpl) + sizeof(ObjectElements);
}
static size_t getFixedSlotOffset(size_t slot) {
return sizeof(ObjectImpl) + slot * sizeof(Value);
}
static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
/* These functions are public, and they should remain public. */
public:
JSObject * getProto() const {
return type_->proto;
}
inline bool isExtensible() const;
};
} /* namespace js */
#endif /* ObjectImpl_h__ */