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 : class ObjectImpl;
23 :
24 : class DenseElementsHeader;
25 : class SparseElementsHeader;
26 : class Uint8ElementsHeader;
27 : class Int8ElementsHeader;
28 : class Uint16ElementsHeader;
29 : class Int16ElementsHeader;
30 : class Uint32ElementsHeader;
31 : class Int32ElementsHeader;
32 : class Uint8ClampedElementsHeader;
33 : class Float32ElementsHeader;
34 : class Float64ElementsHeader;
35 : class ArrayBufferElementsHeader;
36 :
37 : enum ElementsKind {
38 : DenseElements,
39 : SparseElements,
40 : Uint8Elements,
41 : Int8Elements,
42 : Uint16Elements,
43 : Int16Elements,
44 : Uint32Elements,
45 : Int32Elements,
46 : Uint8ClampedElements,
47 : Float32Elements,
48 : Float64Elements,
49 : ArrayBufferElements
50 : };
51 :
52 : class ElementsHeader
53 : {
54 : protected:
55 : uint32_t type;
56 : uint32_t length; /* Array length, byte length of ArrayBuffer */
57 :
58 : union {
59 : class {
60 : friend class DenseElementsHeader;
61 : uint32_t initializedLength;
62 : uint32_t capacity;
63 : } dense;
64 : class {
65 : friend class SparseElementsHeader;
66 : Shape * shape;
67 : } sparse;
68 : };
69 :
70 : void staticAsserts() {
71 : MOZ_STATIC_ASSERT(sizeof(ElementsHeader) == ValuesPerHeader * sizeof(Value),
72 : "Elements size and values-per-Elements mismatch");
73 : }
74 :
75 : public:
76 0 : ElementsKind kind() const {
77 0 : MOZ_ASSERT(type <= ArrayBufferElements);
78 0 : return ElementsKind(type);
79 : }
80 :
81 0 : inline bool isDenseElements() const { return kind() == DenseElements; }
82 0 : inline bool isSparseElements() const { return kind() == SparseElements; }
83 : inline bool isUint8Elements() const { return kind() == Uint8Elements; }
84 : inline bool isInt8Elements() const { return kind() == Int8Elements; }
85 : inline bool isUint16Elements() const { return kind() == Uint16Elements; }
86 : inline bool isInt16Elements() const { return kind() == Int16Elements; }
87 : inline bool isUint32Elements() const { return kind() == Uint32Elements; }
88 : inline bool isInt32Elements() const { return kind() == Int32Elements; }
89 : inline bool isUint8ClampedElements() const { return kind() == Uint8ClampedElements; }
90 : inline bool isFloat32Elements() const { return kind() == Float32Elements; }
91 : inline bool isFloat64Elements() const { return kind() == Float64Elements; }
92 : inline bool isArrayBufferElements() const { return kind() == ArrayBufferElements; }
93 :
94 : inline DenseElementsHeader & asDenseElements();
95 : inline SparseElementsHeader & asSparseElements();
96 : inline Uint8ElementsHeader & asUint8Elements();
97 : inline Int8ElementsHeader & asInt8Elements();
98 : inline Uint16ElementsHeader & asUint16Elements();
99 : inline Int16ElementsHeader & asInt16Elements();
100 : inline Uint32ElementsHeader & asUint32Elements();
101 : inline Int32ElementsHeader & asInt32Elements();
102 : inline Uint8ClampedElementsHeader & asUint8ClampedElements();
103 : inline Float32ElementsHeader & asFloat32Elements();
104 : inline Float64ElementsHeader & asFloat64Elements();
105 : inline ArrayBufferElementsHeader & asArrayBufferElements();
106 :
107 : static ElementsHeader * fromElements(HeapSlot *elems) {
108 : return reinterpret_cast<ElementsHeader *>(uintptr_t(elems) - sizeof(ElementsHeader));
109 : }
110 :
111 : static const size_t ValuesPerHeader = 2;
112 : };
113 :
114 : class DenseElementsHeader : public ElementsHeader
115 : {
116 : public:
117 : uint32_t capacity() const {
118 : MOZ_ASSERT(ElementsHeader::isDenseElements());
119 : return dense.capacity;
120 : }
121 :
122 0 : uint32_t initializedLength() const {
123 0 : MOZ_ASSERT(ElementsHeader::isDenseElements());
124 0 : return dense.initializedLength;
125 : }
126 :
127 : uint32_t length() const {
128 : MOZ_ASSERT(ElementsHeader::isDenseElements());
129 : return ElementsHeader::length;
130 : }
131 :
132 : bool defineElement(JSContext *cx, ObjectImpl *obj,
133 : uint32_t index, const Value &value,
134 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
135 :
136 : private:
137 : inline bool isDenseElements() const MOZ_DELETE;
138 : inline DenseElementsHeader & asDenseElements() MOZ_DELETE;
139 :
140 : DenseElementsHeader(const DenseElementsHeader &other) MOZ_DELETE;
141 : void operator=(const DenseElementsHeader &other) MOZ_DELETE;
142 : };
143 :
144 : class SparseElementsHeader : public ElementsHeader
145 : {
146 : public:
147 : Shape * shape() {
148 : MOZ_ASSERT(ElementsHeader::isSparseElements());
149 : return sparse.shape;
150 : }
151 :
152 : uint32_t length() const {
153 : MOZ_ASSERT(ElementsHeader::isSparseElements());
154 : return ElementsHeader::length;
155 : }
156 :
157 : bool defineElement(JSContext *cx, ObjectImpl *obj,
158 : uint32_t index, const Value &value,
159 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
160 :
161 : private:
162 : inline bool isSparseElements() const MOZ_DELETE;
163 : inline SparseElementsHeader & asSparseElements() MOZ_DELETE;
164 :
165 : SparseElementsHeader(const SparseElementsHeader &other) MOZ_DELETE;
166 : void operator=(const SparseElementsHeader &other) MOZ_DELETE;
167 : };
168 :
169 : template <typename T>
170 : class TypedElementsHeader : public ElementsHeader
171 : {
172 : public:
173 : uint32_t byteLength() const {
174 : return ElementsHeader::length;
175 : }
176 :
177 : bool defineElement(JSContext *cx, ObjectImpl *obj,
178 : uint32_t index, const Value &value,
179 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
180 :
181 : private:
182 : TypedElementsHeader(const TypedElementsHeader &other) MOZ_DELETE;
183 : void operator=(const TypedElementsHeader &other) MOZ_DELETE;
184 : };
185 :
186 : class Uint8ElementsHeader : public TypedElementsHeader<uint8_t>
187 : {
188 : private:
189 : inline bool isUint8Elements() const MOZ_DELETE;
190 : inline Uint8ElementsHeader & asUint8Elements() MOZ_DELETE;
191 : Uint8ElementsHeader(const Uint8ElementsHeader &other) MOZ_DELETE;
192 : void operator=(const Uint8ElementsHeader &other) MOZ_DELETE;
193 : };
194 : class Int8ElementsHeader : public TypedElementsHeader<int8_t>
195 : {
196 : private:
197 : bool isInt8Elements() const MOZ_DELETE;
198 : Int8ElementsHeader & asInt8Elements() MOZ_DELETE;
199 : Int8ElementsHeader(const Int8ElementsHeader &other) MOZ_DELETE;
200 : void operator=(const Int8ElementsHeader &other) MOZ_DELETE;
201 : };
202 : class Uint16ElementsHeader : public TypedElementsHeader<uint16_t>
203 : {
204 : private:
205 : bool isUint16Elements() const MOZ_DELETE;
206 : Uint16ElementsHeader & asUint16Elements() MOZ_DELETE;
207 : Uint16ElementsHeader(const Uint16ElementsHeader &other) MOZ_DELETE;
208 : void operator=(const Uint16ElementsHeader &other) MOZ_DELETE;
209 : };
210 : class Int16ElementsHeader : public TypedElementsHeader<int16_t>
211 : {
212 : private:
213 : bool isInt16Elements() const MOZ_DELETE;
214 : Int16ElementsHeader & asInt16Elements() MOZ_DELETE;
215 : Int16ElementsHeader(const Int16ElementsHeader &other) MOZ_DELETE;
216 : void operator=(const Int16ElementsHeader &other) MOZ_DELETE;
217 : };
218 : class Uint32ElementsHeader : public TypedElementsHeader<uint32_t>
219 : {
220 : private:
221 : bool isUint32Elements() const MOZ_DELETE;
222 : Uint32ElementsHeader & asUint32Elements() MOZ_DELETE;
223 : Uint32ElementsHeader(const Uint32ElementsHeader &other) MOZ_DELETE;
224 : void operator=(const Uint32ElementsHeader &other) MOZ_DELETE;
225 : };
226 : class Int32ElementsHeader : public TypedElementsHeader<int32_t>
227 : {
228 : private:
229 : bool isInt32Elements() const MOZ_DELETE;
230 : Int32ElementsHeader & asInt32Elements() MOZ_DELETE;
231 : Int32ElementsHeader(const Int32ElementsHeader &other) MOZ_DELETE;
232 : void operator=(const Int32ElementsHeader &other) MOZ_DELETE;
233 : };
234 : class Float32ElementsHeader : public TypedElementsHeader<float>
235 : {
236 : private:
237 : bool isFloat32Elements() const MOZ_DELETE;
238 : Float32ElementsHeader & asFloat32Elements() MOZ_DELETE;
239 : Float32ElementsHeader(const Float32ElementsHeader &other) MOZ_DELETE;
240 : void operator=(const Float32ElementsHeader &other) MOZ_DELETE;
241 : };
242 : class Float64ElementsHeader : public TypedElementsHeader<double>
243 : {
244 : private:
245 : bool isFloat64Elements() const MOZ_DELETE;
246 : Float64ElementsHeader & asFloat64Elements() MOZ_DELETE;
247 : Float64ElementsHeader(const Float64ElementsHeader &other) MOZ_DELETE;
248 : void operator=(const Float64ElementsHeader &other) MOZ_DELETE;
249 : };
250 :
251 : class Uint8ClampedElementsHeader : public TypedElementsHeader<uint8_t>
252 : {
253 : private:
254 : inline bool isUint8Clamped() const MOZ_DELETE;
255 : inline Uint8ClampedElementsHeader & asUint8ClampedElements() MOZ_DELETE;
256 : Uint8ClampedElementsHeader(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
257 : void operator=(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
258 : };
259 :
260 : class ArrayBufferElementsHeader : public ElementsHeader
261 : {
262 : public:
263 : bool defineElement(JSContext *cx, ObjectImpl *obj,
264 : uint32_t index, const Value &value,
265 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
266 :
267 : private:
268 : inline bool isArrayBufferElements() const MOZ_DELETE;
269 : inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE;
270 :
271 : ArrayBufferElementsHeader(const ArrayBufferElementsHeader &other) MOZ_DELETE;
272 : void operator=(const ArrayBufferElementsHeader &other) MOZ_DELETE;
273 : };
274 :
275 : inline DenseElementsHeader &
276 : ElementsHeader::asDenseElements()
277 : {
278 : MOZ_ASSERT(isDenseElements());
279 : return *static_cast<DenseElementsHeader *>(this);
280 : }
281 :
282 : inline SparseElementsHeader &
283 0 : ElementsHeader::asSparseElements()
284 : {
285 0 : MOZ_ASSERT(isSparseElements());
286 0 : return *static_cast<SparseElementsHeader *>(this);
287 : }
288 :
289 : inline Uint8ElementsHeader &
290 : ElementsHeader::asUint8Elements()
291 : {
292 : MOZ_ASSERT(isUint8Elements());
293 : return *static_cast<Uint8ElementsHeader *>(this);
294 : }
295 :
296 : inline Int8ElementsHeader &
297 : ElementsHeader::asInt8Elements()
298 : {
299 : MOZ_ASSERT(isInt8Elements());
300 : return *static_cast<Int8ElementsHeader *>(this);
301 : }
302 :
303 : inline Uint16ElementsHeader &
304 : ElementsHeader::asUint16Elements()
305 : {
306 : MOZ_ASSERT(isUint16Elements());
307 : return *static_cast<Uint16ElementsHeader *>(this);
308 : }
309 :
310 : inline Int16ElementsHeader &
311 : ElementsHeader::asInt16Elements()
312 : {
313 : MOZ_ASSERT(isInt16Elements());
314 : return *static_cast<Int16ElementsHeader *>(this);
315 : }
316 :
317 : inline Uint32ElementsHeader &
318 : ElementsHeader::asUint32Elements()
319 : {
320 : MOZ_ASSERT(isUint32Elements());
321 : return *static_cast<Uint32ElementsHeader *>(this);
322 : }
323 :
324 : inline Int32ElementsHeader &
325 : ElementsHeader::asInt32Elements()
326 : {
327 : MOZ_ASSERT(isInt32Elements());
328 : return *static_cast<Int32ElementsHeader *>(this);
329 : }
330 :
331 : inline Uint8ClampedElementsHeader &
332 : ElementsHeader::asUint8ClampedElements()
333 : {
334 : MOZ_ASSERT(isUint8ClampedElements());
335 : return *static_cast<Uint8ClampedElementsHeader *>(this);
336 : }
337 :
338 : inline Float32ElementsHeader &
339 : ElementsHeader::asFloat32Elements()
340 : {
341 : MOZ_ASSERT(isFloat32Elements());
342 : return *static_cast<Float32ElementsHeader *>(this);
343 : }
344 :
345 : inline Float64ElementsHeader &
346 : ElementsHeader::asFloat64Elements()
347 : {
348 : MOZ_ASSERT(isFloat64Elements());
349 : return *static_cast<Float64ElementsHeader *>(this);
350 : }
351 :
352 : inline ArrayBufferElementsHeader &
353 : ElementsHeader::asArrayBufferElements()
354 : {
355 : MOZ_ASSERT(isArrayBufferElements());
356 : return *static_cast<ArrayBufferElementsHeader *>(this);
357 : }
358 :
359 : /*
360 : * Header structure for object element arrays. This structure is immediately
361 : * followed by an array of elements, with the elements member in an object
362 : * pointing to the beginning of that array (the end of this structure).
363 : * See below for usage of this structure.
364 : */
365 : class ObjectElements
366 : {
367 : friend struct ::JSObject;
368 : friend class ObjectImpl;
369 :
370 : /* Number of allocated slots. */
371 : uint32_t capacity;
372 :
373 : /*
374 : * Number of initialized elements. This is <= the capacity, and for arrays
375 : * is <= the length. Memory for elements above the initialized length is
376 : * uninitialized, but values between the initialized length and the proper
377 : * length are conceptually holes.
378 : */
379 : uint32_t initializedLength;
380 :
381 : /* 'length' property of array objects, unused for other objects. */
382 : uint32_t length;
383 :
384 : /* :XXX: bug 586842 store state about sparse slots. */
385 : uint32_t unused;
386 :
387 : void staticAsserts() {
388 : MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
389 : "Elements size and values-per-Elements mismatch");
390 : }
391 :
392 : public:
393 :
394 473715 : ObjectElements(uint32_t capacity, uint32_t length)
395 473715 : : capacity(capacity), initializedLength(0), length(length)
396 473715 : {}
397 :
398 291325 : HeapSlot *elements() { return (HeapSlot *)(uintptr_t(this) + sizeof(ObjectElements)); }
399 224613608 : static ObjectElements * fromElements(HeapSlot *elems) {
400 224613608 : return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements));
401 : }
402 :
403 18989 : static int offsetOfCapacity() {
404 18989 : return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements);
405 : }
406 137055 : static int offsetOfInitializedLength() {
407 137055 : return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements);
408 : }
409 42629 : static int offsetOfLength() {
410 42629 : return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements);
411 : }
412 :
413 : static const size_t VALUES_PER_HEADER = 2;
414 : };
415 :
416 : /* Shared singleton for objects with no elements. */
417 : extern HeapSlot *emptyObjectElements;
418 :
419 : struct Class;
420 : struct GCMarker;
421 : struct ObjectOps;
422 : struct Shape;
423 :
424 : class NewObjectCache;
425 :
426 : /*
427 : * ObjectImpl specifies the internal implementation of an object. (In contrast
428 : * JSObject specifies an "external" interface, at the conceptual level of that
429 : * exposed in ECMAScript.)
430 : *
431 : * The |shape_| member stores the shape of the object, which includes the
432 : * object's class and the layout of all its properties.
433 : *
434 : * The type member stores the type of the object, which contains its prototype
435 : * object and the possible types of its properties.
436 : *
437 : * The rest of the object stores its named properties and indexed elements.
438 : * These are stored separately from one another. Objects are followed by an
439 : * variable-sized array of values for inline storage, which may be used by
440 : * either properties of native objects (fixed slots) or by elements.
441 : *
442 : * Two native objects with the same shape are guaranteed to have the same
443 : * number of fixed slots.
444 : *
445 : * Named property storage can be split between fixed slots and a dynamically
446 : * allocated array (the slots member). For an object with N fixed slots, shapes
447 : * with slots [0..N-1] are stored in the fixed slots, and the remainder are
448 : * stored in the dynamic array. If all properties fit in the fixed slots, the
449 : * 'slots' member is NULL.
450 : *
451 : * Elements are indexed via the 'elements' member. This member can point to
452 : * either the shared emptyObjectElements singleton, into the inline value array
453 : * (the address of the third value, to leave room for a ObjectElements header;
454 : * in this case numFixedSlots() is zero) or to a dynamically allocated array.
455 : *
456 : * Only certain combinations of properties and elements storage are currently
457 : * possible. This will be changing soon :XXX: bug 586842.
458 : *
459 : * - For objects other than arrays and typed arrays, the elements are empty.
460 : *
461 : * - For 'slow' arrays, both elements and properties are used, but the
462 : * elements have zero capacity --- only the length member is used.
463 : *
464 : * - For dense arrays, elements are used and properties are not used.
465 : *
466 : * - For typed array buffers, elements are used and properties are not used.
467 : * The data indexed by the elements do not represent Values, but primitive
468 : * unboxed integers or floating point values.
469 : *
470 : * The members of this class are currently protected; in the long run this will
471 : * will change so that some members are private, and only certain methods that
472 : * act upon them will be protected.
473 : */
474 : class ObjectImpl : public gc::Cell
475 3385370 : {
476 : protected:
477 : /*
478 : * Shape of the object, encodes the layout of the object's properties and
479 : * all other information about its structure. See jsscope.h.
480 : */
481 : HeapPtrShape shape_;
482 :
483 : /*
484 : * The object's type and prototype. For objects with the LAZY_TYPE flag
485 : * set, this is the prototype's default 'new' type and can only be used
486 : * to get that prototype.
487 : */
488 : HeapPtrTypeObject type_;
489 :
490 : HeapSlot *slots; /* Slots for object properties. */
491 : HeapSlot *elements; /* Slots for object elements. */
492 :
493 : private:
494 : static void staticAsserts() {
495 : MOZ_STATIC_ASSERT(sizeof(ObjectImpl) == sizeof(shadow::Object),
496 : "shadow interface must match actual implementation");
497 : MOZ_STATIC_ASSERT(sizeof(ObjectImpl) % sizeof(Value) == 0,
498 : "fixed slots after an object must be aligned");
499 :
500 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
501 : "shadow shape must match actual shape");
502 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
503 : "shadow type must match actual type");
504 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
505 : "shadow slots must match actual slots");
506 : MOZ_STATIC_ASSERT(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
507 : "shadow placeholder must match actual elements");
508 : }
509 :
510 104938476 : JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
511 :
512 : /* These functions are public, and they should remain public. */
513 :
514 : public:
515 204013694 : JSObject * getProto() const {
516 204013694 : return type_->proto;
517 : }
518 :
519 : inline bool isExtensible() const;
520 :
521 : /*
522 : * XXX Once the property/element split of bug 586842 is complete, these
523 : * methods should move back to JSObject.
524 : */
525 : inline bool isDenseArray() const;
526 : inline bool isSlowArray() const;
527 : inline bool isArray() const;
528 :
529 : inline HeapSlotArray getDenseArrayElements();
530 : inline const Value & getDenseArrayElement(uint32_t idx);
531 : inline uint32_t getDenseArrayInitializedLength();
532 :
533 0 : bool makeElementsSparse(JSContext *cx) {
534 0 : NEW_OBJECT_REPRESENTATION_ONLY();
535 :
536 : MOZ_NOT_REACHED("NYI");
537 : return false;
538 : }
539 :
540 : protected:
541 : #ifdef DEBUG
542 : void checkShapeConsistency();
543 : #else
544 : void checkShapeConsistency() { }
545 : #endif
546 :
547 : private:
548 : /*
549 : * Get internal pointers to the range of values starting at start and
550 : * running for length.
551 : */
552 : inline void getSlotRangeUnchecked(uint32_t start, uint32_t length,
553 : HeapSlot **fixedStart, HeapSlot **fixedEnd,
554 : HeapSlot **slotsStart, HeapSlot **slotsEnd);
555 : inline void getSlotRange(uint32_t start, uint32_t length,
556 : HeapSlot **fixedStart, HeapSlot **fixedEnd,
557 : HeapSlot **slotsStart, HeapSlot **slotsEnd);
558 :
559 : protected:
560 : friend struct GCMarker;
561 : friend struct Shape;
562 : friend class NewObjectCache;
563 :
564 : inline bool hasContiguousSlots(uint32_t start, uint32_t count) const;
565 :
566 : inline void invalidateSlotRange(uint32_t start, uint32_t count);
567 : inline void initializeSlotRange(uint32_t start, uint32_t count);
568 :
569 : /*
570 : * Initialize a flat array of slots to this object at a start slot. The
571 : * caller must ensure that are enough slots.
572 : */
573 : void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
574 :
575 : /*
576 : * Copy a flat array of slots to this object at a start slot. Caller must
577 : * ensure there are enough slots in this object.
578 : */
579 : void copySlotRange(uint32_t start, const Value *vector, uint32_t length);
580 :
581 : #ifdef DEBUG
582 : enum SentinelAllowed {
583 : SENTINEL_NOT_ALLOWED,
584 : SENTINEL_ALLOWED
585 : };
586 :
587 : /*
588 : * Check that slot is in range for the object's allocated slots.
589 : * If sentinelAllowed then slot may equal the slot capacity.
590 : */
591 : bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
592 : #endif
593 :
594 : /* Minimum size for dynamically allocated slots. */
595 : static const uint32_t SLOT_CAPACITY_MIN = 8;
596 :
597 296858016 : HeapSlot *fixedSlots() const {
598 296858016 : return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
599 : }
600 :
601 : friend class ElementsHeader;
602 : friend class DenseElementsHeader;
603 : friend class SparseElementsHeader;
604 :
605 : enum DenseElementsResult {
606 : Failure,
607 : ConvertToSparse,
608 : Succeeded
609 : };
610 :
611 0 : DenseElementsResult ensureDenseElementsInitialized(JSContext *cx, uint32_t index,
612 : uint32_t extra)
613 : {
614 0 : NEW_OBJECT_REPRESENTATION_ONLY();
615 :
616 : MOZ_NOT_REACHED("NYI");
617 : return Failure;
618 : }
619 :
620 : /*
621 : * These functions are currently public for simplicity; in the long run
622 : * it may make sense to make at least some of them private.
623 : */
624 :
625 : public:
626 -1 : Shape * lastProperty() const {
627 -1 : MOZ_ASSERT(shape_);
628 -1 : return shape_;
629 : }
630 :
631 : inline bool isNative() const;
632 :
633 99318882 : types::TypeObject *type() const {
634 99318882 : MOZ_ASSERT(!hasLazyType());
635 99318882 : return type_;
636 : }
637 :
638 1657710731 : uint32_t numFixedSlots() const {
639 1657710731 : return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
640 : }
641 :
642 : /*
643 : * Whether this is the only object which has its specified type. This
644 : * object will have its type constructed lazily as needed by analysis.
645 : */
646 95737434 : bool hasSingletonType() const { return !!type_->singleton; }
647 :
648 : /*
649 : * Whether the object's type has not been constructed yet. If an object
650 : * might have a lazy type, use getType() below, otherwise type().
651 : */
652 146917424 : bool hasLazyType() const { return type_->lazy(); }
653 :
654 : inline uint32_t slotSpan() const;
655 :
656 : /* Compute dynamicSlotsCount() for this object. */
657 : inline uint32_t numDynamicSlots() const;
658 :
659 : const Shape * nativeLookup(JSContext *cx, jsid id);
660 :
661 : inline Class *getClass() const;
662 : inline JSClass *getJSClass() const;
663 : inline bool hasClass(const Class *c) const;
664 : inline const ObjectOps *getOps() const;
665 :
666 : /*
667 : * An object is a delegate if it is on another object's prototype or scope
668 : * chain, and therefore the delegate might be asked implicitly to get or
669 : * set a property on behalf of another object. Delegates may be accessed
670 : * directly too, as may any object, but only those objects linked after the
671 : * head of any prototype or scope chain are flagged as delegates. This
672 : * definition helps to optimize shape-based property cache invalidation
673 : * (see Purge{Scope,Proto}Chain in jsobj.cpp).
674 : */
675 : inline bool isDelegate() const;
676 :
677 : /*
678 : * Return true if this object is a native one that has been converted from
679 : * shared-immutable prototype-rooted shape storage to dictionary-shapes in
680 : * a doubly-linked list.
681 : */
682 : inline bool inDictionaryMode() const;
683 :
684 179766087 : const Value &getSlot(uint32_t slot) const {
685 179766087 : MOZ_ASSERT(slotInRange(slot));
686 179766087 : uint32_t fixed = numFixedSlots();
687 179766087 : if (slot < fixed)
688 93023132 : return fixedSlots()[slot];
689 86742955 : return slots[slot - fixed];
690 : }
691 :
692 151526061 : HeapSlot *getSlotAddressUnchecked(uint32_t slot) {
693 151526061 : uint32_t fixed = numFixedSlots();
694 151526061 : if (slot < fixed)
695 68985043 : return fixedSlots() + slot;
696 82541018 : return slots + (slot - fixed);
697 : }
698 :
699 132882622 : HeapSlot *getSlotAddress(uint32_t slot) {
700 : /*
701 : * This can be used to get the address of the end of the slots for the
702 : * object, which may be necessary when fetching zero-length arrays of
703 : * slots (e.g. for callObjVarArray).
704 : */
705 132882622 : MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
706 132882622 : return getSlotAddressUnchecked(slot);
707 : }
708 :
709 132328864 : HeapSlot &getSlotRef(uint32_t slot) {
710 132328864 : MOZ_ASSERT(slotInRange(slot));
711 132328864 : return *getSlotAddress(slot);
712 : }
713 :
714 : inline HeapSlot &nativeGetSlotRef(uint32_t slot);
715 : inline const Value &nativeGetSlot(uint32_t slot) const;
716 :
717 : inline void setSlot(uint32_t slot, const Value &value);
718 : inline void initSlot(uint32_t slot, const Value &value);
719 : inline void initSlotUnchecked(uint32_t slot, const Value &value);
720 :
721 : /* For slots which are known to always be fixed, due to the way they are allocated. */
722 :
723 47 : HeapSlot &getFixedSlotRef(uint32_t slot) {
724 47 : MOZ_ASSERT(slot < numFixedSlots());
725 47 : return fixedSlots()[slot];
726 : }
727 :
728 46031823 : const Value &getFixedSlot(uint32_t slot) const {
729 46031823 : MOZ_ASSERT(slot < numFixedSlots());
730 46031823 : return fixedSlots()[slot];
731 : }
732 :
733 : inline void setFixedSlot(uint32_t slot, const Value &value);
734 : inline void initFixedSlot(uint32_t slot, const Value &value);
735 :
736 : /*
737 : * Get the number of dynamic slots to allocate to cover the properties in
738 : * an object with the given number of fixed slots and slot span. The slot
739 : * capacity is not stored explicitly, and the allocated size of the slot
740 : * array is kept in sync with this count.
741 : */
742 : static inline uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span);
743 :
744 : /* Memory usage functions. */
745 : inline size_t sizeOfThis() const;
746 :
747 : /* Elements accessors. */
748 :
749 224608873 : ObjectElements * getElementsHeader() const {
750 224608873 : return ObjectElements::fromElements(elements);
751 : }
752 :
753 0 : ElementsHeader & elementsHeader() const {
754 0 : NEW_OBJECT_REPRESENTATION_ONLY();
755 : return *ElementsHeader::fromElements(elements);
756 : }
757 :
758 8755742 : inline HeapSlot *fixedElements() const {
759 : MOZ_STATIC_ASSERT(2 * sizeof(Value) == sizeof(ObjectElements),
760 : "when elements are stored inline, the first two "
761 : "slots will hold the ObjectElements header");
762 8755742 : return &fixedSlots()[2];
763 : }
764 :
765 2266237 : void setFixedElements() { this->elements = fixedElements(); }
766 :
767 33975208 : inline bool hasDynamicElements() const {
768 : /*
769 : * Note: for objects with zero fixed slots this could potentially give
770 : * a spurious 'true' result, if the end of this object is exactly
771 : * aligned with the end of its arena and dynamic slots are allocated
772 : * immediately afterwards. Such cases cannot occur for dense arrays
773 : * (which have at least two fixed slots) and can only result in a leak.
774 : */
775 33975208 : return elements != emptyObjectElements && elements != fixedElements();
776 : }
777 :
778 : /* GC support. */
779 : static inline void readBarrier(ObjectImpl *obj);
780 : static inline void writeBarrierPre(ObjectImpl *obj);
781 : static inline void writeBarrierPost(ObjectImpl *obj, void *addr);
782 : inline void privateWriteBarrierPre(void **oldval);
783 : inline void privateWriteBarrierPost(void **oldval);
784 : void markChildren(JSTracer *trc);
785 :
786 : /* Private data accessors. */
787 :
788 : inline void *&privateRef(uint32_t nfixed) const; /* XXX should be private, not protected! */
789 :
790 : inline bool hasPrivate() const;
791 : inline void *getPrivate() const;
792 : inline void setPrivate(void *data);
793 : inline void setPrivateUnbarriered(void *data);
794 : inline void initPrivate(void *data);
795 :
796 : /* Access private data for an object with a known number of fixed slots. */
797 : inline void *getPrivate(uint32_t nfixed) const;
798 :
799 : /* JIT Accessors */
800 326661 : static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
801 663478 : HeapPtrShape *addressOfShape() { return &shape_; }
802 :
803 112495 : static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
804 244412 : HeapPtrTypeObject *addressOfType() { return &type_; }
805 :
806 153830 : static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
807 17924 : static size_t offsetOfFixedElements() {
808 17924 : return sizeof(ObjectImpl) + sizeof(ObjectElements);
809 : }
810 :
811 130653 : static size_t getFixedSlotOffset(size_t slot) {
812 130653 : return sizeof(ObjectImpl) + slot * sizeof(Value);
813 : }
814 31610 : static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
815 571997 : static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
816 : };
817 :
818 : extern bool
819 : DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const Value &value,
820 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
821 :
822 : } /* namespace js */
823 :
824 : #endif /* ObjectImpl_h__ */
|