1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=78:
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #ifndef ObjectImpl_h___
9 : #define ObjectImpl_h___
10 :
11 : #include "mozilla/Assertions.h"
12 : #include "mozilla/StandardInteger.h"
13 :
14 : #include "jsfriendapi.h"
15 : #include "jsinfer.h"
16 : #include "jsval.h"
17 :
18 : #include "gc/Barrier.h"
19 :
20 : namespace js {
21 :
22 : /*
23 : * Header structure for object element arrays. This structure is immediately
24 : * followed by an array of elements, with the elements member in an object
25 : * pointing to the beginning of that array (the end of this structure).
26 : * See below for usage of this structure.
27 : */
28 : class ObjectElements
29 : {
30 : friend struct ::JSObject;
31 :
32 : /* Number of allocated slots. */
33 : uint32_t capacity;
34 :
35 : /*
36 : * Number of initialized elements. This is <= the capacity, and for arrays
37 : * is <= the length. Memory for elements above the initialized length is
38 : * uninitialized, but values between the initialized length and the proper
39 : * length are conceptually holes.
40 : */
41 : uint32_t initializedLength;
42 :
43 : /* 'length' property of array objects, unused for other objects. */
44 : uint32_t length;
45 :
46 : /* :XXX: bug 586842 store state about sparse slots. */
47 : uint32_t unused;
48 :
49 : void staticAsserts() {
50 : MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
51 : "Elements size and values-per-Elements mismatch");
52 : }
53 :
54 : public:
55 :
56 414569 : ObjectElements(uint32_t capacity, uint32_t length)
57 414569 : : capacity(capacity), initializedLength(0), length(length)
58 414569 : {}
59 :
60 608242 : HeapSlot *elements() { return (HeapSlot *)(uintptr_t(this) + sizeof(ObjectElements)); }
61 508541724 : static ObjectElements * fromElements(HeapSlot *elems) {
62 508541724 : return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements));
63 : }
64 :
65 18999 : static int offsetOfCapacity() {
66 18999 : return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements);
67 : }
68 138687 : static int offsetOfInitializedLength() {
69 138687 : return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements);
70 : }
71 44865 : static int offsetOfLength() {
72 44865 : return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements);
73 : }
74 :
75 : static const size_t VALUES_PER_HEADER = 2;
76 : };
77 :
78 : /* Shared singleton for objects with no elements. */
79 : extern HeapSlot *emptyObjectElements;
80 :
81 : struct Class;
82 : struct GCMarker;
83 : struct ObjectOps;
84 : struct Shape;
85 :
86 : class NewObjectCache;
87 :
88 : /*
89 : * ObjectImpl specifies the internal implementation of an object. (In contrast
90 : * JSObject specifies an "external" interface, at the conceptual level of that
91 : * exposed in ECMAScript.)
92 : *
93 : * The |shape_| member stores the shape of the object, which includes the
94 : * object's class and the layout of all its properties.
95 : *
96 : * The type member stores the type of the object, which contains its prototype
97 : * object and the possible types of its properties.
98 : *
99 : * The rest of the object stores its named properties and indexed elements.
100 : * These are stored separately from one another. Objects are followed by an
101 : * variable-sized array of values for inline storage, which may be used by
102 : * either properties of native objects (fixed slots) or by elements.
103 : *
104 : * Two native objects with the same shape are guaranteed to have the same
105 : * number of fixed slots.
106 : *
107 : * Named property storage can be split between fixed slots and a dynamically
108 : * allocated array (the slots member). For an object with N fixed slots, shapes
109 : * with slots [0..N-1] are stored in the fixed slots, and the remainder are
110 : * stored in the dynamic array. If all properties fit in the fixed slots, the
111 : * 'slots' member is NULL.
112 : *
113 : * Elements are indexed via the 'elements' member. This member can point to
114 : * either the shared emptyObjectElements singleton, into the inline value array
115 : * (the address of the third value, to leave room for a ObjectElements header;
116 : * in this case numFixedSlots() is zero) or to a dynamically allocated array.
117 : *
118 : * Only certain combinations of properties and elements storage are currently
119 : * possible. This will be changing soon :XXX: bug 586842.
120 : *
121 : * - For objects other than arrays and typed arrays, the elements are empty.
122 : *
123 : * - For 'slow' arrays, both elements and properties are used, but the
124 : * elements have zero capacity --- only the length member is used.
125 : *
126 : * - For dense arrays, elements are used and properties are not used.
127 : *
128 : * - For typed array buffers, elements are used and properties are not used.
129 : * The data indexed by the elements do not represent Values, but primitive
130 : * unboxed integers or floating point values.
131 : *
132 : * The members of this class are currently protected; in the long run this will
133 : * will change so that some members are private, and only certain methods that
134 : * act upon them will be protected.
135 : */
136 : class ObjectImpl : public gc::Cell
137 3737027 : {
138 : protected:
139 : /*
140 : * Shape of the object, encodes the layout of the object's properties and
141 : * all other information about its structure. See jsscope.h.
142 : */
143 : HeapPtrShape shape_;
144 :
145 : /*
146 : * The object's type and prototype. For objects with the LAZY_TYPE flag
147 : * set, this is the prototype's default 'new' type and can only be used
148 : * to get that prototype.
149 : */
150 : HeapPtrTypeObject type_;
151 :
152 : HeapSlot *slots; /* Slots for object properties. */
153 : HeapSlot *elements; /* Slots for object elements. */
154 :
155 : private:
156 : static void staticAsserts() {
157 : MOZ_STATIC_ASSERT(sizeof(ObjectImpl) == sizeof(shadow::Object),
158 : "shadow interface must match actual implementation");
159 : MOZ_STATIC_ASSERT(sizeof(ObjectImpl) % sizeof(Value) == 0,
160 : "fixed slots after an object must be aligned");
161 :
162 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
163 : "shadow shape must match actual shape");
164 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
165 : "shadow type must match actual type");
166 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
167 : "shadow slots must match actual slots");
168 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
169 : "shadow placeholder must match actual elements");
170 : }
171 :
172 3335693 : JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
173 :
174 : protected:
175 : friend struct GCMarker;
176 : friend struct Shape;
177 : friend class NewObjectCache;
178 :
179 : /* Minimum size for dynamically allocated slots. */
180 : static const uint32_t SLOT_CAPACITY_MIN = 8;
181 :
182 423521024 : HeapSlot *fixedSlots() const {
183 423521024 : return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
184 : }
185 :
186 : /*
187 : * These functions are currently public for simplicity; in the long run
188 : * it may make sense to make at least some of them private.
189 : */
190 :
191 : public:
192 -1 : Shape * lastProperty() const {
193 -1 : MOZ_ASSERT(shape_);
194 -1 : return shape_;
195 : }
196 :
197 135435317 : types::TypeObject *type() const {
198 135435317 : MOZ_ASSERT(!hasLazyType());
199 135435317 : return type_;
200 : }
201 :
202 -1876973095 : size_t numFixedSlots() const {
203 -1876973095 : return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
204 : }
205 :
206 : /*
207 : * Whether this is the only object which has its specified type. This
208 : * object will have its type constructed lazily as needed by analysis.
209 : */
210 133344137 : bool hasSingletonType() const { return !!type_->singleton; }
211 :
212 : /*
213 : * Whether the object's type has not been constructed yet. If an object
214 : * might have a lazy type, use getType() below, otherwise type().
215 : */
216 183786396 : bool hasLazyType() const { return type_->lazy(); }
217 :
218 : inline bool isNative() const;
219 :
220 : const Shape * nativeLookup(JSContext *cx, jsid id);
221 :
222 : inline Class *getClass() const;
223 : inline JSClass *getJSClass() const;
224 : inline bool hasClass(const Class *c) const;
225 : inline const ObjectOps *getOps() const;
226 :
227 : /*
228 : * An object is a delegate if it is on another object's prototype or scope
229 : * chain, and therefore the delegate might be asked implicitly to get or
230 : * set a property on behalf of another object. Delegates may be accessed
231 : * directly too, as may any object, but only those objects linked after the
232 : * head of any prototype or scope chain are flagged as delegates. This
233 : * definition helps to optimize shape-based property cache invalidation
234 : * (see Purge{Scope,Proto}Chain in jsobj.cpp).
235 : */
236 : inline bool isDelegate() const;
237 :
238 : /*
239 : * Return true if this object is a native one that has been converted from
240 : * shared-immutable prototype-rooted shape storage to dictionary-shapes in
241 : * a doubly-linked list.
242 : */
243 : inline bool inDictionaryMode() const;
244 :
245 : /*
246 : * Get the number of dynamic slots to allocate to cover the properties in
247 : * an object with the given number of fixed slots and slot span. The slot
248 : * capacity is not stored explicitly, and the allocated size of the slot
249 : * array is kept in sync with this count.
250 : */
251 : static inline size_t dynamicSlotsCount(size_t nfixed, size_t span);
252 :
253 : /* Memory usage functions. */
254 : inline size_t sizeOfThis() const;
255 :
256 : /* Elements accessors. */
257 :
258 508531686 : ObjectElements * getElementsHeader() const {
259 508531686 : return ObjectElements::fromElements(elements);
260 : }
261 :
262 10929685 : inline HeapSlot *fixedElements() const {
263 : MOZ_STATIC_ASSERT(2 * sizeof(Value) == sizeof(ObjectElements),
264 : "when elements are stored inline, the first two "
265 : "slots will hold the ObjectElements header");
266 10929685 : return &fixedSlots()[2];
267 : }
268 :
269 2960481 : void setFixedElements() { this->elements = fixedElements(); }
270 :
271 49742191 : inline bool hasDynamicElements() const {
272 : /*
273 : * Note: for objects with zero fixed slots this could potentially give
274 : * a spurious 'true' result, if the end of this object is exactly
275 : * aligned with the end of its arena and dynamic slots are allocated
276 : * immediately afterwards. Such cases cannot occur for dense arrays
277 : * (which have at least two fixed slots) and can only result in a leak.
278 : */
279 49742191 : return elements != emptyObjectElements && elements != fixedElements();
280 : }
281 :
282 : /* GC support. */
283 : static inline void readBarrier(ObjectImpl *obj);
284 : static inline void writeBarrierPre(ObjectImpl *obj);
285 : static inline void writeBarrierPost(ObjectImpl *obj, void *addr);
286 : inline void privateWriteBarrierPre(void **oldval);
287 : inline void privateWriteBarrierPost(void **oldval);
288 : void markChildren(JSTracer *trc);
289 :
290 : /* JIT Accessors */
291 992256 : static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
292 776524 : HeapPtrShape *addressOfShape() { return &shape_; }
293 :
294 119327 : static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
295 373937 : HeapPtrTypeObject *addressOfType() { return &type_; }
296 :
297 158765 : static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
298 19251 : static size_t offsetOfFixedElements() {
299 19251 : return sizeof(ObjectImpl) + sizeof(ObjectElements);
300 : }
301 :
302 251949 : static size_t getFixedSlotOffset(size_t slot) {
303 251949 : return sizeof(ObjectImpl) + slot * sizeof(Value);
304 : }
305 36433 : static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
306 1225568 : static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
307 :
308 : /* These functions are public, and they should remain public. */
309 :
310 : public:
311 309269929 : JSObject * getProto() const {
312 309269929 : return type_->proto;
313 : }
314 :
315 : inline bool isExtensible() const;
316 : };
317 :
318 : } /* namespace js */
319 :
320 : #endif /* ObjectImpl_h__ */
|